Files
Sylpheed/docs/re/data/difficulty-is-a-dialog.txt
sylph-decoder 2dba970c29 re: the dialog id to pak-entry join is not positional -- hypothesis refuted
GP_DIALOG has exactly 140 entries against the table's 70 records, a 2:1 ratio that
would make the unbound join an ordering question. It does not hold: adjacent
pairing gives identical element-name sets on 2 of 65 pairs, halves pairing on 0.
GP_TITLE's language pairs share element sets exactly, so identical sets are the
signature there; in GP_DIALOG almost nothing matches.

Residual and unexplained: the only two adjacent pairs that DO match are entries 0/1
and 2/3, and 2/3 is the DIFFICULTY build.

A reading I am not asserting: dialog text may be baked into language-specific
sprites, which would explain the 63 by construction but leaves the 2 needing their
own explanation. Not tested.

The join stays unbound; positional ordering is now ruled out, which narrows where
to look next.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-31 02:54:46 +00:00

148 lines
7.8 KiB
Plaintext

# Where does the DIFFICULTY screen live? ✅ DECODED 2026-08-31.
# It is a DIALOG -- `DLG_SELECT_DIFFICULTY`, GP_DIALOG.pak entries 2/3.
#
# CLOSES A NEGATIVE OF MINE. gp-title-holds-three-button-screens.txt recorded
# "not an 8-record btn-named build anywhere on the disc", with the failed
# assumption named as mine: I assumed DIFFICULTY's four items pair with `f` focus
# variants in an archive of its own, the way GP_TITLE's screens do. Both halves
# of that were wrong -- it has its own button prefix and it is not a GamePart
# screen at all.
#
################################################################################
# ROUTE 1 -- THE IMAGE. /image/sylpheed.pe, 3 occurrences of "DIFFICULTY":
# 0x820A2548 STAGE | DIFFICULTY | TITLE | FADE | BASE_EXTRA ...
# (a GamePartTask::RegisterToFactory name list)
# 0x820A3377 RECORD_DIFFICULTY (a results/record field)
# 0x820A41BB DLG_LEADERBOARD_MENU_NEXT | DLG_SYSTEM_PAUSE |
# **DLG_SELECT_DIFFICULTY** | DLG_MISSION_OBJECTIVE |
# DLG_MESSAGE_BOX | DLG_MESSAGE_BOX_YES_NO | ...
#
# ✅ The third is the answer: DIFFICULTY is one of the game's DLG_* dialogs.
# ⚠️ "GP_DIFFICULTY" appears 0 times in the image, which is consistent.
#
################################################################################
# ROUTE 2 -- THE DISC. GP_DIALOG.pak entries 2 and 3 are the only builds in that
# archive carrying `pcbtn00`..`pcbtn03` -- FOUR buttons, matching
# EASY / NORMAL / HARD / BACK. Design rows and spacing:
#
# entry 2 y 259 / 329 / 399 / 469 spacing 70, 70, 70
# entry 3 identical (the EN/JP pair, as everywhere else)
#
# ✅ CONTROL: the same reader on GP_TITLE entry 5 returns 162/242/322/401/482,
# spacing 80 -- the rows that archive is independently known to place.
#
################################################################################
# ROUTE 3 -- THE ORACLE. My own capture of the running DIFFICULTY screen
# (captures/menu-nav/live-difficulty-opens-normal.png), with the disc-grounded
# calibration capture_y = 64.82 + 0.9919 * design_y:
#
# design row predicted measured in the capture residual
# 259 321.7 323.5 +1.8
# 329 391.2 394.0 +2.8
# 399 460.6 463.5 +2.9
# 469 530.0 533.5 +3.5
# measured spacing 70.5 / 69.5 / 70.0 against the disc's 70 / 70 / 70
#
# Four rows, all under 4 px, with the spacing agreeing exactly. The residual is a
# uniform ~+2.8 px offset, which is the calibration's own systematic and not a
# mismatch.
#
# => THREE INDEPENDENT ROUTES: the executable names it a dialog, the disc has a
# four-button dialog build, and the running game draws its rows where that
# build says they are.
#
# 📌 WHY IT MATTERS BEYOND THE LOCATION: DIFFICULTY being a DIALOG explains why
# NEW GAME's destination is not a screen in GP_TITLE, and it means the "four menu
# items load an external archive" reading of the event numbers
# (boot-config-and-gamepart-registry.md's count-match) is looser than it looked --
# NEW GAME opens a dialog from GP_DIALOG.pak, which is an external archive, but a
# dialog is not the same kind of thing as OPTIONS or TUTORIAL opening a GamePart.
# The count still matches; the categories are not uniform.
#
# ⚠️ REACH: entries 2/3 are identified by button count and geometry, not by a
# name binding DLG_SELECT_DIFFICULTY to a pak entry. No such binding was found --
# the DLG_* names live in a string list, and what maps a name to an archive entry
# is not decoded. Another 4-button dialog with the same rows would be
# indistinguishable by this evidence.
################################################################################
# ✅ DECODED 2026-08-31 (later): THE DIALOG TABLE. `DLG_SELECT_DIFFICULTY` = id 2000.
#
# Chasing the reach above -- "no binding from the DLG_ name to anything" -- found
# one. Every DLG_ string in the image is pointed at by exactly one aligned word,
# at a regular 12-byte stride. The table is:
#
# struct { u32 handler; u32 id; u32 name_ptr; } // 12 bytes, big-endian
#
# spanning 0x820A0A2C .. 0x820A0D68, three distinct handler values
# (0x821CFD80, 0x821D05D8, 0x821D0808).
#
# ✅ COMPLETE: 70 DLG_ names in the image, 70 records, ZERO names without one.
# ids are banded and monotonic, with a single gap at 24:
# 0..23 sign-in, storage, save/load/replay, GO_TITLE, GO_NEXT
# 25..43 autosave, training, weapon develop, custom keys, menu jumps
# 98, 99 DLG_MESSAGE_BOX_YES_NO, DLG_MESSAGE_BOX
# 1000 DLG_MISSION_OBJECTIVE
# 2000 **DLG_SELECT_DIFFICULTY**
# 2001..3 SYSTEM_PAUSE, LEADERBOARD_MENU_JUMP, LEADERBOARD_MENU_NEXT
# 2100..15 DLG_STAGE_TITLE01..16
# 8000 DLG_RATING_ESRB
# 9000..2 trial dialogs
#
# Read from /image/sylpheed.pe directly -- these are the bytes the console ran,
# not a database row.
#
################################################################################
# ✅ REFUTATION ATTEMPT ON THE SHARED REACH -- IT SURVIVES, AND IS NOW BOUNDED.
#
# Both agents recorded: "another four-button dialog with the same rows would be
# indistinguishable by this evidence". Tested by scanning EVERY build in EVERY pak
# for four buttons within 6 px of rows 259/329/399/469
# (examples/four_button_row_rivals.rs):
#
# INCUMBENT GP_DIALOG.pak entry 2 rows [259, 329, 399, 469]
# INCUMBENT GP_DIALOG.pak entry 3 rows [259, 329, 399, 469]
# control: 2 incumbents found (want 2) -- PASSED
# RIVALS ELSEWHERE ON THE DISC: **0**
#
# So the hypothetical rival does not exist here. The geometric identification is
# UNIQUE DISC-WIDE, which is a stronger statement than the one either of us
# recorded, and it was cheap to get.
#
# ⚠️ WHAT IS STILL NOT BOUND: id 2000 -> a pak entry. The table gives name -> id
# and the disc gives a unique four-button build; nothing found so far connects the
# two. The tie is uniqueness of geometry plus the oracle capture, not a pointer.
################################################################################
# ❌ REFUTED: the id -> pak-entry join is NOT positional. 2026-08-31.
#
# GP_DIALOG.pak has exactly **140 entries** and the dialog table has exactly **70
# records** — a 2:1 ratio that looks like one EN/JP pair per dialog, which would
# make the unbound join an ordering question rather than a search. Tested, and it
# does not hold:
#
# ADJACENT pairing (2k, 2k+1) identical element-name sets: 2 of 65
# HALVES pairing (i, i+70) identical element-name sets: 0 of 65
# (5 pairs unreadable — entries that do not parse as builds)
#
# GP_TITLE's language pairs share their element sets exactly (except 4/7, the
# title art), so identical sets are the signature of a pair there. In GP_DIALOG
# almost nothing matches, so **the 2:1 ratio is not established as a language
# pairing** and no positional rule connects id 2000 to entries 2/3.
#
# 📌 RESIDUAL OBSERVATION, recorded because it is odd rather than because it is
# understood: the only two adjacent pairs with identical element sets are
# **entries 0/1 and 2/3** — and 2/3 is the DIFFICULTY build. Whatever makes those
# two structurally uniform in an archive where 63 of 65 pairs are not, this does
# not explain.
#
# ⚠️ A plausible reading I am NOT asserting: dialog text may be baked into
# language-specific sprites, which would make EN/JP entries differ in element
# names by construction. That is consistent with the 63, and it is one
# measurement away from being tested — but it is not tested here, and the 2 that
# DO match would then need their own explanation.
#
# => The join stays unbound. Table gives name -> id; disc gives a unique build;
# the tie is uniqueness plus the oracle capture. Positional ordering is now
# ruled out as the missing pointer, which narrows where to look next.