Two corpus claims died in one boot, and both were costing us. Q9's last row: a movie IS skippable with a single A. One tap ~45s into the boot put the title up at ~57s, against a ~193s no-input baseline measured over three boots, and Canary's own keystroke counter went 3->4 so exactly one press was delivered. The skipped-to title is fully functional -- it draws the PRESS A plate and a second A opens the main menu. What actually breaks the boot is hammering: the 88-press run in the traps doc. The scripts' "tapping breaks the title" comment is too broad and costs every scripted boot two and a half minutes. Q4's last row: A on NEW GAME does not hang. It opens DIFFICULTY (EASY/NORMAL/HARD/BACK, focus on NORMAL), then SELECT DATA, and only then does the guest throw -- at PC 0x82307128, which is inside sub_823070B0, the cache-manager STL erase this corpus already documents and which has nothing to do with the menu path. The screen sat unchanged for 90s because it was a menu waiting for input from a loop that never pressed anything. That is now a METHOD line: a screen that never changes is not necessarily hung, and the fix is to look at it and press something. Also METHOD: never run ps -ef in this container -- all three long-lived processes carry the entire loop prompt as argv.
128 lines
6.3 KiB
Markdown
128 lines
6.3 KiB
Markdown
# Which movie plays where — the boot intro, the attract loop, the new-game intro
|
||
|
||
**Status:** ✅ `CONFIRMED`. The bindings are **decoded** from the movie manifest,
|
||
and the attract movie is independently **measured** from captured frames. One
|
||
part — whether playback is skippable — is 🟡 and the corpus contradicts itself
|
||
about it; that is written down rather than resolved by assertion.
|
||
|
||
Answers [MISSION Q9](../port/MISSION.md), and contributes to Q6.
|
||
|
||
## The manifest names the boot-side slots — decoded
|
||
|
||
The movie manifest (`dat/tables.pak` entry `0x5b983a08`, schema `0x067025b9`,
|
||
[`movie_manifest.rs`](../../crates/sylpheed-formats/src/movie_manifest.rs)) is an
|
||
array of slots whose **key is the semantic role**, with a parallel array of value
|
||
records in the same order. Its first eight slots are the whole boot-side flow:
|
||
|
||
| slot key | movie | also bound |
|
||
|---|---|---|
|
||
| `LOGO1` … `LOGO4` | `logo1.wmv` … `logo4.wmv` | — |
|
||
| **`ADVERTISE_MOVIE`** | **`ADV.wmv`** | `VOICE_ADV` |
|
||
| `STAFF_ROLL` | `SYLPH_HD720p_8M-CBR_2ch.wmv` | subtitle table |
|
||
| **`MS00A`** | **`S00A.wmv`** | `SUBTITLE_S00A`, `VOICE_S00A`, a `pwterop_s01a.prt` overlay |
|
||
| `MS01A` | `S01A.wmv` | `SUBTITLE_S01A`, `VOICE_S01A` |
|
||
|
||
The alignment is not in doubt here even though the manifest has valueless slots
|
||
elsewhere: `logo1..4` zip 1:1 onto `LOGO1..4`, and `MS00A`→`S00A.wmv`,
|
||
`MS01A`→`S01A.wmv` are the manifest's own anchor rule.
|
||
|
||
**The `logo1`–`logo4` slots are bound to `.wmv` files that are not on the disc** —
|
||
already established, and the reason the developer splash is a screen, not a video.
|
||
|
||
## ✅ The boot intro and the attract movie are the same asset
|
||
|
||
There is **no separate boot-intro slot**. `ADV.wmv` is bound to
|
||
`ADVERTISE_MOVIE` — it *is* the advertise movie, and the boot simply plays it
|
||
first. For the port that means one video, not two.
|
||
|
||
### Measured independently, from captured frames
|
||
|
||
Frames captured 5 s apart during an attract cycle were matched against five
|
||
candidate movies by frame signature (32×18 normalised grayscale, movie frames
|
||
cropped to the 675 of 720 rows the game surface shows, 1 fps sampling).
|
||
`tools/re-capture/frame_match.py`; full table in
|
||
[`data/attract-frame-match.txt`](data/attract-frame-match.txt).
|
||
|
||
**15 of 19 attract frames matched `ADV.wmv`, and the matched timestamps advance
|
||
monotonically at the sampling rate** — 39, 45, 56, 62, 75, 80, 85, 92, 102, 108,
|
||
113, 119, 131, 137 s — ending at 137 s, which is `ADV.wmv`'s full length, after
|
||
which the title returned. That is not a similarity score, it is a playhead.
|
||
|
||
**The control was run first and behaves the same way.** Frames captured during
|
||
the *boot* movie — known to be `ADV.wmv` — matched `ADV` at 116, 121, 129, 134 s.
|
||
Its failure mode is worth stating: on near-black frames the correlation collapses
|
||
(one control frame scored 0.000, another tied `S13A` 0.984 against `ADV` 0.926).
|
||
Those are exactly the 4 attract frames that did not match. **A dark frame carries
|
||
no signature; it is not evidence for the runner-up.**
|
||
|
||
### 🔴 This corrects an earlier claim of mine
|
||
|
||
Two iterations ago I recorded the attract movie as "≈85 s, so probably not
|
||
`ADV.wmv`'s 137 s". That was wrong, and the mistake was arithmetic on an
|
||
unobserved start: my sampling began when the movie was already **39 s in**, so
|
||
what I timed was the *tail* of it, not the whole thing.
|
||
|
||
## ✅ The new-game intro is `S00A.wmv`
|
||
|
||
Slot `MS00A` — the prologue story intro, 93.87 s, with its own subtitle table,
|
||
`VOICE_S00A`, and a text overlay. Decoded from the manifest, **not** measured:
|
||
Ⓐ on `NEW GAME` hangs the emulator
|
||
([`menu-navigation-semantics.md`](menu-navigation-semantics.md)), so this
|
||
binding has not been watched happening.
|
||
|
||
## 🟡 Skippable — the corpus contradicts itself, and I did not settle it
|
||
|
||
* [`canary-scripted-input-traps.md`](canary-scripted-input-traps.md) states
|
||
plainly that "Ⓐ during a movie skips the movie, every time".
|
||
* But `boot_menu.sh` / `skip_intro.sh` as they stand **deliberately do not tap
|
||
during a movie**, logging `movie … -> waiting it out (tapping breaks the
|
||
title)`, and the same document records run G: 88 Ⓐ presses through the boot
|
||
left a permanent black screen.
|
||
|
||
Both cannot be the whole story. **The test**: boot, tap Ⓐ exactly once well
|
||
inside the movie, and record whether the title arrives early. One boot, and it
|
||
was not run this iteration.
|
||
|
||
## ✅ What ends the attract movie
|
||
|
||
Nothing intervenes: it **plays to its end**. The last matched frame is `ADV` at
|
||
137 s — the file's full duration — and the title is back on the next sample. So
|
||
the attract cycle is: title, idle ~8–10 s, fade to black, `ADV.wmv` in full, back
|
||
to the title (which redraws `PRESS Ⓐ BUTTON`).
|
||
|
||
## What this contributes to Q6
|
||
|
||
The manifest is **data the game reads** to sequence the boot side: the slot keys
|
||
are in play order and the key *is* the role. That is not the whole driver — it
|
||
says what plays, not what decides to advance — but it is the first file-side
|
||
piece of Q6's second half, and it means the boot-side asset order does not have
|
||
to be authored.
|
||
|
||
## ✅ Skippable — settled 2026-08-28: **one Ⓐ skips the movie**
|
||
|
||
The test named above was run, and the answer is unambiguous.
|
||
|
||
| | |
|
||
|---|---|
|
||
| baseline: title arrives with **no** input | ~193 s, ~196 s, ~193 s (three boots) |
|
||
| **one Ⓐ tapped at ~45 s into the boot** | **title at ~57 s** |
|
||
|
||
The press is provably the cause and provably singular: Canary's own
|
||
`[RE-INPUT] XamInputGetKeystrokeEx reached the driver` counter went **3 → 4**
|
||
across the tap, so exactly one keystroke was delivered, and the title arrived
|
||
~12 s later instead of ~150 s later.
|
||
|
||
**And the skipped-to title is fully functional**, which is the part that matters
|
||
for the harness folklore: it draws the `PRESS Ⓐ BUTTON` plate (2 408 plate pixels
|
||
by the same probe used elsewhere), and a second Ⓐ opened the main menu normally
|
||
([`title-after-single-A-skip.png`](captures/newgame-path/title-after-single-A-skip.png)).
|
||
|
||
### So what is `skip_intro.sh` protecting against?
|
||
|
||
Not a single tap. The failure recorded in
|
||
[`canary-scripted-input-traps.md`](canary-scripted-input-traps.md) is run G —
|
||
**88 presses at 4 s intervals through the whole boot** — which left a permanent
|
||
black screen. Hammering breaks it; one press does exactly what the button is for.
|
||
The scripts' `waiting it out (tapping breaks the title)` comment is **too broad**,
|
||
and it costs every scripted boot ~2.5 minutes.
|