Commit Graph
2833 Commits
Author SHA1 Message Date
MrBruh 66dfd1367c Merge pull request #223 from HiIAmMoot/profiling-cpu
Add a profiling build: CPU recordings for Perfetto and a report tool

Conflicts resolved: CI runs main's tests and test_profile.py; the build
scripts take both main's opus and target flags and the PR's
configuration_defines; port_config.c keeps debug.memory_watch before the
profile settings; main.c and network_distributed.c keep voice chat, and
network_votekick_host_tick stays its own statement after the game state's
profile scope, not under its if.
2026-10-10 16:28:45 +13:00
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 400d62bb76 Merge pull request #123 from startupfoundry/split-halo-android
Split HALO_ANDROID into HALO_ARM64_GUEST, HALO_GLES and HALO_ANDROID

Conflict resolved: main's render-target eviction and mip composites are kept, with the PR's HALO_GLES guard on the ES blit fallback after them.
2026-10-10 15:41:32 +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 30771b1b2c Structure triangle limit: port comments (#232)
The raised limits' and the walk's comments are marked as the port's, with the unverified HAC2 and MCC comparison left out; the walk's says why the index is compared whole, and the once-only log of a frame reaching the limit gets a comment of its own.
2026-10-10 15:20:36 +13:00
MrBruh a58fd479e5 Item resting surface: a port comment, its helpers with the private code (#231)
The helpers' comment is marked as the port's and says plainly what the short holds; their definitions move to the file's private code, and the plane the item is moved onto is indented inside its new surface check.
2026-10-10 15:14:51 +13:00
MrBruh 691532327e Frame throttle sleep: a port comment, no unused precache test (#229)
The sleep's comment is marked as the port's and says what the spin cost (a core held busy, not system calls: the clock is read through the vDSO on Linux and Android), and the precache test the sleep no longer depends on is gone rather than cast to void.
2026-10-10 15:09:24 +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 f2cb0916dc Merge pull request #232 from innerhat-dev/structure-triangle-limit
Let a frame draw 32768 structure triangles
2026-10-10 15:00:00 +13:00
MrBruh da24e4c726 Merge pull request #231 from innerhat-dev/item-rested-surface
Keep an item's resting surface past 32767
2026-10-10 15:00:00 +13:00
MrBruh 96ee110671 Merge pull request #229 from thelinkin3000/fix/throttle-sleep
Sleep in the frame throttle instead of spinning
2026-10-10 15:00:00 +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 5ed36d17f2 CE maps: an index past a tag block's end no longer stops a debug build
Halo PC reads a Custom Edition map's tags unchecked, so maps made for it
can hold an index past a block's end that never mattered there. OpenCE
already gives such an index the empty data and logs it, as it does for a
tag data's offset, but a debug build still stopped at the block's
assertions first (foundation@ce, 13 seconds in). With a Custom Edition map
loaded they are skipped, as tag_data_get_pointer's are; Xbox maps keep
their checks.

Only the assertions: OpenCE had the rest of the commit's change, made
another way (tag_empty_data).

(cherry picked from commit c953c65409ff9f3f230849bc6fc287727e3e3213)
2026-10-10 13:59:04 +13:00
Milenko 90f3fdf25f Director debug controls: each variable's own hyper scale
The debug camera controls applied the height variable's hyper-scale
setting to every variable. Camera debugging only.

(cherry picked from commit 3db16e4499c7aa8ee9c82f28c3454009f877bccc)

(cherry picked from commit a5074861b2f9682e791adfd587c3a2b43e2f6daf)
2026-10-10 13:59:04 +13:00
Milenko 42cfa397f7 AI debugging checks: the vehicle exit time
The unit activation check compared the last vehicle's index where it
meant the time the unit left it, so it could report a false "unit
activation logic error" just after a vehicle exit. Messages only.

The actors.c line only; the commit's other fix, the movement point's y
printed as z, came with "Log and error messages print what their formats
ask for".

(cherry picked from commit e3089220a6bfa8479ba2e334a0070f97c97dd851)
2026-10-10 13:59:04 +13:00
xshxdex98 234d4c2295 AI profiler: meters averaged right
The AI profiler's meters took the oldest sample out of their running sum
but never put the new one in, so their averages were wrong; the actor
line's units also lacked their tab and a separator.

The ai_profile.c fixes only, from a commit that is otherwise a rewording
of the AI code's comments.

(cherry picked from commit 95b838d13e276e41aa37f4646ce4acf5d18b8639)
2026-10-10 13:59:04 +13:00
Milenko f2a0f91e48 Antennas and cloth flags follow a jump of more than one unit
Their attachment's movement was truncated to whole units before the
test, so it took two units of movement in one update, not one, to move
the vertices along with it. Visual only.

(cherry picked from commit 99c2db2d4da3d6d66b6ec28d459c756aeab55a64)
(cherry picked from commit eb0667bcc81ed1d970422c7856162e8aadff6fd7)
2026-10-10 13:59:04 +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 fee00e9c79 Particles: a Halo PC map's particle of more bitmaps than a draw takes
Particles of one kind are drawn together, at most 8 bitmaps' worth. A Halo
PC map's particle may have a bitmap a frame: beavercreek_rev_beta's fluid
bursts have up to 56. A debug build halted ("a build_sprites_begin call can
accomodate at most 8 bitmaps") when such particles were in view; a release
build drew the first 8 bitmaps' sprites and not the others. The builds that
play Halo PC's maps now do as a release build does in a debug build too, and
log it once. The Xbox's maps' particles stay within 8, and the Xbox build is
unchanged.

Without its #ifdef HALO_CUSTOM_EDITION, which OpenCE never defines (it
compiled to nothing): the log is for Custom Edition maps
(custom_edition_cache_tags_loaded), the assertion stays for the Xbox's.

(cherry picked from commit afa6413f1e922621cc04e7953e730d5571b3aae6)
2026-10-10 13:59:03 +13:00
xshxdex98 c875cbda5d Sound: play a Custom Edition sound louder than a channel at full gain
Some maps' sounds have gain modifiers above 1 (foundation's Reach sniper
rifle fire, 1.5; ten on Hornet's Nest). The game asserted on them (a halt
in a debug build; in a release build the volume went on to assert again in
dsound_volume_from_gain); it now clamps the gain to 1, as Halo PC plays
them.

Written for OpenCE's dsound_channel_set_properties: the original change
only joined a 32-bit build to its 64-bit build's clamp, which OpenCE does
not have.

(cherry picked from commit 312960464ca0868746bfea19eb004635a5acbb8e)
2026-10-10 13:59:03 +13:00
lantos1618 f815e1ccba Zoom effect: no ghosting at high resolutions
The scope's screen effect (a warp: copies of the screen scaled a little
from the center, blended outside the scope's mask) spreads its copies by a
radius in the Xbox's pixels. At 640x480 the few copies blended into a
radial blur; at several screen pixels to the Xbox's one they stood apart as
sharp ghosts. The native builds keep the spread and split it into that
many times the passes (halo_screen_scale), each a step of it.

(cherry picked from commit b7fa7f742a72924514eef69d50daf31ef7f7f836)
(cherry picked from commit d1b40a6fc74ab46641313a6e0095e596494a1e7b)

Without its #ifdef HALO_LINUX, which OpenCE's builds never define (it compiled to nothing), and with the copied parameters declared with the others (gnu89).

(cherry picked from commit 763567dcc7ad8e6a851fec6bb5cb9f9e10452579)
2026-10-10 13:59:03 +13:00
xshxdex98 b5229d7ad5 Custom Edition: linear bitmaps with uneven rows draw with the right pitch
rasterizer_xbox_bitmap_rebuild_hardware_format pads a linear bitmap's rows
to 64 bytes, rounding up; the texture header rounded its pitch down, so a
Custom Edition bitmap whose rows were not a whole multiple was drawn
skewed. The header now rounds up too (Xbox maps' rows always are a
multiple, so they are unchanged).

The texture header's pitch only: OpenCE never had the misalignment log the commit's custom_edition_bitmaps.c part removes.

(cherry picked from commit 90a057778f76eb96d45a112b95be2a0c1e1d69a2)
2026-10-10 13:59:03 +13:00
Milenko 2db3174366 Server: a banned machine's join is refused as banned
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)
2026-10-10 13:59:03 +13:00
Milenko eb0f6e07a7 Game speed: a number from 0 to 100
game_speed takes only finite speeds from 0 to 100.

(cherry picked from commit 4c6e68a6021204563aedb1f91e9a10d90744b5d8)
(cherry picked from commit bdbb182d0fc653960d1baf7a8b46360537eafe32)
2026-10-10 12:53:23 +13:00
Milenko acb71c2f88 Cache file header: its name ends within its field
The header's name is read only within its field.

(cherry picked from commit d4ff4cc226e25d315ca1db853ebef14953521691)
(cherry picked from commit f0dd7c9fa533a95e8e653e203064a985965f4007)
2026-10-10 12:53:23 +13:00
Milenko f7ea5db0e9 Sounds: a range's permutation mask without shifts past its bits
A range with no previous permutation (NONE) set the bit NONE as a byte
shifted to, 255.

(cherry picked from commit a35ddbe6bfcd31d5aa0c501dac52721fc295fa50)
(cherry picked from commit cd87b861b1203df530e22e777219255c21408984)
2026-10-10 12:53:23 +13:00
Milenko d978f66373 Multiplayer: a map with fewer than three multiplayer vehicles
game_engine_predict_resources and game_engine_remap_vehicle took the
globals' multiplayer vehicles 0, 1 and 2 (warthog, ghost, scorpion)
without looking at the block's count. Every retail map has them; a Custom
Edition map's globals may not, and the game then stopped on
tag_block_get_element's assertion or, with assertions off, read past the
block and predicted or compared whatever was there. A missing one is now
NONE: not predicted, and matching no placed vehicle. Maps with all three
play as before.

(cherry picked from commit f1eb47cf3da8cf3e34ad2b6c2e304f994540ab46)
(cherry picked from commit 2f282f1aa2342af9619d5b7fcf0d92d1962b9ee8)
2026-10-10 12:53:23 +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
Milenko 129d3483dc Multiplayer: the pause menu's controller no longer moves the player
A network game's pause menu pauses nothing, and the controller that moved
about it also moved its player: the D-pad and sticks walked and turned
them as they chose an item. While a menu of a player's own is up
(ui_widgets_active_for_local_player), the player gets no input, as when
the director holds it, and the buttons still held as the menu closes are
let go of first, as before (ui_widget_delete).

Fixes #119

(cherry picked from commit 771a257f25ecf64fe52d84d0dbd77dc11b2a8680)
(cherry picked from commit b5fc042ca61cdfeb9a27693b2cb3f65bf93e2c0c)
2026-10-10 12:53:23 +13:00
Milenko 0fb9b57605 Telnet console: a client sending an HTTP request is dropped
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)
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
xshxdex98 e970305724 Profiler: frame descriptions stay inside their buffer
Each of the 25 appends now goes through profile_append, which bounds and
terminates; a 150-tick frame could run past the 512-byte buffer.

