At a glance

Where
data/cheats/legaia-ntsc-u.gs.txt (GameShark text) and data/cheats/legaia-ntsc-u.cht (Mednafen) - committed; labelled (address, value) pairs only, no Sony bytes
Region
NTSC-U (SCUS_942.54)
Parser
crates/cheats (legaia_cheats) + the cheat-tool CLI
Applier
legaia-engine play-window --cheat-file via engine_core::cheat_applier
Pins
Character record, inventory, battle actor, script-VM globals, camera, minigame scratch, four code-patch sites
Used by
Save record, RAM map, Inventory, Battle

Data files

FileFormatShape
legaia-ntsc-u.gs.txtGameShark text dumpOne write per line, fixed columns
legaia-ntsc-u.chtMednafen .chtIndexed cheatN_desc / _code / _enable triplets; multi-write effects join codes with +

Both files describe the same effects in different encodings; cheat-tool diff compares them.

How a code is encoded

A code is eight hex digits of address and four of value. The high byte of the "address" is not an address at all - it is the operation prefix that says what kind of write (or condition) the cartridge performs.

example code: 8 0 0 8 4 8 1 6 0 0 6 4 80 prefix (1 byte) 084816 RAM offset, 24 bits - address is 0x80000000 + offset 0064 value (16 bits) 80 = write u16 30 = write u8 D0 = run next line if mem16 == value E0 = run next line if mem16 != value mem16[0x80084816] = 0x0064 ("100 AP")
One 12-digit code: prefix, 24-bit offset, 16-bit value. Conditional prefixes gate the next line - that is how "press Select to activate" cheats work.
PrefixOperationExample
0x80u16 little-endian write80084816 0064mem16[0x80084816] = 0x0064
0x30u8 write300848A3 0000mem8[0x800848A3] = 0x00
0xD0if mem16 == value, execute next lineD007B7C0 0100 (Select pressed)
0xE0if mem16 != value, execute next lineE007B83C 0003
Column layout of the GameShark text dump
ColumnMeaning
Rread/write classifier (always R - a cheat is a write)
Iencoding flag (always I)
1 / 2 / 4width in bytes
Lendianness (little)
0compression group (always 0)
80084816address, 8 hex digits, no 0x
64value, hex
rest of linedescription

For prefix 0x80 the parser trusts the width column (1 / 2 / 4) over the prefix and rewrites the prefix to match - hand-edited dumps occasionally disagree with themselves.

Parser, classifier and CLI

crates/cheats parses both files into one Database, then sorts every address into a RAM region (a Category) with a detail label such as the record field it hits.

ItemPurpose
parse_gs_text / parse_mednafen_chtEither file → Database
Database::dedupe_identicalDrop the "Have 99 Items × 70" duplicate sprawl
classify_addressOne address → Category + detail label
CategoryCharacterRecord / PartyMoney / Inventory / BattleActor / ScriptVmGlobal / PadInput / CameraGlobal / WorldStoryFlag / Minigame / FieldVmCollision / ScratchActiveActor / CodePatch / Unknown
taxonomy::classify_writesRoll a set of changed RAM addresses into per-region buckets; the classification half of a write tracer (mednafen-state write-taxonomy LEFT RIGHT)
cheat-tool list data/cheats/legaia-ntsc-u.gs.txt
cheat-tool classify data/cheats/legaia-ntsc-u.gs.txt --dedupe
cheat-tool diff data/cheats/legaia-ntsc-u.gs.txt data/cheats/legaia-ntsc-u.cht
cheat-tool offset-table data/cheats/legaia-ntsc-u.cht

parse and extract-offsets are the other subcommands. In the release archive the databases are embedded, so no path is needed (modding guide).

What the write taxonomy is for

Diffing two save states yields a set of changed addresses. classify_writes flags the two interesting kinds: writes outside every known data region (Unknown) and writes into the 0x8007Bxxx script-VM / build-flag scratch (ScriptVmGlobal, the band holding the 0x8007B8C2 build-mode selector and the debug-menu enable). It is pure - input is a list of u32 - so it is unit-tested on synthetic deltas.

What the corpus pins, per region

Each row is one RAM region the classifier knows and what the cheats in it establish about the game's memory layout.

