This repository has been archived on 2026-09-16. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Syplheed-Reborn/docs/re/movie-subtitle-link.md
Sylpheed RE agent fedb31a5f9 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
2026-08-25 23:13:41 +00:00

4.6 KiB

The movie ↔ subtitle ↔ voice link (static)

INDEX carried the IXUD subtitle format as 🟡 with "movie↔track link unknown (dynamic item)" — i.e. a question expected to need the running game. It does not: the link is a config record on the disc, and it verifies against the disc's own contents.

Where it is

dat/tables.pak, the IDXD record with schema 0x067025b9. Its keys come from the movie game-part — the executable carries them next to the symbol silph::GamePart_Movie::Impl::OnPrepare:

PATH = dat\movie\      SUBTITLE_FONT = fra.pak+GOTHICB.TTF
SUBTITLE_Y = 600       SUBTITLE_HEIGHT = 33
MOVIE   TELOP   SUBTITLE   VOICETRACK

Each movie is one group of values:

S02A.wmv                              MOVIE
fra.pak+pwterop_s02a.prt              TELOP        (optional overlay)
fra.pak+SUBTITLE_S02A.tbl             SUBTITLE
VOICE_S02A                            VOICETRACK

<lang>.pak+<member> resolves inside dat/movie/<lang>.pak, and the six 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, 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 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 more exceptions than were recorded:

  • subtitles are SUBTITLE_<movie base>.tbl, with 3 departures — the staff roll (SYLPH_HD720p_8M-CBR_2ch.wmvSYLPH_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 should read this table, not apply the convention with a short exception list.

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 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 earlier contributes no new value token and its group silently disappears. The id list is therefore until the binary node/index region is decoded — and the CSV is deliberately keyed by movie file, which is the part the data actually supports.

Note for the intro-movie investigation

ADV.wmv — the one the emulator work is about — has VOICETRACK = VOICE_ADV and no subtitle and no telop. So a correct playback of it needs the video and that one voice track, nothing else from this table.