re: rebuild the movie manifest on the record table — the old counts measured pool strings

movie_manifest::parse now reads BASE_INFO's positional field keys (the game's
own cutscene ids, stage*100 + slot) and follows each to its record, instead of
scraping the string pool. The pool stores each distinct string once, so a
REPEAT reference produced no token and read as "no binding".

That single cause explains every wrong cell: 13 later references to
VOICE_D_450..454, two to SUBTITLE_hokyu_LS_s11A.tbl, and MS01A's share of
pwterop_s01a.prt. All 18 hokyu movies are bound, not five.

Counts, verified independently by me against the disc before recording:
104 cutscene SLOTS binding 101 distinct MOVIES; 99 slots / 96 movies with a
voice track, 99 / 96 with a subtitle, 22 / 22 with a telop. The docs' old
94 / 83 / 21 are exactly the counts of DISTINCT POOL STRINGS -- not wrong
measurements, measurements of the wrong thing. Three denominators were being
conflated; the new test pins all three.

Two assertions in movie_manifest_disc.rs were false and are corrected:
hokyu_DS_s13A binds VOICE_D_452 and resolves to eng\etc\VOICE_D_452.slb. The
in-game verdict that rejected that value tested an INFERENCE from a shared
demo id, on a decoder that discards 85-87% of banks in this class -- see
voice-bank-leading-region.md, committed earlier today.

The ~104 script ids are no longer open: they are literal positional keys,
each naming its record, and all 104 resolve. The old "counts differ by three,
positional pairing does not work" has a concrete cause -- three resupply
movies are bound by TWO slots each.

