re: STAGENN_UNIT_MAX holds two per-stage caps, PLANE and VESSEL

Reading sub_82261F70 past the table lookup finishes the mechanism the
stage index feeds: the section name is built from the 0-based stage
index, looked up, and two ints land in the phase --

  [phase+356] = PLANE   (default 200)
  [phase+360] = VESSEL  (default 20)

with the defaults taken when a stage has no entry.  Key strings are
0x820A8B14 "PLANE" and 0x820A8B1C "VESSEL"; section and both keys are
the game's own names.  Surrounding reads (GP_SCRIPT, SCRIPTS,
Resource2D, TABLE) plus the pak census's 40 <?xm entries make this an
XML config reader.

Register discipline mattered twice: in sub_82261F70 r21 is the phase
and r31 is the STACK frame, and 0x82273400 lwz r11, 360(r11) in the
built-in switch is a vtable slot 90 call, not a phase read.

Not settled: the values (a crude zlib scan found no UNIT_MAX, but it
did not use the corpus's pak reader, so that is not evidence of
absence), and no consumer of the two fields was identified.

Docs only; artefacts byte-identical.
This commit is contained in:
Sylpheed RE agent
2026-08-27 11:14:17 +00:00
parent 17d1d2c999
commit ad5270cfdd
2 changed files with 71 additions and 0 deletions

View File

@@ -290,6 +290,51 @@ the built-in switch looks like a read of this field. It is not: `r11` had just
been loaded from `0(r31)`, so it is the **vptr** — that instruction is a virtual
call to **slot 38**. Offset 152 recurs; the base register decides.
## ✅ (2026-08-27) What `STAGENN_UNIT_MAX` is: two per-stage unit caps, `PLANE` and `VESSEL`
The lookup in `sub_82261F70` continues straight past the table read. `r21` is the
phase there; `r31` is the **stack frame** (`addi r4, r31, 452`, `lwz r11, 376(r31)`
— easy to misread as phase fields).
```
82262308 bl 0x824480D0 ; open the config node -> [r31+84]
8226230C lwz r11, 152(r21) ; the 0-based stage index
8226231C lwzx r4, r11, r10 ; "STAGE(N+1)_UNIT_MAX"
82262320 bl 0x82448AA0 ; find that section
82262328 bc 4, eq, 0x82262340 ; found -> read two keys
; NOT found — defaults:
82262334 stw r11(=20), 360(r21)
82262338 stw r10(=200), 356(r21)
; found:
82262348 addi r4, r11, -29932 ; 0x820A8B14 = "PLANE"
82262360 stw r11, 356(r21)
8226235C addi r4, r10, -29924 ; 0x820A8B1C = "VESSEL"
82262368 stw r3, 360(r21)
```
| phase field | config key | default |
|---|---|---|
| `[phase+356]` | **`PLANE`** | **200** |
| `[phase+360]` | **`VESSEL`** | **20** |
So the section is a per-stage pair of **unit caps** — planes (fighters) and
vessels (capital ships) — with the section name built from the stage index and
the whole thing falling back to 200/20 when a stage has no entry. All three names
are the game's own.
The surrounding reads name the config itself: `GP_SCRIPT` (`0x820A8244`),
`SCRIPTS`, `Resource2D`, `TABLE`. The pak census counts **40 `<?xm` entries**, so
this is an XML config reader (`sub_824480D0` open, `sub_82448AA0` find-section,
`sub_824482D0` read-int, `sub_82448C50` / `sub_824490E0` others).
🟡 **The values themselves are not confirmed from the data side.** A crude
`Z1`+zlib scan over `dat/*.pak` found no `UNIT_MAX` — but that scan did not use
the corpus's own pak reader (`unitgroup.py`), so it is **not** evidence of
absence. 🟡 No reader of `[phase+356]` / `[phase+360]` was identified: the
offsets recur, and the one ISL-region hit that looked promising
(`0x82273400 lwz r11, 360(r11)`) is a **vtable slot 90 call** — `r11` is the
vptr — which is built-in 123, consistent with the known mapping.
🟡 Its neighbours belong to the same cluster: `builtin103` reads
`[phase+10156]` and `[phase+10152]` (9 and 7 writers), and a sibling vtable stub
clears `[phase+10152]`. The shape is an engine→script status trio, but that is a