re: a Stage 02 clear condition read end to end, with squadron names

Resolving symbol-table-2 indices turns the bytecode into mission logic. At
0xF524 Stage02.ssb polls unit_state on ADN110, ADN111 and ADN112, updates each
one's objective marker, then latches set_flag(8) -- exactly the
trigger/predicate/set_flag/END_PHASE shape predicted from the disassembly, now
observed in the mission's own code with names the roster tables already gave.

The 12 END_PHASE sites are outro sequences (wait_cmds_drained / fade_sound(3) /
builtin85(3) / wait_s(3) / END_PHASE / yield) -- the terminator, not the
decision.

Fixes a decode bug that hid every argument: the tracker only followed
local[i] = special[0], but the common form is an immediate written straight into
local[i] (k=01,03), so every unit predicate printed with NO arguments. The
disassembly looked complete while being empty exactly where it mattered.

Also records the live probe result: the phase mirror at [*(0x828F35F8)+236]
stayed 0 for ~530s of actively-hunting flight, no advance observed -- which is
what the static analysis predicts for phase 1, since ChangePhase only posts once
the ordinal exceeds 1.
This commit is contained in:
Sylpheed RE agent
2026-08-25 12:42:50 +00:00
parent 70cff9ca21
commit dcf37bcf93
3 changed files with 426 additions and 5 deletions

View File

