port: audit the handoff -- four stale statements, a broken link, and the
residue in one place Every MISSION row is answered, so this iteration checked the deliverable itself rather than opening new scope: an answer that is not reachable from HANDOFF.md has not been delivered, and I have been editing that page by surgical replacement for a dozen iterations. Four things were wrong or stale: - the Q5 row still said initial focus was 2x TUTORIAL, 1x NEW GAME while its own bullet said four boots -- I updated the body last time and not the row; - the Q2 bullet still described the other four main-menu destinations as "likely by name -- an inference, not a measurement", which Q4 has since MEASURED, and it listed GP_MISSION_SELECT as a main-menu destination when MISSION SELECT lives under EXTRAS; - the Q1 bullet claimed that if the game presents at 60 Hz "nothing else on this page changes". That is now false: Q7's declared fade-in lengths are keyframe-derived and would halve. The same bullet also missed that the transition capture is a SECOND independent measurement supporting 1 unit = 1/60 s -- the quad is declared black for 12 units, 0.20 s under the conversion, and the capture measured the plateau at 0.17-0.23 s. Recorded as corroboration, not proof, because the plateau spans two screens' fades and cannot separate them; - bgm-two-stems.md linked ../port/MISSION.md from inside structures/, which resolves nowhere. Also named the two videos actually in scope, since "3.3 GB of video, two files are in scope" is not much use without the filenames. And added a What Is Still Open section. With every row green the residue was scattered across eight pages; it is now one table with why each item is stuck. Two entries share a single unblocker -- an emulator whose audio path can be observed -- and they are the only ones that would change a port decision.
This commit is contained in:
@@ -31,7 +31,7 @@ authored version can be deleted.
|
||||
| Q2 | which build is which screen state | ✅ answered | `GP_TITLE` is **8 screens shipped twice, EN/JP**: 4/7 title art, 2/3 the `PRESS Ⓐ` plate, 5/8 main menu, 6/9 `EXTRAS`, 0/1 and 10/11 two unidentified `DELTASABER` plates — [`ui-title-build-map.md`](../re/ui-title-build-map.md) |
|
||||
| Q3 | paint order for the six screens | ✅ answered | **decoded**: a `u16` layer key at `+0x0A` of each `T8aD` sprite header, stable-sorted with declaration index; unkeyed elements get an implied key. Confirmed on 5 measured orders + `EXTRAS` vs a capture. One residual: the **tie-break** is unknown and bites on one element of the title — [`structures/ui-paint-order-key.md`](../re/structures/ui-paint-order-key.md) |
|
||||
| Q4 | button → GamePart | ✅ answered | **measured** which screen all **5** buttons open — `NEW GAME` → `DIFFICULTY` → `SELECT DATA`, not a hang. The **GamePart id is still a name match**, not a measurement — [`menu-navigation-semantics.md`](../re/menu-navigation-semantics.md) |
|
||||
| Q5 | navigation semantics | ✅ answered | **measured**: initial focus varies boot to boot (2× `TUTORIAL`, 1× `NEW GAME`); ⬆⬇ one step, **wraps both ends**; ⬅➡ do nothing; Ⓑ returns to the parent **with focus restored**; Ⓑ on the main menu → title; Ⓑ on the title → nothing — [`menu-navigation-semantics.md`](../re/menu-navigation-semantics.md) |
|
||||
| Q5 | navigation semantics | ✅ answered | **measured**: initial focus varies boot to boot (2× `TUTORIAL`, 2× `NEW GAME`); ⬆⬇ one step, **wraps both ends**; ⬅➡ do nothing; Ⓑ returns to the parent **with focus restored**; Ⓑ on the main menu → title; Ⓑ on the title → nothing — [`menu-navigation-semantics.md`](../re/menu-navigation-semantics.md) |
|
||||
| Q6 | boot sequence + what drives it | ✅ answered | sequence **measured** end to end; the driver is **code, not data** — four search spaces closed, so the port **authors** the sequence — [`boot-config-and-gamepart-registry.md`](../re/boot-config-and-gamepart-registry.md) |
|
||||
| Q7 | transitions | ✅ answered | a **fade through black**, drawn by the screen's own last-painting `.prm` quad. Fade-in ramp is **decoded** from its keyframes; the ~0.4 s fade-out is **measured** (not in the file) — [`screen-transitions.md`](../re/screen-transitions.md) |
|
||||
| Q8 | menu audio bindings | ✅ answered | cue vocabulary + bank **decoded**; event binding is a **name match** (the authors' own event names); SE audio is **undecodable from the disc** — no XACT container exists anywhere — [`menu-audio-cues.md`](../re/menu-audio-cues.md) |
|
||||
@@ -51,9 +51,8 @@ authored version can be deleted.
|
||||
captures for the four English screens the boot path shows;
|
||||
[`ui-title-build-map.md`](../re/ui-title-build-map.md).
|
||||
**Withdrawn:** the earlier "builds 6/8/9 are submenus" — 8 is the Japanese main
|
||||
menu. The other four main-menu buttons leave the archive (`GP_SAVE_LOAD`,
|
||||
`GP_TUTORIAL`, `GP_OPTIONS`, `GP_MISSION_SELECT` are the likely destinations by
|
||||
name — an inference, not a measurement).
|
||||
menu. The other four main-menu buttons leave the archive, and where each one
|
||||
goes is **measured** — see the button-destination bullet below.
|
||||
* **Buttons are identifiable as data.** Element kind `0x3002` = button, `0x0` =
|
||||
decoration, `0x10` = primitive. ✅ decoded **for the title-side screens**.
|
||||
⚠️ `0x3002` is one member of a `0x3000` family with sub-bits, and it is not the
|
||||
@@ -78,10 +77,18 @@ authored version can be deleted.
|
||||
with `k` stepping 2, 4, 6, 8, 10, 12, 14 on seven consecutive submitted frames.
|
||||
**measured**, not decoded — the disc says `t=30`, it does not say what a `t` is.
|
||||
The seconds conversion (`1 unit = 1/60 s`, so a 30 fps screen) rests on a
|
||||
measured 27.6 present-frames/second and is the one part still worth re-testing;
|
||||
[`ui-keyframe-time-unit.md`](../re/ui-keyframe-time-unit.md) names the test.
|
||||
If it turns out the game presents at 60 Hz, every duration halves — nothing
|
||||
else on this page changes.
|
||||
measured 27.6 present-frames/second; [`ui-keyframe-time-unit.md`](../re/ui-keyframe-time-unit.md)
|
||||
names the re-test. 🟡 **A second, independent measurement now supports it**: the
|
||||
transition quad is declared black from `t=0` to `t=12` — 12 units, i.e. 0.20 s
|
||||
under this conversion — and a 30 fps capture measured the pure-black plateau at
|
||||
**0.17–0.23 s** ([`screen-transitions.md`](../re/screen-transitions.md)). That
|
||||
is corroboration and not proof: the plateau spans the outgoing screen's
|
||||
fade-out tail as well as the incoming screen's black, and this measurement
|
||||
cannot separate them.
|
||||
⚠️ If the game turns out to present at 60 Hz, **every duration on this page
|
||||
derived from keyframe units halves** — including Q7's declared fade-in lengths
|
||||
(0.87 s / 0.97 s / 4.08 s). The wall-clock numbers measured off a capture (the
|
||||
~0.4 s fade-out, the black hold, the attract timings) do not move.
|
||||
* **The paint order is derivable from the file.** Each `T8aD` sprite header
|
||||
carries a **`u16` layer key at `+0x0A`** (the upper half of the 32-bit word at
|
||||
`+0x08` is zero in all 21 184 sprites on the disc). Paint order is that key,
|
||||
@@ -105,7 +112,8 @@ authored version can be deleted.
|
||||
nothing. Ⓑ goes up one level **and restores focus to the item you came from**;
|
||||
Ⓑ on the main menu returns to the title; Ⓑ on the title does nothing. **Initial
|
||||
focus is not stable**: four boots of the same script gave `TUTORIAL`,
|
||||
`TUTORIAL`, `NEW GAME`, `NEW GAME`. Do not hardcode it; pick one and say you picked it. All **measured**, none of it on the disc.
|
||||
`TUTORIAL`, `NEW GAME`, `NEW GAME`. Do not hardcode it; pick one and say you
|
||||
picked it. All **measured**, none of it on the disc.
|
||||
* **Each button's destination is measured; its GamePart id is not.**
|
||||
**`NEW GAME` → `DIFFICULTY`** (`EASY`/`NORMAL`/`HARD`/`BACK`, opening on
|
||||
`NORMAL`) **→ `SELECT DATA`** — it does *not* hang; the run then hits the
|
||||
@@ -208,8 +216,10 @@ authored version can be deleted.
|
||||
* **`ADV.wmv` is WMV3 video + WMA Pro audio**, 1280×720 at 30 fps, 137 s. Godot 4
|
||||
plays only Ogg Theora natively. How to handle that is the port's decision, not
|
||||
ours — but it is not optional.
|
||||
* **The disc holds 3.3 GB of video.** Only the boot intro and the one new-game
|
||||
intro are in scope.
|
||||
* **The disc holds 3.3 GB of video, and exactly two files are in scope:**
|
||||
`dat/movie/ADV.wmv` (the boot intro *and* the attract loop — one asset) and
|
||||
`dat/movie/S00A.wmv` (the new-game intro, 93.9 s). Named from the movie
|
||||
manifest, ✅ decoded.
|
||||
* **`Static.slb` over-declares its size** by 616 768 bytes — it is the
|
||||
highest-offset entry in `sound.pak` and its size field is an allocation size. A
|
||||
reader must allow a short read there and only there.
|
||||
@@ -234,6 +244,25 @@ authored version can be deleted.
|
||||
* **`JNGL_001.slb` does not decode.** One bank in 9 519; its payload is not a whole
|
||||
number of XMA1 packets from any known data offset.
|
||||
|
||||
## What is still open
|
||||
|
||||
Every question above is answered, so this is the honest residue rather than a
|
||||
work queue. **None of it blocks the five screens.**
|
||||
|
||||
| | what | why it is stuck |
|
||||
|---|---|---|
|
||||
| 🟡 | **cue → event binding as a measurement** (Q8) | nobody has watched the game emit `SE_UI_CURSOR` on a d-pad press. Needs the guest's cue call observed with its argument |
|
||||
| ❔ | **the wave index into `Static.slb`** (Q8) | same instrumentation. This container runs `--mute=true` against an SDL dummy device, so it cannot watch the audio path at all |
|
||||
| 🟡 | **the paint-order tie-break** (Q3) | eight candidates refuted; costs one element's blend on one screen |
|
||||
| 🟡 | **GamePart ids behind the buttons** (Q4) | the *screens* are measured; the ids are a name match onto the executable's class names |
|
||||
| 🟡 | **`1 unit = 1/60 s`** (Q1) | two independent measurements agree, neither is proof; if it is 60 Hz every keyframe-derived duration halves |
|
||||
| ❔ | **the boot transitions in code** (Q6) | bounded as code-not-data, not proven. `sub_821C6458` — the substantial function in `GamePart_Title`'s neighbourhood — has **not been read** |
|
||||
| ❔ | **`MS00A` → `S00A.wmv` never watched** (Q9) | decoded from the manifest; the one run that reached it crashed at `SELECT DATA` first |
|
||||
| ❔ | **builds 0/1 and 10/11**, the `DELTASABER` plates (Q2) | never seen on screen anywhere in the boot path, the title-side screens or the attract loop |
|
||||
|
||||
The first two share one unblocker — an emulator build whose audio path can be
|
||||
observed — and would be the only entries here that change a port decision.
|
||||
|
||||
## Reference data
|
||||
|
||||
Committed alongside the findings, so the port can be built without a disc in the
|
||||
|
||||
@@ -5,7 +5,7 @@ over all 32 BGM banks. 🟡 for the *role* of the second wave — **measured** b
|
||||
signal analysis, and the two readings that survive are named below. ❔ which bank
|
||||
is the menu's music is **undecodable from the disc**, with the reach stated.
|
||||
|
||||
Answers [MISSION Q10](../port/MISSION.md). It also **withdraws the premise**: the
|
||||
Answers [MISSION Q10](../../port/MISSION.md). It also **withdraws the premise**: the
|
||||
handoff said `BGM_001.slb` is *three* sub-waves of 10 KB / 4.47 MB / 4.67 MB. The
|
||||
10 KB is the bank **header**, not a wave.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user