Files
Sylpheed/crates/sylpheed-formats/examples/find_difficulty_build.rs
sylph-decoder 3f46b9cf16 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) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-31 02:18:06 +00:00

63 lines
2.9 KiB
Rust

//! 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<String> = 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 " });
}