Table base + record layout

(DAT_800752C0 is a Ghidra label for the fixed RAM address the table occupies once the executable is loaded; static data, so the address maps directly to a file offset in SCUS_942.54 on the disc. Each record is 4 bytes - the "stride".)

FieldValue
Record baseDAT_800752C0 (file offset 0x65AC0 in SCUS_942.54)
Stride0x4 bytes
Record count130 (subtypes 0x00..=0x81); ends at the spell table 0x800754C8
OffsetTypeField
+0u8effect class (action-validator arm)
+1u8tier / sub-case (per-class selector; e.g. heal-HP 0/1/2 = 200/800/max)
+2u8flags: 0x80 populated, 0x20 whole-party target, 0x04 battle-usable, 0x02 field-usable
+3u8passive-effect index (0x00..=0x3F) for accessory / quest-item rows; 0x41 = no-passive sentinel on consumable rows (see the accessory-passive table; ids resolve through the item-name table)

Healers carry 0x04 | 0x02 (field + battle); permanent stat-ups and field-utility items carry 0x02 only; status-cures and revive carry 0x04 only. Key items resolve to a descriptor with neither usability bit set, which is how the item menu greys them out. The class byte is meaningful only together with the usability flags - many key items funnel to class 0 with no usability bit, so "class 0" alone is not "an HP potion".

Indexing (double-indirected)

The lookup goes item id → subtype → descriptor: an item's record in the name table carries a subtype byte, and the subtype picks the descriptor here. From FUN_8003043C (FUN_80xxxxxx names are Ghidra-traced functions, labelled by their RAM address):

subtype    = item_name_table[id].byte(+1)      ; DAT_80074369[id*0xC]
descriptor = (&DAT_800752C0)[subtype * 4]      ; stride-4 record
arm        = descriptor[+0]                    ; effect class / validator arm
tier       = descriptor[+1]
flags      = descriptor[+2]

The & 0x20 all-party test is read in FUN_8003043C itself; the 0x02/0x04 field-vs-battle bits are read by the field item-menu list builder FUN_80030628; the battle item path reads class + tier straight into the actor's action context (battle overlay 0x801E3BA4).

Class byte (+0)

Class labels are validated against the on-disc item description strings (item record +8 pointer):

ClassEffectExample item
0 / 1heal HP, one ally / whole partyHealing Leaf / Healing Bloom
2restore MPMagic Leaf
3 / 8cure all status / cure single statusMedicine / Antidote
4revivePhoenix
5extend action gauge (one battle)Fury Boost
6permanent stat-up (tier = which stat)Miracle Water, the Water line
7temporary stat buff (one battle, ×6/5)Power Elixir
11/12/13arts book (Fire/Wind/Thunder; tier = book level)Fire Book I
126/127summon fluteLippian Flute
128 / 129field escape (dungeon) / field warp (city)Door of Light / Door of Wind
130reduce encounter rateIncense

Heal-amount table (0x8007655C)

This table holds class + tier + flags, not the literal restore amounts - those live in a separate, also-static pair of u16[4] sub-tables the apply handler FUN_800402F4 reads, indexed by the descriptor tier (base + tier*2):

VASub-tableTier 0Tier 1Tier 2
0x8007655C (file 0x66D5C)HP restore cap (classes 0/1)2008009999
0x80076564MP restore cap (class 2)5020020

Each restore is deficit-clamped (applied = min(max - current, table[tier])), so tier 2's 9999 is an effective full restore. Tier 3+ HP heals are character-relative (scaled off the per-character Seru-heal tables), and revive (class 4) is max_hp×0.4 + rand()%(max_hp/8) at tier 0, full at higher tiers. The class 5/6/7 stat magnitudes are inline immediates in the handler's switch, pinned per (class, tier): the Water line adds a flat +16 HP / +8 MP / +4 stat to the character record, the Elixirs multiply battle-actor stats by 6/5 for one battle.

Parser + provenance

legaia_asset::item_effect::ItemEffectTable::from_scus resolves both tables from a SCUS_942.54 image (PSX-EXE t_addr → file-offset map, the same resolver as the item-name table). heal_amounts() exposes the two u16 arrays, restore_amount(id) resolves an item id through its (class, tier) to Hp/Mp/CharRelative, and stat_effect(id) decodes the class 5/6/7 items. Apply handler FUN_800402F4 is reached through a 132-entry jump table at 0x80014FA0 indexed by the class byte; it handles both the field item menu and the battle item path (branching on game_mode == 0x15). The disc-gated item_effect_real test pins the descriptor bytes and cross-checks each against its on-disc description; the engine consumes the flags via ItemCatalog::apply_effect_flags and the amounts via the shared stat-raise / buff / gauge paths.

Superseded readings

An earlier reading held that the restore amounts were "a switch of immediates inside an overlay-resident apply handler, not in the dumped corpus". The HP / MP amounts are in fact on the disc in the static tier-indexed tables at 0x8007655C / 0x80076564, read by the static FUN_800402F4; only the class 5/6/7 stat magnitudes are inline immediates.

See also