re: the save screen's key table is compiled into the executable -- a 4th difficulty, 3 states, 16 stages

Static, no emulator. The LOAD/SAVE screen's config keys sit in .rdata as a
pointer array at 0x820a0074, identified as config keys (not loose strings) by
the Arsenal's own key list sitting a few hundred bytes earlier and matching its
pak record exactly.

  - GAME_VERY_HARD exists alongside EASY/NORMAL/HARD, while the stage tables
    only carry BonusPoint_EASY/NORMAL/HARD -- a fourth, unpriced tier.
  - Game Status is a 3-valued enum: STATE_STAND_BY (our save's "At Standby"),
    STATE_STAGE_CLEAR, STATE_GAME_CLEAR.
  - Exactly 16 STAGE sprite keys, matching weapon.tbl's stage01..16 (plus 6
    tutorials and 6 challenges). So 16 is the story-stage count and the "22
    stages" figure used elsewhere counts a different set -- flagged, not
    silently changed.

Also recovered: the panel's field names and positions (Points, FlightTime
%03d:%02d:%02d, ClearTimes, CompletionRate, RatioOfClear, Index, Label, Date,
BrokenData).

It does NOT name the stage/difficulty save fields, and it explains why the probe
sweep could not: the screen picks a sprite key BY INDEX through a config lookup,
so there is no lis/ori immediate to xref back to the selecting code.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-11 20:13:01 +00:00
parent 2da9b8a9b8
commit bc42c0970e

View File

@@ -332,4 +332,46 @@ labels per slot" are not yet separated. The next move is not another probe — i
is to find the code that formats `STAGE %02d` and read which offset it loads, is to find the code that formats `STAGE %02d` and read which offset it loads,
which the static DB can answer directly. which the static DB can answer directly.
### What the screen itself is built from (static, `.rdata`)
The LOAD/SAVE screen's config **key list is compiled into the executable**, as a
pointer array of key strings — the same shape as the Arsenal's (whose keys sit a
few hundred bytes earlier and match the pak record exactly, which is what
identifies these as config keys rather than loose strings). The save-screen run
starts at **`0x820a0074`**:
```
game, replay, LOADING, GAME, REPLAY, SELECTOR, SAVE_BASES, SAVE_MENUS,
LOAD_BASES, LOAD_MENUS, THUMBNAIL, FONT, EX_FONT, AUTO_SAVED,
AUTO_SAVED_DETAIL, MISSION_SELECT, MISSION_SELECT_DETAIL, CLEARED, EMPTY,
EMPTY_DETAIL, SLOT, VOLUME, STRINGS,
GAME_EASY, GAME_NORMAL, GAME_HARD, GAME_VERY_HARD,
STATE_STAND_BY, STATE_STAGE_CLEAR, STATE_GAME_CLEAR,
LOCATE, …, STAGE01 … STAGE16, CLEAR_TIME_RANKING
```
Three things fall out, none of which needed the emulator:
- **There is a fourth difficulty.** `GAME_VERY_HARD` exists alongside EASY /
NORMAL / HARD, while the stage tables only carry `BonusPoint_EASY/NORMAL/HARD`.
So VERY HARD is 🟡 an unlockable tier the stage bonus table does not price.
- **`Game Status` is a three-valued enum** — `STATE_STAND_BY` (what our save
shows as `At Standby`), `STATE_STAGE_CLEAR`, `STATE_GAME_CLEAR`.
- **The screen can label exactly 16 stages**, `STAGE01`…`STAGE16`. That matches
`weapon.tbl`'s `AUTO_SETTINGS` list — `stage01…16` plus `tutorial01…06` and
`challenge01…06` — so **16 is the story-stage count**, and the "22 stages"
figure used elsewhere in these notes counts a different set (🟡 probably story
plus challenge). Worth reconciling before either number is relied on.
The panel's own field names are here too, with their screen positions:
`Points`, `FlightTime` (`%03d:%02d:%02d`), `ClearTimes`, `CompletionRate`,
`RatioOfClear`, `Index`, `Label`, `Date`, `BrokenData`.
**This does not name the stage/difficulty save fields**, and it explains why the
probe sweep could not either: the screen selects a *sprite key by index*, so the
value it indexes with is whatever the loader put in the live object — and the
strings are reached through a config lookup, not an immediate, so there is no
`lis/ori` pair to xref back to the selecting code. Chasing it further means
disassembling the save-screen's populate path, not another grep.
Editing beyond a throwaway slot is still the user's call. Editing beyond a throwaway slot is still the user's call.