own corroboration from last iteration Last iteration I listed a candidate name vocabulary from "upper-case strings the callers reference", marked it amber because those are not proven arguments, and named the check: confirm per call site which string actually lands in r5. Ran the check. It fired. The first extractor FAILED ITS OWN CONTROL -- a backward scan for addi r5 recovered 7 of 48 sites and missed both title sites I had already read by eye, because there the name is built in r27 and reaches r5 via a later mr. Rewritten as a forward register simulation it reproduces all three known sites and recovers 46 of 48, giving 28 distinct names. Two of my own claims die. DIFFICULTY and EXTRA_MENU are NOT arguments at any site -- they are strings that merely live in the same functions, so the "independently corroborated by measurement" line I wrote was an artifact of the loose filter. Only TUTORIAL_MENU survives. And sub_821CC860 is not a screen factory at all: its real arguments include BG, BLACK, FADE, FILE, KEY, PAD, SOUND and GAMMA_RGB. It is a generic name-keyed lookup, mostly config, which the title part happens to call with its three state names. The title finding itself is untouched -- sub_821C6458 really does transition by calling this with TITLE_SCREEN, TITLE_MENU and LOADING. What is gone is the inference that the 28 names are a screen vocabulary. Two METHOD lines, both earned here: strings a function references are not arguments it passes, and a backward scan for a destination register misses arguments staged through a scratch register.
14 KiB
What the game reads at boot — config.ini, and which GameParts actually exist
Status: ✅ CONFIRMED and decoded for the language selection. ❔ a bounded
negative for the boot order. 🟡 for what the registration strings imply
about the attract loop.
Contributes to MISSION Q6, and firms up Q4's ids.
✅ config.ini — the disc's only config, and it selects the language
config.ini sits at the disc root, is 400 bytes, and is the only .ini,
.cfg or .txt anywhere on the disc. Its own header comment (Shift-JIS) names
it:
アプリケーション/ゲームパート初期設定テーブル— "Application / GamePart initial settings table"
SYSTEM セクションには、ゲーム及び各ゲームパートで共通にアクセスする情報を記述する— "the SYSTEM section describes information accessed in common by the game and each game part"
[SYSTEM]
[LANGUAGE]
= eng ; default
#0x01 = eng ; XC_LANGUAGE_ENGLISH
#0x02 = jpn ; XC_LANGUAGE_JAPANESE
#0x03 = deu ; XC_LANGUAGE_GERMAN
#0x04 = fra ; XC_LANGUAGE_FRENCH
#0x05 = esp ; XC_LANGUAGE_SPANISH
#0x06 = ita ; XC_LANGUAGE_ITALIAN
This is the mechanism behind the EN/JP screen pairs. The console's
XC_LANGUAGE_* setting selects a three-letter code, and that code is what picks
GP_TITLE's English or Japanese build (ui-title-build-map.md)
and the <lang>.pak families. Default is eng, keyed by the empty line — an
unlisted language falls back to English. ✅ decoded. The executable does read the
file: the string config.ini is at .rdata 0x82062b44.
❔ But the boot ORDER is not in it — and this is the whole search space
[SYSTEM] — the section the file's own comment says holds what the game and every
game part share — is empty. So the file the game itself calls the GamePart
initial settings table says nothing about which part runs first or what follows
what.
Reach of the negative: this is the only config file on the disc (one find
over the whole extract). The boot order is therefore not in disc-side
configuration at all; it is in code, or in a table inside the executable that has
not been located.
🟡 GP_ADVERTISE_DEMO is never registered — the attract loop is not its own part
The executable carries one diagnostic string per GamePart registration site
(silph::GamePartTask::RegisterToFactory<N, class silph::GamePart_X>::RegisterToFactory is failed!)
— the same evidence the corpus used to pin the id table
(challenge-mission-gate.md §3). Extracting all of
them gives 24 of the 29 ids bound to a C++ class; full list in
data/gamepart-class-ids.txt.
The five ids with no registration site are 1, 2, 16, 18, 28 — in the
id table's naming, GP_ADVERTISE_DEMO, GP_SELECT_STORAGE, GP_DEMO,
GP_SELECTOR, GP_TEST.
That GP_ADVERTISE_DEMO (1) is among them matters for Q6, and it agrees with
what was measured: the attract loop is the title screen replaying ADV.wmv
(movie-binding.md), not a transition into a separate
advertise part. The id table names a part the shipped build never registers.
🟡 not ✅, because this is an argument from a diagnostic string: no error message for id 1 implies no registration site for id 1. That is how the corpus already reads these strings, and it is sound, but it is not the code.
Two bonuses for Q4
3and4are the same class —GamePart_SaveLoadis registered twice. The id table's separateGP_LOAD/GP_SAVEnames are two ids on one part.- The ids behind the menu buttons now match the executable's own class names,
not just a list of table names:
GamePart_Options= 8,GamePart_Tutorial= 25,GamePart_Extras= 5,GamePart_MissionSelect= 7,GamePart_MovieTheater= 6,GamePart_Title= 0. Still a name match — screen title ↔ class name — but anchored one level closer to the code.
What is still missing for Q6
The transitions. Nothing found so far says "title, then movie, then title" — the
manifest gives the boot-side assets in play order
(movie-binding.md), config.ini gives the language, and
the registry gives which parts exist. What decides to advance is in
GamePart_Title's own code, and reading it is a static PPC job that has not been
started.
❔ The transitions are code, not data — the reach of that negative
Q6's remaining half asked what the game reads to decide the boot order. The answer is: nothing. It is not data-driven. Four independent places were checked, and the sequence is in none of them.
| looked in | result |
|---|---|
| disc configuration | config.ini is the only config file on the disc, its [SYSTEM] section is empty (above) |
| the movie manifest | carries the boot-side assets in play order, and no transitions — movie-binding.md |
| a persistent part-id field | already refuted: the requested GamePart id exists only as a stack argument in flight, with no literal store anywhere — challenge-mission-gate.md §5 |
| the id table's attract entry | the string GP_ADVERTISE_DEMO at 0x820a1fe8 has zero xrefs of any kind; nothing in the code reads it |
So a transition is a call with an id argument, chosen by code. There is no table to read and nothing to poke.
Where that code is, as far as it was traced. The RegisterToFactory<0, class silph::GamePart_Title> diagnostic string at 0x820a3d60 is referenced from
exactly one place, sub_8280E148 — the registration site — which also takes the
address of sub_821C7D98 (addi), the position a factory template puts its
creator. 🟡 That identification is by position and convention, not proven;
sub_821C7D98 itself has 0 .rdata references, consistent with a small
new+ctor thunk rather than the state machine. The substantial function in the
same class neighbourhood is sub_821C6458 (4 460 bytes, has EH, 15 .rdata
refs), and reading it has not been attempted.
What this means for the port
The boot sequence is authored, not transcribed — and that is fine, because the sequence itself is measured end to end:
developer splash (a RATC screen, not a video)
→ ADV.wmv
→ title + PRESS Ⓐ ──idle ~8–10 s──> fade to black → ADV.wmv in full → title
→ Ⓐ → main menu
with the fade-through-black timings in screen-transitions.md
and Ⓑ from the main menu returning to the title.
🟡 sub_821C6458 read — the title's states are NAMED in the executable
The page above left this function as the named next step: "the substantial
function in GamePart_Title's neighbourhood, and reading it has not been
attempted". It has now been looked at — not disassembled line by line, but
characterised, which is enough to sharpen Q6.
It is the title part's screen-state function. 4 460 bytes, has EH, and called
from exactly one place — sub_821C7850, which sits in the same neighbourhood
as the creator the registration site points at (sub_821C7D98). It makes 33
distinct calls.
What it names. Its .rdata string references are:
| string | at |
|---|---|
TITLE_SCREEN |
0x820a3d3c |
TITLE_MENU |
0x820a3d30 |
LOADING |
0x820a214c |
BASE_INFO (×2) |
0x820a20ec |
Those are the states measured off the running game, in the game's own words: the
title carrying PRESS Ⓐ BUTTON, the five-button menu, and a loading state. And
BASE_INFO is this corpus's own marker for a screen-config lookup rather than
a table read (REFUTED.md, "BASE_INFO discriminates
screen-config from table-read, 9/9 vs 10/10").
The sharper negative
So the title part does ask for configuration keyed by TITLE_SCREEN and
TITLE_MENU — and config.ini,
the disc's only config file, contains no such sections. Its only sections are
an empty [SYSTEM] and [LANGUAGE]. The lookups find nothing, and the values are
whatever the code defaults to.
That is a better answer than "the order is not in config": the game asks the question, the shipped disc does not answer it, and the defaults live in code. For the port it means the state names are transcribable even though their contents are not.
🟡 Not ✅. This is a characterisation from string references and call counts,
not a read of the control flow. Two self-references (0x821c6498, 0x821c6b7c)
inside the function look like jump tables — a switch, which is what a state
machine compiles to — but that was not confirmed, and nothing here shows which
state leads to which.
🔴 Refuted on the way, because it looked like a find
The words at 0x820a3b48… resolve as neat {func, func, ptr} triples and read
convincingly as a state/handler table. They are not. The bytes immediately
before them are the tail of
…SaveLoad>::RegisterToFactory is failed!, and the 0x8210c1xx targets are
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
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.
✅ The argument is now decoded — and it refutes my own corroboration
The section above listed a candidate vocabulary from "upper-case strings the
callers reference", flagged 🟡 because those are not proven arguments, and named
the check: confirm per call site which string actually lands in r5. That check
has been run, and it fired.
Method. Forward register simulation over the 100 instructions before each of
the 48 call sites of sub_821CC860, tracking lis / addi / subi / mr.
Full table in data/name-lookup-callsites.txt.
Gated on a control, and the first version failed it. A backward scan for
addi r5, … recovered only 7/48 and missed both title sites I had read by
eye — because there the name goes into r27 first and reaches r5 via a later
mr. The rewritten forward simulation reproduces all three known sites
(TITLE_SCREEN, TITLE_MENU, LOADING) and then recovers 46 of 48.
🔴 DIFFICULTY and EXTRA_MENU are not arguments
Last section I wrote that three names were "independently corroborated by
measurement": DIFFICULTY, EXTRA_MENU, TUTORIAL_MENU. Only
TUTORIAL_MENU survives. DIFFICULTY and EXTRA_MENU never appear in r5 at
any of the 48 sites — they are strings that merely live in the same functions.
The corroboration I claimed was an artifact of the loose filter, and the 🟡 I put
on it is exactly what caught it.
The 28 names that ARE passed
BASE BASE(x3) BG(x3) BLACK(x2) BUTTON DEBRIEFING DETAIL EXTRA FADE(x3)
FILE(x5) GAME GAMMA_RGB GAMMA_TITLE INFO KEY LIVE_BOARD(x2) LOADING(x2)
LOCAL_BOARD(x2) MENU(x2) MENU_DISABLE_SKIP MESSAGE NEW_ITEM(x2) PAD SOUND
TITLE(x2) TITLE_MENU TITLE_SCREEN(x2) TUTORIAL_MENU WINDOW
🔴 So sub_821CC860 is not a screen factory
The previous section called it one. The real argument list says otherwise:
BG, BLACK, FADE, FILE, KEY, PAD, SOUND, WINDOW, GAMMA_RGB,
MENU_DISABLE_SKIP are not screens. It is a generic name-keyed lookup —
a named-entry getter used for config and resources throughout the executable, of
which the title part happens to call it with its three state names.
That weakens nothing about the title finding itself — sub_821C6458 really does
transition by calling this with TITLE_SCREEN / TITLE_MENU / LOADING — but it
removes the inference that the 28 names are a screen vocabulary. They are a
lookup-key vocabulary, mostly config.