re: +36/+52/+56 are neither stage nor difficulty -- refuted with eleven probe saves

Those three fields all hold 2, and "difficulty or stage, undecidable from one
save" has been the reading since the format was parsed. Writing saves makes it
decidable and the answer is neither.

boot_menu.sh boots to the title menu WITHOUT loading anything, and LOAD GAME's
slot list renders each slot's Details panel from that slot's payload. Extra
slots can be fabricated (copy the directory plus a gameNN.header with its
UTF-16BE display string and ASCII name patched), so four probes fit in one boot,
read-only.

Probed: +36 at 1/3/9, +52 and +56 at 1/9, and +0, +16, +32, +48, +28,
SHAB[0].a. Every one left the panel at STAGE 02 / EASY / At Standby /
Times Cleared 0.

The negative is meaningful because the panel does read each payload -- slot 02
shows 5% clear ratio against the others' 6%, and Points tracked +24 exactly.
Two controls: patching a slot header to "STAGE09 HARD" changed nothing (the
display is payload-driven, not header text), and the row date follows the
container FILETIME.

Remaining candidates: +12, +20, +40 (u64), +60, +64, or the phase string.

Also here: savegame_edit.py --slot for SHAB records, and boot_menu.sh itself --
nav_probe.sh's boot loads a save, which with probe slots on disc loads a probe,
and a dropped d-pad step there put A on TAKE OFF and spent a boot loading a
mission.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-11 19:37:06 +00:00
parent 6e0fbe52a6
commit eac3435cc7
3 changed files with 87 additions and 3 deletions

View File

@@ -82,11 +82,11 @@ photographed against this exact save (see "Naming the fields", further down).
| +24 | **4101** (`0x1005`) | ✅ **Points — the spendable balance.** Named from the Details panel, and **separated from +28** by the develop differential: spending 4000 P moved *only* this field (4101 → 101) and the panel then read `Points 101 P` |
| +28 | **4101** (`0x1005`) | 🟡 **not** the displayed Points — it did **not** move when 4000 P was spent. A lifetime/earned total is the obvious read; unproven until a save is taken after *earning* points |
| +32 | 79 | ❔ |
| +36 | 2 | 🟡 **difficulty or stage** — the panel shows `Difficulty EASY` *and* `STAGE 02`, and +36/+52/+56 all hold 2, so which is which is **not** decidable from one save |
| +36 | 2 | **not** difficulty and **not** stage — refuted by probe saves (see below) |
| +40 (u64) | 2014400 | ❔ |
| +48 | 0 | ❔ (`Times Cleared: 0` is on screen, so it is one of the zero fields) |
| +52 | 2 | 🟡 see +36 |
| +56 | 2 | 🟡 see +36 |
| +52 | 2 | see +36 — refuted |
| +56 | 2 | see +36 — refuted |
| +60 | 0 | ❔ |
| +64 (raw 4) | `09 15 00 00` | ❔ the trailer's u32 is the **same** value |
| +68 (raw 54) | see below | ✅ **per-item Arsenal development state**, one byte per item, `4` = owned, `2` = developable now, `0` = locked ([evidence](#the-develop-differential-one-weapon-three-fields)). Only the `4`s are stored state — `2` is re-derived at load. The index space is **solved**: it is `strings.tbl`'s item order, cut items included ([mapping](../arsenal-develop-economy.md)) |
@@ -298,4 +298,35 @@ What the title does with an edited save is itself a finding: on load it
can now develop …"). So the blob's `4`s are authoritative state and its `2`s are
not — see the economy note.
### What the probes then refuted: +36 / +52 / +56 are **not** stage or difficulty
The three fields that all hold `2` were read as "difficulty or stage, undecidable
from one save" from the day the format was parsed. Writing saves makes it
decidable, and the answer is **neither**.
Method — [`boot_menu.sh`](../../../tools/re-capture/boot_menu.sh) boots to the
title menu **without loading anything**, and LOAD GAME's slot list renders each
slot's Details panel (`STAGE`, `Game Status`, `Points`, `Times Cleared`) plus a
row (date, `Difficulty`, flight time, clear ratio) straight out of that slot's
payload. Extra slots can be fabricated — copy the save directory and its
`Headers/…/gameNN.header`, patching the UTF-16BE display string and the ASCII
`gameNN` inside it — so **four probes fit in one boot**, read-only, nothing
loaded.
Eleven candidate fields were written and read back: `+36` at 1, 3 and 9; `+52`
and `+56` at 1 and 9; `+0`, `+16`, `+32`, `+48`, `+28`, and `SHAB[0].a` — every
one of them left the panel at `STAGE 02 / Declaration of War`, `Difficulty EASY`,
`At Standby`, `Times Cleared 0`.
The negative is meaningful because the panel demonstrably *does* read each
payload: slot 02 shows `Clear Ratio 5 %` against the others' `6 %`, and `Points`
tracked `+24` exactly. Two further controls: patching a slot's **header** string
to `STAGE09 HARD` changed nothing, so the display is payload-driven, not header
text; and the row's date follows the **container FILETIME**, which is why every
fabricated slot showed 18:04.
So stage and difficulty live in one of the remaining unprobed fields — `+12`,
`+20`, `+40` (u64), `+60`, `+64` (raw 4) — or in the phase string. That is the
next probe round, and it is now cheap.
Editing beyond a throwaway slot is still the user's call.