re: X+12 is a 0-based STAGE INDEX -- proved by the game's own string table
Three iterations circled this. Following the value rather than the
filename settles it in two hops:
1. SilphScriptPhase's ctor sub_8225FEF8 never touches r7 (zero
mentions). The BASE ctor sub_822700C0 keeps it:
or r26, r7, r7 -> stw r26, 152(r30)
2. sub_82261F70 indexes a stack table of string pointers with that
field. The table is contiguous at 0x820A8880, 20 bytes/entry:
index 0 = STAGE01_UNIT_MAX ... index 32 = STAGE33_UNIT_MAX,
then PLANE at 33.
So X+12 = [phase+152] = a 0-based stage index, N -> STAGE(N+1), and the
gate is explained rather than described: <= 32 is the array bound (33
entries) and != 16 is STAGE17, the one stage number with no .ssb.
This retracts my own "not adopted": the stage-index reading was 1-of-1
but coincidence-shaped two iterations ago; 0-based is now PROVED by
index 5 -> STAGE06.
Caught a false positive: 0x82272D88 lwz r11, 152(r11) in the built-in
switch is a virtual call to slot 38 -- r11 is the vptr, not the phase.
Also names a third class: sub_822700C0 stamps 0x820A8E44 =
SilphScriptPhaseBase, so the hierarchy is Base <- ScriptPhase and
Base <- Demo.
Docs only; artefacts byte-identical.
This commit is contained in:
@@ -567,6 +567,40 @@ unknown, what evidence exists, and what the first step would be. Move an item in
|
||||
construction site is in `sub_8225EC78` — `sub_82260568(Y, r26, [X+12])` at
|
||||
`0x8225ED5C`. The kind goes **straight into the constructor as arg 3**.
|
||||
|
||||
* ✅✅ **(2026-08-27) SETTLED — `X+12` IS A 0-BASED STAGE INDEX. The gate is a
|
||||
bounds check on a 33-entry table, and `!= 16` is Stage17.
|
||||
[structures/isl-condition-builtins](structures/isl-condition-builtins.md).**
|
||||
Three iterations circled this. Following the *value* rather than the filename
|
||||
does it in two hops. **(1)** `SilphScriptPhase`'s ctor `sub_8225FEF8` **never
|
||||
touches `r7`** — zero mentions; the *base* ctor `sub_822700C0` keeps it:
|
||||
`or r26, r7, r7` → **`stw r26, 152(r30)`**. **(2)** `sub_82261F70` builds a
|
||||
string-pointer table on its stack and indexes it with exactly that field
|
||||
(`lwz r11, 152(r21)`; `rlwinm ×4`; `lwzx r4, r11, r10` where `r10 = r31+144`).
|
||||
The table is contiguous at **`0x820A8880`**, 20 bytes/entry:
|
||||
**index 0 = `STAGE01_UNIT_MAX` … index 16 = `STAGE17_UNIT_MAX` … index 32 =
|
||||
`STAGE33_UNIT_MAX`**, then `PLANE` at 33.
|
||||
⇒ **`X+12` = `[phase+152]` = a 0-based stage index, `N → STAGE(N+1)`** — and the
|
||||
gate is now explained rather than described: **`<= 32` is the array bound**
|
||||
(33 entries, 0…32) and **`!= 16` is STAGE17**, the one stage number with no
|
||||
`.ssb` on the disc.
|
||||
✅ **Retracts my own "not adopted".** Two iterations ago the stage-index reading
|
||||
scored 1-of-1 but was coincidence-shaped and deliberately not believed. It is
|
||||
now read off the game's own strings, and **0-based is PROVED by index 5 →
|
||||
`STAGE06`**, not assumed.
|
||||
⚠️ **False positive caught**: `0x82272D88 lwz r11, 152(r11)` in the built-in
|
||||
switch is not this field — `r11` had just been loaded from `0(r31)`, so it is
|
||||
the **vptr**, and the instruction is a virtual call to **slot 38**. Offset 152
|
||||
recurs; the base register decides.
|
||||
✅ **And a THIRD class** — [structures/isl-builtin-dispatch](structures/isl-builtin-dispatch.md).
|
||||
`sub_822700C0` stamps its own vptr `0x820A8E44` before `sub_8225FEF8` overwrites
|
||||
it: **`.?AVSilphScriptPhaseBase@silph@@`**, also 113 slots. So the hierarchy is
|
||||
`SilphScriptPhaseBase` ← `SilphScriptPhase` and ← `SilphScriptPhaseDemo`, and
|
||||
the Demo object is built by calling the **base** ctor then stamping the Demo
|
||||
vptr — which is why `sub_822700C0` shows up on both construction paths.
|
||||
🟡 Not settled: what `STAGENN_UNIT_MAX` resolves to (the lookup goes through
|
||||
`sub_824480D0` / `sub_82448AA0`), and whether `Stage30`–`Stage33` exist on the
|
||||
disc at all — the table has 33 slots but only 28 scripts were extracted.
|
||||
|
||||
## ✅✅ SOLVED — the mission freeze was a modal sign-in dialog (2026-08-26)
|
||||
|
||||
`XamShowSigninUI` opens a modal dialog and `xeXamDispatchDialog` blocks the
|
||||
|
||||
Reference in New Issue
Block a user