Confidence

Confirmed for every offset in the table below. Each is cross-referenced against at least two of: a Ghidra-dumped function, a captured save-state observation, or a GameShark cheat with a labelled effect.

Per-character bases

SlotBaseOwner
00x80084708Vahn
10x80084B1CNoa
20x80084F30Gala
30x80085344guest / future-party-member

Layout

+0x000  u32 LE   xp_low_word_alt          ; "Max Exp" cheat target.
+0x004  u16 LE   xp_cumulative_u16        ; captured XP cell - level-up logic
                                          ; reads here (Noa 4-jump 102 -> 336).
+0x0F4  u8[16]   ability_bits             ; OR'd into 0x80074358 each frame
+0x104  u16 LE   hp_curr_live             ; "Infinite HP" / "Max HP"
+0x106  u16 LE   hp_max_live
+0x108  u16 LE   mp_curr_live             ; "Max MP"
+0x10A  u16 LE   mp_max_live
+0x10C  u16 LE   sp_curr_live
+0x10E  u16 LE   sp_max_live              ; "100 AP"
+0x110  u16 LE   agl_live                 ; "Max AGL" (live copy)
+0x112  u16 LE   atk_live                 ; "Max ATK"
+0x114  u16 LE   udf_live                 ; "Max UDF"
+0x116  u16 LE   ldf_live                 ; "Max LDF"
+0x118  u16 LE   spd_live                 ; "Max SPD"
+0x11A  u16 LE   int_live                 ; "Max INT" (legacy stat_cap target)
+0x11C  u16 LE   hp_max_record
+0x11E  u16 LE   mp_max_record
+0x120  u16 LE   stat_cap_constant        ; always 100 in captured saves
+0x122  u16 LE   agl_record
+0x124  u16 LE   atk_record
+0x126  u16 LE   udf_record
+0x128  u16 LE   ldf_record
+0x12A  u16 LE   spd_record
+0x12C  u16 LE   int_record
+0x130  u8       magic_rank               ; "Level 99" cheat target. See note.
+0x13C  u8       magic_slot_activator     ; cheat sets to 0x24 to enable
+0x13D  u8[12]   magic_group_0            ; "Magic Modifier 1..12" hits
+0x149  u8[12]   magic_group_1
+0x155  u8[12]   magic_group_2
+0x161  u8[16]   summon_levels            ; "All Summons Level 9"
+0x185  u8       displayed_skill_count
+0x186  u8[16]   displayed_skill_ids      ; "Has all Arts" target
+0x196  u8       armor_id                 ; "Armor Modifier"
+0x197  u8       head_gear_id             ; "Head Gear Modifier"
+0x198  u8       weapon_id                ; "Weapon Modifier"
+0x199  u8       accessory_or_seru_lock   ; "Activate Meta/Terra/Ozma at Lv9"
+0x19A  u8       leg_gear_id              ; "Leg Gear Modifier"
+0x19B..0x19D    accessory_1..3_id        ; "Accessory N Modifier"
+0x2B0..0x37F    active_spell_slots[14]   ; 14 x 0x14-byte runtime slots

Reconciled contradictions

+0x130 is Magic Rank, not character level

The captured Noa + Gala 4-level jumps show +0x130 ticking +1 per level-up event regardless of the levels gained. The Level 99 GameShark cheat sets the same byte to 0x63 (99). Both readings reconcile if +0x130 is the Magic Rank: setting it to 99 unlocks every magic / summon at maximum power without affecting the character's combat level (which is derived from cumulative XP via legaia_save::level_for_cumulative_xp).

+0x161..+0x178 is the summon-level array, not spell levels

The prior SpellList::levels field claimed +0x161..+0x184 was a parallel "spell level" array. The All Summons Level 9 cheat stamps 0x09 into 16 bytes at +0x161..+0x178 - one byte per summon ID, not per spell. The corrected accessor in legaia_save::CharacterRecord is summon_levels().

The +0x120 cap constant

Across every captured save, +0x120 reads as 100. The level-up overlay writes this constant on every level-up event regardless of character or stat. Interpreted as the hard ceiling the record-side stats clamp against; the runtime then re-projects through FUN_80042558's 0x3E7 clamp on the live copy, so equipment / buffs can push past the record-side cap up to 999 in battle.

See also

  • Cheat databases - the GameShark / Mednafen cheat parser, full citation table, and runtime applier.
  • RAM map - newly-pinned globals around the per-character records.
  • Level-up subsystem - the multi-frame write split during a level-up event.