At a glance

Magic
none - static data in SCUS_942.54
Where
DAT_80077828 (file offset 0x68028), 2-byte stride, 1-based monster id; not in the PROT 867 monster record
Parser
legaia_asset::steal_table::StealTable; randomizer legaia_patcher::steal
Confidence
Confirmed - pinned from a live steal capture and byte-exact against the complete published steal table (steal_table_real)
Used by
Enemy table (steal column), Randomizer, ROM patcher

Field order is [chance, item] - the reverse of the drop pair in the monster record. Read it item-first and every chance shifts by one monster.

Table base + record layout

(DAT_80077828 is a Ghidra label - the disassembler's name for the fixed RAM address the table occupies. Static data: the address maps directly to a file offset in SCUS_942.54 on the disc.)

FieldValue
Base addressDAT_80077828 (file offset 0x68028 in SCUS_942.54)
Index formDAT_80077828 + monster_id*2 (1-based monster id, same id space as the monster archive)
Stride0x2 bytes
Id rangemonster ids 1.. (entry 0 is a reserved sentinel)
OffsetTypeField
+0u8steal_chance_pct - steal success chance, percent
+1u8steal_item_id - stolen item id in the item-name table's id space; 0 = none
steal table (SCUS) chance % item id +0 +1 drop pair (monster record) item id chance % ← reversed order
Two bytes per monster, chance first - the reverse of the drop pair in the monster record.

Field order is chance-then-item - the reverse of the drop fields in the monster record (+0x48 item / +0x49 chance). Reading the table with the record's item-first order shifts every chance by one monster. A chance of 0 (or item 0) means the enemy can't be stolen from; a raw steal id resolves to a name the same way a drop id does (0x8A → Incense).

How we know

Pinned from a live player-steal RAM capture (Evil God Icon equipped): the Skeleton (monster id 13) entry at 0x80077842 is 1e 8a = 30% Incense, exactly the steal the in-battle banner shows. Base, stride, and the [chance, item] order are confirmed byte-exact against the complete published steal table - item and chance columns - across every resolvable monster id, zero mismatches. The table is static rodata, resident in RAM identical to the file bytes.

Why the monster record has no steal field

An exhaustive offset scan of the decoded monster record (extraction entry 0867 / raw TOC index 0x365 - a numbered entry of PROT.DAT, the disc's single big archive - the battle_data monster archive), correlated against ground-truth steal data, finds no steal field there: the reward block at +0x44..+0x49 holds only gold / exp / drop. Every record-only search for the steal item was structurally doomed - the data was never in the archive.

Parser

legaia_asset::steal_table::StealTable::from_scus resolves the table from a SCUS_942.54 image (PSX-EXE t_addr → file-offset map, identical to the item-name table resolver). entry(monster_id) returns the [chance, item] pair; steal_item(monster_id) returns the item only when the entry is stealable. The disc-gated steal_table_real test pins the Skeleton→Incense anchor plus a span of ids against the real executable. CLI: asset steal-table <SCUS> [--all] [--json], with the item id joined to its name.

The randomizer (legaia_patcher::steal) edits this table on a user-supplied disc to reassign steal items.

See also