Region (Category)AddressesWhat the cheats establish
CharacterRecord0x80084708 + slot * 0x414Per-character 0x414-byte record; every offset is named on the save record page
PartyMoney0x80084540..0x800845DCParty-wide globals: scene-name slot 0x80084540, game time 0x80084570 (u32), member count 0x80084594, member ids + Noa / Gala join gates 0x80084598..9A, gold 0x8008459C (u32), casino coins 0x800845A4 / A6, scene-name mirror 0x800845DC
Inventory0x80085958, 2-byte stride(id, count) pairs. "Have 99 Items" stamps 0x63 across a 72-slot page - the cheat's span, not an engine bound; the live window is 128 or 256 slots (inventory)
BattleActor0x800EC9E8 + n * 0x2D4Per-actor battle record; HP / MP offsets in the table below
ScriptVmGlobal0x8007B450..0x8007B83CMenu-request, encounter counter, save-anywhere, pad and next-game-mode registers (table below)
CameraGlobal0x8007B6F4Camera mode word ("Control Camera", "Small Maps")
WorldStoryFlag0x80085600..0x80085800Story-flag block. No shipped cheat lands here; the Door-of-Wind bitmask at 0x8008575C / 5E is claimed first by the script-VM arm (classifier ordering, not a fact about the cheat)
Minigame0x801D3CAC..0x801DC06CMinigame scratch - fishing tension / cast power / life / fish id at 0x801D9168 / 9274 / 9298 / 91CC, Baka Fighter 0x801DBFC4 / BFF0 / C06C, dance points 0x801D53CC, slot machine 0x801D3CAC. Citations only; the engine's minigame ports do not consume them
FieldVmCollision0x801D065C / 06BC / 071C / 078C"Walk Thru Walls": four 1-byte gates in the field overlay; 0x06 in all four disables the collision check
ScratchActiveActor0x8007A6BCScratch for the currently-acting character; every "Infinite HP / MP" hits it first, then the per-record copy
CodePatchfour sitesCheats that patch instructions, not data (table below)

Battle actor offsets

OffsetFieldCheat
+0x14Chp_curr"Infinite HP" (per character)
+0x14Ehp_maxread at battle init
+0x150mp_curr"Infinite MP"
+0x152mp_max
+0x172hp_max_settled"Infinite HP" second site
+0x174mp_max_settled"Infinite MP" second site

The second-site pair is the copy that survives the per-frame stat-aggregation clamp (how we know); cheats write both so the value stays pinned through clamping.

Script-VM globals

AddressCheatEngine meaning
0x8007B450"Status Modifier Menu", "Save Anywhere", "Shop Modifier", "End of Game Stat Page"Menu-request register the menu overlay polls each frame
0x8007B5FC"No Random Battles"Encounter step counter (set to 0x377 to force or suppress a trigger)
0x8007B6A8"Save Anywhere (Press Select+X)"Save-anywhere allow flag
0x8007B7C0condition gate in many cheatsPad state register the D0 / E0 lines read
0x8007B83C"Press R2 For Debug Menu"Next game-mode register (0x1A = FMV)

Code patches

Three cheats write 0x2400 to an instruction's upper halfword (addr % 4 == 2), turning it into addiu $zero, $zero, imm - the GameShark nop idiom. The fourth shortens a branch. All four are callsite anchors a static address scan would not find.

AddressCheatEffect
0x8004309E"Infinite Items All Slots"nops the count-decrement instruction
0x8004390E"Remove Vahn's Chest"nops a draw-call site
0x8007EA96"Maxed HP for All Characters"Past the end of the SCUS image (text ends 0x8007B800) - patches something other than SCUS code
0x800422F4"Bought Any Item ... 99 Quantity"Writes 0001 over bne r2, r0, +2 in the inventory-add clamp, so the clamp to 99 always runs

Runtime applier

legaia-engine play-window --cheat-file <PATH> applies every entry once at boot, routing each write through the ram_map registry to the matching World / CharacterRecord field. Conditional lines count as always-true unless --cheat-strict is given (which then skips every button-gated cheat, since the engine does not emulate the pad register).

Cheat report (49 entries, 96 writes; 71 applied, 25 unmapped, 0 unknown):
  ok    Infinite HP (Vahn)............... 4/4 writes
  ok    Infinite Gold (Never Glitchy).... 1/1 writes
  skip  Walk Thru Walls.................. 0/4 writes
  • ok - every write mapped onto engine state.
  • skip - every write landed in a region ram_map does not map (Walk Thru Walls: FieldVmCollision).
  • part - a mixed entry.

The report is a memory-map regression check: a cheat that stops applying means the engine field was renamed (update ram_map), is no longer exposed (update WorldField), or the database row is stale.

How we know

EvidenceAddressWhat it proves
Cheat corpus itselfevery row aboveEach published code is an (address, value) pair that visibly worked on hardware
Stat aggregation clampFUN_80042558Why "Infinite HP" needs the +0x172 / +0x174 second site
Next-mode writerFUN_801E30E40x8007B83C is the next-game-mode register (writes 0x1A for FMV)
Inventory-add clamp0x800422F4The slti r2,r2,100 / addiu r3,99 / sb sequence the "99 quantity" patch shortens into
SCUS image extent0x80010000..0x8007B8000x8007EA96 is not SCUS code

See also