Followed the writer, not the reader. [phase+10160]'s only writer in the image is one site in the mission frame loop sub_821AA1B0: it does obj->get() on an object fetched from a registry by id 0x20FFFF02, stores it to the phase, then clears the object -- read, publish, clear, every frame. The id namespace has exactly three members (0x20FFFF00/01/02), each built at exactly 4 sites, and two of those are in sub_821D5178, which gets 0x20FFFF01 and 0x20FFFF02 and logs both: GamePart_ReadyRoom::Impl::OnCommand - Wait() command is requested. Check flow control valiables. WAIT_MODE : %d, REQUEST_NEXT : %d Argument order gives 0x20FFFF01 = WAIT_MODE, 0x20FFFF02 = REQUEST_NEXT. PrepareScript corroborates: it sets WAIT_MODE=1, REQUEST_NEXT=0 before an ISL script runs. So the six tutorial stages' lone dominating condition request_next() != 1 is the script waiting on the game part's proceed flag. 6 artefact lines changed, all 6 pair exactly.
6.4 KiB
🟡 The three built-ins that appear inside clear conditions — read, not named
isl-phase-guards produced the per-phase clear
conditions, but three of the built-ins in them were unread, so the conditions
were only half-readable. All three are read now. None of them is named — the
corpus has withdrawn two names taken from usage shape, and what I read is not
enough to name these.
Implementations via the vtable at 0x820A84BC (control: built-in 69
unit_state → slot 184 → 0x8226ADF0, as recorded).
| built-in | slot | implementation |
|---|---|---|
| 104 | 288 | 0x8226BFE0 |
| 141 | 428 | 0x8226C9B8 |
| 7 | 40 | 0x82266C68 |
✅ builtin104 is a pure getter — and it is the whole tutorial clear condition
8226BFE0 lwz r11, 10160(r3) ; r3 = the ScriptPhase
8226BFE4 stw r11, 164(r3) ; -> special[0]
8226BFE8 blr
Three instructions. It returns [phase+10160] and nothing else. So all six
tutorial stages (S18–S23) end on the value of a single engine-written word —
which is exactly why their exits have one dominating condition each and why
isl-builtins.md saw built-in 104 only ever inside a poll loop.
That word has exactly one writer in the whole image:
821AAD74 lwz r11, 104(r30)
821AAD84 lwz r11, 12(r11)
821AAD88 cmpi cr6, 0, r11, 16 ; skip if == 16
821AAD90 cmpi cr6, 0, r11, 32 ; skip if > 32
821AAD98 lwz r11, 4(r10)
821AAD9C stw r29, 10160(r11) ; <- the only write
inside sub_821AA1B0, gated on a type/kind field being in (16, 32]. r29
there comes from or r29, r3, r3 — the return of a preceding call.
✅ (2026-08-27) NAMED — built-in 104 is request_next, and the game says so itself
r29 is the return of a getter on an object fetched from a registry by id:
821AAD1C lwz r4, 2424(r30) ; the registry
821AAD20 addis r5, r0, 0x20FF
821AAD28 ori r5, r5, 0xFF02 ; <- the id
821AAD38 bcctrl ; registry->slot1(&out, 0x20FFFF02)
821AAD40 lwz r11, 0(r3) ; lwz r11, 8(r11)
821AAD4C bcctrl ; r29 = obj->slot2() -- GET
821AAD9C stw r29, 10160(r11) ; -> [phase+10160]
821AADA0..DD4 ; then the SAME id again, obj->slot1(0) -- CLEAR
So the frame loop reads the value, publishes it to the script, and clears it.
The id namespace has exactly three members — 0x20FFFF00, 0x20FFFF01,
0x20FFFF02 — each built at exactly 4 sites image-wide. Two of those sites are
in sub_821D5178, which fetches 0x20FFFF01 and 0x20FFFF02, calls the same
slot2() getter on each, and passes both to a log call whose format string is
at 0x820A4968:
silph::GamePart_ReadyRoom::Impl::OnCommand - Wait() command is requested.Check flow control valiables. WAIT_MODE : %d, REQUEST_NEXT : %d
Argument order settles which is which: r4 (first %d, WAIT_MODE) is
0x20FFFF01's value, r5 (second, REQUEST_NEXT) is 0x20FFFF02's.
⇒
[phase+10160]isREQUEST_NEXT, and built-in 104 returns it.
That is the game's own name for the variable, not a shape-based guess.
Corroboration: GamePart_ReadyRoom::Impl::PrepareScript sets WAIT_MODE = 1
and REQUEST_NEXT = 0 before an ISL script runs, and sub_821AA1B0 clears both
each frame after reading. [phase+10160] has exactly one writer and one
reader in the whole image (the two above); the three other hits on offset
10160 are lfs on unrelated objects.
So the six tutorial stages' exit condition request_next() != 1 is the script
waiting on the surrounding game part's proceed flag — which is why S18–S23
each have exactly one dominating condition.
🟡 Still unread: what the (16, 32] gate on [r30+104]'s +12 selects, and
0x20FFFF00, the third id (used by the GRAPH_PATH / EX_FONT / SYSTEM
code in sub_821D6350 and sub_821D6A40).
🟡 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
description, not a name.
✅ builtin7's mechanism — and an independent confirmation
82266C84 lwz r11, 324(r25) ; the unit array
82266C88 lwz r10, 4(r26) ; local[4]
82266C94 lwzx r11, r10, r11 ; -> the record
82266C98 lwz r10, 4(r11) ; the handle … (alive?)
82266CA4 lwz r11, 16(r11) ; rec+16 = the unit STATE
82266CA8..CBC ; bail if state == 1, 3 or 4
82266CC0 lwz r10, 12(r26) ; local[12]
82266CC8 lwz r11, 244(r25) ; [phase+244] = SYMBOL TABLE 1
82266CD8 lwzx r10, r10, r11 ; -> resolve local[12] as a symtab-1 index
82266CD0 lfd f31, 25600(r9) ; a double constant
82266CD4 lwz r9, 16(r26) ; local[16]
🔑 isl.py's SYM1_SLOTS already lists slot 12 for built-in 7, derived
purely from operand ranges. Reading the implementation shows the mechanism —
local[12] is indexed into [phase+244], which
isl-bytecode.md documents as symbol table 1 (routes,
messages, objectives). Two independent methods, same conclusion.
That makes the Stage 02 phase-2 condition
builtin7(TCT206, 1, Route_TCT206_p2S, 4294967295, 500) == 1
structurally coherent — a unit, a route symbol, and two numbers — but what
it asks about the route is not read, so it stays builtin7.
🟡 builtin141 — only the entry read
8226C9D4 lwz r11, 324(r29) ; unit array
8226C9D8 lwz r10, 4(r31) ; local[4]
8226C9E8 lwz r8, 4(r8) ; handle
8226C9F0 bc … 0x8226CA0C ; if alive, continue
8226C9F4 addi r11, r0, 0
8226C9F8 stw r11, 164(r29) ; dead -> special[0] = 0
The same unit-array opening as every unit predicate, returning 0 when the unit is
gone. Everything past 0x8226CA0C is unread. Stage 16 calls it twice with
arguments differing in one position (0 vs -4000), which looks like a
coordinate — and looking like one is precisely the evidence this corpus does not
accept.
🟡 Not settled
- No name for any of the three. For 104 that needs the meaning of
r29at0x821AAD9Cand of the(16, 32]gate; for 7 and 141, their bodies past the entry checks. builtin103's fields[phase+10152]/[phase+10156]have 9 and 7 writers, none read.- This does not change any artefact — the conditions already printed
builtin104,builtin7,builtin141, and still do.