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:
345
docs/re/data/isl-stage02-conditions.txt
Normal file
345
docs/re/data/isl-stage02-conditions.txt
Normal 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
|
||||||
|
|
||||||
@@ -110,6 +110,41 @@ is not.
|
|||||||
⚠️ Scoped to Stage 02. Other stages may well use `squad_survival_pct` — the
|
⚠️ Scoped to Stage 02. Other stages may well use `squad_survival_pct` — the
|
||||||
counting is per-file and cheap to repeat.
|
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
|
## 🟡 Not settled
|
||||||
|
|
||||||
* **Three handlers resisted**: id 55 (`vt35`, 411 instructions, returns a float),
|
* **Three handlers resisted**: id 55 (`vt35`, 411 instructions, returns a float),
|
||||||
|
|||||||
@@ -105,7 +105,33 @@ def load(path):
|
|||||||
return open(path, 'rb').read()
|
return open(path, 'rb').read()
|
||||||
|
|
||||||
|
|
||||||
def dis(b, off, count=40, code_base=0x24, args=True):
|
def symbols(b, which):
|
||||||
|
"""Parse a .ssb symbol table -> {index: (type, name)}.
|
||||||
|
|
||||||
|
Built-in argument blobs carry INDICES into these: fields that index
|
||||||
|
`[phase+244]` are symtab-1 (routes, messages, subobjectives) and fields that
|
||||||
|
index `[phase+324]` are symtab-2 (the unit ids). Resolving them is what turns
|
||||||
|
`unit_state(0x2b)` into `unit_state(ADN201)`.
|
||||||
|
"""
|
||||||
|
off = struct.unpack_from('>I', b, 0x0C if which == 1 else 0x10)[0]
|
||||||
|
cnt = struct.unpack_from('>I', b, off)[0]
|
||||||
|
base = off + 4
|
||||||
|
out = {}
|
||||||
|
for i in range(cnt):
|
||||||
|
o = struct.unpack_from('>I', b, base + 4 * i)[0]
|
||||||
|
if o == 0:
|
||||||
|
continue
|
||||||
|
rp = base + o
|
||||||
|
typ = struct.unpack_from('>I', b, rp)[0]
|
||||||
|
e = b.index(b'\0', rp + 4)
|
||||||
|
out[i] = (typ, b[rp + 4:e].decode('latin-1'))
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
UNIT_ARG = {18, 20, 24, 26, 56, 69, 70, 94, 95, 105, 109} # unit idx at blob[4]
|
||||||
|
|
||||||
|
|
||||||
|
def dis(b, off, count=40, code_base=0x24, args=True, sym2=None):
|
||||||
out = []
|
out = []
|
||||||
staged = {} # local[] slot -> last value staged into it
|
staged = {} # local[] slot -> last value staged into it
|
||||||
pending = None # value most recently put in special[0]
|
pending = None # value most recently put in special[0]
|
||||||
@@ -152,12 +178,26 @@ def dis(b, off, count=40, code_base=0x24, args=True):
|
|||||||
pending = words[1]
|
pending = words[1]
|
||||||
elif k0 == 3 and k1 == 2 and pending is not None:
|
elif k0 == 3 and k1 == 2 and pending is not None:
|
||||||
staged[words[0]] = pending
|
staged[words[0]] = pending
|
||||||
|
elif k0 == 3 and k1 == 1:
|
||||||
|
# local[i] = immediate, DIRECTLY -- the common form. Missing this
|
||||||
|
# made every unit predicate print with no arguments at all.
|
||||||
|
if op == 1:
|
||||||
|
lo = words[2] if len(words) > 2 else 0
|
||||||
|
staged[words[0]] = '%.6g' % struct.unpack(
|
||||||
|
'>d', struct.pack('>II', words[1], lo))[0]
|
||||||
|
else:
|
||||||
|
staged[words[0]] = words[1]
|
||||||
if op == 19 and words:
|
if op == 19 and words:
|
||||||
extra = ' %s' % BUILTIN.get(words[0], 'builtin%d' % words[0])
|
extra = ' %s' % BUILTIN.get(words[0], 'builtin%d' % words[0])
|
||||||
if args and staged:
|
if args and staged:
|
||||||
extra += '(' + ', '.join(
|
parts = []
|
||||||
'%s' % (('0x%X' % v) if isinstance(v, int) else v)
|
for slot, v in sorted(staged.items()):
|
||||||
for _, v in sorted(staged.items())) + ')'
|
txt = ('0x%X' % v) if isinstance(v, int) else v
|
||||||
|
if (sym2 and slot == 4 and words[0] in UNIT_ARG
|
||||||
|
and isinstance(v, int) and v in sym2):
|
||||||
|
txt = sym2[v][1]
|
||||||
|
parts.append(txt)
|
||||||
|
extra += '(' + ', '.join(parts) + ')'
|
||||||
staged = {}
|
staged = {}
|
||||||
elif op == 12 and words:
|
elif op == 12 and words:
|
||||||
extra = ' -> code+0x%X (file 0x%X)' % (words[0], code_base + words[0])
|
extra = ' -> code+0x%X (file 0x%X)' % (words[0], code_base + words[0])
|
||||||
@@ -228,7 +268,8 @@ if __name__ == '__main__':
|
|||||||
if st is None:
|
if st is None:
|
||||||
print('could not resync into 0x%X' % t); sys.exit(1)
|
print('could not resync into 0x%X' % t); sys.exit(1)
|
||||||
print('resync from 0x%X' % st)
|
print('resync from 0x%X' % st)
|
||||||
print('\n'.join(dis(b, st, int(sys.argv[4], 0) if len(sys.argv) > 4 else 40)))
|
print('\n'.join(dis(b, st, int(sys.argv[4], 0) if len(sys.argv) > 4 else 40,
|
||||||
|
sym2=symbols(b, 2))))
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
code_base = struct.unpack_from('>I', b, CODE_BASE_FIELD)[0]
|
code_base = struct.unpack_from('>I', b, CODE_BASE_FIELD)[0]
|
||||||
a = sys.argv[2]
|
a = sys.argv[2]
|
||||||
|
|||||||
Reference in New Issue
Block a user