@@ -0,0 +1,345 @@
# Stage02.ssb -- condition sites, symbols resolved
# unit args are symbol-table-2 indices; resolved to names.
== set_flag: 12 sites
-- 0x2BE8
002A50: builtin91(0x1, 0x6F, 0x1)
002A8C: builtin91(0x1, 0x0, 0x1)
002AB0: start_coroutine(0x4C2C)
002AD4: start_coroutine(0x64C0)
002AF8: start_coroutine(0x6198)
002B7C: builtin75(0x39, 0x3A, 0x3B, 0x3C, 0x3D)
002BA0: play_stream(0x3ED)
002BC4: builtin38(0x1)
002BE8: set_flag(0x5)
-- 0x2DCC
002A8C: builtin91(0x1, 0x0, 0x1)
002AB0: start_coroutine(0x4C2C)
002AD4: start_coroutine(0x64C0)
002AF8: start_coroutine(0x6198)
002B7C: builtin75(0x39, 0x3A, 0x3B, 0x3C, 0x3D)
002BA0: play_stream(0x3ED)
002BC4: builtin38(0x1)
002BE8: set_flag(0x5)
002BF4: yield
-- 0xF7C0
00F4E4: objective_marker(0x1, 0x2D, 0x0, 0x8, 0x0)
00F524: unit_state(0x1, ADN110)
00F5A8: objective_marker(0x1, 0x1, 0x0, 0x8, 0x0)
00F5E8: unit_state(0x1, ADN111)
00F66C: objective_marker(0x1, 0x2, 0x0, 0x8, 0x0)
00F6AC: unit_state(0x1, ADN112)
00F730: objective_marker(0x1, 0x5, 0x0, 0x8, 0x0)
00F79C: objective_marker(0x1, 0x3A, 0x1, 0x8, 0x0)
00F7C0: set_flag(0x8)
-- 0x183B8
018220: start_coroutine(0x77D0)
018244: start_coroutine(0x8718)
018268: start_coroutine(0x91DC)
0182A4: builtin79(0x1, 0x6, 0x1, 0x75)
0182C8: start_coroutine(0x9264)
01834C: builtin75(0xBC, 0xBD, 0xBE, 0xBF, 0xC0)
018370: play_stream(0x3EB)
018394: builtin38(0x1)
0183B8: set_flag(0x5)
-- 0x18504
018244: start_coroutine(0x8718)
018268: start_coroutine(0x91DC)
0182A4: builtin79(0x1, 0x6, 0x1, 0x75)
0182C8: start_coroutine(0x9264)
01834C: builtin75(0xBC, 0xBD, 0xBE, 0xBF, 0xC0)
018370: play_stream(0x3EB)
018394: builtin38(0x1)
0183B8: set_flag(0x5)
0183C4: yield
-- 0x1A8B8
01A56C: unit_alive(0x1, ADN227)
01A5C8: unit_alive(0x1, ADN228)
01A624: unit_alive(0x1, ADN229)
01A680: unit_alive(0x1, ADN230)
01A6DC: unit_alive(0x1, ADN231)
01A738: unit_alive(0x1, ADN232)
01A824: builtin64(0xC3, 0x2, 0x1, 0x9, 0x1, -1)
01A87C: named_event(0xC4)
01A8B8: set_flag(0xE)
-- 0x1A980
01A680: unit_alive(0x1, ADN230)
01A6DC: unit_alive(0x1, ADN231)
01A738: unit_alive(0x1, ADN232)
01A824: builtin64(0xC3, 0x2, 0x1, 0x9, 0x1, -1)
01A87C: named_event(0xC4)
01A8B8: set_flag(0xE)
01A914: hp_pct_test(0x1, TCT206, 89.9)
01A950: named_event(0xC5)
01A980: set_flag(0xF)
-- 0x23750
023474: objective_marker(0x1, 0x1B, 0x0, 0x8, 0x0)
0234B4: unit_state(0x1, ADN206)
023538: objective_marker(0x1, 0x22, 0x0, 0x8, 0x0)
023578: unit_state(0x1, ADN208)
0235FC: objective_marker(0x1, 0x2F, 0x0, 0x8, 0x0)
02363C: unit_state(0x1, ADN209)
0236C0: objective_marker(0x1, 0x35, 0x0, 0x8, 0x0)
02372C: objective_marker(0x1, 0x40, 0x1, 0x8, 0x0)
023750: set_flag(0x8)
-- 0x289D0
028808: builtin91(0x1, 0x56, 0x1)
028844: builtin91(0x1, 0x74, 0x1)
028880: builtin91(0x1, 0x78, 0x1)
0288BC: builtin91(0x1, 0x5D, 0x1)
0288E0: start_coroutine(0x694C)
028964: builtin75(0x124, 0x125, 0x126, 0x127, 0x128)
028988: play_stream(0x3EE)
0289AC: builtin38(0x1)
0289D0: set_flag(0x5)
-- 0x28B1C
028844: builtin91(0x1, 0x74, 0x1)
028880: builtin91(0x1, 0x78, 0x1)
0288BC: builtin91(0x1, 0x5D, 0x1)
0288E0: start_coroutine(0x694C)
028964: builtin75(0x124, 0x125, 0x126, 0x127, 0x128)
028988: play_stream(0x3EE)
0289AC: builtin38(0x1)
0289D0: set_flag(0x5)
0289DC: yield
-- 0x2CB60
02C900: hp_pct_test(0x1, ADN327, 0)
02C954: hp_pct_test(0x1, ADN328, 0)
02C9A8: hp_pct_test(0x1, ADN329, 0)
02C9FC: hp_pct_test(0x1, ADN330, 0)
02CA50: hp_pct_test(0x1, ADN331, 0)
02CAA4: hp_pct_test(0x1, ADN332, 0)
02CAF8: hp_pct_test(0x1, ADS351, 0)
02CB30: named_event(0x132)
02CB60: set_flag(0xE)
-- 0x2CC68
02C9FC: hp_pct_test(0x1, ADN330, 0)
02CA50: hp_pct_test(0x1, ADN331, 0)
02CAA4: hp_pct_test(0x1, ADN332, 0)
02CAF8: hp_pct_test(0x1, ADS351, 0)
02CB30: named_event(0x132)
02CB60: set_flag(0xE)
02CC00: builtin64(0x133, 0x2, 0x1, 0x9, 0x1, -1)
02CC38: named_event(0x134)
02CC68: set_flag(0xF)
== END_PHASE: 12 sites
-- 0x51E4
004EFC: builtin64(0x3F, 0x2, 0x1, 0x9, 0x1, -1)
004FA4: builtin64(0x40, 0x2, 0x1, 0x9, 0x1, -1)
00504C: builtin64(0x41, 0x2, 0x1, 0x9, 0x1, -1)
0050F4: builtin64(0x42, 0x2, 0x1, 0x9, 0x1, -1)
005160: wait_cmds_drained
005188: fade_sound(3)
0051B0: builtin85(3)
0051D8: wait_s(3)
0051E4: END_PHASE
-- 0x5828
005518: builtin64(0x1, 0x9, 0x1, -1)
0055C0: builtin64(0x46, 0x2, 0x1, 0x9, 0x1, -1)
005668: builtin64(0x47, 0x2, 0x1, 0x9, 0x1, -1)
005710: builtin64(0x48, 0x2, 0x1, 0x9, 0x1, -1)
0057A4: wait_cmds_drained
0057CC: fade_sound(3)
0057F4: builtin85(3)
00581C: wait_s(3)
005828: END_PHASE
-- 0x6010
005E24: hp_pct_test(0x1, ADN112, 0)
005E78: hp_pct_test(0x1, ADN114, 0)
005ECC: hp_pct_test(0x1, ADN115, 0)
005F80: builtin64(0x4A, 0x2, 0x1, 0x9, 0x1, -1)
005F8C: wait_cmds_drained
005FB4: fade_sound(3)
005FDC: builtin85(3)
006004: wait_s(3)
006010: END_PHASE
-- 0x6260
0060FC: MARK_LAST_PHASE
006108: builtin82
006130: wait_s(4)
0061D0: builtin64(0x4B, 0x2, 0x1, 0x9, 0x1, -1)
0061DC: wait_cmds_drained
006204: fade_sound(3)
00622C: builtin85(3)
006254: wait_s(3)
006260: END_PHASE
-- 0x19640
019358: builtin64(0x3F, 0x2, 0x1, 0x9, 0x1, -1)
019400: builtin64(0x40, 0x2, 0x1, 0x9, 0x1, -1)
0194A8: builtin64(0x41, 0x2, 0x1, 0x9, 0x1, -1)
019550: builtin64(0x42, 0x2, 0x1, 0x9, 0x1, -1)
0195BC: wait_cmds_drained
0195E4: fade_sound(3)
01960C: builtin85(3)
019634: wait_s(3)
019640: END_PHASE
-- 0x19934
019758: wait_s(4)
0197F8: builtin64(0xC1, 0x2, 0x1, 0x9, 0x1, -1)
019804: wait_cmds_drained
0198A4: builtin64(0xC2, 0x2, 0x1, 0x9, 0x1, -1)
0198B0: wait_cmds_drained
0198D8: fade_sound(3)
019900: builtin85(3)
019928: wait_s(3)
019934: END_PHASE
-- 0x1AC44
01AAE0: builtin64(0xC7, 0x2, 0x1, 0x9, 0x1, -1)
01AAEC: wait_cmds_drained
01AB44: read_freg(5)
01AB80: read_freg(5)
01ABC0: wait_s(5)
01ABE8: fade_sound(3)
01AC10: builtin85(3)
01AC38: wait_s(3)
01AC44: END_PHASE
-- 0x2B96C
02B684: builtin64(0x3F, 0x2, 0x1, 0x9, 0x1, -1)
02B72C: builtin64(0x40, 0x2, 0x1, 0x9, 0x1, -1)
02B7D4: builtin64(0x41, 0x2, 0x1, 0x9, 0x1, -1)
02B87C: builtin64(0x42, 0x2, 0x1, 0x9, 0x1, -1)
02B8E8: wait_cmds_drained
02B910: fade_sound(3)
02B938: builtin85(3)
02B960: wait_s(3)
02B96C: END_PHASE
-- 0x2BFB0
02BCA0: builtin64(0x1, 0x9, 0x1, -1)
02BD48: builtin64(0x46, 0x2, 0x1, 0x9, 0x1, -1)
02BDF0: builtin64(0x47, 0x2, 0x1, 0x9, 0x1, -1)
02BE98: builtin64(0x48, 0x2, 0x1, 0x9, 0x1, -1)
02BF2C: wait_cmds_drained
02BF54: fade_sound(3)
02BF7C: builtin85(3)
02BFA4: wait_s(3)
02BFB0: END_PHASE
-- 0x2C1E0
02C060: builtin82
02C088: wait_s(4)
02C0B0: wait_s(5)
02C150: builtin64(0x131, 0x2, 0x1, 0x9, 0x1, -1)
02C15C: wait_cmds_drained
02C184: fade_sound(3)
02C1AC: builtin85(3)
02C1D4: wait_s(3)
02C1E0: END_PHASE
-- 0x2CF74
02CDBC: wait_cmds_drained
02CE14: read_freg(5)
02CE50: read_freg(5)
02CE90: wait_s(5)
02CECC: builtin99
02CF18: fade_sound(3)
02CF40: builtin85(3)
02CF68: wait_s(3)
02CF74: END_PHASE
-- 0x2D1DC
02D06C: mark_not_last
02D078: builtin78
02D0A0: wait_s(4)
02D140: builtin64(0x136, 0x2, 0x1, 0x9, 0x1, -1)
02D14C: wait_cmds_drained
02D180: fade_sound(3)
02D1A8: builtin85(3)
02D1D0: wait_s(3)
02D1DC: END_PHASE
== FORCE_END_PHASE: 3 sites
-- 0x1482C
0144B0: builtin64
-- 0x249F0
0246B0: unit_state(0x1, ADN208)
0246EC: start_coroutine(0xD5A8)
0246F8: yield
02474C: unit_state(0x1, ADN209)
024788: start_coroutine(0xD5A8)
024794: yield
-- 0x34A10
034868: unit_state(0x1, ADT305)
03488C: yield
0348E0: unit_state(0x1, ADT306)
034904: yield
034958: unit_state(0x1, ADT307)
03497C: yield
0349D0: unit_state(0x1, ADT308)
0349F4: yield
034A00: yield
== MARK_LAST_PHASE: 8 sites
-- 0x4DFC
004A94: start_coroutine(0x7290)
004AB8: start_coroutine(0x8A68)
004ADC: start_coroutine(0x93D8)
004AE8: yield
-- 0x52C8
0051F0: yield
005230: hp_pct_test(0x1, TCN004, 0)
005268: builtin116(0x0)
005274: builtin101
005280: push_trigger
00528C: timer_stop
0052B0: clear_flag(0xFFFFFFFF)
0052BC: builtin118
0052C8: MARK_LAST_PHASE
-- 0x60FC
00601C: yield
006060: read_freg(0x0)
00609C: builtin116(0x0)
0060A8: builtin101
0060B4: push_trigger
0060C0: timer_stop
0060E4: clear_flag(0xFFFFFFFF)
0060F0: builtin118
0060FC: MARK_LAST_PHASE
-- 0x19258
018F04: builtin58(0x1, 0x35, 0x1)
018F5C: builtin15(0x1, 0x35, 0x2, 380)
018FB0: builtin47(0x1, 0x35, 0x1, 0x75, 0x0)
018FF0: hp_pct_test(0x1, ADN208, 0)
019028: builtin63(0x1, 0x4E)
01907C: builtin47(0x1, 0x4E, 0x1, 0x35, 0x1)
0190D8: builtin47(0x1, 0x4E, 0x1, 0x35, 0x0)
0190FC: start_coroutine(0xC48C)
019108: yield
-- 0x19724
01964C: yield
01968C: hp_pct_test(0x1, TCT206, 0)
0196C4: builtin116(0x0)
0196D0: builtin101
0196DC: push_trigger
0196E8: timer_stop
01970C: clear_flag(0xFFFFFFFF)
019718: builtin118
019724: MARK_LAST_PHASE
-- 0x2B584
02B304: builtin47(0x1, 0x51, 0x1, 0x15, 0x0)
02B328: start_coroutine(0x9680)
02B34C: start_coroutine(0x9708)
02B370: start_coroutine(0x9790)
02B394: start_coroutine(0xA2D8)
02B3B8: start_coroutine(0xA4F8)
02B3DC: start_coroutine(0xAA10)
02B47C: builtin64(0x130, 0x2, 0x0, 0x8, 0x1, -1)
02B488: yield
-- 0x2BA50
02B978: yield
02B9B8: hp_pct_test(0x1, TCN004, 0)
02B9F0: builtin116(0x0)
02B9FC: builtin101
02BA08: push_trigger
02BA14: timer_stop
02BA38: clear_flag(0xFFFFFFFF)
02BA44: builtin118
02BA50: MARK_LAST_PHASE
-- 0x2C054
02BFB0: END_PHASE
02BFBC: yield
02BFF4: builtin116(0x0)
02C000: builtin101
02C00C: push_trigger
02C018: timer_stop
02C03C: clear_flag(0xFFFFFFFF)
02C048: builtin118
02C054: MARK_LAST_PHASE

