diff --git a/crates/sylpheed-formats/examples/dialog_pair_37.rs b/crates/sylpheed-formats/examples/dialog_pair_37.rs new file mode 100644 index 00000000..cc821037 --- /dev/null +++ b/crates/sylpheed-formats/examples/dialog_pair_37.rs @@ -0,0 +1,58 @@ +//! Are the 37 equal-button-count `GP_DIALOG` pairs language pairs, or not? +//! +//! 26 of 65 adjacent pairs differ in BUTTON COUNT — two languages cannot, so those +//! are unrelated dialogs. For the rest my language reading was left UNSUPPORTED +//! rather than refuted, and both agents observed that nothing rewards closing it. +//! +//! A language pair must share its BUTTON NAMES and ROWS exactly (a locale changes +//! glyphs, not layout) and differ only elsewhere. An unrelated pair will differ in +//! button names or rows too. +//! +//! CONTROL: entries 2/3 (identical element sets) must come out as "buttons match". +//! +//! cargo run -p sylpheed-formats --example dialog_pair_37 +use sylpheed_formats::{pak::PakArchive, ui_layout}; +use std::path::PathBuf; + +fn sig(ar: &PakArchive, i: usize) -> Option<(Vec<(String, i32)>, usize)> { + let by = ar.read(&ar.entries()[i]).ok()?; + let b = ui_layout::parse_build(&by)?; + let mut v: Vec<(String, i32)> = b + .elements + .iter() + .filter(|e| e.name.contains("btn")) + .map(|e| (e.name.clone(), e.rest().map(|k| k.y).unwrap_or(e.pivot_y as i32))) + .collect(); + v.sort(); + let n = v.len(); + Some((v, n)) +} + +fn main() { + let root = PathBuf::from(std::env::var("SYLPHEED_DISC").expect("SYLPHEED_DISC")); + let ar = PakArchive::open(root.join("dat/GP_DIALOG.pak")).expect("GP_DIALOG"); + let n = ar.entries().len(); + let (mut match_btn, mut differ_btn, mut ctrl) = (0, 0, false); + let mut examples = 0; + for k in (0..n).step_by(2) { + let (Some((a, na)), Some((b, nb))) = (sig(&ar, k), sig(&ar, k + 1)) else { continue }; + if na != nb { + continue; // the 26 already settled + } + if a == b { + match_btn += 1; + if k == 2 { ctrl = true } + } else { + differ_btn += 1; + if examples < 5 { + println!(" entries {k:3}/{:<3} buttons DIFFER", k + 1); + println!(" {:?}", a.iter().map(|x| &x.0).collect::>()); + println!(" {:?}", b.iter().map(|x| &x.0).collect::>()); + examples += 1; + } + } + } + println!("\nequal-button-count pairs whose button NAMES+ROWS match : {match_btn}"); + println!("equal-button-count pairs whose buttons DIFFER : {differ_btn}"); + println!("control (entries 2/3 counted as matching): {}", if ctrl { "PASSED" } else { "FAILED" }); +} diff --git a/crates/sylpheed-formats/examples/dialog_pair_diffs.rs b/crates/sylpheed-formats/examples/dialog_pair_diffs.rs new file mode 100644 index 00000000..10027fe8 --- /dev/null +++ b/crates/sylpheed-formats/examples/dialog_pair_diffs.rs @@ -0,0 +1,43 @@ +//! What differs between equal-button-count `GP_DIALOG` adjacent pairs? +//! +//! All 39 share button names and rows. That is consistent with a LANGUAGE PAIR and +//! equally with TWO DIALOGS SHARING A BUTTON TEMPLATE (two yes/no boxes differing +//! only in their message sprite). The difference is in what else differs: a +//! language pair should differ in the SAME slots with locale-marked names. +//! +//! cargo run -p sylpheed-formats --example dialog_pair_diffs +use sylpheed_formats::{pak::PakArchive, ui_layout}; +use std::collections::BTreeSet; +use std::path::PathBuf; + +fn names(ar: &PakArchive, i: usize) -> Option> { + let by = ar.read(&ar.entries()[i]).ok()?; + let b = ui_layout::parse_build(&by)?; + Some(b.elements.iter().map(|e| e.name.clone()).collect()) +} + +fn main() { + let root = PathBuf::from(std::env::var("SYLPHEED_DISC").expect("SYLPHEED_DISC")); + let ar = PakArchive::open(root.join("dat/GP_DIALOG.pak")).expect("GP_DIALOG"); + let n = ar.entries().len(); + let mut shown = 0; + for k in (0..n).step_by(2) { + let (Some(a), Some(b)) = (names(&ar, k), names(&ar, k + 1)) else { continue }; + if a == b { + continue; + } + let oa: Vec<&String> = a.difference(&b).collect(); + let ob: Vec<&String> = b.difference(&a).collect(); + // only the equal-button-count ones + let ba = a.iter().filter(|x| x.contains("btn")).count(); + let bb = b.iter().filter(|x| x.contains("btn")).count(); + if ba != bb { + continue; + } + if shown < 6 { + println!("entries {k:3}/{:<3} shared {} only-in-{k}: {:?} only-in-{}: {:?}", + k + 1, a.intersection(&b).count(), oa, k + 1, ob); + shown += 1; + } + } +} diff --git a/docs/re/data/difficulty-is-a-dialog.txt b/docs/re/data/difficulty-is-a-dialog.txt index 063d9273..5ad81ba7 100644 --- a/docs/re/data/difficulty-is-a-dialog.txt +++ b/docs/re/data/difficulty-is-a-dialog.txt @@ -187,3 +187,45 @@ # rest on the pairing -- it rests on the unique four-button geometry (0 rivals # disc-wide) plus the oracle capture -- but the pairing was stated as fact and was # not one. + +################################################################################ +# ❌ AND THE 37 ARE NOW REFUTED TOO, not merely unsupported. 2026-08-31. +# +# Both agents recorded that the language reading survived for the 37 pairs that +# differ WITHOUT a button-count mismatch, and both noted that nothing rewarded +# closing it. It cost one scan. +# +# STEP 1: all 39 equal-button-count pairs share their button NAMES AND ROWS +# exactly (examples/dialog_pair_37.rs; control: entries 2/3 counted as matching). +# ⚠️ That does NOT settle it -- two different dialogs sharing a button template, +# like two yes/no boxes, look identical by that test. +# +# STEP 2: look at what actually differs (examples/dialog_pair_diffs.rs): +# +# entries 10/11 pzstg10_01..20 + _eff vs pzstg02_01..16 + _eff +# entries 12/13 pzstg11_* vs pzstg03_* +# entries 14/15 pzstg12_* vs pzstg13_* +# entries 16/17 pzstg04_* vs pzstg14_* +# entries 18/19 pzstg05_* vs pzstg15_* +# entries 20/21 pzstg06_* vs pzstg16_* +# +# ✅ THESE ARE DIFFERENT STAGES. They are the sixteen DLG_STAGE_TITLE01..16 +# dialogs from the table above, and an adjacent pair carries TWO DIFFERENT STAGES, +# not two languages of one. The sprite COUNTS differ too (stg10 has 20 title +# sprites, stg02 has 16), which is a different amount of text, not a translation +# of the same text. +# +# => The language reading is refuted for the 37 as well. The whole 63 is now +# explained by one fact: **adjacent GP_DIALOG entries are unrelated dialogs.** +# No residue, no special case. +# +# 📌 THE 2 REMAINING PAIRS (0/1 and 2/3) are still the only ones with identical +# element sets, and still unexplained -- but they are no longer anomalous against +# a hypothesis, because the hypothesis is gone. Whether they are a language pair, +# a duplicate, or two dialogs sharing every element is untested. +# +# ⚠️ WORTH RECORDING ABOUT THE PROCESS, not the disc: this question was left open +# by both agents with the explicit observation that "nothing rewards closing it". +# It cost two scans and went AGAINST the reading I had offered. A bound nobody is +# incentivised to test is exactly where a convenient claim survives -- and the +# next reader cannot tell whether a bound was respected or merely never revisited.