formats: two more measured paint orders, and the first independent confirmation
The three orders the derived rule was built from all live in GP_TITLE.pak, so
they cannot confirm it - the rule was fitted to them. These two are from
GP_SAVE_LOAD.pak, read off the running game now that the Canary threading fix
makes the main menu dependable.
The 9-element slot-list header composites EXACTLY as the sort predicts, on all 6
instances of it, and nothing about this screen was fed into the rule:
measured 7 8 0 1 2 3 4 5 6
derived 7 8 0 1 2 3 4 5 6
including TWO tied groups (0xb102 x2 and 0xb210 x5) that both come out in
declaration order, and the unkeyed pfeff00.prm fade quad last.
The 13-element save/load frame differs in exactly the two open questions and no
new ones: two unkeyed pfbase.tbm backgrounds paint FIRST where the sort puts the
keyless last - the splash's palogo_eff0.prm behaviour in a different file type,
so implied_layer_key now covers it - and the 0xb100 group of four paints
10,11,8,12 where declaration order is 8,10,11,12.
That second point is a SECOND screen with a mis-ordered tie, which is what the
question needed, and it immediately kills a candidate: 10 and 11 are kind=0x2002
while 8 and 12 are 0x0000, so "descending kind then declaration index"
reproduces 10,11,8,12 exactly - and then fails both title groups, where every
element of 0x8083 is kind 0 and where 0x80a0 would predict 2,3,4,5,0,1,7 against
a measured 0,2,4,7,1,3,5. Seven candidates refuted now.
16 disc tests green.
This commit is contained in:
@@ -900,3 +900,67 @@ fn order_disagreements_that_change_pixels_are_pinned() {
|
||||
"the set of order disagreements that actually change pixels has moved"
|
||||
);
|
||||
}
|
||||
|
||||
/// Two more paint orders read off the running game, from `GP_SAVE_LOAD` — and
|
||||
/// the first **independent confirmation** of the derived rule.
|
||||
///
|
||||
/// The three orders the rule was built from all live in `GP_TITLE.pak`. These do
|
||||
/// not, and one of them the sort gets exactly right without having been told
|
||||
/// anything about it:
|
||||
///
|
||||
/// * the **slot list header** (9 elements) composites `[7,8,0,1,2,3,4,5,6]`,
|
||||
/// which is what sorting by layer key gives — including **two tied groups**
|
||||
/// (`0xb102` ×2 and `0xb210` ×5) that both come out in declaration order, and
|
||||
/// the unkeyed `pfeff00.prm` fade quad last. Exact on all five bundle
|
||||
/// instances of it.
|
||||
/// * the **save/load frame** (13 elements) does not, in exactly two ways, and
|
||||
/// both are already-known open questions rather than new ones: two unkeyed
|
||||
/// `pfbase.tbm` background elements paint **first** where the sort puts the
|
||||
/// keyless last, and the `0xb100` group of four paints `10,11,8,12` where
|
||||
/// declaration order is `8,10,11,12`.
|
||||
#[test]
|
||||
fn the_save_load_screens_match_what_the_running_game_paints() {
|
||||
skip_without_disc!(root);
|
||||
let header: [usize; 9] = [7, 8, 0, 1, 2, 3, 4, 5, 6];
|
||||
let frame: [usize; 13] = [0, 1, 2, 3, 4, 5, 6, 7, 10, 11, 8, 12, 9];
|
||||
let arc = PakArchive::open(root.join("dat").join("GP_SAVE_LOAD.pak")).expect("pak");
|
||||
let (mut headers, mut frames) = (0usize, 0usize);
|
||||
for e in arc.entries() {
|
||||
let Ok(bundle) = arc.read(e) else { continue };
|
||||
let Some(b) = ui_layout::parse_build(&bundle) else {
|
||||
continue;
|
||||
};
|
||||
let names: Vec<&str> = b.elements.iter().map(|e| e.name.as_str()).collect();
|
||||
let derived = ui_layout::derived_paint_order(&b, &bundle);
|
||||
if b.elements.len() == 9 && names[0] == "pftitlebase.t32" && names[6] == "pfeff00.prm" {
|
||||
headers += 1;
|
||||
assert_eq!(
|
||||
derived,
|
||||
header.to_vec(),
|
||||
"the slot-list header no longer composites in the order the game paints"
|
||||
);
|
||||
}
|
||||
if b.elements.len() == 13 && names[0] == "pfbase.tbm" {
|
||||
frames += 1;
|
||||
// The two known gaps, stated as the measured difference rather than
|
||||
// asserted away: the sort must at least agree on everything else.
|
||||
let key = |i: usize| {
|
||||
let el = &b.elements[i];
|
||||
ui_layout::sprite_layer_key(&b, &bundle, el)
|
||||
.or_else(|| ui_layout::implied_layer_key(&el.name))
|
||||
.unwrap_or(u32::MAX)
|
||||
};
|
||||
let dk: Vec<u32> = derived.iter().map(|&i| key(i)).collect();
|
||||
let mk: Vec<u32> = frame.iter().map(|&i| key(i)).collect();
|
||||
assert_eq!(
|
||||
dk, mk,
|
||||
"the save/load frame's layer-key sequence differs from the game's \
|
||||
— the only accepted differences are WITHIN a key group\n \
|
||||
derived {derived:?}\n measured {frame:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
assert!(headers >= 3, "found {headers} slot-list headers, expected several");
|
||||
assert!(frames >= 1, "found {frames} save/load frames");
|
||||
eprintln!("GP_SAVE_LOAD: {headers} headers exact, {frames} frames agree by layer group");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user