Overview

#define init_data 0
#define gameover_data 1
#define town01 3
#define town0b 12
#define town0c 21
...
#define vab_01 1072

Implementation: crates/prot/src/cdname.rs.

Block-start semantics

Each #define name N marks the start of a block: the name applies to entry N and every subsequent entry until the next define. Subsequent PROT entries inherit the name of the most recent block:

  • entry 3 → block town01
  • entry 11 → block town01 (since town0b starts at 12)
  • entry 12 → block town0b

Most blocks correspond to one scene (a town, dungeon room, or menu) and reserve a handful of entries for that scene's assets. prot-extract uses these names to produce filenames like 0148_retock.BIN.

Numbering space (the −2 correction)

The boot TOC loader copies PROT.DAT verbatim (8-byte header included) into RAM at 0x801C70F0, so raw index = extraction index + 2 (see PROT TOC § In-RAM TOC). The default NNNN_<name>.BIN naming is kept for stability; legaia_prot::cdname::block_for_extraction_index resolves the retail-space name for an extraction index, and scripts/asset-investigation/cdname_shift_analysis.py reproduces the full quantitative analysis against a local extraction.

Evidence

Loader-constant identities (strongest - retail hard-codes raw-TOC indices for dev-named files, and each constant equals the same-named define):

Block (defines)Retail raw-TOC constantProvenance
battle_data 865..8680x361..0x364 = 865..868, data\battle\PLAYER1..4FUN_800558FC(char+0x360) live trace; extraction 863..866 start at the traced PROT.DAT offsets
monster_se 8930x37D = 893, h:\mpack\monster.sndFUN_8003E104 (li v0,0x37d); extraction 891 is a 206-bank multi-VAB SE archive
bat_back_dat 895..8960x37F/0x380 = 895/896, summon.dat/readef.DATFUN_801F17F8; byte-verified RAM↔disc at extraction 893/894
xxx_dat 897..0x381+, overlay slotsFUN_8003EBE4/FUN_8003EC70 call FUN_8003E8A8(param + 0x381); param 2 = field overlay = extraction 0897

Structural (scene region, defines 3..864): the per-scene v12 fixup table recurs once per scene block, and scene block lengths vary (7..11 slots), so its slot position is shift-sensitive. At shift 0 the 96 scene-region v12 tables scatter across slots 4..10; at −2 all 96 sit at slot 1. The identity anchors pin −2 exactly. The universal field-.MAP-at-define − 2 rule is this same fact: each scene's .MAP is retail slot 0 of its block, the v12 table slot 1, the event prescript slot 2, the 7-asset table slot 3.

Semantic scoring: over the name blocks with checkable expectations (VAB/SEQ shapes for the sound blocks, the \DATA\MOV*.STR program table for move_program_no, OTHER<n> overlay banners for other_game), shift −2 outscores shift 0 - e.g. vab_01 → extraction 1070..1192 is 121/121 VAB-headed.

Consequential relabelings

Per-entry content claims on this site stay in extraction space (unambiguous); the retail-space names below are what the dev defines actually cover. The most consequential corrections:

