From f41ef43fa4eb85efcf2a04d33a35940289b4c284 Mon Sep 17 00:00:00 2001 From: Sylpheed RE agent Date: Wed, 26 Aug 2026 00:44:38 +0000 Subject: [PATCH] re: name the five mission-banner built-ins from call-site structure 77, 78, 81, 82 and 135 were unnamed. The engine has five contiguous strings -- MISSION_START_PRT at 0x820A83F0, then _END_, _UPDATE_, _FAILED_, _RESTART_ -- and five sequential ScriptPhase fields at +388/+392/+396/+400/ +404, stored in ascending order by one constructor region. Five names, five fields, five unnamed built-ins. Which is which is decided by call-site structure, measured over all 28 stages, and it is exact: 39 MARK_LAST_PHASE 89 sites -> 82 in 89/89 82 banner_mission_failed <- 39 in 89/89, then wait_s 89/89 40 mark_not_last 50 sites -> 78 (27) + 81 (17) + END_PHASE (6) = 50 78 banner_mission_complete <- 40 in 27/27 81 banner_objective_update <- 40 in 17/17 77 banner_mission_start 22 sites in 22 stages, one per stage, after play_bgm 135 banner_mission_restart 16 sites, after play_bgm, phase >= 2 39 -> 82 is a perfect pairing and 40's sites partition exactly three ways. Stated as inferred rather than read: the string-to-field pairing itself comes from both sequences ascending in the same order; my operand tracker did not catch the string loads in that constructor. The ROLES above do not depend on it. 76 is left unnamed on purpose. It has 38 sites = 22 + 16, exactly 77's count plus 135's, and precedes them; its body sets [phase+332] = 1 and nothing in the image reads that field. Suggestive arithmetic is not a name. Flagged as a consequence: MARK_LAST_PHASE is followed by the FAILED banner in 89 of 89 sites and mark_not_last by END or UPDATE. So [phase+300] = 2 reads less like "this is the last phase" than "end the mission now, unsuccessfully" -- the existing names for that pair may be mis-framing it. Artifact regenerated: docs/re/data/isl-stage02.txt. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE --- docs/re/data/isl-stage02.txt | 7 +++++- docs/re/structures/isl-builtins.md | 40 ++++++++++++++++++++++++++++++ tools/re-capture/isl.py | 3 +++ 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/docs/re/data/isl-stage02.txt b/docs/re/data/isl-stage02.txt index 2aff4ba7..e05498dc 100644 --- a/docs/re/data/isl-stage02.txt +++ b/docs/re/data/isl-stage02.txt @@ -110,6 +110,7 @@ Generated by `tools/re-capture/isl_report.py calls`. 115 named_event 9 48 squadron_escort 8 39 MARK_LAST_PHASE 8 + 82 banner_mission_failed 8 17 wait_frames 6 10 random 6 123 timer_resume 5 @@ -118,6 +119,10 @@ Generated by `tools/re-capture/isl_report.py calls`. 52 play_stream 3 14 play_bgm 3 62 FORCE_END_PHASE 3 + 81 banner_objective_update 2 + 135 banner_mission_restart 2 + 78 banner_mission_complete 2 + 77 banner_mission_start 1 127 timer_set 1 ## phase code bases @@ -180,7 +185,7 @@ resync from 0x5058 0052B0: 00000C13 call len=12 k=00,00 0000005D 00000257 clear_flag(0xFFFFFFFF) 0052BC: 00000C13 call len=12 k=00,00 00000076 00000258 builtin118 0052C8: 00000C13 call len=12 k=00,00 00000027 0000025A MARK_LAST_PHASE -0052D4: 00000C13 call len=12 k=00,00 00000052 0000025B builtin82 +0052D4: 00000C13 call len=12 k=00,00 00000052 0000025B banner_mission_failed 0052E0: 01021001 set.f len=16 k=01,02 00000000 40100000 00000000 special[0] = imm 4 0052F0: 02030C01 set.f len=12 k=02,03 00000000 00000000 local[0] = special[0] 0052FC: 00000C13 call len=12 k=00,00 00000004 0000025C wait_s(4) diff --git a/docs/re/structures/isl-builtins.md b/docs/re/structures/isl-builtins.md index e0acc9b1..cbede089 100644 --- a/docs/re/structures/isl-builtins.md +++ b/docs/re/structures/isl-builtins.md @@ -140,6 +140,46 @@ and spread checks but its maximum *exceeds* the table — flag indices run 0..31 against symbol tables as small as 40 — so it is excluded, and the disassembler now declines to resolve it rather than printing an invented name. +### ✅ Five built-ins are the mission banners — named from usage, not from a guess + +`77`, `78`, `81`, `82` and `135` were unnamed. The engine has five contiguous +strings — `MISSION_START_PRT` (`0x820A83F0`), `_END_`, `_UPDATE_`, `_FAILED_`, +`_RESTART_` — and five sequential `ScriptPhase` fields at `+388/+392/+396/+400/ ++404`, stored in ascending order by one constructor region +(`0x82262D30 … 0x82263340`). Five names, five fields, five unnamed built-ins. + +What decides *which is which* is the call-site structure, and it is exact: + +| built-in | sites | stages | preceded by | followed by | +|---|---|---|---|---| +| **39** `MARK_LAST_PHASE` | 89 | 22 | 118 (89/89) | **82 (89/89)** | +| **82** → `banner_mission_failed` | 89 | 22 | **39 (89/89)** | `wait_s` (89/89) | +| **40** `mark_not_last` | 50 | 28 | 118 (43) | **78 (27) + 81 (17) + `END_PHASE` (6) = 50** | +| **78** → `banner_mission_complete` | 27 | 22 | **40 (27/27)** | `wait_s` (27/27) | +| **81** → `banner_objective_update` | 17 | 12 | **40 (17/17)** | `wait_s` (17/17) | +| **77** → `banner_mission_start` | 22 | **22 — one per stage** | `play_bgm` (15) | `end_coroutine` (21) | +| **135** → `banner_mission_restart` | 16 | 12 | `play_bgm` (16/16) | `end_coroutine` (16/16) | + +`39 → 82` is a perfect 89/89 pairing, and `40`'s 50 sites partition *exactly* +into 78 / 81 / `END_PHASE`. One banner per stage after the music starts is a +mission-start banner; one after `mark_not_last` in a non-final phase is an +objective update. + +🟡 The string↔field pairing itself is **inferred from ordering** — both sequences +ascend in the same order — not read directly; my operand tracker did not catch +the string loads in that constructor. The *roles* above do not depend on it. + +❔ **76 is left unnamed**, deliberately. It has **38 sites = 22 + 16**, exactly +`77`'s count plus `135`'s, and it precedes them; its body sets `[phase+332] = 1` +and nothing in the image reads that field. The arithmetic is suggestive but a +name would be a guess. + +🟡 **A consequence worth flagging:** `MARK_LAST_PHASE` is followed by the +**FAILED** banner in 89 of 89 sites, and `mark_not_last` by the END or UPDATE +banner. So `[phase+300] = 2` reads less like "this is the last phase" and more +like "end the mission now, unsuccessfully". The names in this file are the +original ones and may be mis-framing that pair. + ### ✅ A symbol operand is a two-word pair: a **tag**, then the index This is why the unit indices sit at slots 4/12/20 and never at 0/8/16 — the even diff --git a/tools/re-capture/isl.py b/tools/re-capture/isl.py index a2811c7f..ea1b4ece 100755 --- a/tools/re-capture/isl.py +++ b/tools/re-capture/isl.py @@ -95,6 +95,9 @@ BUILTIN = { # resolves to symbol-table-1 type 7 -- `eff_n0071`, an EFFECT name -- in # 8/8, with a per-missile `Route_ADT30N_p3M` at slot 20. Whatever it does, # it is not aimed at a camera. Left unnamed rather than renamed on a guess. + 77: 'banner_mission_start', 78: 'banner_mission_complete', + 81: 'banner_objective_update', 82: 'banner_mission_failed', + 135: 'banner_mission_restart', 93: 'clear_flag', 94: 'is_engaged', 95: 'unit_hp_pct', 100: 'reset_phase_threads', 102: 'prompt_yes_no', 109: 'set_unit_flags', 115: 'named_event', 120: 'wait_cmds_drained', 123: 'timer_resume', 124: 'timer_stop',