re: a title-side transition is a screen lookup BY NAME, not by id

Continuing Q6's last residual -- the control flow I left unread.

All three state-name sites in sub_821C6458 compile to the same shape:
load the name, then bl 0x821CC860 with it in r5 and 0 in r6, then hand
the result to sub_82187B78. So a transition is lookup-by-string then
install: sub_821CC860(this+88, this+24, "TITLE_SCREEN", 0). Not a numeric
id and not a table index. That also explains something that had been
sitting unexplained -- GP_ADVERTISE_DEMO having zero xrefs -- because at
this level the screen graph is keyed by name rather than by GamePart id.

sub_821CC860 has 28 callers, and the upper-case identifiers in that
neighbourhood split cleanly into screen names and config keys. Three of
the screen names are corroborated by measurements I took before ever
opening this function: DIFFICULTY is what NEW GAME opens, EXTRA_MENU is
the EXTRAS submenu, TUTORIAL_MENU the lesson list. That is the static
side agreeing with the dynamic side on names neither knew about the
other.

Held at amber deliberately. The 35 strings are what those callers
REFERENCE, not proven arguments, and the list plainly mixes screen names
with things like TEXT_FONT and GAMMA_RGB. Confirming it means checking
per call site which string actually lands in r5, and I did not do that.

Still unread: which state leads to which. The three lookups sit in
different branches and TITLE_MENU's is guarded by a cmplwi/bne, but I did
not trace the branch structure, so the ORDER still comes from measurement
rather than from the code.
This commit is contained in:
Sylpheed RE agent
2026-08-28 19:46:43 +00:00
parent ab99dedd02
commit 82b2f861f0
2 changed files with 74 additions and 6 deletions

View File

@@ -189,3 +189,63 @@ before them are the tail of
zero-filled descriptors — static-initialiser records trailing the registration
strings, not a dispatch table. A plausible-looking array of function pointers next
to relevant strings is not evidence of anything until its neighbours are read.
## 🟡 The title's transition is a screen lookup BY NAME — `sub_821CC860`
Reading the code around each of the three state names shows the **same four
instructions** at all three sites:
```
lwz r29, 20(r30) ; an object off the part
lwz r3, 4(...) ; ...
bl 0x822F2328
lis r11, 0x820A
li r6, 0
lwz r4, 24(r30)
addi r5, r11, 15676 ; "TITLE_SCREEN" (15664 = "TITLE_MENU",
lwz r3, 88(r30) ; 8524 = "LOADING")
bl 0x821CC860 ; <- lookup(this+88, this+24, NAME, 0)
mr r4, r3
bl 0x82187B78 ; <- install the result
```
So a title-side transition is **`sub_821CC860(…, "<NAME>", 0)` followed by
`sub_82187B78(result)`** — a *string-keyed* screen lookup, then an install. Not a
numeric id, not a table index. That also fits `GP_ADVERTISE_DEMO` having zero
xrefs: at this level the screen graph is keyed by **name**, not by GamePart id.
### The candidate name vocabulary
`sub_821CC860` is called from **28 distinct functions**. Collecting the
upper-case identifier strings those callers reference gives 35 names, and they
split into two obvious families:
* **screen/state names** — `TITLE_SCREEN`, `TITLE_MENU`, `LOADING`,
**`DIFFICULTY`**, `EXTRA_MENU`, `TUTORIAL_MENU`, `STANDARD_MENU`, `DEBRIEFING`,
`CHALLENGE`, `MISSIONS`, `LIVE_BOARD`, `LOCAL_BOARD`, `EXTRA_MENU`;
* **config keys** — `TEXT_FONT`, `TEXT_HEIGHT`, `LINE_SPACE`, `GAMMA_RGB`,
`GAMMA_WB`, `TEXT_SPEED_PER_LETTER`, `EXIT_VALUE`, `INPUT_DIR`,
`MENU_ENABLE_SKIP`/`_DISABLE_SKIP`, `PAUSE_SE`, `JINGLE`, …
plus `BASE_INFO` in **19 of the 28** callers, which is this corpus's existing
marker for a screen-config function.
**Three of the screen names are independently corroborated by measurement**:
`DIFFICULTY` is exactly the screen `NEW GAME` opens, `EXTRA_MENU` matches the
`EXTRAS` submenu and `TUTORIAL_MENU` the lesson list — all three measured off the
running game in [`menu-navigation-semantics.md`](menu-navigation-semantics.md)
before this function was ever looked at.
⚠️ **Why this is 🟡 and not ✅.** The 35 strings are what those callers
*reference*, **not** proven arguments to `sub_821CC860` — the list plainly mixes
screen names with config keys, so it is a **candidate vocabulary**, not a decoded
one. Confirming it means checking, per call site, which string actually lands in
`r5`. That was not done.
### What is still unread
Which state leads to which. The three lookups sit in different branches of one
function and at least one (`TITLE_MENU`) is guarded by a `cmplwi`/`bne`, but the
branch structure was not traced, so the *order* still comes from measurement, not
from the code.