(cherry picked from commit ecba1a0cecc7ff5d60d26654bdd50b7330d43f65)
2026-10-10 12:53:22 +13:00
xshxdex98 65e690321d Log and error messages print what their formats ask for
Arguments a format never read are dropped, missing ones passed (the
migration speech type, DirectSound's result), a real printed as %f, a
target AI's name printed for it rather than the source's twice, and two
messages built from saved-game names printed through %s.

(cherry picked from commit dbcf4ab91c2e42c19f57ca436f1d4f2b41964582)
2026-10-10 12:53:22 +13:00
xshxdex98 07bb950064 Co-op: the scripts' look tests pass for any player
objects_can_see_object and objects_can_see_flag on player0 tested one player only, the first with a unit, so the Pillar of Autumn tutorial's panels (look at each light in turn) never lit for anyone else. In network co-op a test of the players now passes when any player looks, as volume_test_objects_all already does.

(cherry picked from commit 1e8e0f9affe212d3e30817b768d3124027b678f7)
2026-10-10 12:53:22 +13:00
Milenko 953b0298d4 Scripts: boolean and short results are whole values, not part uninitialized
Seven of the script engine's conversions and comparisons wrote only the
low byte or word of a long and returned the rest uninitialized, which
the scripts' stacks and globals, and so the saved games, carried along.
Every reader takes only the low byte or word (the script type sizes), so
the scripts' results are unchanged.

(cherry picked from commit bb239e2207668593679eea5de45eda8e5f635b34)
(cherry picked from commit d6811ee3264b2082ba6b943087ce26293f59768a)
2026-10-10 12:53:22 +13:00
Milenko 84dd8a2c32 Particles: a fully culled group stores no NaN in its shader
The average radius of a group whose particles were all culled divided
zero by zero, leaving a NaN in the effect shader's secondary map radius.

(cherry picked from commit 11128fd78ade85c50a9a3a5a292bd2bb33bebf30)
(cherry picked from commit b52d79541dc2143de41943367542ae63ad4f384f)
2026-10-10 12:53:22 +13:00
Milenko 794cbb92c5 Bitmap sampling: the compressed-block messages print the lod; an unknown format reads black
bitmap_2d_get_pixel's out-of-range block messages printed a short where
they say lod=%f, and a compressed format it can't decode returned an
uninitialized pixel (release builds carry on past the assertion). Object
lighting is its only caller.

(cherry picked from commit e1169e05a374071e74b3da3d285762c45f1c2a77)
(cherry picked from commit 9d827c0dd9164196da54b10a2fbfdd63bf72a0cd)
2026-10-10 12:53:22 +13:00
Milenko 712d1ebe36 Projectile trails: their bitmaps read before a weapon's first shot
A trail's first draw asks the texture cache for its bitmap without
waiting and is skipped until the read finishes, so a weapon's first shots
could show no trail (the sniper rifle's most of all). A weapon created or
readied now asks the cache, without waiting, for the bitmaps of its
projectiles' contrails. Only the texture cache sees it: nothing in the
game state or on the network changes.

From pfista's halo-og (4e66af91), the source/items/weapons.c part only;
that commit's spawn inventory and teleport prediction changes are not
taken, as they change what a host and its clients exchange.

Co-authored-by: Michael Pfister <pfista@gmail.com>
(cherry picked from commit 7fff24d4843758ddcb6468c9f1febecfbce68aa5)
(cherry picked from commit 965f48f5c5e2063ba025766f1276467708e8112c)
2026-10-10 12:53:22 +13:00
xshxdex98 ab3c388c15 Joining: a connection made is open, whatever came before it
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)
2026-10-10 12:53:22 +13:00
xshxdex98 ff8fc7a654 Network: log the Winsock error behind a failed send; the connect wait's select
A send that fails with an error the transport doesn't name became endpoint_io with nothing to say why (a first join to a host that then failed). The error is logged now, once for each. The connect wait treats a select that times out as still connecting, and sets its timeout each time (select may leave what is left of it).

(cherry picked from commit 5b02133ce00edcb7d9fd788db459a77cd98e9ac4)
2026-10-10 12:53:22 +13:00
xshxdex98 d5dedf19e0 Rotational particles: don't read past a bitmap's last sequence
Rotational sprites draw their edge-on view from the sequence after the state's. A particle bitmap on foundation has only one sequence, which halted the game in particle_system_render. Without that sequence the face-on sprite is drawn alone.

(cherry picked from commit d436a0c0c3abaf069dd34e4b8d761b49569311e6)
2026-10-10 12:53:22 +13:00
xshxdex98 744040c870 Lens flares out of view are not tested or drawn
A structure BSP's lens flare markers are submitted for every visible
cluster, and each gets an occlusion test every frame, including those
behind the camera or off the screen, whose tests count no pixels (so
they are never drawn). On the Xbox a test was nearly free; here each is
a draw and a query of its own, and a level of many lights (Medical
Block) tested about 460 a frame (debug.gpu_trace_heavy). A flare whose
test could not reach the screen, by the frustum and a sphere taking in
the test's offset point and size, is no longer submitted.

(cherry picked from commit e020bbc58dd08b4bcd609d8cf561c94b87cf4580)
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