534 IXUD entries across 36 paks, 94 distinct keys, 92 resolved by name. Content identified: mission objective/lose/hint panels, 91 bonus-objective banners, scripted radio, cutscene dialogue, the reactive combat-chatter pool (MSG_ADAN 23,236 fields, MSG_RHIN 21,196, ...), resupply barks, speaker labels and the hangar weapon Name/Desc/Condition. Verified independently: language\MissionDialog_local_string.tbl decodes to 600 fields with the trailer identity holding, giving Stage 02's real objectives -- phase 1 'Shoot down all invading enemy fighters / while watching out for attacks / on the ACROPOLIS', phase 2 'Protect the Admiral's ship the CALIBAN', phase 3 'Destroy the interstellar cruise missiles'. That matches the script exactly: the phase-1 condition polls three enemy squadrons and the escort's loss is the fail branch, and phase 2 is positional, which is why no kill count appears there. The .ssb symbol names (S02_P1_OBJECTIVE etc.) are NOT IXUD keys -- they are records in an IDXD map, message\MissionDialogMessage.tbl, whose positional fields list the lowercase per-line IXUD names; *_GRAPH holds a texture instead. Structure: one record per object (except the six 63-record hangar files), 624,440 named fields, 55% of them empty line slots, no control characters, the only escape a literal two-char \n in block-text tables, and records/fields in ascending key order so lookup is a binary search. '[OB]' turns out to be a HUD marker label in this text -- the same one the REMAINING OB work chased. Six languages confirmed D/E/F/I/J/S; J omits the trailing empty line slot in 78 of 86 objects. Two keys remain unresolved, byte-identical across all six paks (untranslated Japanese voice transcripts). Also corrects mission-objectives-text.md: SUBOBJ_009 does have text, and SUBOBJ_005 is two fields.
6.4 KiB
✅ CORRECTED 2026-08-25 by decoding the IXUD containers directly — see structures/ixud-localised-text. Two errors here:
SUBOBJ_009does have text ('You destroyed all enemy units!'— all 91 of 91 sub-objectives have an_Mes_L1string), andSUBOBJ_005is two fields ('You rescued'+'the ally destroyer!'), which a single-line rendering drops.
The mission script in plain English — and why phase 1 never completed
Status: ✅ the localised string tables are decoded and readable; ✅ the phase structure is confirmed narratively and by roster composition; 🟡 a concrete, testable reason the phase never advanced in any run.
✅ IXUD — the localised string container
language\*_local_string.tbl (the prefix is language\, a third convention
after stage\ and message\) is not IDXD. Magic is IXUD, and its strings
are UTF-16 big-endian. That is why every earlier ASCII-oriented dump of these
files produced garbage.
Reading them is immediate once the encoding is known, and it makes the mission design directly legible instead of inferred.
✅ Stage 02's nine sub-objectives, in words
| id | text |
|---|---|
SUBOBJ_005 |
You rescued the ally destroyer! |
SUBOBJ_006 |
You destroyed all enemy fighters! |
SUBOBJ_007 |
You sunk all enemy warships! |
SUBOBJ_008 |
You rescued the ally cruiser, Amalthea! |
SUBOBJ_010 |
The ally cruiser CALIBAN took no damage! |
SUBOBJ_011 |
You sunk the enemy destroyer targeting the ACROPOLIS! |
SUBOBJ_013 |
You destroyed all enemy cruise missiles! |
SUBOBJ_014 |
You destroyed all enemy missiles and units! |
(SUBOBJ_009 has no text.) 91 objectives are defined across the game.
✅ The three phases, confirmed twice over
The guide script reads as three distinct acts, and each matches the per-phase roster composition found independently in mission-phase-deployment.md:
| phase | script | roster |
|---|---|---|
| 1 | "The attackers with the orange markers, right?", "Protect the ACROPOLIS!" | turrets, attackers, fighters |
| 2 | "destroy the ship's engine", "destroy that ship's weapons", "take out the enemy's shield projector" | destroyers, frigates, cruisers |
| 3 | "start by taking out that missile", "Concentrate on destroying the missiles one by one" | UN_e201_ADAN_ISCMissile ×9 |
Phase 3's nine cruise missiles against SUBOBJ_013 "You destroyed all enemy
cruise missiles!" is an exact match between two files decoded on different days
by different routes.
🟡 Why phase 1 never advanced: the pilot killed the wrong things
The phase-1 objective is stated outright — destroy the marked attackers:
"Rhinos, prepare for combat. Are you all clear on your targets?" "The attackers with the orange markers, right? Roger that!" "Katana, those attackers are our targets!"
Those are UN_e010_ADAN_Attacker_S, of which phase 1 fields four squadrons.
The hunting pilot targeted turrets almost exclusively. Every loss line in the
run logs reads UN_e007_ADAN_Turret, with UN_e010_ADAN_Attacker_S appearing
only twice across all runs — unsurprising, since SYLPH_HUNT was built to make
turrets targets and SYLPH_KEEPOUT was tuned for them. So 42 kills were
overwhelmingly the wrong 42.
That gives a mundane explanation for the whole run of null results, and it does not require the frames reading or event-gating to be settled first.
Prediction: destroying the phase-1 UN_e010_ADAN_Attacker_S squadrons should
advance the phase, which is directly observable as deployed jumping from 41
toward the phase-2 roster.
Test: a pilot that prioritises e010 over e007 — a target-preference knob,
not new decoding — and the existing probe watching deployed.
This is 🟡, not ✅: the objective text is certain, but that this particular objective gates the phase advance is inference from the script's structure.
The target-preference knob works, and the blocker is now combat, not RE (2026-08-24)
✅ SYLPH_PREFER added and measured
pilot.py gained a target-preference knob: a unit-name substring whose matches
get their target score multiplied by 0.05 and everything else by 4.0. With
SYLPH_PREFER=e010, one clean 320 s run (witness: 0 stalls):
| killed | count |
|---|---|
UN_e007_ADAN_Turret |
8 |
UN_e010_ADAN_Attacker_S |
2 |
The preference is real — e010 kills went from about one across all previous
runs to two in a single run — but it is weak: turrets still outnumber
attackers 4:1 in the kill log. Target commitment (COMMIT_MAX, COMMIT_DROP)
and simple proximity keep pulling the nose back to turrets, which are far more
numerous.
deployed stayed at 41 throughout. No phase advance.
🚧 The blocker, quantified
Phase 1's roster, by craft rather than by squadron:
| unit | members | craft (sum(n)) |
|---|---|---|
UN_e007_ADAN_Turret |
12 | 108 |
UN_e106_ADAN_Destroyer |
7 | 7 |
UN_f001_TCAF_DeltaSaber_T |
7 | 7 |
UN_e010_ADAN_Attacker_S |
4 | 16 |
Clearing the marked attackers means destroying 16 craft. At the measured rate of 2 per 320 s that is ~2560 s — roughly 43 minutes of continuous verified-live flight, across many chained attaches, with a freeze rate of about two runs in five.
This is no longer a reverse-engineering problem. Everything needed to observe the phase advance is built and validated: the roster link, the liveness read, the stall witness, chained attaches, the discard rule. What is missing is a pilot good enough to actually complete the mission objective, and that is game-playing work with an uncertain payoff.
The choice, which is the user's to make
- Invest in the pilot — better target selection, missiles, using the marker/lock the script keeps referring to. Uncertain, potentially several iterations, and drifts away from RE.
- Accept the static answer. The phase structure, per-phase rosters, route paths and objective texts are all decoded and cross-confirmed. Only the trigger is inferred rather than observed, and it is inferred from the game's own guide script naming the objective outright.
- One very long run — 40+ minutes of chained attaches — betting against the freeze rate.
Recorded rather than chosen, because it is a question about how much effort this one confirmation is worth, not a technical unknown.