OpenCE gametypes named in the server browser (network version 37), and
the host may leave the shield effects to each player (SHIELD EFFECTS'
PLAYERS' OWN, network version 38). The conflict: our Android listing
declarations stay beside upstream's p2p_set_game_listing with its new
kind.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
New gametypes (SWAT, Infection, Gun Game, Hardcore), shield effects the
host's choice in network games, co-op ally friendly fire, network fixes
(scenery shields, tripmines, co-op teleports), Custom Edition HUD and
texture fixes, ASTC for Android GPUs without S3TC.
Left out on purpose: upstream's two Android workarounds for Mali phones,
the GL shadow state refreshed before every draw (prepare_draw) and the
geometry cache bypassed (mirror_range). Both would cost every draw of
both eyes on the Quest, which never showed the corruption they work
around; their tests are skipped. Conflicts: the GL capabilities log
keeps multiview and adds ASTC; xbox_textures.c keeps vr.c's texture work
counters; README.md stays the player's.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Server Setup's Co-op Options has ALLY FRIENDLY FIRE
(network.coop_ally_friendly_fire), ON by default as in the campaign. OFF,
the players' weapons, grenades, melee and vehicles do their AI allies no
damage, so that no player can kill Captain Keyes on Truth and
Reconciliation, the Marines, or the other allies a level needs. The AI's
own hits of its allies, the enemies' damage, and FRIENDLY FIRE between
players are unchanged. A hit is the players' when its owner is a player
and the victim is a friendly unit that is no player's, so friendly-team
vehicles are immune to the players too, splatter included. An ally that
cannot die cannot raise an allegiance incident, so the players cannot turn
the Marines hostile either.
The rule is in game_engine_friendly_damage (game_engine.c), which only the
host's damage reaches: a client's hits are the host's to deal. The host
sends the choice with the game's settings, as bit 1 of network_game's
cooperative_flags beside PLAYER COLLISIONS', so network version 33: a
client of version 32 would play the game's settings without it. NETCODE.md
says so, and network_format.txt is recorded for 33.
The menu row is tools/port_settings.py's (COOP_SETUP_SCREENS); only the
server settings screen was written again. Its 8 rows fit above the help
area.
Checked: the Windows build; the harness tests, the new
test_coop_ally_friendly_fire (a player's hit of an ally ON and OFF, the
AI's own hit, players' friendly fire in every mode, no unit, the campaign
without co-op, and four negative controls) and test_coop_scaling_menu with
the eighth row; network_format.py; the Co-op Options screen drawn with the
row; and in play as the host on a10 and a50 (Keyes and the Marines
unharmed with OFF) and b30 (no splatter). Not yet: a client's hits online,
d20's ending, c20's Sentinels.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ringfall's side of it:
- The bots: OpenCE's own (bots.c, a local split screen game's) are not
used in VR builds (their lobby hook would take Ringfall's host bots
off, and their bots.count and bots.skill differ); Ringfall's are now
host_bots.c, so that OpenCE's bots.c merges as it changes. Each
platform's bots.count and bots.skill are its own (config_setting_index
takes this platform's of two of a name).
- HDR is never on in VR (d3d8_gl.c); the flat window's present is
OpenCE's, inside the VR port's branch for it.
- The VR frame begins where the events are pumped (sdl_platform.c), as
before, now that exit_after_check is apart.
- The message numbers: OpenCE's aim assist policy (90) before the VR
port's poses (240), which stay last.
- The visibility counters keep the VR port's snapshot ring (both eyes'
counts halved); OpenCE's tone mapping goes before the antialiasing, off
the VR eyes' pass.
- Join codes, the online list and OpenCE's probes all in the signalling
topics; the HUD's PNG helpers both ways; the disc import keeps the
language file.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Several of the fixes taken from the forks changed source/ without the
port: comment that marks a change from the original (the second copy's
datagram ports, the downloaded maps' refusals, the main menu's clock,
the one-magazine HUD states, the render lists' sizes and others), and a
comment still named a function of that fork's. Each change now says so.
network_game_server_dispose keeps the Xbox's one-second grace period
(SleepEx) only for builds other than Windows, Android and Linux, whose
transports need none; the web build is no __linux__ to Emscripten, so it
still waited a second each time a hosted game ended. It is left out there
too.
(cherry picked from the server part of commit bea41d710988e9aeac6cec44f4fd69b5203906e2,
whose dispose change OpenCE already had for the native builds)
A second game on one computer listens on another port and hears none of the
host's broadcast advertisements, and the host answered searches no more
than once each advertisement interval. Such a searcher is now answered
directly every time; the broadcast keeps its interval.
(cherry picked from commit b49c83d1c871a23f76825bdcdc52a228167f1c37)
The unreliable queue kept only a datagram's source address, so every
reader saw port 0. The host's answers to where a client's datagrams come
from (a second game on its computer, a direct answer to a game search) went
to port 0. The queue now keeps the port after the address.
(cherry picked from commit 781b98e9333c2cb85a85360267b24cc6656100c1)
Both games bound the client port (SO_REUSEADDR lets Windows share it and
hands each datagram to one of them), the host matched a distributed
datagram to the first machine at its address (its own), and sent every
client's per-tick datagrams to the fixed client port. The second game got
only the reliable messages: no units, no spawn, no co-op cutscene camera,
its camera left at the origin (the purple screen), and in PvP it waited
for space to clear.
A client now listens on any free port when another game has the client
port, the host takes a distributed datagram from the machine at its address
that isn't its own before its own, and answers each machine where its
datagrams come from. A game search from another port is answered there too.
(cherry picked from commit 0f4e71eba0787b8d3cd28c436cdb44ec6d79abda)
A machine that asked to join as a game ended, before the server switched
to the pregame, was left waiting behind the one the server holds: the
server refused every later join with "network_game_add_player() failed"
and sat in the lobby for good. A host that starts its next game by itself
(network_test.c's host, which the dedicated servers run) never recovered.
Those joins are now dropped when the next game starts. Only the host's own
bookkeeping changes; nothing on the wire does.
From JoshRob297's halo-ce-touch (18a6fc58), reworked for our tree, which
has no network_game_server_port_set_minimum_players.
Co-authored-by: JoshRob297 <99092299+JoshRob297@users.noreply.github.com>
(cherry picked from commit 4582817b2bb4241b53bfa4c523f02aa267595feb)
(cherry picked from commit be7362f2d0b9983e3e12a25f5c76871be5e9132f)
Several of the fixes taken from the forks changed source/ without the
port: comment that marks a change from the original, and three removed
the notes on the original's bugs without saying they were fixed. Each
change now says so.
The packet table had begin game, graceful exit and keep-alive each on its
neighbor's field list (the Xbox game's table order is not their type
order), so a keep-alive's short was encoded and decoded as a long: the host
sent 2 bytes of stack past it, and a client wrote 2 bytes from the network
past it on its stack. The field lists now sit under the messages whose wire
they describe, and the keep-alive is a long. Not a byte on the wire moves:
begin game still carries a short (16 bits of its long), exit and keep-alive
a long, so OpenCE and earlier builds play as before; the keep-alive's 2
bytes that came off the stack are zero now. tools/test_network_messages.py
encodes every message under AddressSanitizer and compares the bytes with
upstream's table.
(cherry picked from commit ee32bdad42615402053291344e3c89f8bcc04161)
A machine still downloading the map when the game started has its players held out of it until the download finishes (OpenCE's). One whose download did not finish before the game ended came back to the pregame without its players, as the reset dropped the held ones; they are put back in the game's list instead, as the other players are kept.
(cherry picked from commit 6aa90bfb59557b8c98e2c8543aa4c42d9e3918c1)
The bots make room for a person who joins, and the server browser's
listing counted their slots as free, but the LAN advertisement and the
join's check still asked for a free slot: with 15 bots and the host a
lobby of 16 was advertised closed, and a Quest on the LAN was refused
("attempted to join a closed game"). Both now count a bot's slot in a
lobby as a person's, as the listing does (network_game_server_room_for_person).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Computer players for a game played on this computer alone: bots.count (0,
the default, to 15) of them join the lobby of a local split screen Slayer
game, as far as it has room, on the teams bots.teams asks for ("even", or
"against" the players), and follow the players' team changes there. A bot
is the one player of a machine of its own at the top of the machine indices
(113 up), which no real machine takes, so every machine of the game - only
this one - spawns, respawns and scores it as any player.
network_server_manager.c adds and removes them in the pregame;
players_update_before_game takes each bot's action of the tick from
port/linux/game/bots.c in place of its empty queue.
A bot looks for enemies (the AI's line of sight, its skill's reach and
field of view), reacts, turns at a limited speed with an aim error that
settles and leads by its weapon's projectile speed, fires in bursts or a
press a shot, throws grenades, strikes close up and strafes; otherwise it
goes where an enemy was last seen, to a better weapon lying near (the
action button once the game offers the swap), or about the map's starting
locations and item spawns. It walks the paths the campaign's AI finds:
path.c's searches over the walkable surfaces every stock multiplayer map
carries, on a copy of them less those with no room above (Longest's walls)
and those under scenery or machines its path's obstacle avoidance found no
way past (Sidewinder's blast door); stuck, it jumps, sidesteps and looks
again. The searches run in the tick, three a tick at most, so two runs of
the same input play the same. bots.skill sets reaction, sight, aim, turning
and bursts; debug.bot_trace logs each bot's state.
Nothing changes in system link or internet games: no bot joins a game that
accepts remote connections, and bots_update_actions returns unless a local
game runs, so nothing the machines send each other changes and the network
version stays the same. Other gametypes get no bots yet (their goals come
in a later change). The code is BirchWoodGod's, from the Halo CE for PS
Vita port's offline bots, contributed under CC0; this is their core.
Checked (Linux, debug and release builds, SDL's offscreen video driver,
debug.network_test "local:" with debug.test_input "bot:1" as the player):
- 150 s games on Blood Gulch (Slayer, 6 bots; Team Slayer, 7, legendary),
Chill Out (Team Slayer, 5, heroic), Longest (Slayer, 8), Sidewinder (Team
Slayer, 9), Hang 'em High (Team Slayer, 5, "against"), Damnation (Slayer,
6, easy) and Prisoner (Slayer, 15): every bot walked 125-280 units, the
bots killed 7-118 times and died, teams evened or all against the
player, and every game ended cleanly with no assert. With
debug.bot_trace, bots took up rocket launchers, shotguns and sniper
rifles, and debug.txt had none of the distributed netcode's idle action
lines.
- bots.count 0: a 60 s local game logs the same lines as origin/main with
only the network test's local mode (numbers apart), and config.toml
differs only by the new settings' lines (and the network test's
comment). bots.count 6 in a system link
game (host:) and in a local CTF game: no bot joins, nothing logged.
- ninja web and ninja android (Emscripten 6.0.10, NDK r27c) build, debug
and release.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011ucYZ9cvWn3nrnk7kK3S5X
A game's level name is the map's own (custom_maps\hugeass), so no screen or
server browser listing shows a hash, and the game record's map version is
the map's hash's first 32 bits, which a client finds its file by. Maps are
no longer renamed; a download beside another version of its name is named
<name>_<hash>.map and listed as "(2)"; maps the last build renamed get
their names back. Network version 29: the level name and the map version
mean something else.
A client that joins a lobby on a Custom Edition map it does not have
downloads it by map sharing. When the host started the game meanwhile, the
host held the client's players out, as it should, but the client, whose
download began in the lobby, did not know the game had started and asked
for its player again; the host took the request as a late joiner's and
started it at once. The client then loaded a map it did not have yet:
cache_files_precache_map_begin's damaged disc error, which stops the game
for good. Stock build-201 does the same with its own host.
- The host (network_server_manager.c): a player asked for by a machine
still downloading the map waits with those held at the start
(network_game_server_hold_requested_player), and joins with them, the
machine started as a late joiner, once its download is done
(network_game_server_release_map_fetchers).
- The client (network_client_manager.c): a start that comes while the
map is still being downloaded, from a host of an earlier build, is put
off until the map is there (network_game_client_begin_game,
network_game_client_idle_pregame), and dropped if the game it was for is
over by then (another map, or another game).
- NETCODE.md's "Map sharing" says what happens when a host starts during a
download (it said the host waited, which it has not since version 28).
Nothing sent changes: no network version.
Checked: the Linux CI steps, the web build and its tests, and the Windows
release build. End to end on Linux in Docker, the host starting the lobby
game at once while the client downloads (the case that stopped the game):
this build both ends (the host held the player and started it at game tick
296 once the map was there); build-201 hosting this build's client (the
start put off until the map was there); this build hosting build-201's
client (held, then played). Each client played the game.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On the "pc" menu style, a LAN game whose players were all on the host's
computer could not start a local splitscreen game. This patch fixes that
check.
START NOW only starts a countdown for a game that takes no remote connections, has two machines, or
is "alone" (server_alone). server_alone only passed if there was literally one player, making splitscreen play impossible.
Note the "xbox" menu style did not have this bug since its splitscreen
didn't accept remote connections at all.
server_alone becomes server_players_on_one_machine: TRUE if there is at
least one player and every player is on the same machine.
One player still qualifies. Machines that have joined without a player are not
counted, so a lone host's countdown is not stopped when one connects (the
per-tick server_ok_to_countdown check).
The countdown is fully controlled by the host machine, so there is no
change to the network protocol.
There's an existing test failure on test_elevator_prediction which also
exists on main, ignore.
Conflicts:
- rasterizer.h: upstream raised the transparent geometry groups to 2048
as we had (halo_port_capacity.h); theirs.
- d3d8_gl.c: the ES capabilities' log with upstream's base vertex and our
multiview.
- p2p.c, p2p_internal.h, p2p_signal.c: upstream's several joins and
reconnect, with our join codes' state and the codes' and public list's
updates each pass.
- network_server_manager.c: a machine downloading the map is not refused,
and the bots' room logic stays.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Network version 28: the host now holds a downloading machine's players out
of the game, and keeps a multiplayer map's first scripted BSP. Dynamic lights
and the flashlight stay on past the Xbox limits, and a second weapon picked
up while firing is readied. Machines of version 27 would disagree on these.
- A large co-op game's respawn fallback no longer picks a teammate who is in
the air, outside the BSP, or riding an AI vehicle.
- A machine still downloading the map times out when it goes silent.
- Held players join through the late-join queue, so they get the same checks.
A machine with no held players is started instead of being refused.
- The co-op teleport uses world positions, which are right for seated players.
- Overshield drain no longer cuts off a hit's flash, and hits over 0.02 flash.
- The menu XML is the generator's (Custom Edition's layout) again.
- port: markers on two new declarations.
Checked: ninja linux, android and web build; tools/harness,
test_touch_menu and test_web_build pass.
Hosts send players who join without the game's Custom Edition map the map
and the resource maps it needs; the other players help, torrent-style.
Network version 27: new map sharing messages, and players of an internet
game now reach each other.
Conflicts:
- render_objects.c: upstream's first-person legs and our VR body share one
node_matrices (ours no longer shadowed it); upstream's legs never in VR
(first_person_legs_wanted: set back behind a flat view's eye, they would
stand behind the player; the VR body is vr.body "full").
- AndroidManifest.xml: upstream's ':game' process left out (the Steam
Frame's Lepton waits for the app's process to end; the headsets have no
Java heap over the Xbox window); HaloApplication kept, idle without it.
- xinput_sdl.c: the touch controls and the web port's, never in VR; the
controllers' rumble in VR before the phone's.
- d3d8_gl.c: multiview's uniforms and upstream's blend constant, both.
- build.yml: Android only; upstream's web and pages jobs off.
- README.md: ours; upstream's in docs/OPENCE_README.md.
- menu_tags.c: our VR pause-list fit dropped: upstream now spaces the rows
30 apart and moves the button hints below them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
248 OpenCE commits (network version 25): touch controls and touch menus for
phones, single-player in-game Settings, opt-in FOV/viewmodel settings, voice
chat and votes to kick, lens flare culling, memory leak fixes (render
targets, gamepads, the Android audio stream), profiling builds, the
HALO_ANDROID split into HALO_ARM64_GUEST / HALO_GLES / HALO_ANDROID.
Conflicts and how they were resolved:
- README.md: ours kept whole. Upstream's README changes (portable build,
profiling builds) went into docs/OPENCE_README.md: upstream's new text
with our header note, links rewritten to ../ and our "made from your own
copy" wording.
- port/android/README.md: both merged; upstream's touch, WSL and save
notes taken, with our application id in every adb path; our VR section,
signing.properties and wording kept; the stale "How it works" list
dropped as upstream dropped it.
- Launcher icons (mipmap-*/ic_launcher_foreground.png, art/android-icon.png):
ours (the Ringfall art). Upstream's helmet monochrome layers,
drawable/ic_launcher_background.xml and its ic_launcher.xml were left out;
our ic_launcher.xml, values/ic_launcher_background.xml and
tools/android_icon.py stay. (port/assets/icon and tools/app_icon.py come
in for the desktop builds' window icon only; do not run app_icon.py, it
would write the helmet into the Android resources.)
- port/android/host/host_main.c: both config helpers kept, and upstream's
emulator write tracking (native_bridge_active); upstream's display width
block dropped in favour of ours (640 in VR) and its display density for
the touch controls moved into our flat (non-VR) branch.
- port/linux/game/menu_functions.c: platform_text_field(typing, password)
from upstream; the VR keyboard launch for text fields kept after it.
- port/linux/game/network_distributed.c: upstream's profile_scope wrappers,
with network_vr_tick and bots_tick kept in their places.
- port/linux/src/dsound_sdl.c: both (our debug.audio_log, upstream's
audio.output_device).
- port/linux/src/port_config.c: our temp-and-rename config write kept,
under upstream's HALO_ARM64_GUEST (it is guest file I/O).
- port/linux/src/sdl_platform.c/.h: upstream's (Android menu pointer from
the touchscreen, Steam keyboard, scoreboard pointer); our quit marker for
the Steam Frame launcher, clipboard_seen and VR frame hooks kept. Our
flat-mouse menu pointer (an emulator aid) is replaced by upstream's touch
pointer, which also drives the menus on the emulator.
- port/linux/src/d3d8_gl.c: halo_ui_pointer_update is upstream's, with the
VR controller ray taking over while VR is active (the touchscreen then
is not the pointer); our persistent-buffer writes kept for stream and
index uploads, now writing upstream's exact length and under HALO_GLES
like the code around them (stream_reserve, index_upload, mirror_refresh
too); multiview uniforms stay under HALO_ANDROID, the counter binding
under HALO_GLES. Visibility counters: ours kept (the snapshot ring with
multiview views, host_gl_counters_snapshot) over upstream's per-frame
glCopyBufferSubData into counter_snapshots: ours reads finished frames
without stalling and counts both eyes' samples once; upstream's
desktop query batches come in unchanged.
- port/linux/src/xinput_sdl.c: both (VR controllers and touch controls).
In VR the touch controls neither show nor act (touch_input_gamepad,
touch_input_controls, touch move/look skipped); rumble goes to the
controllers in VR, to the phone otherwise.
- source/interface/first_person_weapons.c: both (VR scope pass check and
display.viewmodel_visible).
- source/interface/ui_widget.c: upstream's reworked menu targets taken
(ui_mouse_fit_button_targets, merged rows, widened values), which do
what our icon_x0 key picking and the 12-unit value arrows did; our VR
label distance (25) kept, and a VR ray counts as a coarse pointer, so it
gets the taller legend areas and the widened values (not the merged
rows: a row's label still presses A). Our join code and VR options
panels kept; their early return now forgets the frame's targets too.
The on-screen keyboard: upstream's virtual_keyboard_click for taps and
the mouse, ours (hover highlights the key) for the VR ray only.
- source/main/main.c: both (VR phases around upstream's profile scopes).
VR guards for new upstream features:
- view_fov.c: display.fov, display.viewmodel_fov and
display.viewmodel_visible do nothing while VR is active (the headset
gives each eye's frustum; the weapon is in the hand).
- Touch controls: off in VR (xinput_sdl.c), the menus' touch pointer too
(d3d8_gl.c); the overlay stays hidden as the game never reports a scene.
- Lens flare culling (744040c8, b1a71709) uses global_window_parameters'
frustum, which in VR is each eye's (per-eye passes) or the union frustum
of the multiview centre camera: no change needed.
- In-game Settings: VR options still open with Y on the main and pause
menus (checked flat with debug.vr_options).
- The back button change (enableOnBackInvokedCallback=false) keeps the
legacy KEYCODE_BACK path, which targetSdk 35 already had: no change on
Quest or Frame.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A machine whose address or hardware id is in bans.txt, or that was dropped
for cheating, was told the game is not open when it tried to join again;
it is told it is kept out (_rejection_code_blacklisted_machine), as at the
ban itself.
(cherry picked from commit 73c78610c67cd3827592673f1b06a1d38babe4ac)
Adapted: without the dedicated server's drop function it was declared
beside (in a server/ folder, not taken), and a machine kept out by a
vote (OpenCE's network_votekick.c) is told it is kept out too.
(cherry picked from commit c0191dd9beb4bfd26dd73ba0923cb7edeea44d49)
The console runs what it is sent as scripts. A browser can be made to send
an HTTP request to a local port; such a client is now dropped at its first
line instead of having its lines run.
(cherry picked from commit faa2a331383f4dedce63487d813b7348c00b6f26)
(cherry picked from commit 40a6262e9be05db11317522f9ee9424405124025)
While searching for games the client wrote to its connection before it had a socket (Winsock error 10038); that marked the connection closed, and when the player then picked a game every write of the join request failed, so the first join to a host hung and gave up. Connecting now clears that, and any half-sent data. A second try worked only because it made a new connection.
(cherry picked from commit 4b18b99af6d977707203b304d104c84fb23fecb4)
Opus voice chat (port/third_party/opus 1.5.2, port/linux/src/voice_audio.c, port/linux/game/network_voice.c), relayed by the host, in the lobby too. The host decides in Server Setup > Teamplay Options: lobby voice (on by default), the game's mode (off, team near, anyone near, team, team and enemies near: the default), the near distance, and the quality, 8 to 64 kbps (24). Each player picks push to talk (V), open mic or off, the voices' volume, and the output and input devices in Settings > Audio, and mutes others from the scoreboard's menu. A speaker icon marks who talks in the lobby, on the scoreboard and in a list in game. The host takes a machine's frames only with the key it gave it over its stream, within the quality's size, 50 a second and 8 talkers at once, and sends voices only to machines that asked for them, so the network version stays.
Any player of a network game can start a vote to kick another, on any team, by picking their name on the scoreboard (right-click while it is open frees the mouse) or with the console's votekick; the host's own scoreboard also has Kick and Ban (Ban picked twice). The host alone counts (port/linux/game/network_votekick.c): votes only from each voter's stream, one per real address and again per hardware id (which only removes votes), time played on the host before starting (network.votekick_minutes) and voting, more than half of everyone with the target counted and at least two, one vote at a time with cooldowns for a failed vote's starter and target, and a passed vote keeps the player out for network.votekick_ban_minutes. Builds without it drop the new messages, so the network version stays.
Conflicts:
- d3d8_gl.c, xgpu.h: upstream's own snapshot ring for the visibility
counters left out for ours (host_gl_counters_snapshot, the same idea,
tried on both headsets, which also halves multiview's counts; its copy
already has the memory barrier upstream added); both declarations kept.
- rasterizer_xbox.c: the mirrored skinning's winding and upstream's
many-node matrices, both.
- main.c, network_server_manager.c: both (bots' machines and a lone host
may count down).
- android_build.py: the OpenXR loader and upstream's SDL mouse patch
(another SDL file than ours), both.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A host's map name of con, nul, com1 and the like made a client on Windows
open that device as the map, which could hang it. Such names are now
refused with the other invalid map names.
A client refused a host's map name with any character outside letters,
digits and _ - . space and backslash, so a game on a Custom Edition map
named like [H2]_Lockout could not be joined. These five characters mean
nothing to a path and are now accepted too.
Fixed: Weapons whose trigger had flag "analog rate of fire" now read how far the trigger is pulled: fully for mouse/keyboard, the actual pressure for a controller trigger. Before they never fired.
source/input/input_abstraction.c
source/input/input_abstraction.h
source/game/player_control.c
Fixed: Weapon spawn orientation on Custom Edition maps. Multiplayer weapons and items now spawn facing the way the map places them, as in Halo PC.
source/game/game_engine.c
Added: PC vehicle set. There's a new PC option in the vehicle set list, between Gun Turrets and Custom. A team set to PC gets every vehicle the map places, as in Halo PC. On Custom Edition maps that means every placement whose spawn flags name the gametype.
port/assets/menus/ce/strings.xml
port/linux/game/menu_functions.c
source/game/game_engine.h
source/game/game_engine.c
Added: Start LAN, internet and split screen games alone. A game with one machine and one player can now start. Pressing start alone begins the countdown, others can join while the game is in progress, and the lobby no longer says it's waiting for another machine or player.
source/networking/network_server_manager.c
source/interface/ui_widget_game_data_input_functions.c
A client joining a game on a Custom Edition map checked only that it had a
file of that name. With another version of the map (an older release, a
re-edit), its tags are not the host's: the objects, weapons and vehicles the
host sends are other things there, and the game desyncs or crashes.
The host now sends its map file's header checksum as the game record's map
version, which the Xbox game always left 0, and a client whose copy has
another checksum leaves with an error saying so and where to copy the
host's. The record's layout is unchanged: a host that sends 0 (an older
one, or the game's own maps, whose builds of other regions play together)
is not checked, and older clients ignore the field.