formats: a primitive layer is not in the file - measure it, table it, prove it

Two places checked for the key a .prm element sorts by, both empty:

  * the declaration entry's four unread words are constant across every element
    of all three measured screens (+28=0, +36=0xffffffff, +56=0, and +44 is a
    button ordinal 1-5, 0xffffffff elsewhere);
  * the bundle carries NO data for a primitive at all - the menu build declares
    pteff00.prm, pteff02.prm and pteff05.t32 and has zero RATC children for any
    of them, its 34 children being 21 T8aD sprites and 13 .rat records.

So the layer comes from the game code. But it is consistent, which is what makes
a per-name table a measurement rather than a fudge. Bracketing each unkeyed
element between the keys of its measured neighbours: pteff02.prm falls in
(0x8010, 0x8040) on BOTH screens it appears on, pteff00.prm is past the maximum
on both, and palogo_eff0.prm is below the minimum on the splash.

implied_layer_key records exactly those and nothing else; an unlisted primitive
keeps u32::MAX and still sorts last. With it, derived_paint_order produces the
same layer-key sequence as the order read off the running game on all three
measured screens - primitives included - and matches element-for-element on four
of the five bundle instances. The fifth is the title, differing only inside its
tied groups, which is a separate open question.

This does not make include_primitives safe by default: the 36 builds that come
out one colour are wiped by pzeff00.prm and pceff00.prm, never measured, hence
not in the table.

14 disc tests green.
This commit is contained in:
Sylpheed RE agent
2026-08-19 09:15:55 +00:00
parent a1624af24e
commit 610b21c434
3 changed files with 159 additions and 3 deletions

View File

@@ -116,9 +116,53 @@ The genuinely wiped ones are a different set, wiped by an *opaque* quad.
## What is not settled
## Where a primitive paints — refuted in the file, measured in the game (2026-08-19)
**🔴 Refuted: the key is not in the bundle.** Two places were checked and both
are empty:
* the **declaration entry**'s four unread words are constant across every
element of all three measured screens — `+28` = 0, `+36` = `0xffffffff`,
`+56` = 0, and `+44` is a button ordinal (1…5 on the menu's five buttons,
`0xffffffff` everywhere else). No key there.
* the **bundle carries no data at all** for a primitive. The menu build declares
`pteff00.prm`, `pteff02.prm` and `pteff05.t32` and has **zero** RATC children
for any of them — its 34 children are 21 `T8aD` sprites and 13 `.rat` records,
none of them named for a primitive.
So the layer a primitive draws on comes from the game's own code, not the file.
**✅ But it is consistent, which makes a per-name table honest.** Bracketing each
unkeyed element between its measured neighbours' keys:
| element | title screen | main menu | splash |
|---|---|---|---|
| `pteff05.t32` | — | (0x8010, 0x8040) | — |
| `pteff04.t32` | (0x8010, 0x8040) | — | — |
| `pteff02.prm` | **(0x8010, 0x8040)** | **(0x8010, 0x8040)** | — |
| `pteff00.prm` | (0x8100, end) | (0x8110, end) | — |
| `palogo_eff0.prm` | — | — | (start, 0xa100) |
`pteff02.prm` falls in the **same interval on both** screens it appears on, the
fade quad is past the maximum on both, and the splash backdrop is below the
minimum. `ui_layout::implied_layer_key` records exactly these, and nothing more —
an unlisted primitive keeps `u32::MAX` and still sorts last.
With it, `derived_paint_order` produces **the same layer-key sequence as the
order read off the running game on all three measured screens**, primitives
included, and matches element-for-element on four of the five bundle instances
(the fifth is the title, which differs only inside its tied groups — a separate
open question). Pinned by
`the_derived_order_puts_every_element_in_the_right_layer_group`.
This does **not** make `include_primitives` safe by default: the 36 builds that
come out one colour are wiped by `pzeff00.prm` and `pceff00.prm`, whose positions
have never been measured, so they are not in the table.
## What is not settled
***Where a primitive paints.** The blocker, described above. It has no layer
***Where an *unmeasured* primitive paints.** The blocker, unchanged for the
ones not in the table. It has no layer
key and the two measured screens rule out every constant default. The cheapest
next step is a third measured order from a screen that carries a primitive —
the `GP_DIALOG` DIFFICULTY box is reachable from the main menu and has exactly