Files
Sylpheed/crates/sylpheed-formats/examples/gp_title_pair_check.rs
sylph-decoder e35c56a5ed re: refutation attempt on Q2's 'shipped twice' -- it survives, with one real caveat
The doubt was my own artefact: the entry dump printed only the first two sprite
names in HashMap order, making 11 and 14 look like different studios. Full sets
are identical.

7 of 8 pairs declare identical sprite sets, control included. 4/7 does not: entry
7 carries nine sprites entry 4 lacks, including ptlogo_jp and ptlogo_jpeff, so the
Japanese title is a different element inventory rather than the same screen
localised. That matches the JP capture work from the other side.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-30 22:05:03 +00:00

43 lines
2.1 KiB
Rust

//! Is `GP_TITLE.pak` really "8 screens shipped twice, EN/JP"?
//!
//! The Q2 headline says each screen appears twice. The entry dump raised a
//! doubt: entry 11 shows `palogo_gamearts` and entry 14 shows `palogo_seta`,
//! which are different studios, not a language pair. If the two halves of a
//! "pair" declare different sprites, "shipped twice" is the wrong description of
//! at least that pair.
//!
//! CONTROL: a pair known to be a real EN/JP pair must come out as matching. 2/3
//! (the PRESS Ⓐ plate) is byte-identical in size and is the control.
//!
//! cargo run -p sylpheed-formats --example gp_title_pair_check
use sylpheed_formats::{pak::PakArchive, ui_layout};
use std::collections::BTreeSet;
use std::path::PathBuf;
fn sprites(ar: &PakArchive, i: usize) -> BTreeSet<String> {
let Ok(by) = ar.read(&ar.entries()[i]) else { return BTreeSet::new() };
ui_layout::parse_build(&by)
.map(|b| b.sprites.keys().cloned().collect())
.unwrap_or_default()
}
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");
let pairs = [(0, 1, "loading plain"), (2, 3, "PRESS (A) plate [CONTROL]"),
(4, 7, "title art"), (5, 8, "main menu"), (6, 9, "EXTRAS"),
(10, 13, "publisher splash"), (11, 14, "developer splash"),
(12, 15, "loading dressed")];
for (a, b, what) in pairs {
let (sa, sb) = (sprites(&ar, a), sprites(&ar, b));
let only_a: Vec<_> = sa.difference(&sb).cloned().collect();
let only_b: Vec<_> = sb.difference(&sa).cloned().collect();
let shared = sa.intersection(&sb).count();
let verdict = if only_a.is_empty() && only_b.is_empty() { "IDENTICAL SET" }
else { "DIFFERS" };
println!("\n{a:2}/{b:<2} {what:26} {shared:3} shared {verdict}");
if !only_a.is_empty() { println!(" only in {a}: {only_a:?}"); }
if !only_b.is_empty() { println!(" only in {b}: {only_b:?}"); }
}
}