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
28 lines
1.0 KiB
Rust
28 lines
1.0 KiB
Rust
//! 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()
|
|
);
|
|
}
|
|
}
|