ExtractionFilename label saysRetail-space block (content)
raw 0..1 (LBA 3..120, unindexed by extraction)-init_data + gameover_data slot 0 - the boot-UI gap with the menu-glyph atlas
0000init_datagameover_data (second slot)
0863..0866edstati3/battle_databattle_data = the four per-character battle files PLAYER1..4 (player battle files)
0867battle_datamonster_data - the 16 MB monster stat archive (the source of the old “battle_data 0865 vs monster archive 0867” conflation)
0868..0869monster_data/sound_datasound_data (VAB-prefixed streams)
0870..0873sound_data/befect_databefect_data - etim (0870, the pixel-verified effect-texture source), etmd+vdf, billboard pack, efect.dat (0873) - see effect bundles
0874befect_dataplayer_data - the field character-mesh pack (character-mesh)
0875..0888player_data/sound_data2sound_data2 (VAB streams)
0889..0890sound_data2/level_uplevel_up (large VAB carriers)
0891level_upmonster_se = monster.snd, the 206-bank monster-SE archive
0892level_upcard_data (12 MB LZS container; content not yet pinned)
0893..0894monster_se/card_databat_back_dat = summon.dat/readef.DAT mid-cast backdrop streams
0895..0969bat_back_dat/xxx_datxxx_dat - slot 0 (extraction 0895) is the boot init.pak bundle loaded through overlay-slot param 0 (boot); overlay code blobs follow (MIPS overlay, overlay pointer-table)
0970..0971xxx_datmove_program_no - a \DATA\MOV*.STR FMV program/path table + debug strings. The block names MOVie program numbers (STR FMV table), not Tactical-Arts moves; the extraction files 0972/0973 the old “layout mismatch” was tested against are other_game overlays
0972..0977move_program_no/other_gameother_game - casino/minigame overlays; extraction 0973/0974 open with literal OTHER2 / OTHER3 banners
1070..1192music_01/vab_01vab_01 (121/121 VAB-headed)

Exceptions and caveats

Residual caveats (none contradict the uniform −2):

  • level_up → extraction 0890 is a DATA_FIELD streaming carrier (its VABs are wrapped inside), so bare-magic checks miss it at every shift.
  • Extraction 0888 (in sound_data2) and 1062 (in music_01) are unidentified non-VAB blobs under any shift.
  • other_game: only 2 of 6 entries carry an OTHER<n> banner; the rest are banner-less minigame data, undecidable by name.
  • Extraction 0893 (summon.dat) opens with a [u32 2][u16 table…] shape that mimics a sound-address bank - a shift-0 reading “confirms” monster_se on it spuriously; the byte-pins show texture streaming slots. Trust byte-pins over shape coincidences.
  • One v12-shaped header sits at extraction 1227 (other7 region), outside the scene region.
  • Opaque names (other1/other4/other5/other6/other7, card_data) are unscoreable; nothing about them conflicts with −2.
  • other7 (extraction 1226+, define 1228) is a dev-leftover earlier revision of koin3's field MAN: its 8 partition-2 records are a name-exact prefix subset of koin3's 12 (koin3 appends four later records), and its partition-1 pool shares koin3's gate flags (0x431/0x4CA/0x3DA at matching record shapes). No captured code loads it (no path string, no raw-index loader) - orphaned content, consistent with its leftover-JP text.

Engine consequence: scene windows are the retail block

Scene::load (engine-core) converts the raw-TOC block range to the extraction frame (raw - 2) so a scene's entries are its retail block: the first entry is the scene's .MAP file, the second typically its v12 trigger sidecar. An unshifted window is two entries late - it drops those and bleeds in the next block's first two, which mis-frames any scene whose load-bearing entry sits at a block edge (an unshifted rikuroa window picks up geremi's v12 sidecar and loads Jeremi's MAN under the rikuroa label; the “suimon == dolk2 MAN” identity is the same bleed). The two head defines (init_data 0, gameover_data 1) sit inside the TOC header rows where the conversion has no content to land on; those blocks keep their unshifted legacy windows.

Block names can still mislead

A block name describes the developer's organisation, not the runtime semantics of every entry inside the block - and any name read off an extraction filename must first be corrected by the +2 numbering shift above. Once that shift is applied, the dev names turn out to be accurate far more often than the historical “label gotcha” catalogue suggested: vab_01 really is wall-to-wall VAB banks, battle_data really is the player battle files, bat_back_dat really names the battle side-band summon.dat/readef.DAT files (extraction 893/894). When a (shift-corrected) block name still conflicts with what the bytes look like, trust the bytes: re-derive structure from the leading magic + the loader-call constant in SCUS, not from the CDNAME label.

Per-scene asset reservations

Most scene blocks reserve 6–8 PROT slots for asset variants. Unused slots get filled with the dev placeholder pattern documented in pochi-filler. The edstati3 block (likely "ending station 3", possibly cut content) is almost entirely pochi-filled.

See also