re: the per-phase objectives, from the game's own text
TextIndex in sylpheed-formats::localization already indexes per-phase objective text under S<NN>_P<n>_Objective_<i>, with hints and lose conditions alongside. Querying it settles what the wave work spent many iterations circling, and a disc test now pins it. Stage 02 phase 1 is "Shoot down all invading enemy fighters while watching out for attacks on the ACROPOLIS", losing if the ACROPOLIS is sunk. Phase 2 is "Protect the Admiral's ship the CALIBAN until it has entered the safe zone", losing if the CALIBAN is sunk. Phase 3 is "Destroy the interstellar cruise missiles headed for Schlos Base", matching phase 3's roster of exactly nine ISCMissile and SUBOBJ_013. That explains the phase advances and shows they are not all the same kind. Phase 1 is a kill-all-marked-fighters gate -- fighters, not the turrets every run killed almost exclusively. Phase 2 is positional and ends when the CALIBAN reaches a safe zone, so "what advances a phase" never had a single answer. It also closes a loop to the first session. The hints say red mission markers [OB] indicate your targets, so REMAINING OB -- the HUD counter hunted in the earliest iterations and located at 0xbdb59668 -- is the count of remaining marked objective targets, which is phase-1 progress itself. The old reframing that the counter is not a roster was right, and this names what it is. It is also the correct signal to watch for an advance: not deployed, which only changes once the next phase deploys, but REMAINING OB reaching zero, which is the cause. Method lesson recorded because the reflex will recur: localization.rs has had objectives, hints and lose_conditions for some time, and several iterations were spent reconstructing the same information by hand from SUBObjective strings and the guide script. The reconstruction was not wasted -- it produced the IXUD UTF-16BE and language\ prefix findings independently -- but the corpus should have been searched before the disc was, and grep -rl TextIndex crates/ would have saved the detour. Minor discrepancy noted, not investigated: ixud.rs documents the string pool as UTF-16BE and localization.rs as UTF-16LE.
This commit is contained in:
46
crates/sylpheed-formats/tests/phase_objectives_disc.rs
Normal file
46
crates/sylpheed-formats/tests/phase_objectives_disc.rs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
//! Per-phase MAIN objectives, straight from the localisation index.
|
||||||
|
//!
|
||||||
|
//! The mission-phase work went looking for what a phase asks the player to do
|
||||||
|
//! and reconstructed it from `SUBObjective_local_string.tbl` — the *bonus*
|
||||||
|
//! objectives — plus the guide script. `TextIndex` already indexes the main
|
||||||
|
//! ones under `S<NN>_P<n>_Objective_<i>`, so this pins them as a disc test and
|
||||||
|
//! makes the per-phase goals a checkable artifact rather than an inference.
|
||||||
|
|
||||||
|
use sylpheed_formats::{localization::TextIndex, PakArchive};
|
||||||
|
|
||||||
|
fn pak() -> Option<PakArchive> {
|
||||||
|
let disc = std::env::var("SYLPHEED_DISC").ok()?;
|
||||||
|
PakArchive::open(format!("{disc}/dat/GP_MAIN_GAME_E.pak")).ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn stage02_has_a_main_objective_for_each_phase() {
|
||||||
|
let Some(pak) = pak() else {
|
||||||
|
eprintln!("SYLPHEED_DISC unset - skipping");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let text = TextIndex::build(&pak);
|
||||||
|
assert!(text.len() > 0, "text index is empty");
|
||||||
|
|
||||||
|
for stage in ["S01", "S02"] {
|
||||||
|
for phase in 1..=3u32 {
|
||||||
|
let objs = text.objectives(stage, phase);
|
||||||
|
eprintln!("{stage} phase {phase}: {} objective line(s)", objs.len());
|
||||||
|
for o in &objs {
|
||||||
|
eprintln!(" {o}");
|
||||||
|
}
|
||||||
|
for h in text.hints(stage, phase) {
|
||||||
|
eprintln!(" hint: {h}");
|
||||||
|
}
|
||||||
|
for l in text.lose_conditions(stage, phase) {
|
||||||
|
eprintln!(" lose: {l}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Phase 1 of Stage 02 is the case the wave work could not observe; if the
|
||||||
|
// game states its goal at all, it is here.
|
||||||
|
assert!(
|
||||||
|
!text.objectives("S02", 1).is_empty(),
|
||||||
|
"no main objective text for Stage 02 phase 1"
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -560,6 +560,20 @@ search cannot find a *schedule*.
|
|||||||
the pilot (game-playing, uncertain); (2) accept the static answer (structure,
|
the pilot (game-playing, uncertain); (2) accept the static answer (structure,
|
||||||
rosters, routes, objective texts all decoded and cross-confirmed; only the
|
rosters, routes, objective texts all decoded and cross-confirmed; only the
|
||||||
*trigger* is inferred); (3) one 40+ min chained run betting against freezes.
|
*trigger* is inferred); (3) one 40+ min chained run betting against freezes.
|
||||||
|
* ✅✅ **(2026-08-24) THE OBJECTIVES, FROM THE GAME'S OWN TEXT** — pinned by
|
||||||
|
`tests/phase_objectives_disc.rs`; `TextIndex::objectives(stage, phase)` already
|
||||||
|
existed. **S02 phase 1: "Shoot down all invading enemy fighters while watching
|
||||||
|
out for attacks on the ACROPOLIS"** (lose: ACROPOLIS sunk). **Phase 2: "Protect
|
||||||
|
the CALIBAN until it has entered the safe zone"** — *positional, not a kill
|
||||||
|
count*, so phase triggers are NOT all the same kind. **Phase 3: "Destroy the
|
||||||
|
interstellar cruise missiles headed for Schlos Base"** (matches the 9
|
||||||
|
`ISCMissile` + `SUBOBJ_013`). ✅ **`[OB]` = objective marker** — hints say *"Red
|
||||||
|
mission markers [OB] indicate your targets"*, so **`REMAINING OB` at
|
||||||
|
`0xbdb59668` is phase-1 progress** and is the right signal to watch, not
|
||||||
|
`deployed`. Closes a loop to the first session. 🔴 **Method lesson: the crate
|
||||||
|
already knew this** — several iterations reconstructed it the hard way;
|
||||||
|
`grep -rl TextIndex crates/` would have saved the detour. ❔ Minor: `ixud.rs`
|
||||||
|
says UTF-16BE, `localization.rs` says LE — one comment is wrong.
|
||||||
🔴 `SYLPH_HZ=3` refuted as a lever: it gave the LOWEST frame rate (8/s) with the
|
🔴 `SYLPH_HZ=3` refuted as a lever: it gave the LOWEST frame rate (8/s) with the
|
||||||
most kills, so pilot polling is not the throttle.
|
most kills, so pilot polling is not the throttle.
|
||||||
* ~~🚧 BLOCKER: t=210/240 unreachable in one turn~~ — **superseded, see above**;
|
* ~~🚧 BLOCKER: t=210/240 unreachable in one turn~~ — **superseded, see above**;
|
||||||
|
|||||||
71
docs/re/mission-phase-objectives.md
Normal file
71
docs/re/mission-phase-objectives.md
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
# What each phase asks for — from the game's own objective text
|
||||||
|
|
||||||
|
Status: ✅ pinned by a disc test (`crates/sylpheed-formats/tests/phase_objectives_disc.rs`).
|
||||||
|
|
||||||
|
`TextIndex` in `sylpheed-formats::localization` already indexes per-phase objective
|
||||||
|
text under `S<NN>_P<n>_Objective_<i>`, with hints and lose conditions alongside.
|
||||||
|
Querying it settles what the wave work spent many iterations circling.
|
||||||
|
|
||||||
|
## Stage 02
|
||||||
|
|
||||||
|
| phase | objective | lose condition |
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | **"Shoot down all invading enemy fighters while watching out for attacks on the ACROPOLIS."** | The ACROPOLIS is sunk |
|
||||||
|
| 2 | **"Protect the Admiral's ship the CALIBAN until it has entered the safe zone."** | The CALIBAN is sunk |
|
||||||
|
| 3 | **"Destroy the interstellar cruise missiles headed for Schlos Base."** | Schlos Base is destroyed |
|
||||||
|
|
||||||
|
Stage 01 phase 1 is *"Repel the enemy's surprise attack."*, phase 2 *"Cooperate
|
||||||
|
with your allies to repel the enemy units."*
|
||||||
|
|
||||||
|
## ✅ This explains the phase advances, and they are not all the same kind
|
||||||
|
|
||||||
|
* **Phase 1 is a kill-all-marked-fighters gate.** Not turrets — *fighters*. Every
|
||||||
|
run in [mission-arrival-watch.md](mission-arrival-watch.md) killed turrets
|
||||||
|
almost exclusively, so no run came close to satisfying it.
|
||||||
|
* **Phase 2 is positional, not a kill count** — it ends when the CALIBAN reaches
|
||||||
|
a safe zone. That is a completely different trigger type, and it means "what
|
||||||
|
advances a phase" never had one answer.
|
||||||
|
* **Phase 3 is destroy-the-missiles**, matching phase 3's roster of exactly nine
|
||||||
|
`UN_e201_ADAN_ISCMissile` and `SUBOBJ_013`.
|
||||||
|
|
||||||
|
## ✅ `[OB]` is the objective marker — closing a loop to the first session
|
||||||
|
|
||||||
|
The hints name the mechanic outright:
|
||||||
|
|
||||||
|
> *"Red mission markers **[OB]** indicate your targets."*
|
||||||
|
> *"Take out these enemy units."*
|
||||||
|
|
||||||
|
**`REMAINING OB`** — the HUD counter hunted in the earliest iterations of this
|
||||||
|
work and located at `0xbdb59668` — is therefore the count of **remaining marked
|
||||||
|
objective targets**, i.e. phase-1 progress itself. The reframing recorded back
|
||||||
|
then ("the counter is not a roster") was right, and this names what it *is*.
|
||||||
|
|
||||||
|
That also makes it the correct signal to watch for a phase advance: not
|
||||||
|
`deployed`, which only changes when the next phase deploys, but `REMAINING OB`
|
||||||
|
reaching zero, which is the cause.
|
||||||
|
|
||||||
|
## 🔴 Method lesson: the crate already knew this
|
||||||
|
|
||||||
|
`localization.rs` has had `objectives(stage, phase)`, `hints` and
|
||||||
|
`lose_conditions` for some time. Several iterations were spent reconstructing
|
||||||
|
the same information the hard way — decoding `SUBObjective_local_string.tbl` by
|
||||||
|
hand, reading the guide script, inferring the phase-1 goal from
|
||||||
|
*"the attackers with the orange markers"*.
|
||||||
|
|
||||||
|
The reconstruction was not wrong, and it produced the IXUD/UTF-16BE and
|
||||||
|
`language\` prefix findings independently. But **the corpus should have been
|
||||||
|
searched before the disc was**: `grep -rl TextIndex crates/` would have saved
|
||||||
|
the detour. Recorded because the same reflex will apply to the next unknown.
|
||||||
|
|
||||||
|
Note also a discrepancy worth resolving: `ixud.rs` documents the pool as
|
||||||
|
UTF-16**BE** and `localization.rs` as UTF-16**LE**. Both work on their own
|
||||||
|
inputs, so one comment is wrong, or the two consumers genuinely differ. Not
|
||||||
|
investigated.
|
||||||
|
|
||||||
|
## What is still not observed
|
||||||
|
|
||||||
|
The phase-1 advance itself. The objective is now known exactly, and
|
||||||
|
[mission-objectives-text.md](mission-objectives-text.md) quantifies the cost:
|
||||||
|
the marked fighters are ~16 craft and the pilot manages about two per five
|
||||||
|
minutes. Nothing here changes that arithmetic — it only means the target list is
|
||||||
|
now certain rather than guessed.
|
||||||
Reference in New Issue
Block a user