Also corrected: the naming convention has 3 subtitle exceptions (s24A/s27A
borrow s11A's track) and 18 voice exceptions, not one and five.

The legacy scraper is kept as a fallback for blobs with no record table, so
the synthetic unit fixtures still exercise it.

Artifacts: examples/movie_map_csv.rs regenerates the CSV, now slot-keyed
(104 rows; the movie-keyed version silently dropped one slot of each
duplicate). Disc tests green.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
This commit is contained in:
Sylpheed RE agent
2026-08-25 23:13:41 +00:00
parent 49c00e0955
commit fedb31a5f9
7 changed files with 313 additions and 134 deletions

View File

@@ -0,0 +1,27 @@
//! Regenerate `docs/re/captures/movie-subtitle-voice-map.csv` from the record
//! table. Keyed by cutscene SLOT, not by movie: three resupply movies are bound
//! by two slots each, and the old movie-keyed CSV silently dropped one of each.
use sylpheed_formats::{movie_manifest, IdxdObject, PakArchive};
fn main() {
let disc = std::env::var("SYLPHEED_DISC").expect("set SYLPHEED_DISC");
let arc = PakArchive::open(format!("{disc}/dat/tables.pak")).expect("tables.pak");
let manifest = arc
.entries()
.iter()
.filter_map(|e| arc.read(e).ok())
.find(|b| IdxdObject::is_idxd(b) && movie_manifest::is_manifest(b))
.expect("movie manifest");
println!("slot,movie,telop,subtitle,voicetrack");
for e in movie_manifest::parse(&manifest) {
println!(
"{},{}.wmv,{},{},{}",
e.slot,
e.movie,
e.telop.unwrap_or_default(),
e.subtitle.unwrap_or_default(),
e.voice_token.unwrap_or_default()
);
}
}

View File

@@ -100,6 +100,61 @@ const FIELD_KEYS: [&str; 4] = ["MOVIE", "VOICETRACK", "SUBTITLE", "TELOP"];
/// mission/phase; otherwise (a blob without the key array) the kind is inferred
/// from the movie name and `slot` is empty.
pub fn parse(bytes: &[u8]) -> Vec<MovieEntry> {
if let Some(rows) = parse_records(bytes) {
return rows;
}
parse_string_pool(bytes)
}
/// Read the manifest out of the IDXD **record table** — the authoritative path.
///
/// `BASE_INFO` carries 104 *positional* fields whose keys are the game's own
/// cutscene ids (`stage*100 + slot`) and whose values name sibling records; each
/// of those records carries `MOVIE` / `VOICETRACK` / `SUBTITLE` / `TELOP`.
///
/// This replaces a string-pool scrape that could not see a **repeat reference**:
/// the pool stores each distinct string once, so the 13 later references to
/// `VOICE_D_450..454`, the two to `SUBTITLE_hokyu_LS_s11A.tbl` and `MS01A`'s
/// share of `pwterop_s01a.prt` produced no token and read as "no binding". That
/// is why `hokyu_DS_s13A` was recorded as having no voice-over.
///
/// Returns `None` for a blob with no usable record table, so the synthetic
/// fixtures in this module's tests still exercise the old reader.
fn parse_records(bytes: &[u8]) -> Option<Vec<MovieEntry>> {
let obj = crate::IdxdObject::parse(bytes).ok()?;
let base = obj.record("BASE_INFO")?;
// Ids ascend; the game's own order is play order.
let mut ids: Vec<(u32, &str)> = base
.fields
.iter()
.filter_map(|f| f.index().map(|i| (i, f.value.as_str())))
.collect();
if ids.is_empty() {
return None;
}
ids.sort_unstable();
let mut out = Vec::with_capacity(ids.len());
for (_, slot) in ids {
let Some(rec) = obj.record(slot) else { continue };
let Some(movie) = rec.get("MOVIE") else { continue };
let (kind, mission, phase) = classify_slot(slot);
out.push(MovieEntry {
slot: slot.to_string(),
kind,
mission,
phase,
movie: movie.trim_end_matches(".wmv").to_string(),
voice_token: rec.get("VOICETRACK").map(after_plus),
subtitle: rec.get("SUBTITLE").map(after_plus),
telop: rec.get("TELOP").map(after_plus),
});
}
(!out.is_empty()).then_some(out)
}
/// The legacy string-pool reader. Kept for blobs with no record table; see
/// [`parse_records`] for why it is no longer the primary path.
fn parse_string_pool(bytes: &[u8]) -> Vec<MovieEntry> {
let toks = ascii_runs(bytes, 3);
// Locate the slot-key array (`LOGO1` … first `<movie>.wmv`) and the value
@@ -334,7 +389,11 @@ mod tests {
assert_eq!(m[0].subtitle.as_deref(), Some("SUBTITLE_S13A.tbl"));
assert_eq!(m[1].voice_token.as_deref(), Some("VOICE_D_450"));
assert_eq!(m[1].kind, MovieKind::Supply);
assert_eq!(m[2].voice_token, None, "hokyu_DS_s13A has no voice-over");
// NB: in the synthetic blob below this movie really has no token. On the
// retail disc it does — `VOICE_D_452` — which the string-pool reader
// cannot see because the pool stores each value once and this is a
// repeat reference. The disc test pins the real value.
assert_eq!(m[2].voice_token, None);
assert_eq!(m[2].kind, MovieKind::Supply);
}

View File

@@ -35,7 +35,14 @@ fn binds_and_resolves_movie_voice() {
};
let (manifest, sounds) = load_manifest_and_sounds(&root);
let entries = movie_manifest::parse(&manifest);
assert!(entries.len() > 90, "expected ~101 movies, got {}", entries.len());
// 104 cutscene SLOTS binding 101 distinct movies — three resupply movies are
// bound by two slots each. Conflating the two is how the old counts went
// wrong, so state which one this is.
assert!(
entries.len() > 90,
"expected 101 distinct movies (104 slots), got {}",
entries.len()
);
// Standard story movie → VOICE_<movie> in <lang>\Movie\.
assert_eq!(
@@ -65,17 +72,26 @@ fn binds_and_resolves_movie_voice() {
Some("eng\\etc\\VOICE_D_450.slb")
);
// A resupply movie the game leaves unbound in the manifest → no DIRECT
// binding. (Extending to unbound movies by shared demo line was verified
// WRONG against the running game, so we do NOT resolve these.)
// ❌ This movie was recorded as having NO voice binding, on the strength of
// an in-game test that rejected `VOICE_D_452`. Both halves of that were
// wrong. The record table binds it directly — record `S13_SUPPLY_ACROPOLIS`,
// slot 1391 — and the value the game rejected was reached by *inferring*
// from a shared demo id, which is different evidence for the same claim.
// The decoder was also discarding 8587 % of banks in this class, so the
// listening test was not a test of the binding. See
// docs/re/voice-bank-leading-region.md.
//
// The old reader could not see it: the pool stores each string once, so the
// 13 later references to `VOICE_D_450..454` contribute no token at all.
let e = entries
.iter()
.find(|e| e.movie == "hokyu_DS_s13A")
.expect("hokyu_DS_s13A present in manifest");
assert_eq!(e.voice_token, None, "hokyu_DS_s13A has no direct voice binding");
assert_eq!(e.voice_token.as_deref(), Some("VOICE_D_452"));
assert_eq!(
movie_manifest::resolve_voice_entry(&manifest, &sounds, "hokyu_DS_s13A", VoiceLang::English),
None
movie_manifest::resolve_voice_entry(&manifest, &sounds, "hokyu_DS_s13A", VoiceLang::English)
.as_deref(),
Some("eng\\etc\\VOICE_D_452.slb")
);
// Every resolved voice entry must actually exist in sound.pak.
@@ -100,3 +116,54 @@ fn binds_and_resolves_movie_voice() {
assert!(resolved > 80, "expected 80+ voiced movies, got {resolved}");
assert!(missing.is_empty(), "resolved but absent in sound.pak: {missing:?}");
}
/// The manifest's shape, pinned. These counts were wrong in the docs for a long
/// time in a specific and instructive way: 94 / 83 / 21 are the numbers of
/// **distinct pool strings**, which is exactly what a string-pool scraper can
/// see, not the numbers of bound slots or movies.
#[test]
fn manifest_slot_and_movie_counts() {
let Some(root) = disc_root() else {
eprintln!("SKIP: set SYLPHEED_DISC");
return;
};
let (manifest, _sounds) = load_manifest_and_sounds(&root);
let entries = movie_manifest::parse(&manifest);
use std::collections::{HashMap, HashSet};
let movies: HashSet<&str> = entries.iter().map(|e| e.movie.as_str()).collect();
assert_eq!(entries.len(), 104, "cutscene slots");
assert_eq!(movies.len(), 101, "distinct movies");
let bound = |f: fn(&movie_manifest::MovieEntry) -> Option<&String>| {
let slots = entries.iter().filter(|e| f(e).is_some()).count();
let movies: HashSet<&str> = entries
.iter()
.filter(|e| f(e).is_some())
.map(|e| e.movie.as_str())
.collect();
let distinct: HashSet<&str> = entries.iter().filter_map(|e| f(e)).map(String::as_str).collect();
(slots, movies.len(), distinct.len())
};
// (slots, movies, distinct strings) — the third is what the docs used to report.
assert_eq!(bound(|e| e.voice_token.as_ref()), (99, 96, 83));
assert_eq!(bound(|e| e.subtitle.as_ref()), (99, 96, 94));
assert_eq!(bound(|e| e.telop.as_ref()), (22, 22, 21));
// Three resupply movies are bound by two slots each — which is why "slots"
// and "movies" are not interchangeable.
let mut per_movie: HashMap<&str, Vec<&str>> = HashMap::new();
for e in &entries {
per_movie.entry(&e.movie).or_default().push(&e.slot);
}
let mut shared: Vec<&str> = per_movie
.iter()
.filter(|(_, slots)| slots.len() > 1)
.map(|(m, _)| *m)
.collect();
shared.sort_unstable();
assert_eq!(shared, ["hokyu_DS_s07A", "hokyu_DS_s07H", "hokyu_LS_s02A"]);
// Every id names a real record, so nothing dangles.
assert!(entries.iter().all(|e| !e.slot.is_empty() && !e.movie.is_empty()));
}

View File

@@ -17,7 +17,7 @@ Promote to a prose `structures/…md` file when a format needs behavioural notes
| T8aD 2D texture | ✅ | `sylpheed-formats/src/t8ad.rs` | **100 % of the disc decodes** (19 216/19 216, measured). The "~15 % deferred variants" were a wrong model, not a variant: a surface is a list of **arbitrary sub-rectangles**, each with a 16-byte header of `dst X, dst Y, width, height`, not a 256×256 grid — `0x1c` is the **rectangle count**. Uncovered area stays transparent. **Colours ✅ CONFIRMED** ([k8888](structures/texture-color-k8888.md)) |
| RATC bundle | ✅ | `sylpheed-formats/src/ratc.rs` | child listing confirmed. **"One level deep" is not a limitation — there is nothing deeper**: 2 859 bundles hold 18 002 children at depth 1 and **0 at depth 2**, with no parse failures. Nested RATC blobs are **leaf records that reference siblings by name** (`opt `, the sprite name): 3 311 leaves, all embedding sibling names, **10 144 of 10 148 references resolve**. The 4 that do not are one dangling asset — `pmbase.rat``pmbase.t32` in `GP_STAGE_CLEAR.pak`'s four language builds, and `pmbase.t32` is **on the disc nowhere** |
| LSTA sprite list | ✅ | `sylpheed-formats/src/lsta.rs` | A display list of inline elements: **T8aD sprites and `PRMD` primitives**. The `count` at `0x04` is **exact and counts both**`count == T8aD + PRMD` for **64/64** lists on the disc, which retires the old "a few entries disagree" note (it compared sprites against a total including primitives). **All 1 281 sprite frames decode** after the T8aD rectangle-list fix |
| IXUD subtitle | 🟡/✅ | `sylpheed-formats/src/ixud.rs` + [movie link](movie-subtitle-link.md) | timed cues. **The movie↔subtitle↔voice link is solved — statically**, from the movie config record in `tables.pak` (schema `0x067025b9`), not from the running game as this row previously assumed: [101 movies mapped](captures/movie-subtitle-voice-map.csv), 94 with subtitles, 83 with voice, 21 with a telop overlay. 93 of 94 subtitle refs resolve in the language paks; **`SUBTITLE_S12B.tbl` is missing from all six languages** — a dangling reference on the disc. Naming is `SUBTITLE_<base>.tbl` / `VOICE_<base>` with six documented exceptions. The record's ~104 **script ids** are ❔ — positional pairing drifts by three because the IDXD pool dedupes repeated values |
| IXUD subtitle | 🟡/✅ | `sylpheed-formats/src/ixud.rs` + [movie link](movie-subtitle-link.md) | timed cues. **The movie↔subtitle↔voice link is solved — statically**, and as of 2026-08-25 read from the IDXD **record table** rather than scraped from the string pool: **104 cutscene slots binding 101 distinct movies**, 99 slots / 96 movies with a subtitle, 99 / 96 with a voice track, 22 / 22 with a telop. ⚠️ The previous counts (94 / 83 / 21) were the numbers of **distinct pool strings** — a repeat reference contributes no token, so 13 later `VOICE_D_450..454` references read as "no binding". **All 18 hokyu movies are bound**, not five. 93 of the 94 distinct subtitle members resolve; `SUBTITLE_S12B.tbl` resolves in none of the six languages — a dangling reference on the disc. The ~104 **script ids are no longer ❔**: they are literal positional field keys in `BASE_INFO`, each naming its record, and all 104 resolve. `movie_manifest::parse` now reads the record table; CSV regenerated by `examples/movie_map_csv.rs` |
| Fonts (ttf/otf/ttc) | ✅ | `sylpheed-formats/src/font.rs` | standard OpenType, parsed via ttf-parser |
| XBG7 mesh | ✅/🟡 | `sylpheed-formats/src/mesh.rs` + `tests/mesh_disc.rs` ([xbg7](structures/xbg7-mesh.md)) | **6 294 resources, 6 209 decode (98.7 %), 82 searched-and-missed** (2026-08-12, up from 5 480 / 87.1 %). Five evidence-driven fixes got there: **distinct anchor assignment** (no two resources may claim one buffer — proved by a capture showing the container holds both mirrored `e106` hull halves), the connectivity cap replaced by a **winding-consistency gate at 0.70**, **structural requirements on pre-pivot sub-meshes** (index range, then exact pool coverage), and **filtering after the assignment** so a subset query cannot differ from the full decode. Validated against a runtime capture that names the file offset of every buffer the engine drew: **46/46 drawn buffers claimed, 45 anchored exactly**. **No real mesh now decodes differently in different containers** — all 89 remaining cross-container disagreements are interchangeable 24-vertex bounding boxes, which no anchoring rule can pin (monotone order re-tested and refuted). Remaining misses attribute to the degeneracy/extent gate (42), winding (31) and coverage (9); the first was probed and its "obvious" fix refuted. Every decoded sub-mesh covers its own vertex pool. **The `[index buffer][vertex buffer]` layout is now runtime-verified** (2026-08-13): with the F10 capture extended to log each draw's index buffer, all **42** drawn `Stage_S02` buffers match our decoded index count exactly, all 42 have their index union cover the pool exactly, and the 30 single-block cases all sit at `pad ≤ 3` — so `e106_eng_02_l`'s old rejection was the connectivity gate, not a misplaced index buffer. The `indices=` mystery was the capture keeping only the **first of several index batches** per buffer. **And comparing index VALUES found the biggest silent defect yet**: the anchor took the first `pad` that validated, so a block whose index data sits at pad 2 was read **one element late** — 76/93 captured runs matched, all 17 differences a one-element shift. Scoring pads by degenerate triangles + winding fixes it: **93/93** captured runs now match byte for byte, disc-wide degenerate runs **582 → 1** (the grouped path had the same bug; and two resources were anchored on a degenerate lookalike earlier in file order), **590 of 8 850** sub-meshes re-wired with 10 vertex anchors moved, resources decoded unchanged at 6 209. Cross-container minority decodes 89 → 96 — *because* the decoder improved: `_rou_f402_dead` now has a majority (32×25×8) so its seven wrong copies are named instead of hidden. One dirty run remains, blocked by distinct assignment on a 24-vertex box. **Then the descriptor gave up its last structural secret**: it declares a vertex layout **per sub-mesh** (`n201_01` → strides 24/24/24/**28**, capture-confirmed), and grouped selection must prefer the candidate explaining the **whole** pool rather than the first whose pivot validates — together they take never-decoding resources **85 → 47** (**6 247 / 6 294 = 99.25 %** decode), put `n201_01` on all four capture-proven offsets and raise the stage-05 capture oracle to **128/128**. The residual 47 is 30 pose/proxy composites (0.010-unit marker boxes), 6 `.DAT` particle composites, 8 damage/LOD variants and 3 props — not a threshold away |
| Capital-ship part placement | ✅ | `sylpheed-formats/src/ship.rs` (static) + [runtime capture](ship-placement-runtime-capture.md) | Placement is **sound** (hull static-exact against the `e106` capture; cross-id mounting genuinely narrow, 2 pairs across 335 ships). The XBG7 mis-decode this row used to blame for "ships assemble wrong" — a shared turret ~100× too large in some containers — is **fixed** (2026-08-12, the exact-coverage requirement): `e303_wep_01` now decodes 49×23×42 everywhere and places at ±179 on the `e106` hull, and no real mesh disagrees across containers. A composite-node audit confirmed the assembler itself never applied a bad scale (all nodes scale 1.0, orthonormal). Still open: `static_assembly_matches_runtime_capture` walks capture parts only, so **extra** static placements cannot fail it |

View File

@@ -1,102 +1,105 @@
movie,telop,subtitle,voicetrack
logo1.wmv,,,
logo2.wmv,,,
logo3.wmv,,,
logo4.wmv,,,
ADV.wmv,,,VOICE_ADV
SYLPH_HD720p_8M-CBR_2ch.wmv,pwterop_s01a.prt,SYLPH_HD720p_8M-CBR_2ch.tbl,
S00A.wmv,,SUBTITLE_S00A.tbl,VOICE_S00A
S01A.wmv,,SUBTITLE_S01A.tbl,VOICE_S01A
RT01A.wmv,pwrt01.prt,SUBTITLE_RT01A.tbl,VOICE_RT01A
RT01B.wmv,,SUBTITLE_RT01B.tbl,VOICE_RT01B
RT01C_1.wmv,,SUBTITLE_RT01C_1.tbl,VOICE_RT01C_1
RT01C_2.wmv,,SUBTITLE_RT01C_2.tbl,VOICE_RT01C_2
S02A.wmv,pwterop_s02a.prt,SUBTITLE_S02A.tbl,VOICE_S02A
S02B.wmv,,SUBTITLE_S02B.tbl,VOICE_S02B
S02C.wmv,,SUBTITLE_S02C.tbl,VOICE_S02C
RT02A.wmv,pwrt02.prt,SUBTITLE_RT02A.tbl,VOICE_RT02A
RT02B.wmv,,SUBTITLE_RT02B.tbl,VOICE_RT02B
RT02C.wmv,,SUBTITLE_RT02C.tbl,VOICE_RT02C
RT02D_1.wmv,,SUBTITLE_RT02D_1.tbl,VOICE_RT02D_1
RT02D_2.wmv,,SUBTITLE_RT02D_2.tbl,VOICE_RT02D_2
hokyu_LS_s02A.wmv,,SUBTITLE_hokyu_LS_s02A.tbl,VOICE_D_450
hokyu_LS_s02H.wmv,,SUBTITLE_hokyu_LS_s02H.tbl,VOICE_D_453
S03A.wmv,,SUBTITLE_S03A.tbl,VOICE_S03A
RT03A.wmv,pwrt03.prt,SUBTITLE_RT03A.tbl,VOICE_RT03A
RT03B.wmv,,SUBTITLE_RT03B.tbl,VOICE_RT03B
RT03C.wmv,,SUBTITLE_RT03C.tbl,VOICE_RT03C
RT03D.wmv,,SUBTITLE_RT03D.tbl,VOICE_RT03D
hokyu_LS_s03A.wmv,,SUBTITLE_hokyu_LS_s03A.tbl,
hokyu_LS_s03H.wmv,,SUBTITLE_hokyu_LS_s03H.tbl,
S04A.wmv,,SUBTITLE_S04A.tbl,VOICE_S04A
S04B.wmv,,SUBTITLE_S04B.tbl,VOICE_S04B
RT04A.wmv,pwrt04.prt,SUBTITLE_RT04A.tbl,VOICE_RT04A
RT04B.wmv,,SUBTITLE_RT04B.tbl,VOICE_RT04B
hokyu_DS_s02A.wmv,,SUBTITLE_hokyu_DS_s02A.tbl,VOICE_D_452
S05A.wmv,,SUBTITLE_S05A.tbl,VOICE_S05A
RT05A.wmv,pwrt05.prt,SUBTITLE_RT05A.tbl,VOICE_RT05A
RT05B.wmv,,SUBTITLE_RT05B.tbl,VOICE_RT05B
RT05C.wmv,,SUBTITLE_RT05C.tbl,VOICE_RT05C
S06A.wmv,pwterop_s06a.prt,SUBTITLE_S06A.tbl,VOICE_S06A
S06B.wmv,,SUBTITLE_S06B.tbl,VOICE_S06B
RT06A.wmv,pwrt06.prt,SUBTITLE_RT06A.tbl,VOICE_RT06A
RT06B.wmv,,SUBTITLE_RT06B.tbl,VOICE_RT06B
RT06C.wmv,,SUBTITLE_RT06C.tbl,VOICE_RT06C
RT06D.wmv,,SUBTITLE_RT06D.tbl,VOICE_RT06D
hokyu_LS_s06A.wmv,,SUBTITLE_hokyu_LS_s06A.tbl,
hokyu_LS_s06H.wmv,,SUBTITLE_hokyu_LS_s06H.tbl,
S07A.wmv,,SUBTITLE_S07A.tbl,VOICE_S07A
S07B.wmv,,SUBTITLE_S07B.tbl,VOICE_S07B
RT07A.wmv,pwrt07.prt,SUBTITLE_RT07A.tbl,VOICE_RT07A
RT07B.wmv,,SUBTITLE_RT07B.tbl,VOICE_RT07B
RT07C.wmv,,SUBTITLE_RT07C.tbl,VOICE_RT07C
hokyu_DS_s07A.wmv,,SUBTITLE_hokyu_DS_s07A.tbl,
hokyu_DS_s07H.wmv,,SUBTITLE_hokyu_DS_s07H.tbl,VOICE_D_454
RT08A.wmv,pwrt08.prt,SUBTITLE_RT08A.tbl,VOICE_RT08A
RT08B.wmv,,SUBTITLE_RT08B.tbl,VOICE_RT08B
RT08C.wmv,,SUBTITLE_RT08C.tbl,VOICE_RT08C
hokyu_DS_s08A.wmv,,SUBTITLE_hokyu_DS_s08A.tbl,
S09B.wmv,,SUBTITLE_S09B.tbl,VOICE_S09B
RT09A.wmv,pwrt09.prt,SUBTITLE_RT09A.tbl,VOICE_RT09A
RT09B.wmv,,SUBTITLE_RT09B.tbl,VOICE_RT09B
RT09C.wmv,,SUBTITLE_RT09C.tbl,VOICE_RT09C
RT09D.wmv,,SUBTITLE_RT09D.tbl,VOICE_RT09D
hokyu_LS_s09A.wmv,,SUBTITLE_hokyu_LS_s09A.tbl,VOICE_D_451
hokyu_LS_s09H.wmv,,SUBTITLE_hokyu_LS_s09H.tbl,
S10B.wmv,,SUBTITLE_S10B.tbl,VOICE_S10B
RT10A.wmv,pwrt10.prt,SUBTITLE_RT10A.tbl,VOICE_RT10A
RT10B.wmv,,SUBTITLE_RT10B.tbl,VOICE_RT10B
S11A.wmv,,SUBTITLE_S11A.tbl,VOICE_S11A
S11C.wmv,,SUBTITLE_S11C.tbl,VOICE_S11C
RT11A.wmv,pwrt11.prt,SUBTITLE_RT11A.tbl,VOICE_RT11A
RT11B.wmv,,SUBTITLE_RT11B.tbl,VOICE_RT11B
RT11C.wmv,,SUBTITLE_RT11C.tbl,VOICE_RT11C
hokyu_LS_s11A.wmv,,SUBTITLE_hokyu_LS_s11A.tbl,
S12A.wmv,,SUBTITLE_S12A.tbl,VOICE_S12A
S12B.wmv,,SUBTITLE_S12B.tbl,VOICE_S12B
S12C.wmv,,SUBTITLE_S12C.tbl,VOICE_S12C
RT12A.wmv,pwrt12.prt,SUBTITLE_RT12A.tbl,VOICE_RT12A
RT12B_1.wmv,,SUBTITLE_RT12B_1.tbl,VOICE_RT12B_1
RT12B_2.wmv,,SUBTITLE_RT12B_2.tbl,VOICE_RT12B_2
S13A.wmv,,SUBTITLE_S13A.tbl,VOICE_S13A
S13B.wmv,,SUBTITLE_S13B.tbl,VOICE_S13B
RT13A.wmv,pwrt13.prt,SUBTITLE_RT13A.tbl,VOICE_RT13A
RT13B_1.wmv,,SUBTITLE_RT13B_1.tbl,VOICE_RT13B_1
RT13B_2.wmv,,SUBTITLE_RT13B_2.tbl,VOICE_RT13B_2
hokyu_DS_s13A.wmv,,SUBTITLE_hokyu_DS_s13A.tbl,
S14A.wmv,,SUBTITLE_S14A.tbl,VOICE_S14A
RT14A.wmv,pwrt14.prt,SUBTITLE_RT14A.tbl,VOICE_RT14A
RT14B.wmv,,SUBTITLE_RT14B.tbl,VOICE_RT14B
RT14C.wmv,,SUBTITLE_RT14C.tbl,VOICE_RT14C
hokyu_DS_s14H.wmv,,SUBTITLE_hokyu_DS_s14H.tbl,
S15A.wmv,pwterop_s15a.prt,SUBTITLE_S15A.tbl,VOICE_S15A
S15B.wmv,,SUBTITLE_S15B.tbl,VOICE_S15B
S15C.wmv,,SUBTITLE_S15C.tbl,VOICE_S15C
RT15A.wmv,pwrt15.prt,SUBTITLE_RT15A.tbl,VOICE_RT15A
RT15B.wmv,,SUBTITLE_RT15B.tbl,VOICE_RT15B
RT15C.wmv,,SUBTITLE_RT15C.tbl,VOICE_RT15C
hokyu_LS_s15A.wmv,,SUBTITLE_hokyu_LS_s15A.tbl,
S16A.wmv,pwterop_s16a.prt,SUBTITLE_S16A.tbl,VOICE_S16A
RT16C.wmv,pwrt16.prt,SUBTITLE_RT16C.tbl,VOICE_RT16C
hokyu_LS_s24A.wmv,,,
hokyu_LS_s27A.wmv,,,
slot,movie,telop,subtitle,voicetrack
LOGO1,logo1.wmv,,,
LOGO2,logo2.wmv,,,
LOGO3,logo3.wmv,,,
LOGO4,logo4.wmv,,,
ADVERTISE_MOVIE,ADV.wmv,,,VOICE_ADV
STAFF_ROLL,SYLPH_HD720p_8M-CBR_2ch.wmv,pwterop_s01a.prt,SYLPH_HD720p_8M-CBR_2ch.tbl,
MS00A,S00A.wmv,,SUBTITLE_S00A.tbl,VOICE_S00A
MS01A,S01A.wmv,pwterop_s01a.prt,SUBTITLE_S01A.tbl,VOICE_S01A
STAGE01_PHASE01,RT01A.wmv,pwrt01.prt,SUBTITLE_RT01A.tbl,VOICE_RT01A
STAGE01_PHASE02,RT01B.wmv,,SUBTITLE_RT01B.tbl,VOICE_RT01B
STAGE01_PHASE_END_01,RT01C_1.wmv,,SUBTITLE_RT01C_1.tbl,VOICE_RT01C_1
STAGE01_PHASE_END_02,RT01C_2.wmv,,SUBTITLE_RT01C_2.tbl,VOICE_RT01C_2
MS02A,S02A.wmv,pwterop_s02a.prt,SUBTITLE_S02A.tbl,VOICE_S02A
MS02B,S02B.wmv,,SUBTITLE_S02B.tbl,VOICE_S02B
MS02C,S02C.wmv,,SUBTITLE_S02C.tbl,VOICE_S02C
STAGE02_PHASE01,RT02A.wmv,pwrt02.prt,SUBTITLE_RT02A.tbl,VOICE_RT02A
STAGE02_PHASE02,RT02B.wmv,,SUBTITLE_RT02B.tbl,VOICE_RT02B
STAGE02_PHASE03,RT02C.wmv,,SUBTITLE_RT02C.tbl,VOICE_RT02C
STAGE02_PHASE_END_01,RT02D_1.wmv,,SUBTITLE_RT02D_1.tbl,VOICE_RT02D_1
STAGE02_PHASE_END_02,RT02D_2.wmv,,SUBTITLE_RT02D_2.tbl,VOICE_RT02D_2
S02_SUPPLY_ACROPOLIS,hokyu_LS_s02A.wmv,,SUBTITLE_hokyu_LS_s02A.tbl,VOICE_D_450
S02_SUPPLY_TANKER,hokyu_LS_s02H.wmv,,SUBTITLE_hokyu_LS_s02H.tbl,VOICE_D_453
MS03A,S03A.wmv,,SUBTITLE_S03A.tbl,VOICE_S03A
STAGE03_PHASE01,RT03A.wmv,pwrt03.prt,SUBTITLE_RT03A.tbl,VOICE_RT03A
STAGE03_PHASE02,RT03B.wmv,,SUBTITLE_RT03B.tbl,VOICE_RT03B
STAGE03_PHASE03,RT03C.wmv,,SUBTITLE_RT03C.tbl,VOICE_RT03C
STAGE03_PHASE_END,RT03D.wmv,,SUBTITLE_RT03D.tbl,VOICE_RT03D
S03_SUPPLY_ACROPOLIS,hokyu_LS_s03A.wmv,,SUBTITLE_hokyu_LS_s03A.tbl,VOICE_D_450
S03_SUPPLY_TANKER,hokyu_LS_s03H.wmv,,SUBTITLE_hokyu_LS_s03H.tbl,VOICE_D_453
MS04A,S04A.wmv,,SUBTITLE_S04A.tbl,VOICE_S04A
MS04B,S04B.wmv,,SUBTITLE_S04B.tbl,VOICE_S04B
STAGE04_PHASE01,RT04A.wmv,pwrt04.prt,SUBTITLE_RT04A.tbl,VOICE_RT04A
STAGE04_PHASE02,RT04B.wmv,,SUBTITLE_RT04B.tbl,VOICE_RT04B
S04_SUPPLY_ACROPOLIS,hokyu_DS_s02A.wmv,,SUBTITLE_hokyu_DS_s02A.tbl,VOICE_D_452
MS05A,S05A.wmv,,SUBTITLE_S05A.tbl,VOICE_S05A
STAGE05_PHASE01,RT05A.wmv,pwrt05.prt,SUBTITLE_RT05A.tbl,VOICE_RT05A
STAGE05_PHASE02,RT05B.wmv,,SUBTITLE_RT05B.tbl,VOICE_RT05B
STAGE05_PHASE_END,RT05C.wmv,,SUBTITLE_RT05C.tbl,VOICE_RT05C
S05_SUPPLY_ACROPOLIS,hokyu_LS_s02A.wmv,,SUBTITLE_hokyu_LS_s02A.tbl,VOICE_D_450
MS06A,S06A.wmv,pwterop_s06a.prt,SUBTITLE_S06A.tbl,VOICE_S06A
MS06B,S06B.wmv,,SUBTITLE_S06B.tbl,VOICE_S06B
STAGE06_PHASE01,RT06A.wmv,pwrt06.prt,SUBTITLE_RT06A.tbl,VOICE_RT06A
STAGE06_PHASE02,RT06B.wmv,,SUBTITLE_RT06B.tbl,VOICE_RT06B
STAGE06_PHASE03,RT06C.wmv,,SUBTITLE_RT06C.tbl,VOICE_RT06C
STAGE06_PHASE_END,RT06D.wmv,,SUBTITLE_RT06D.tbl,VOICE_RT06D
S06_SUPPLY_ACROPOLIS,hokyu_LS_s06A.wmv,,SUBTITLE_hokyu_LS_s06A.tbl,VOICE_D_450
S06_SUPPLY_TANKER,hokyu_LS_s06H.wmv,,SUBTITLE_hokyu_LS_s06H.tbl,VOICE_D_453
MS07A,S07A.wmv,,SUBTITLE_S07A.tbl,VOICE_S07A
MS07B,S07B.wmv,,SUBTITLE_S07B.tbl,VOICE_S07B
STAGE07_PHASE01,RT07A.wmv,pwrt07.prt,SUBTITLE_RT07A.tbl,VOICE_RT07A
STAGE07_PHASE02,RT07B.wmv,,SUBTITLE_RT07B.tbl,VOICE_RT07B
STAGE07_PHASE_END,RT07C.wmv,,SUBTITLE_RT07C.tbl,VOICE_RT07C
S07_SUPPLY_ACROPOLIS,hokyu_DS_s07A.wmv,,SUBTITLE_hokyu_DS_s07A.tbl,VOICE_D_452
S07_SUPPLY_TANKER,hokyu_DS_s07H.wmv,,SUBTITLE_hokyu_DS_s07H.tbl,VOICE_D_454
STAGE08_PHASE01,RT08A.wmv,pwrt08.prt,SUBTITLE_RT08A.tbl,VOICE_RT08A
STAGE08_PHASE02,RT08B.wmv,,SUBTITLE_RT08B.tbl,VOICE_RT08B
STAGE08_PHASE_END,RT08C.wmv,,SUBTITLE_RT08C.tbl,VOICE_RT08C
S08_SUPPLY_ACROPOLIS,hokyu_DS_s08A.wmv,,SUBTITLE_hokyu_DS_s08A.tbl,VOICE_D_452
MS09B,S09B.wmv,,SUBTITLE_S09B.tbl,VOICE_S09B
STAGE09_PHASE01,RT09A.wmv,pwrt09.prt,SUBTITLE_RT09A.tbl,VOICE_RT09A
STAGE09_PHASE02,RT09B.wmv,,SUBTITLE_RT09B.tbl,VOICE_RT09B
STAGE09_PHASE03,RT09C.wmv,,SUBTITLE_RT09C.tbl,VOICE_RT09C
STAGE09_PHASE_END,RT09D.wmv,,SUBTITLE_RT09D.tbl,VOICE_RT09D
S09_SUPPLY_ACROPOLIS,hokyu_LS_s09A.wmv,,SUBTITLE_hokyu_LS_s09A.tbl,VOICE_D_451
S09_SUPPLY_TANKER,hokyu_LS_s09H.wmv,,SUBTITLE_hokyu_LS_s09H.tbl,VOICE_D_453
MS10B,S10B.wmv,,SUBTITLE_S10B.tbl,VOICE_S10B
STAGE10_PHASE01,RT10A.wmv,pwrt10.prt,SUBTITLE_RT10A.tbl,VOICE_RT10A
STAGE10_PHASE_END,RT10B.wmv,,SUBTITLE_RT10B.tbl,VOICE_RT10B
MS11A,S11A.wmv,,SUBTITLE_S11A.tbl,VOICE_S11A
MS11C,S11C.wmv,,SUBTITLE_S11C.tbl,VOICE_S11C
STAGE11_PHASE01,RT11A.wmv,pwrt11.prt,SUBTITLE_RT11A.tbl,VOICE_RT11A
STAGE11_PHASE02,RT11B.wmv,,SUBTITLE_RT11B.tbl,VOICE_RT11B
STAGE11_PHASE_END,RT11C.wmv,,SUBTITLE_RT11C.tbl,VOICE_RT11C
S11_SUPPLY_ACROPOLIS,hokyu_LS_s11A.wmv,,SUBTITLE_hokyu_LS_s11A.tbl,VOICE_D_451
MS12A,S12A.wmv,,SUBTITLE_S12A.tbl,VOICE_S12A
MS12B,S12B.wmv,,SUBTITLE_S12B.tbl,VOICE_S12B
MS12C,S12C.wmv,,SUBTITLE_S12C.tbl,VOICE_S12C
STAGE12_PHASE01,RT12A.wmv,pwrt12.prt,SUBTITLE_RT12A.tbl,VOICE_RT12A
STAGE12_PHASE_END_01,RT12B_1.wmv,,SUBTITLE_RT12B_1.tbl,VOICE_RT12B_1
STAGE12_PHASE_END_02,RT12B_2.wmv,,SUBTITLE_RT12B_2.tbl,VOICE_RT12B_2
S12_SUPPLY_ACROPOLIS,hokyu_DS_s07A.wmv,,SUBTITLE_hokyu_DS_s07A.tbl,VOICE_D_452
S12_SUPPLY_TANKER,hokyu_DS_s07H.wmv,,SUBTITLE_hokyu_DS_s07H.tbl,VOICE_D_454
MS13A,S13A.wmv,,SUBTITLE_S13A.tbl,VOICE_S13A
MS13B,S13B.wmv,,SUBTITLE_S13B.tbl,VOICE_S13B
STAGE13_PHASE01,RT13A.wmv,pwrt13.prt,SUBTITLE_RT13A.tbl,VOICE_RT13A
STAGE13_PHASE_END_01,RT13B_1.wmv,,SUBTITLE_RT13B_1.tbl,VOICE_RT13B_1
STAGE13_PHASE_END_02,RT13B_2.wmv,,SUBTITLE_RT13B_2.tbl,VOICE_RT13B_2
S13_SUPPLY_ACROPOLIS,hokyu_DS_s13A.wmv,,SUBTITLE_hokyu_DS_s13A.tbl,VOICE_D_452
MS14A,S14A.wmv,,SUBTITLE_S14A.tbl,VOICE_S14A
STAGE14_PHASE01,RT14A.wmv,pwrt14.prt,SUBTITLE_RT14A.tbl,VOICE_RT14A
STAGE14_PHASE02,RT14B.wmv,,SUBTITLE_RT14B.tbl,VOICE_RT14B
STAGE14_PHASE_END,RT14C.wmv,,SUBTITLE_RT14C.tbl,VOICE_RT14C
S14_SUPPLY_TANKER,hokyu_DS_s14H.wmv,,SUBTITLE_hokyu_DS_s14H.tbl,VOICE_D_454
MS15A,S15A.wmv,pwterop_s15a.prt,SUBTITLE_S15A.tbl,VOICE_S15A
MS15B,S15B.wmv,,SUBTITLE_S15B.tbl,VOICE_S15B
MS15C,S15C.wmv,,SUBTITLE_S15C.tbl,VOICE_S15C
STAGE15_PHASE01,RT15A.wmv,pwrt15.prt,SUBTITLE_RT15A.tbl,VOICE_RT15A
STAGE15_PHASE02,RT15B.wmv,,SUBTITLE_RT15B.tbl,VOICE_RT15B
STAGE15_PHASE_END,RT15C.wmv,,SUBTITLE_RT15C.tbl,VOICE_RT15C
S15_SUPPLY_ACROPOLIS,hokyu_LS_s15A.wmv,,SUBTITLE_hokyu_LS_s15A.tbl,VOICE_D_451
MS16A,S16A.wmv,pwterop_s16a.prt,SUBTITLE_S16A.tbl,VOICE_S16A
STAGE16_PHASE01,RT16C.wmv,pwrt16.prt,SUBTITLE_RT16C.tbl,VOICE_RT16C
S24_SUPPLY_ACROPOLIS,hokyu_LS_s24A.wmv,,SUBTITLE_hokyu_LS_s11A.tbl,VOICE_D_451
S27_SUPPLY_ACROPOLIS,hokyu_LS_s27A.wmv,,SUBTITLE_hokyu_LS_s11A.tbl,VOICE_D_451
1 slot movie telop subtitle voicetrack
2 LOGO1 logo1.wmv
3 LOGO2 logo2.wmv
4 LOGO3 logo3.wmv
5 LOGO4 logo4.wmv
6 ADVERTISE_MOVIE ADV.wmv VOICE_ADV
7 STAFF_ROLL SYLPH_HD720p_8M-CBR_2ch.wmv pwterop_s01a.prt SYLPH_HD720p_8M-CBR_2ch.tbl
8 MS00A S00A.wmv SUBTITLE_S00A.tbl VOICE_S00A
9 MS01A S01A.wmv pwterop_s01a.prt SUBTITLE_S01A.tbl VOICE_S01A
10 STAGE01_PHASE01 RT01A.wmv pwrt01.prt SUBTITLE_RT01A.tbl VOICE_RT01A
11 STAGE01_PHASE02 RT01B.wmv SUBTITLE_RT01B.tbl VOICE_RT01B
12 STAGE01_PHASE_END_01 RT01C_1.wmv SUBTITLE_RT01C_1.tbl VOICE_RT01C_1
13 STAGE01_PHASE_END_02 RT01C_2.wmv SUBTITLE_RT01C_2.tbl VOICE_RT01C_2
14 MS02A S02A.wmv pwterop_s02a.prt SUBTITLE_S02A.tbl VOICE_S02A
15 MS02B S02B.wmv SUBTITLE_S02B.tbl VOICE_S02B
16 MS02C S02C.wmv SUBTITLE_S02C.tbl VOICE_S02C
17 STAGE02_PHASE01 RT02A.wmv pwrt02.prt SUBTITLE_RT02A.tbl VOICE_RT02A
18 STAGE02_PHASE02 RT02B.wmv SUBTITLE_RT02B.tbl VOICE_RT02B
19 STAGE02_PHASE03 RT02C.wmv SUBTITLE_RT02C.tbl VOICE_RT02C
20 STAGE02_PHASE_END_01 RT02D_1.wmv SUBTITLE_RT02D_1.tbl VOICE_RT02D_1
21 STAGE02_PHASE_END_02 RT02D_2.wmv SUBTITLE_RT02D_2.tbl VOICE_RT02D_2
22 S02_SUPPLY_ACROPOLIS hokyu_LS_s02A.wmv SUBTITLE_hokyu_LS_s02A.tbl VOICE_D_450
23 S02_SUPPLY_TANKER hokyu_LS_s02H.wmv SUBTITLE_hokyu_LS_s02H.tbl VOICE_D_453
24 MS03A S03A.wmv SUBTITLE_S03A.tbl VOICE_S03A
25 STAGE03_PHASE01 RT03A.wmv pwrt03.prt SUBTITLE_RT03A.tbl VOICE_RT03A
26 STAGE03_PHASE02 RT03B.wmv SUBTITLE_RT03B.tbl VOICE_RT03B
27 STAGE03_PHASE03 RT03C.wmv SUBTITLE_RT03C.tbl VOICE_RT03C
28 STAGE03_PHASE_END RT03D.wmv SUBTITLE_RT03D.tbl VOICE_RT03D
29 S03_SUPPLY_ACROPOLIS hokyu_LS_s03A.wmv SUBTITLE_hokyu_LS_s03A.tbl VOICE_D_450
30 S03_SUPPLY_TANKER hokyu_LS_s03H.wmv SUBTITLE_hokyu_LS_s03H.tbl VOICE_D_453
31 MS04A S04A.wmv SUBTITLE_S04A.tbl VOICE_S04A
32 MS04B S04B.wmv SUBTITLE_S04B.tbl VOICE_S04B
33 STAGE04_PHASE01 RT04A.wmv pwrt04.prt SUBTITLE_RT04A.tbl VOICE_RT04A
34 STAGE04_PHASE02 RT04B.wmv SUBTITLE_RT04B.tbl VOICE_RT04B
35 S04_SUPPLY_ACROPOLIS hokyu_DS_s02A.wmv SUBTITLE_hokyu_DS_s02A.tbl VOICE_D_452
36 MS05A S05A.wmv SUBTITLE_S05A.tbl VOICE_S05A
37 STAGE05_PHASE01 RT05A.wmv pwrt05.prt SUBTITLE_RT05A.tbl VOICE_RT05A
38 STAGE05_PHASE02 RT05B.wmv SUBTITLE_RT05B.tbl VOICE_RT05B
39 STAGE05_PHASE_END RT05C.wmv SUBTITLE_RT05C.tbl VOICE_RT05C
40 S05_SUPPLY_ACROPOLIS S06A.wmv hokyu_LS_s02A.wmv pwterop_s06a.prt SUBTITLE_S06A.tbl SUBTITLE_hokyu_LS_s02A.tbl VOICE_S06A VOICE_D_450
41 MS06A S06B.wmv S06A.wmv pwterop_s06a.prt SUBTITLE_S06B.tbl SUBTITLE_S06A.tbl VOICE_S06B VOICE_S06A
42 MS06B RT06A.wmv S06B.wmv pwrt06.prt SUBTITLE_RT06A.tbl SUBTITLE_S06B.tbl VOICE_RT06A VOICE_S06B
43 STAGE06_PHASE01 RT06B.wmv RT06A.wmv pwrt06.prt SUBTITLE_RT06B.tbl SUBTITLE_RT06A.tbl VOICE_RT06B VOICE_RT06A
44 STAGE06_PHASE02 RT06C.wmv RT06B.wmv SUBTITLE_RT06C.tbl SUBTITLE_RT06B.tbl VOICE_RT06C VOICE_RT06B
45 STAGE06_PHASE03 RT06D.wmv RT06C.wmv SUBTITLE_RT06D.tbl SUBTITLE_RT06C.tbl VOICE_RT06D VOICE_RT06C
46 STAGE06_PHASE_END hokyu_LS_s06A.wmv RT06D.wmv SUBTITLE_hokyu_LS_s06A.tbl SUBTITLE_RT06D.tbl VOICE_RT06D
47 S06_SUPPLY_ACROPOLIS hokyu_LS_s06H.wmv hokyu_LS_s06A.wmv SUBTITLE_hokyu_LS_s06H.tbl SUBTITLE_hokyu_LS_s06A.tbl VOICE_D_450
48 S06_SUPPLY_TANKER S07A.wmv hokyu_LS_s06H.wmv SUBTITLE_S07A.tbl SUBTITLE_hokyu_LS_s06H.tbl VOICE_S07A VOICE_D_453
49 MS07A S07B.wmv S07A.wmv SUBTITLE_S07B.tbl SUBTITLE_S07A.tbl VOICE_S07B VOICE_S07A
50 MS07B RT07A.wmv S07B.wmv pwrt07.prt SUBTITLE_RT07A.tbl SUBTITLE_S07B.tbl VOICE_RT07A VOICE_S07B
51 STAGE07_PHASE01 RT07B.wmv RT07A.wmv pwrt07.prt SUBTITLE_RT07B.tbl SUBTITLE_RT07A.tbl VOICE_RT07B VOICE_RT07A
52 STAGE07_PHASE02 RT07C.wmv RT07B.wmv SUBTITLE_RT07C.tbl SUBTITLE_RT07B.tbl VOICE_RT07C VOICE_RT07B
53 STAGE07_PHASE_END hokyu_DS_s07A.wmv RT07C.wmv SUBTITLE_hokyu_DS_s07A.tbl SUBTITLE_RT07C.tbl VOICE_RT07C
54 S07_SUPPLY_ACROPOLIS hokyu_DS_s07H.wmv hokyu_DS_s07A.wmv SUBTITLE_hokyu_DS_s07H.tbl SUBTITLE_hokyu_DS_s07A.tbl VOICE_D_454 VOICE_D_452
55 S07_SUPPLY_TANKER RT08A.wmv hokyu_DS_s07H.wmv pwrt08.prt SUBTITLE_RT08A.tbl SUBTITLE_hokyu_DS_s07H.tbl VOICE_RT08A VOICE_D_454
56 STAGE08_PHASE01 RT08B.wmv RT08A.wmv pwrt08.prt SUBTITLE_RT08B.tbl SUBTITLE_RT08A.tbl VOICE_RT08B VOICE_RT08A
57 STAGE08_PHASE02 RT08C.wmv RT08B.wmv SUBTITLE_RT08C.tbl SUBTITLE_RT08B.tbl VOICE_RT08C VOICE_RT08B
58 STAGE08_PHASE_END hokyu_DS_s08A.wmv RT08C.wmv SUBTITLE_hokyu_DS_s08A.tbl SUBTITLE_RT08C.tbl VOICE_RT08C
59 S08_SUPPLY_ACROPOLIS S09B.wmv hokyu_DS_s08A.wmv SUBTITLE_S09B.tbl SUBTITLE_hokyu_DS_s08A.tbl VOICE_S09B VOICE_D_452
60 MS09B RT09A.wmv S09B.wmv pwrt09.prt SUBTITLE_RT09A.tbl SUBTITLE_S09B.tbl VOICE_RT09A VOICE_S09B
61 STAGE09_PHASE01 RT09B.wmv RT09A.wmv pwrt09.prt SUBTITLE_RT09B.tbl SUBTITLE_RT09A.tbl VOICE_RT09B VOICE_RT09A
62 STAGE09_PHASE02 RT09C.wmv RT09B.wmv SUBTITLE_RT09C.tbl SUBTITLE_RT09B.tbl VOICE_RT09C VOICE_RT09B
63 STAGE09_PHASE03 RT09D.wmv RT09C.wmv SUBTITLE_RT09D.tbl SUBTITLE_RT09C.tbl VOICE_RT09D VOICE_RT09C
64 STAGE09_PHASE_END hokyu_LS_s09A.wmv RT09D.wmv SUBTITLE_hokyu_LS_s09A.tbl SUBTITLE_RT09D.tbl VOICE_D_451 VOICE_RT09D
65 S09_SUPPLY_ACROPOLIS hokyu_LS_s09H.wmv hokyu_LS_s09A.wmv SUBTITLE_hokyu_LS_s09H.tbl SUBTITLE_hokyu_LS_s09A.tbl VOICE_D_451
66 S09_SUPPLY_TANKER S10B.wmv hokyu_LS_s09H.wmv SUBTITLE_S10B.tbl SUBTITLE_hokyu_LS_s09H.tbl VOICE_S10B VOICE_D_453
67 MS10B RT10A.wmv S10B.wmv pwrt10.prt SUBTITLE_RT10A.tbl SUBTITLE_S10B.tbl VOICE_RT10A VOICE_S10B
68 STAGE10_PHASE01 RT10B.wmv RT10A.wmv pwrt10.prt SUBTITLE_RT10B.tbl SUBTITLE_RT10A.tbl VOICE_RT10B VOICE_RT10A
69 STAGE10_PHASE_END S11A.wmv RT10B.wmv SUBTITLE_S11A.tbl SUBTITLE_RT10B.tbl VOICE_S11A VOICE_RT10B
70 MS11A S11C.wmv S11A.wmv SUBTITLE_S11C.tbl SUBTITLE_S11A.tbl VOICE_S11C VOICE_S11A
71 MS11C RT11A.wmv S11C.wmv pwrt11.prt SUBTITLE_RT11A.tbl SUBTITLE_S11C.tbl VOICE_RT11A VOICE_S11C
72 STAGE11_PHASE01 RT11B.wmv RT11A.wmv pwrt11.prt SUBTITLE_RT11B.tbl SUBTITLE_RT11A.tbl VOICE_RT11B VOICE_RT11A
73 STAGE11_PHASE02 RT11C.wmv RT11B.wmv SUBTITLE_RT11C.tbl SUBTITLE_RT11B.tbl VOICE_RT11C VOICE_RT11B
74 STAGE11_PHASE_END hokyu_LS_s11A.wmv RT11C.wmv SUBTITLE_hokyu_LS_s11A.tbl SUBTITLE_RT11C.tbl VOICE_RT11C
75 S11_SUPPLY_ACROPOLIS S12A.wmv hokyu_LS_s11A.wmv SUBTITLE_S12A.tbl SUBTITLE_hokyu_LS_s11A.tbl VOICE_S12A VOICE_D_451
76 MS12A S12B.wmv S12A.wmv SUBTITLE_S12B.tbl SUBTITLE_S12A.tbl VOICE_S12B VOICE_S12A
77 MS12B S12C.wmv S12B.wmv SUBTITLE_S12C.tbl SUBTITLE_S12B.tbl VOICE_S12C VOICE_S12B
78 MS12C RT12A.wmv S12C.wmv pwrt12.prt SUBTITLE_RT12A.tbl SUBTITLE_S12C.tbl VOICE_RT12A VOICE_S12C
79 STAGE12_PHASE01 RT12B_1.wmv RT12A.wmv pwrt12.prt SUBTITLE_RT12B_1.tbl SUBTITLE_RT12A.tbl VOICE_RT12B_1 VOICE_RT12A
80 STAGE12_PHASE_END_01 RT12B_2.wmv RT12B_1.wmv SUBTITLE_RT12B_2.tbl SUBTITLE_RT12B_1.tbl VOICE_RT12B_2 VOICE_RT12B_1
81 STAGE12_PHASE_END_02 S13A.wmv RT12B_2.wmv SUBTITLE_S13A.tbl SUBTITLE_RT12B_2.tbl VOICE_S13A VOICE_RT12B_2
82 S12_SUPPLY_ACROPOLIS S13B.wmv hokyu_DS_s07A.wmv SUBTITLE_S13B.tbl SUBTITLE_hokyu_DS_s07A.tbl VOICE_S13B VOICE_D_452
83 S12_SUPPLY_TANKER RT13A.wmv hokyu_DS_s07H.wmv pwrt13.prt SUBTITLE_RT13A.tbl SUBTITLE_hokyu_DS_s07H.tbl VOICE_RT13A VOICE_D_454
84 MS13A RT13B_1.wmv S13A.wmv SUBTITLE_RT13B_1.tbl SUBTITLE_S13A.tbl VOICE_RT13B_1 VOICE_S13A
85 MS13B RT13B_2.wmv S13B.wmv SUBTITLE_RT13B_2.tbl SUBTITLE_S13B.tbl VOICE_RT13B_2 VOICE_S13B
86 STAGE13_PHASE01 hokyu_DS_s13A.wmv RT13A.wmv pwrt13.prt SUBTITLE_hokyu_DS_s13A.tbl SUBTITLE_RT13A.tbl VOICE_RT13A
87 STAGE13_PHASE_END_01 S14A.wmv RT13B_1.wmv SUBTITLE_S14A.tbl SUBTITLE_RT13B_1.tbl VOICE_S14A VOICE_RT13B_1
88 STAGE13_PHASE_END_02 RT14A.wmv RT13B_2.wmv pwrt14.prt SUBTITLE_RT14A.tbl SUBTITLE_RT13B_2.tbl VOICE_RT14A VOICE_RT13B_2
89 S13_SUPPLY_ACROPOLIS RT14B.wmv hokyu_DS_s13A.wmv SUBTITLE_RT14B.tbl SUBTITLE_hokyu_DS_s13A.tbl VOICE_RT14B VOICE_D_452
90 MS14A RT14C.wmv S14A.wmv SUBTITLE_RT14C.tbl SUBTITLE_S14A.tbl VOICE_RT14C VOICE_S14A
91 STAGE14_PHASE01 hokyu_DS_s14H.wmv RT14A.wmv pwrt14.prt SUBTITLE_hokyu_DS_s14H.tbl SUBTITLE_RT14A.tbl VOICE_RT14A
92 STAGE14_PHASE02 S15A.wmv RT14B.wmv pwterop_s15a.prt SUBTITLE_S15A.tbl SUBTITLE_RT14B.tbl VOICE_S15A VOICE_RT14B
93 STAGE14_PHASE_END S15B.wmv RT14C.wmv SUBTITLE_S15B.tbl SUBTITLE_RT14C.tbl VOICE_S15B VOICE_RT14C
94 S14_SUPPLY_TANKER S15C.wmv hokyu_DS_s14H.wmv SUBTITLE_S15C.tbl SUBTITLE_hokyu_DS_s14H.tbl VOICE_S15C VOICE_D_454
95 MS15A RT15A.wmv S15A.wmv pwrt15.prt pwterop_s15a.prt SUBTITLE_RT15A.tbl SUBTITLE_S15A.tbl VOICE_RT15A VOICE_S15A
96 MS15B RT15B.wmv S15B.wmv SUBTITLE_RT15B.tbl SUBTITLE_S15B.tbl VOICE_RT15B VOICE_S15B
97 MS15C RT15C.wmv S15C.wmv SUBTITLE_RT15C.tbl SUBTITLE_S15C.tbl VOICE_RT15C VOICE_S15C
98 STAGE15_PHASE01 hokyu_LS_s15A.wmv RT15A.wmv pwrt15.prt SUBTITLE_hokyu_LS_s15A.tbl SUBTITLE_RT15A.tbl VOICE_RT15A
99 STAGE15_PHASE02 S16A.wmv RT15B.wmv pwterop_s16a.prt SUBTITLE_S16A.tbl SUBTITLE_RT15B.tbl VOICE_S16A VOICE_RT15B
100 STAGE15_PHASE_END RT16C.wmv RT15C.wmv pwrt16.prt SUBTITLE_RT16C.tbl SUBTITLE_RT15C.tbl VOICE_RT16C VOICE_RT15C
101 S15_SUPPLY_ACROPOLIS hokyu_LS_s24A.wmv hokyu_LS_s15A.wmv SUBTITLE_hokyu_LS_s15A.tbl VOICE_D_451
102 MS16A hokyu_LS_s27A.wmv S16A.wmv pwterop_s16a.prt SUBTITLE_S16A.tbl VOICE_S16A
103 STAGE16_PHASE01 RT16C.wmv pwrt16.prt SUBTITLE_RT16C.tbl VOICE_RT16C
104 S24_SUPPLY_ACROPOLIS hokyu_LS_s24A.wmv SUBTITLE_hokyu_LS_s11A.tbl VOICE_D_451
105 S27_SUPPLY_ACROPOLIS hokyu_LS_s27A.wmv SUBTITLE_hokyu_LS_s11A.tbl VOICE_D_451

View File

@@ -30,36 +30,59 @@ VOICE_S02A VOICETRACK
language paks (`eng`, `fra`, `deu`, `esp`, `ita`, `jpn`) each carry the same
member names — so the prefix in the table is just the build's language and the
member name is the portable part. The recovered map is
[`captures/movie-subtitle-voice-map.csv`](captures/movie-subtitle-voice-map.csv):
**101 movies, 94 with a subtitle, 83 with a voice track, 21 with a telop.**
[`captures/movie-subtitle-voice-map.csv`](captures/movie-subtitle-voice-map.csv),
now regenerated from the **record table** (`examples/movie_map_csv.rs`) and keyed
by cutscene **slot**:
**104 slots binding 101 distinct movies.** 99 slots / 96 movies have a subtitle,
99 slots / 96 movies have a voice track, 22 slots / 22 movies have a telop —
drawing on 94 distinct subtitle tables, 83 distinct voice banks and 21 distinct
telop overlays.
### ❌ The old counts were measuring the wrong thing
This file used to say *"101 movies, 94 with a subtitle, 83 with a voice track, 21
with a telop"*. Those three numbers are exactly the counts of **distinct pool
strings** — which is all a string-pool scraper can see. The pool stores each
value once, so a *repeat* reference contributes no token and read as "no
binding": 13 later references to `VOICE_D_450..454`, two to
`SUBTITLE_hokyu_LS_s11A.tbl`, and `MS01A`'s share of `pwterop_s01a.prt`.
Slots, movies and distinct strings are three different denominators and this file
conflated them. Pinned by `manifest_slot_and_movie_counts`.
## Verified, and one real defect
Every subtitle reference was looked up in the language paks. **93 of 94 resolve.
`SUBTITLE_S12B.tbl` resolves in none of the six languages** — a dangling
reference on the retail disc, not a decode failure on our side. Worth knowing
before the reimplementation treats a missing subtitle table as a bug of its own.
Every subtitle reference was looked up in the language paks. **93 of the 94
distinct members resolve. `SUBTITLE_S12B.tbl` resolves in none of the six
languages** — a dangling reference on the retail disc, not a decode failure on
our side. Worth knowing before the reimplementation treats a missing subtitle
table as a bug of its own.
The naming is a convention with two documented exceptions:
The naming is a convention, with more exceptions than were recorded:
- subtitles are `SUBTITLE_<movie base>.tbl` — the only departure is the staff
roll, `SYLPH_HD720p_8M-CBR_2ch.wmv``SYLPH_HD720p_8M-CBR_2ch.tbl`;
- voice tracks are `VOICE_<movie base>` — except five supply-run movies
(`hokyu_LS_s02A`, `hokyu_LS_s02H`, `hokyu_DS_s02A`, `hokyu_DS_s07H`,
`hokyu_LS_s09A`), which point at shared lines `VOICE_D_450…454`.
- subtitles are `SUBTITLE_<movie base>.tbl`, with **3** departures — the staff
roll (`SYLPH_HD720p_8M-CBR_2ch.wmv``SYLPH_HD720p_8M-CBR_2ch.tbl`), and
`hokyu_LS_s24A` / `hokyu_LS_s27A`, which **borrow `SUBTITLE_hokyu_LS_s11A.tbl`**;
- voice tracks are `VOICE_<movie base>` except **all 18 hokyu movies** (21 supply
slots), which share `VOICE_D_450…454`. The old text said five; the other 13
were invisible to the scraper for the dedup reason above.
So a reimplementation can resolve a movie's subtitle and voice **by convention**,
and should fall back to this table for those six cases rather than assuming it.
So a reimplementation should read this table, **not** apply the convention with a
short exception list.
## What is *not* recoverable from this record
## ✅ The script ids ARE recoverable — the old ❔ is closed
The record also lists 104 **script ids** — the names stage scripts use to trigger
a movie. This file used to say pairing them with the movie groups "does not
work: the counts differ by three". The counts differ by three for a concrete
reason: **three resupply movies are bound by two slots each**
(`hokyu_LS_s02A` by S02 and S05, `hokyu_DS_s07A` and `hokyu_DS_s07H` by S07 and
S12). Positional pairing was never the right model — the ids are stored as
**literal positional field keys** in `BASE_INFO`, each naming its record
directly, so every one of the 104 resolves with nothing to infer. The id is
`stage*100 + slot`, with 91/92 for `_SUPPLY_ACROPOLIS`/`_SUPPLY_TANKER`.
The record also lists ~104 **script ids** (`LOGO1`, `ADVERTISE_MOVIE`,
`STAFF_ROLL`, `MS00A`, `STAGE01_PHASE01`, `S02_SUPPLY_ACROPOLIS`, …) — the names
stage scripts use to trigger a movie. Pairing them positionally with the 101
movie groups **does not work**: the counts differ by three and the drift is
visible at the tail, where the last ids (`S24_SUPPLY_ACROPOLIS`,
`S27_SUPPLY_ACROPOLIS`) would have to map to `hokyu_LS_s24A.wmv` /
`hokyu_LS_s27A.wmv` and under positional pairing do not.
The cause is the same IDXD property that bit the Arsenal table: **the string pool
stores each distinct string once**, so an id whose movie was already named

View File

@@ -73,7 +73,7 @@ guessing both misses real bindings and invents tracks for silent movies:
- **5 `hokyu_*` resupply movies bind to in-mission radio clips** — e.g.
`hokyu_LS_s02A → VOICE_D_450`, which lives in `<lang>\etc\`, *not* `Movie`.
A `VOICE_<movie>` guess would never find these.
- **18 movies have no direct voice token** = 4 boot logos + 1 HD test pattern +
- **❌ WITHDRAWN — 18 movies have no direct voice token** = 4 boot logos + 1 HD test pattern +
**13 `hokyu_*` movies** (incl. `hokyu_DS_s13A`). Only the manifest's **direct**
bindings are trusted for playback.