Need help getting started? Try the player guide. These notes include older work; the game overview explains what’s ready now.

Original completion statistics and checkpoints

The native backend now recovers the complete original 08001E48 completion accumulator and the 08001CF4 / 08001D9C checkpoint helpers. All three also compile byte for byte through the requested local decomp.wtf engine, using ordinary C in recovered/level_statistics.c, recovered/statistics_checkpoint_capture.c and recovered/statistics_checkpoint_restore.c. They add 592 exactly matched bytes.

Completion accumulator

Original completion calls 1231C before 1E48. The former captures weapons and refreshes their statistics rows; the latter performs these writes:

GAME destination Source / operation
+2F0 Replace with score at +88
+2F4 Replace with signed body health at local player body+32
+2F8, +2FC Replace with signed local player protection C6, C4
+300 Replace with unsigned level byte at +7C
+304 Add elapsed at +0C
+308 Add all 12 spawned counters at +130, stride12
+30C Add all 12 kill counters at +138, stride12
+310 Add all 12 player-hit counters at +134, stride12
+314 Add all 10 weapon hit counters at +9C, stride16
+318 Add accepted pickups at +31C

The weapon shot counter at +98 is not added. Pickups are accepted items, not all map objects or secrets: original 1B99C increments +31C only after an accepted ordinary contact. Score replaces the saved score; it is not added again. Arithmetic wraps at 32 bits without saturation. Health and protection sign-extend from 16 bits. No input counter is cleared by 1E48. There is no once-only latch; a second call adds the same counters again.

ssa_statistics_complete in src/statistics.c implements this with value-only SsaLevelStatistics and SsaStatisticsTotals projections. The caller must commit once per actual completion. Null arguments reject before writes.

Checkpoint helpers

1CF4 copies ten complete 16-byte weapon rows from GAME+90 to +1C0 and twelve 12-byte enemy rows from +130 to +260. 1D9C copies those rows back and clears only current accepted pickups at +31C. Both preserve elapsed, score, player vitality, level and campaign totals. The saved rows are not cleared. Native capture/restore helpers retain these exact boundaries; restoring statistics is not player respawn, level initialization or a complete continue workflow.

Native snapshot adapter and limits

ssa_native_game_statistics in src/native_statistics.c collects the live native weapon rows, activation counts, combat counters, elapsed time, score, accepted pickups and player vitality. It uses canonical inventory health and protection; body health is a native mirror. It copies values only and preserves the entire game. It rejects unloaded/error/busy games without changing output, using the same six ownership/query guards as the existing weapon snapshot.

This snapshot observes ongoing counters; it does not run the mutating 1231C password-setting counter reset. The new completion adapter preserves original capture/accumulate/checkpoint ordering, the setting policy and bonus-adjusted score. The frontend now commits campaign-session totals and checkpoint rows after the visible bonus tally, and carries the resulting score to the next level and its entry snapshot. See pause/tally integration. High-score/name entry and scores.dat persistence now connect at Quit-run/ending; see scores.md. Finite-life death/retry/game-over orchestration now connects too; see run-exit.md. Campaign totals currently remain within the run. An original SRAM/disk format for those totals has not been established by this recovery, so their persistence should not be assumed from the older TODO alone. All twelve campaign maps are enabled for manual validation.

Verification

.\decomp.ps1 test-statistics
.\decomp.ps1 test-native-statistics
powershell -NoProfile -ExecutionPolicy Bypass -File scripts/test-statistics.ps1 -SkipBuild

statistics-validation.json records 8,192 complete original-ROM comparisons per routine (24,576 total), plus 512 original save/mutate/restore/twice-accumulate sequences and six null guards under UBSan. No callee is intercepted. Tests compare whole GAME/player/body blocks, including every untouched byte; they cover overflow, signed vitality boundaries, distinct shot/hit counters and all 256 level byte values.

native-statistics-validation.json and windows-native-statistics-validation.json agree on 27,699 checks, 48 starts, 3,072 actual native gameplay frames, 288 read-only snapshots and 480 rejection cases across all 16 maps and three difficulties. Jump, H-view and a quick mouse click are delivered through the actual PC input API. Directed counter fixtures check every column, high 32-bit values and canonical health separately from ordinary gameplay. These fixtures are not campaign-completion evidence. GCC ASan/UBSan/leak detection and MSVC pass.

All 109 portable CMake libraries and 110 Windows libraries build. The complete portable build exposed an existing Windows-only profile disk test outside a platform guard; CMake now includes that target only under WIN32. Both full builds pass after that correction. The final audit checks 565 current source hashes across the four statistics/build reports and confirms the playable Windows executable remains unchanged.

Live exact matching is now 78/526 functions and 2,816/87,648 catalogued bytes (3.21%), after 541 compiler attempts. The imported catalogue is incomplete and does not represent whole-game coverage. The 78-C export and independent rebuild retain the original ROM SHA-1 4ff48d8c18b70a5184758f1917343ae85a70858e.