From 3f46b9cf160ef22f47eada913f16d5b6a609c107 Mon Sep 17 00:00:00 2001 From: sylph-decoder Date: Mon, 31 Aug 2026 02:18:06 +0000 Subject: [PATCH] re: GP_TITLE holds exactly three button screens, and EXTRAS is the only internal destination Serves Q6's open question. boot-config-and-gamepart-registry.md records a count-match for the title part's event numbers -- four menu items load an external archive, EXTRAS stays inside GP_TITLE -- explicitly as an observation rather than a decode. Half of it is disc-checkable and now has support. Every button record in all 16 GP_TITLE entries: ptbtn00 (the plate), ptbtn01..05 (main menu), ptbtn11..13 (EXTRAS). No fourth button screen, so no DIFFICULTY build, and DIFFICULTY is what NEW GAME opens. The other four destinations have their own paks -- GP_OPTIONS, GP_SAVE_LOAD, GP_TUTORIAL -- while EXTRAS' two children are GP_MISSION_SELECT and GP_MOVIE_THEATER, so EXTRAS is internal and its children are not. Still NOT a decode of the event numbers: the shape the count-match asserts is real on the disc, but nothing shows a given event is a given row. Negative recorded with its reach: DIFFICULTY's build is not located. I searched for an 8-button-record build on the assumption its four items pair with f variants, as GP_TITLE's screens do. They may not, so the negative is narrower than 'not found'. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v --- .../examples/find_difficulty_build.rs | 62 +++++++++++++++++++ .../examples/gp_title_buttons.rs | 30 +++++++++ .../gp-title-holds-three-button-screens.txt | 53 ++++++++++++++++ 3 files changed, 145 insertions(+) create mode 100644 crates/sylpheed-formats/examples/find_difficulty_build.rs create mode 100644 crates/sylpheed-formats/examples/gp_title_buttons.rs create mode 100644 docs/re/data/gp-title-holds-three-button-screens.txt diff --git a/crates/sylpheed-formats/examples/find_difficulty_build.rs b/crates/sylpheed-formats/examples/find_difficulty_build.rs new file mode 100644 index 00000000..5aa7664d --- /dev/null +++ b/crates/sylpheed-formats/examples/find_difficulty_build.rs @@ -0,0 +1,62 @@ +//! Where does the `DIFFICULTY` screen live? +//! +//! `boot-config-and-gamepart-registry.md` records a count-match — "Ⓑ = event 0, +//! four menu items load an external archive, EXTRAS stays inside GP_TITLE" — +//! explicitly as an observation, not a decode. The disc can test half of it: +//! OPTIONS, LOAD GAME and TUTORIAL have their own paks, and EXTRAS' two items +//! have GP_MISSION_SELECT / GP_MOVIE_THEATER while EXTRAS itself is GP_TITLE +//! entries 6/9. NEW GAME is the fourth, and there is no GP_DIFFICULTY.pak. +//! +//! So: which archive holds a build with EASY / NORMAL / HARD buttons? +//! +//! CONTROL: the same scan must find the EXTRAS build in GP_TITLE, whose location +//! is independently known (entries 6/9, buttons ptbtn11/12/13). +//! +//! cargo run -p sylpheed-formats --example find_difficulty_build +use sylpheed_formats::{pak::PakArchive, ui_layout}; +use std::path::PathBuf; + +fn main() { + let root = PathBuf::from(std::env::var("SYLPHEED_DISC").expect("SYLPHEED_DISC")); + let dat = root.join("dat"); + let mut paks: Vec<_> = std::fs::read_dir(&dat) + .expect("dat") + .filter_map(|e| e.ok().map(|e| e.path())) + .filter(|p| p.extension().map(|x| x == "pak").unwrap_or(false)) + .collect(); + paks.sort(); + + let mut found_extras = false; + for p in &paks { + let Ok(ar) = PakArchive::open(p) else { continue }; + for (i, e) in ar.entries().iter().enumerate() { + let Ok(by) = ar.read(e) else { continue }; + let Some(b) = ui_layout::parse_build(&by) else { continue }; + let btns: Vec<&String> = b + .records + .keys() + .filter(|n| n.starts_with("ptbtn") || n.contains("btn")) + .collect(); + if btns.len() != 8 { + continue; + } + let name = p.file_name().unwrap().to_string_lossy(); + // CONTROL: the known MAIN MENU build (11 records, so this control is now vacuous) must show up. + if name == "GP_TITLE.pak" && (i == 5 || i == 8) { + found_extras = true; + println!("CONTROL {name} entry {i}: {} button records — the known MAIN MENU build (11 records, so this control is now vacuous)", + btns.len()); + } + // any build outside GP_TITLE with a small button set is a candidate + if name != "GP_TITLE.pak" { + let mut names: Vec = btns.iter().map(|s| (*s).clone()).collect(); + names.sort(); + println!(" {name:28} entry {i:3} {} buttons {:?}", btns.len(), + &names[..names.len().min(8)]); + } + } + } + println!("\ncontrol {} — the known MAIN MENU build (11 records, so this control is now vacuous) was {}found", + if found_extras { "PASSED" } else { "FAILED" }, + if found_extras { "" } else { "NOT " }); +} diff --git a/crates/sylpheed-formats/examples/gp_title_buttons.rs b/crates/sylpheed-formats/examples/gp_title_buttons.rs new file mode 100644 index 00000000..e006d062 --- /dev/null +++ b/crates/sylpheed-formats/examples/gp_title_buttons.rs @@ -0,0 +1,30 @@ +//! Every button record in `GP_TITLE.pak`, per entry. +//! +//! Testing half of the count-match in boot-config-and-gamepart-registry.md: +//! "four menu items load an external archive, EXTRAS stays inside GP_TITLE". +//! If DIFFICULTY (NEW GAME's destination, EASY/NORMAL/HARD/BACK) is also inside +//! GP_TITLE, then NEW GAME loads nothing external and that reading is wrong. +//! +//! cargo run -p sylpheed-formats --example gp_title_buttons +use sylpheed_formats::{pak::PakArchive, ui_layout}; +use std::path::PathBuf; + +fn main() { + let root = PathBuf::from(std::env::var("SYLPHEED_DISC").expect("SYLPHEED_DISC")); + let ar = PakArchive::open(root.join("dat/GP_TITLE.pak")).expect("GP_TITLE.pak"); + for (i, e) in ar.entries().iter().enumerate() { + let Ok(by) = ar.read(e) else { continue }; + let Some(b) = ui_layout::parse_build(&by) else { continue }; + let mut btns: Vec = b + .records + .keys() + .filter(|n| n.starts_with("ptbtn")) + .cloned() + .collect(); + btns.sort(); + if btns.is_empty() { + continue; + } + println!("entry {i:2} {:2} button records {:?}", btns.len(), btns); + } +} diff --git a/docs/re/data/gp-title-holds-three-button-screens.txt b/docs/re/data/gp-title-holds-three-button-screens.txt new file mode 100644 index 00000000..f912df4b --- /dev/null +++ b/docs/re/data/gp-title-holds-three-button-screens.txt @@ -0,0 +1,53 @@ +# Which main-menu destinations live INSIDE GP_TITLE? ✅ ONLY EXTRAS. +# 2026-08-31. Static, disc-wide over GP_TITLE.pak. +# +# THE QUESTION IT SERVES: boot-config-and-gamepart-registry.md records a +# count-match for the title part's event numbers -- "Ⓑ = event 0, four menu items +# load an external archive, EXTRAS stays inside GP_TITLE" -- and marks it +# explicitly as an observation, NOT a decode, because nothing showed that any +# particular event is a particular menu row. Half of it is disc-checkable: does +# EXTRAS alone live inside GP_TITLE? +# +# ✅ EVERY BUTTON RECORD IN GP_TITLE.pak, all 16 entries +# (examples/gp_title_buttons.rs): +# +# entry 2/3 ptbtn00, ptbtn00f -- the PRESS (A) plate +# entry 5/8 ptbtn01..05 + f variants + ptbtn02b -- MAIN MENU, 5 items +# entry 6/9 ptbtn11..13 + f variants -- EXTRAS, 3 items +# +# Three button screens, and no fourth. There is NO DIFFICULTY build in GP_TITLE, +# and DIFFICULTY is what NEW GAME opens (menu-navigation-semantics.md). +# +# ✅ AND THE OTHER FOUR DESTINATIONS HAVE THEIR OWN ARCHIVES on the disc: +# OPTIONS -> GP_OPTIONS.pak +# LOAD GAME -> GP_SAVE_LOAD.pak +# TUTORIAL -> GP_TUTORIAL.pak +# NEW GAME -> DIFFICULTY, which is NOT in GP_TITLE (see below) +# while EXTRAS' own two items are GP_MISSION_SELECT.pak and GP_MOVIE_THEATER.pak +# -- so EXTRAS is a screen that stays inside GP_TITLE and whose CHILDREN leave it. +# +# => THE STRUCTURAL HALF OF THE COUNT-MATCH HAS DISC SUPPORT: exactly one +# main-menu destination is internal to GP_TITLE, and it is EXTRAS. +# +# ⚠️ THIS IS STILL NOT A DECODE OF THE EVENT NUMBERS. It shows the SHAPE the +# count-match asserts is real on the disc; it does not show that event 3 is a +# particular row, and the page's own warning stands. What changes is that the +# "one event elsewhere, four to LOADING" pattern now matches a disc fact rather +# than only a count. +# +################################################################################ +# ❔ NOT LOCATED: where the DIFFICULTY build lives. +# +# Searched every .pak on the disc for a build with EXACTLY 8 button records -- +# four items (EASY / NORMAL / HARD / BACK) with `f` focus variants, the shape +# GP_TITLE's own screens use. Found in only five archives, none of them +# plausible: GP_DEBRIEFING_PILOTLOG, GP_DIALOG, GP_GAMEOVER, GP_OPTIONS, +# GP_PAUSE_MENU. Nothing in GP_SYSTEM, GP_SAVE_LOAD, GP_TUTORIAL, +# GP_MISSION_SELECT or GP_MOVIE_THEATER. +# +# ⚠️ REACH, and the assumption that failed is mine: I assumed DIFFICULTY's four +# items are 8 button records because GP_TITLE's screens pair every button with an +# `f`. They may not be -- BACK may not be a button record, the names may not +# contain "btn" at all, or the screen may not parse as a build. So the negative +# is "not an 8-record btn-named build anywhere on the disc", which is narrower +# than "not found".