Commit Graph
352 Commits
Author SHA1 Message Date
MrBruh b1a71709ef FOV and viewmodel settings: one unit, port marks, the lens flare cull (#234)
render_fov.c, viewmodel_fov.c and viewmodel_visibility.c are one unit,
port/linux/game/view_fov.c, with a header comment as the others have, real
for float, _pi for its own pi, the rasterizer's target by name, and no
isfinite shim in math.h (the angles' range test already refuses NaN). The
game code's hooks are marked "port:", their include at the end of each
block, and rasterizer_lights.c's loops declare before they act (C89).

The first-person weapon's lens flares are not culled by the world's
frustum (main's new off-screen cull): they are
drawn at the weapon's own projection, which display.viewmodel_fov can make
wider than the world's.

HALO_VIEWMODEL_VIS is HALO_VIEWMODEL_VISIBLE; the settings' descriptions and
help lines say "stock" view and fit their boxes; Video Setup's XML is
written again by ce_menus.py; the README's field of view text is a section
of its own.
2026-10-10 16:24:04 +13:00
MrBruh a8178af24a Merge pull request #234 from innerhat-dev/fov-viewmodel-controls
Add opt-in FOV and viewmodel controls to Video Setup
2026-10-10 15:52:26 +13:00
MrBruh b5a4870d05 Saved profile's controls: the comment wrapped as the file's (#227) 2026-10-10 15:23:16 +13:00
MrBruh 124cdd0b17 Any controller's menus: helpers placed and declared as the file's (#228)
The new helpers sat between widget_takes_events_of_controller's comment and the function, so the comment now heads it again; pc_menu_split_players is declared with the file's other port prototypes rather than as an extern among the functions, the players' count is read with players_port_local_player_count (safe before the players' globals are made), the comment names process_ui_widgets, and the test widget_takes_any_controller already makes is not made twice.
2026-10-10 15:06:52 +13:00
MrBruh ef87ea5ae1 Merge pull request #228 from thelinkin3000/fix/menus-any-controller
Let any controller drive the menus while one person plays
2026-10-10 15:00:00 +13:00
MrBruh 010d7520e4 Merge pull request #227 from thelinkin3000/fix/profile-controls-on-save
Apply a saved profile's controls to the player using it
2026-10-10 15:00:00 +13:00
MrBruh 7124534a4b Memory leaks: render targets, gamepads, Android audio stream 2026-10-10 14:42:05 +13:00
xshxdex98 5d5b5dd35e Custom Edition maps: HUD sounds, dialogue variants and camouflage on odd tag data
Three engine checks no longer stop the game on data Halo PC tolerated:
HUD sounds with no tag, dialogue variants with no dialogue, and non-model
shaders under camouflage (an environment shader on a first-person weapon:
not drawn while camouflaged rather than misread as a model shader).

These three only: OpenCE already had the commit's other repairs (protected
maps, node trees, scripts that fail to load, HUD meters and digits, object
functions, collision edges, weapon lists, more than 16 dialogue variants),
some made another way, and has no 64-bit build for its script stacks.

(cherry picked from commit d15b6ca913266b984966897e1be4e24c69a75b30)
2026-10-10 13:59:04 +13:00
xshxdex98 14ebfae230 Menus: the pointer no longer runs a list through all its items
A list whose focus reached its first or last row scrolled on and moved the
focus a row in; the pointer hovering that row took the focus back the next
frame it moved, so the list ran through everything and the row under the
pointer never stayed lit (the game types, the lobby, the internet lobby).
A list now scrolls on at its end only when the d-pad (keys, controller,
the wheel) put the focus there (ui_widget_port_pointer_focused).

(cherry picked from commit e74f5bbb541a480a72871adeb719472908607d12)
2026-10-10 13:59:03 +13:00
Milenko 412c5224e1 Profiles: a deleted profile's name can be used again
Deleting a saved game file moves the files after it down the memory
unit's list, but the players kept their profiles' old indices. A profile
deleted before the one in use left that one's index naming the next file,
often the next profile made: the profile in use was then saved over it,
taking its name in the list, while its folder kept the new name, which
then read as in use ("a profile with this name already exists") with no
such profile shown. The indices the players and the profile editor hold
now follow their files down the list, and one naming the file deleted is
none.

Fixes #148

(cherry picked from commit 4575f6e6ec7010de1036a3a639ee2794181874d8)
(cherry picked from commit 4bbd4965afbbaa22cb3a655a181c3770382bc505)
2026-10-10 12:53:23 +13:00
thelinkin3000 1ac8186d6c Scan the motion sensor for up to four local players
The scan kept each local player's blip count and the scan order in one
array of four, the counts first and the order from 2, and had two camera
positions: all the Xbox's two player co-op needed. With three or four
local players in split screen they were written past their ends and into
the function's stack guard, which halted the game as it started drawing
the HUD ("corrupt stack at 0!"). The counts and the order are now arrays of
their own, and there is a camera position for every local player.

(cherry picked from commit 266a556967273bfcf096c1e6009acdb7a5ee045d)
(cherry picked from commit c02cb986c2c5acc6426fcb043f39d1062617f7f7)
(cherry picked from commit ee9cbf17d1422f2b57b5ca07c98010ece1bcbad6)
2026-10-10 12:53:23 +13:00
xshxdex98 7df9be7785 Give unset locals values, and drop the decompiler's dated audit notes
25 notes ("left unassigned only by this default arm ... approval pending,
2026-09-27 audit") argued that a variable was never read unset. Where the
arm ends in system_exit they were right and simply go. A release build's
assertions return, though, so where the arm only asserts the variable now
starts with a value (a Custom Edition map's HUD data can reach hud_draw's).
A failed map precache reads as failed.

rasterizer_debug_drawing_begin had two declarations, one with an argument
its definition never takes; it now has one, and the port's macro papering
over the mismatch is gone.

(cherry picked from commit 74f8a048e4c3cc7dbc4b050dd41a8bae912bb367)
2026-10-10 12:53:22 +13:00
xshxdex98 60cd1254d6 Fix the decompiled code's latent bugs, and say plainly what is kept
Uninitialised locals get values (debug vertex, datastore result, index
buffer, map tool direction, AI entry points, escape alignment, grenade aim
from a vehicle, game options descriptions, unreachable switch arms), the
AI's squad and platoon records move whole, a speech cause point is read,
the geosphere's out-of-memory path frees itself, a console cond clause
without a result is refused, and the crash reporter rejects truncated map
files. Gameplay the original game has, kept so it plays the same, is noted
in a line rather than a page.

(cherry picked from commit 75afc4a1e57af2ba697e8be0e33b2afeee7639f8)
2026-10-10 12:53:22 +13:00
Milenko 7ac5978158 terminal_printf: take its arguments as a va_list
terminal_printf started its variable arguments into a char *, which is
what va_list is on the Xbox, 32-bit x86 and Apple silicon, but not on
x86-64, where va_list is a one-element array of a register-save
structure. On an Intel Mac (or under Rosetta) va_start wrote through an
uninitialised pointer and vsnprintf read garbage, so the first terminal
line printed with arguments crashed the game.

Choosing an empty profile slot is such a line: "player profile begin
editing" fails, as it does on the Xbox, and console_warning reports it
through terminal_printf, so setting up a profile crashed on Intel Macs.

(cherry picked from commit 024e41b8cb1553d7ad9b96233860848d49e5ad13)
2026-10-10 12:53:22 +13:00
MrBruh 6a74eab5ad Touch controls review fixes
With input.touch_aim_assist false, walking with the touch stick still let the view follow a target: the touch controls now count as aiming without the assist until a stick aims again (halo_linux_touch_aiming), as the mouse does. The stick's diagonal is full on both axes, as a controller's square stick gives. The gyroscope reaches the game apart from the swipe (nativeGyro), so the profile's invert look turns only the swipe.

The overlay shows once the game has been in play for 200 ms, so it does not flash at a level's first frame. The options dialogs are counted, so a dialog opened from another keeps the controls released, and the layout is saved when the last one closes (a slider moved without a finger was not). A floating stick rests where the thumb lands, even near an edge, and not in the bottom gesture zone. A finger's width is at most 34 logical units, so the D-pad's buttons stay apart on a small dense display. A held button that takes over the swipe from another finger starts from where it is, not from where it went down. The system bars coming and going no longer release every finger. Hide stops the gyroscope.

The libtiff comments are corrected: the screenshot_count and screenshot_size globals also reached tiff_export, but read back-buffer memory the port never draws into, so they never had the picture. Stale comments are fixed and the source exclusion test covers folders.
2026-10-10 12:09:19 +13:00
eltanschauung cc41b768bb Add opt-in FOV and viewmodel settings 2026-10-09 08:18:29 -04:00
thelinkin3000andClaude Opus 5.5 59c8d54409 Let any controller drive the menus while one person plays
Each controller's events went only to its own player's screens, and the
main menu is the first player's: a gamepad on any port but the first
did nothing, and a phone can list a device of its own (its touch
controls) before the gamepad. With one person playing, the first
player's screens now read and take every controller's events; with two
or more, each controller keeps to its own player's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 12:00:34 +00:00
thelinkin3000andClaude Opus 5.5 ee1e169f9b Apply a saved profile's controls to the player using it
Saving the profile being edited wrote it to the disk only: a local
player playing with that profile kept its old button and stick layouts,
sensitivity and inversion until the profile was next chosen (the next
mission, the next start). Now each local player whose active profile it
is takes the saved one at once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 12:00:34 +00:00
MrBruh 2aa3897189 Setting rows merged and values widened for a finger only (#50)
A finger's targets: a tap on a setting row's label reaches its value, and the values are wider. The mouse clicks the labels and values where CE's menus have them, as before the PR.
2026-10-10 00:59:22 +13:00
MrBruh f56e120e16 Merge pull request #50 from HiIAmMoot/touch-menus
Operate the Android menus by touch

Conflicts resolved: the pointer's window-to-menu mapping takes main's centering (the scoreboard's) and the PR's missing-back-buffer check, and is shared; the scoreboard's pointer stays the desktop's (an Android stub); FOCUS_LOST drops both the scoreboard's pointer and the touch; main's Steam on-screen keyboard and the PR's Android pointer each keep their side of the #ifndef; CI runs test_touch_menu.py with the harness.
2026-10-10 00:55:30 +13:00
MrBruh 65cd4c29d8 usnprintf as MSVC's again, map formats' widths bounded (#197-#199)
usnprintf terminated every string it wrote, so an exact fit lost its last character on Windows (a score limit of 100 shown as 10); the strings the PRs bound are terminated where they are written, as the rest of the game's are. The title copies are ustrncpy again (title_string[79] is terminated after). A map's format takes flags, then at most three digits of width and three of precision, so %5-d, %1.2.3d and huge widths are not passed to Windows's printf.
2026-10-09 21:06:25 +13:00
MrBruh 5e08c09e78 Merge pull request #199 from ChupathingyCE/upstream-fix/map-format-arguments
Map strings used as formats only with the game's own arguments (with #197 and #198, which it stacks on)
2026-10-09 21:05:46 +13:00
MrBruh 515e6a0ab6 Profiles' Start as CE's again, comment as port's (#222)
main_menu.xml is generated from CE's tags; with the keyboard's typing mode ended as it closes, Enter is A again and CE's own Start handler can stay. Its test is dropped with it.
2026-10-09 21:03:57 +13:00
MrBruh cb66f9ce72 Merge pull request #222 from eltanschauung/fix/profile-keyboard-routing
Fix Profiles opening Multiplayer after profile creation
2026-10-09 21:03:42 +13:00
MrBruh 1254c1661c Merge pull request #142 from kirklandsig/menus-no-save-file-read-each-frame
Menus: no save file read each frame

Conflicts with the Custom Edition map lists resolved: with no last_used, the list is still the Xbox's maps and then the Custom Edition maps (level_count), not the Xbox's 13.
2026-10-09 21:03:21 +13:00
MrBruh 7d821587bf Visibility tests' own scratch query, help text comment
Slot 0 was the tests' scratch query and taken for slot 1, so the game's lens flare 0 read flare 1's visibility; a query of its own is the scratch (#150's full batch too), and every slot is a test's. The query buffer is unbound after it is mapped, so a fallback read is not taken for an offset into it. #171's comment as port: comments are.
2026-10-09 20:09:43 +13:00
MrBruh 4fe5406c41 Merge pull request #185 from xshxdex98/upstream-spinner-descriptions-index
Spinner descriptions' text indices above the Custom Edition maps'
2026-10-09 20:02:39 +13:00
MrBruh 556841cc18 Merge pull request #171 from innerhat-dev/help-text-custom-icon
Skip a help text custom icon instead of halting on a missing button icon
2026-10-09 20:02:39 +13:00
MrBruh 378cb0d427 Refused widget functions fail, resampler comment's figure
A function a map's widget may not run (#203) failed as an invalid one does, so the handler opens and closes no screens after it. The four-taps resampler's difference from tap by tap (#221) is measured at -115 to -126 dB, not -140.
2026-10-09 18:52:31 +13:00
eltanschauung b22dacb026 Fix Profiles routing after creating a profile 2026-10-09 01:51:37 -04:00
MrBruh 3bb4866fbf Merge pull request #203 from ChupathingyCE/upstream-fix/widget-menu-functions
Widgets: a map's widgets don't run the main menu's profile or settings functions
2026-10-09 18:46:28 +13:00
MrBruh e7e5777a88 Voice chat list in name tag colours
The in-game list of who talks colours each name as the names above players' heads are (hud_player_name_color, now shared): allies in the HUD's blue, enemies red, this machine's own players white; in co-op every other player is an ally.
2026-10-09 17:55:00 +13:00
MrBruh 348f8ad4f8 Speaker beside talking players' name tags
A player talking in voice chat has the speaker just left of their name above their head, centred on its capitals, at the name's scale and fade; only where the name itself is shown (display.player_names, and the gametype's motion tracker rules).
2026-10-09 17:44:55 +13:00
MrBruh f97b33391b Voice chat
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.
2026-10-09 14:20:57 +13:00
Milenko c1694f607f HUD item messages: map text formatted only when it takes the count, and bounded
An item's pickup message is a map string that the HUD used as the format
of an unbounded usprintf into a 256-character buffer. It is now used as a
format only if its one conversion is the count the game passes
(ustring_format_takes), with usnprintf, and shown as plain text
otherwise. usnprintf now also terminates a string it cuts short, and
ustrncpy_terminated is a bounded copy that always terminates.
2026-10-08 08:35:30 -04:00
Milenko 6f0f2992cb Widgets: a game map's run none of the main menu's profile functions
A widget's event handlers name their function by its index in the table,
which nothing checked, so a game map's widget could run the main menu's
profile functions (deleting and saving player and playlist profiles, the
demos) and the port's own menu functions (writing config.toml, quitting,
connecting), on its created event too. The shipped maps' widgets run none
of these. Now only the port's own menu tags run the port's functions, and
only the main menu runs its profile functions; a refusal is logged once.
2026-10-08 08:33:20 -04:00
xshxdex98 57038d51c9 Weapon HUD: no secondary magazine drawn for a weapon without one
#180 gave a weapon without a second magazine the secondary's overlays at
rest (default and always) and states at rest (not disabled). The Xbox
never set those overlays, and an empty magazine's total ammunition state
is disabled, so the stock HUDs' secondary numbers and icons, which never
showed, drew over the campaign HUD's ammunition and grenade panels.

Such a weapon now leaves the secondary overlays unset, as the Xbox did,
and its states read the cleared, empty magazine. #180's fix stays: the
secondary's overlays no longer write over the primary's.
2026-10-07 22:27:32 -05:00
xshxdex98 fc616b8c23 Spinner descriptions' text indices above the Custom Edition maps'
Text boxes take a string index from 0x5000 as a spinner's extra item's
description (kills_to_win_extra_descriptions). Custom Edition multiplayer
maps' display indices now run from 0x4000 to 0x6000 (8192 maps), so a
list of more than 4096 showed the next maps' names as kills-to-win
descriptions. The descriptions move to 0x7000, which custom_edition_maps.c
already keeps every map's display index below.
2026-10-07 21:45:46 -05:00
xshxdex98 f7301fcd06 Weapon HUD: the secondary magazine's overlays and warnings are its own
render_weapon_hud set the secondary magazine's overlay flags into slots 0
and 1, over the primary's, where its states and numbers use 4 and 5: a
weapon of one magazine showed its ammunition overlays as the empty second
magazine's (coldsnap's flamethrower read NO FUEL with a full tank).

A weapon of one magazine also read a second it doesn't have:
weapon_build_weapon_interface_state fills only the weapon's own, into
unset stack memory, so the HUD's secondary flash, reload and fired-empty
warnings followed whatever was there. The state is now cleared first, and
a weapon of one magazine keeps its secondary states and overlays at rest.
2026-10-07 20:51:44 -05:00
TwistedFlog 6b1d81c7b1 Custom Edition Map Discrepancy Fixes
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
2026-10-07 17:45:15 -06:00
justinfilip 626c42df60 Skip a help text custom icon instead of halting on a missing button icon. 2026-10-07 17:53:37 -05:00
MrBruh 4e8ed2f196 Tell a joining player which map they are missing
A client joining a game on a map it does not have (a Custom Edition map
not in custom_maps, or one of the game's own not in maps) now leaves with
an error naming the map and where to copy it, instead of the damaged disc
error. It also says when the map cannot run there or the host names a
Custom Edition map as other versions do. The port's error texts wrap to
their dialog, in the smaller font when they would not fit.

Network version 22: hosts now name Custom Edition maps custom_maps\<name>,
which older clients cannot load or explain; they are told to update.
2026-10-07 23:56:33 +13:00
MrBruh ce41b41d78 List Custom Edition maps as custom singleplayer and multiplayer maps
Custom Edition maps are loaded from the custom_maps folder, as level
custom_maps\<name>, apart from the game's own maps of the same name. The
map lists get CUSTOM SINGLEPLAYER and CUSTOM MULTIPLAYER, by the scenario
type in the map: a custom singleplayer map plays as a campaign level, or
as network co-op from the Map screen; a custom multiplayer map plays as a
multiplayer map. A map with an OpenSauce header that asks for nothing of
OpenSauce's runs as stock Custom Edition runs it.
2026-10-07 22:40:09 +13:00
MrBruh 30cd63678a List Custom Edition maps in the menus 2026-10-07 19:02:06 +13:00
MrBruh f823a18d59 Load, check and run Halo Custom Edition and OpenSauce maps 2026-10-07 19:02:01 +13:00
Kirk LazarusandClaude 7e8c8b1d56 Menus: no save file read each frame
The server and LAN browsers name each visible row's map every frame
(map_display_name), and the lobby shows its map every frame
(lobby_map_show). Both went through ui_widget_port_multiplayer_maps,
which also reads the map used last from z:\lastmpmp.txt. Until a game has
been hosted there is no such file, and each failed read also writes two
lines to debug.txt. The map used last is now looked up only when the
caller asks for it (last_used not NULL), as the menus that open a map
list do.

profile_name_show read the last-used profile at most once a second when
the read worked, but read one that could not be read again every frame.
That one is now tried again a second later too.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-06 21:14:15 -04:00
MrBruh 54abd34493 Third hardening round 2026-10-07 13:20:54 +13:00
MrBruh d7efd3934a Validate map tags before loading 2026-10-07 12:01:09 +13:00
MrBruh 76addf661f Second hardening round 2026-10-07 00:01:28 +13:00
MrBruh 7ea610770c Gamepad layout preview in profile settings 2026-10-06 22:41:37 +13:00