//! Test the Decoder's UNTESTED reading of a residual they recorded as odd. //! //! `GP_DIALOG` holds 140 entries against a 70-record dialog table — a 2:1 ratio //! that would make the id→entry join an ordering question. It does not hold: //! adjacent pairing gives identical element-name sets on **2 of 65** pairs, //! halves pairing on **0**. In `GP_TITLE` a language pair shares its element set //! exactly, so identical sets are the signature there and almost nothing matches //! here. //! //! The residual: the only two adjacent pairs that DO match are entries `0/1` and //! `2/3` — and `2/3` is the DIFFICULTY build. Their plausible reading is that //! dialog text is baked into language-specific sprites, so EN/JP entries differ //! by construction. ⚠️ **They flagged it as untested and did not assert it**, and //! it has a hole they named themselves: it would explain the 63 that differ and //! leave the 2 that match needing their own explanation. //! //! This prints what the differences actually look like, so the reading is judged //! against the names rather than accepted as plausible. use std::collections::BTreeSet; use sylpheed_formats::{pak, ratc, ui_layout}; fn main() { let root = std::env::var("SYLPHEED_DISC").expect("set SYLPHEED_DISC to the extracted disc root"); let ar = pak::PakArchive::open(format!("{root}/dat/GP_DIALOG.pak")).expect("GP_DIALOG.pak"); let sets: Vec>> = ar .entries() .iter() .map(|e| { let by = ar.read(e).ok()?; if !ratc::is_ratc(&by) { return None; } let b = ui_layout::parse_build(&by)?; Some(b.elements.iter().map(|el| el.name.clone()).collect()) }) .collect(); let (mut same, mut diff, mut pairs) = (0usize, 0usize, 0usize); let mut shown = 0; for i in (0..sets.len().saturating_sub(1)).step_by(2) { let (Some(a), Some(b)) = (&sets[i], &sets[i + 1]) else { continue; }; pairs += 1; if a == b { same += 1; println!( " entries {i:>3}/{:<3} IDENTICAL sets, {} element(s)", i + 1, a.len() ); continue; } diff += 1; // The stage-dialog pairs, checked by name and by SPRITE COUNT. A // translation of one dialog carries the same amount of text; a // different stage does not. This is the Decoder's closing evidence for // the 37 pairs that differ WITHOUT a button-count mismatch, re-derived // here because it settles a bound I had recorded as unlikely to be // tested -- and saying so is what got it tested. if (10..=15).contains(&i) { let sp = |x: &BTreeSet| x.iter().filter(|n| n.ends_with(".t32")).count(); let stage = |x: &BTreeSet| -> Vec { let mut v: Vec = x .iter() .filter_map(|n| { n.strip_prefix("pzstg") .and_then(|r| r.get(..2)) .map(|s| s.to_string()) }) .collect(); v.sort(); v.dedup(); v }; println!( " entries {i:>3}/{:<3} stages {:?} vs {:?} sprites {} vs {}", i + 1, stage(a), stage(b), sp(a), sp(b) ); } if shown < 3 { shown += 1; let only_a: Vec<_> = a.difference(b).cloned().collect(); let only_b: Vec<_> = b.difference(a).cloned().collect(); println!( " entries {i:>3}/{:<3} differ: {} only-in-first, {} only-in-second", i + 1, only_a.len(), only_b.len() ); println!(" first : {:?}", &only_a[..only_a.len().min(4)]); println!(" second : {:?}", &only_b[..only_b.len().min(4)]); } } // 🔴 THE DECISIVE DETAIL, not the impressionistic one. Two languages of one // dialog cannot differ in BUTTON COUNT. If adjacent entries do, they are // different dialogs and the whole adjacent-pairing premise is wrong -- which // is a stronger statement than "the language reading is untested". let btns = |s: &Option>| -> usize { s.as_ref() .map_or(0, |x| x.iter().filter(|n| n.contains("btn")).count()) }; let mut mismatched = 0; for i in (0..sets.len().saturating_sub(1)).step_by(2) { if sets[i].is_none() || sets[i + 1].is_none() { continue; } if btns(&sets[i]) != btns(&sets[i + 1]) { mismatched += 1 } } println!("\n adjacent pairs whose BUTTON COUNTS differ: {mismatched}"); println!(" A language pair cannot. Every one of these is two different dialogs."); println!("\n {pairs} adjacent pair(s): {same} identical, {diff} differing"); println!(" Their reading -- text baked into language-specific sprites -- predicts"); println!(" the differing names look SYSTEMATIC (a locale suffix, a parallel set)."); println!(" Judge it against the names above rather than against its plausibility."); }