View File

@@ -110,6 +110,41 @@ is not.
⚠️ Scoped to Stage 02. Other stages may well use `squad_survival_pct` — the
counting is per-file and cheap to repeat.
## ✅ A real Stage 02 condition, read end to end
With the symbol tables resolved (unit arguments are symbol-table-2 indices), the
bytecode reads as mission logic. From `Stage02.ssb` at `0xF524`
(`data/isl-stage02-conditions.txt`):
```
unit_state(1, ADN110) objective_marker(1, 0x01, 0, 8, 0)
unit_state(1, ADN111) objective_marker(1, 0x02, 0, 8, 0)
unit_state(1, ADN112) objective_marker(1, 0x05, 0, 8, 0)
objective_marker(1, 0x3A, 1, 8, 0)
set_flag(8)
```
Three **named ADAN squadrons** are polled for lifecycle state, each with its
objective marker updated, and then **flag 8** is latched. That is the shape
[mission-phase-advance](../mission-phase-advance.md) predicted from the
disassembly alone — trigger → predicate → `set_flag` → (later) `END_PHASE` — now
seen in the mission's own code with the squadron names the roster tables already
gave us.
The 12 `END_PHASE` sites are, by contrast, **outro sequences**:
`wait_cmds_drained``fade_sound(3)``builtin85(3)``wait_s(3)`
`END_PHASE``yield`. The *decision* is not there; the terminator is.
### ⚠️ A decode bug that hid every argument
The first version of the argument tracker only followed
`local[i] = special[0]`. But the common form is
**`set.i k=01,03` — an immediate written straight into `local[i]`** — and
missing it meant every unit predicate printed with **no arguments at all**
(`unit_state` rather than `unit_state(1, ADN110)`). The disassembly looked
complete and was silently empty where it mattered most. Both staging forms are
now handled.
## 🟡 Not settled
* **Three handlers resisted**: id 55 (`vt35`, 411 instructions, returns a float),