Builds and debug features
Which Legend of Legaia discs exist and how their executables differ, and the build-level facts that matter when testing against a running game: the debug flags and their pad chords, the developer menus behind them and how to reach them in the port, and the RAM cells that published cheat codes poke. The anchor build is the North American retail disc, SCUS-94254; every address on this page is that build's unless a column says otherwise.
At a glance
- Anchor build
SCUS-94254, the NA retail disc (executableSCUS_942.54).- Debug menu
- Set the byte
0x8007B98F(GameShark8007B98F 0001), then press SELECT + △ on controller port 2. - In the port
LEGAIA_DEV_MENU=1forplay-window; the Dev-menu checkbox on the browser play page.- Sources
- Public cheat-code databases and save-state guides, cross-checked against the disassembly where a row cites a function or an instruction address.
- Terms
PROTis the disc's main archive (PROT.DAT); an overlay is a code image the game loads from it into RAM at runtime.
| If you want | Go to |
|---|---|
| Which discs exist, and how their executables differ | Known builds, region enum |
| How to switch on the debug menu and what it offers | Debug flags, pad chords, developer menus |
What a CDNAME.TXT block label covers | CDNAME subsystem semantics |
| Cheat-pinned RAM cells | Dispatch addresses, mini-game state, character struct |
Known builds
| ID | Date | Notes |
|---|---|---|
PAPX-90040 | 1996-06-02 | Trial on PrePre Vol. 14 demo disc |
PAPX-90055 | 1998-08-19 | Demo 2 (JP) |
PCPX-96130 | 1998-08-18 | Demo 1 / store kiosk video (JP) |
SCPS-10059 | 1998-09-09 | JP retail (Regaia Densetsu) |
SCPS-10059 | 1998-11-16 | NA prototype (uses the JP serial) |
SCUS-94366 | 1998-12-21 | NA demo |
SCUS-94254 | 1999-01-29 | NA retail - the project's anchor build |
SCES-01752 | 1999-09-27 | EU English retail |
SCES-01944 | 2000-04-05 | French |
SCES-01945 | 2000-05-10 | German |
SCES-01946 | 2000-04-26 | Italian |
SCES-01947 | 2000 (day unknown) | Spanish |
SCPS-91246 | unknown | "PlayStation The Best" reissue |
SCPS-45340 | unknown | Unknown JP variant |
What differs between the retail executables
The French, German and Italian discs are container-identical to the USA disc - same PROT layout, same monster records - but their executables are not the NTSC-U engine with swapped text. Two gameplay differences:
- No battle-load stat boost. NTSC-U boosts stats at battle load; the PAL executables do not.
- Different battle spoils. PAL pays half the record's gold and the whole record's EXP; NTSC-U pays a quarter of the gold and three quarters of the EXP.
The JP original (SCPS-10059) matches the PAL behaviour on both counts, so both are NTSC-U additions. The Spanish disc and the EU English disc are unmeasured. Details: PAL localizations.
Cross-region testing priority: SCPS-10059 (original JP), then SCUS-94254 (anchor), then SCES-01752 (EU English).
Region enum
legaia_prot::Region captures the three retail regions. ProtIndex carries it as metadata only - the TOC formula and the CDNAME layout are the same in every region.
| Variant | Product codes | Notes |
|---|---|---|
Region::Na | SCUS-94254 | NA retail; the anchor build and the default. |
Region::Jp | SCPS-10059, SCPS-91246 | JP retail and the "PlayStation The Best" reissue. A separate compile: the +0x1B90 shift against NA holds only for the cells it was derived from. |
Region::Eu | SCES-01752, SCES-01944..01947 | EU English plus the FR / DE / IT / ES localisations. Same PROT.DAT layout as NA with the text swapped; the executables differ in spoils and stat boost. No address shift is applied. |
Region::from_product_code(code) maps a disc-ID prefix to its variant; Region::translate_addr(na_addr) applies the per-region shift to an NA-anchor address.
Developer attribution
- Primary explorer
- Prokion (also styled "Procyon"; ぷろきおん in Japanese).
- Co-credited
- Contrail.
- Publisher
- SCEI (JP), SCEA (US), SCEE (EU).
That explains the developer paths visible in SCUS_942.54 strings (H:\PROT\FIELD\<stage>\tim.dat and similar): Sony PsyQ on a Windows host with H: mapped to the project tree.
Debug flags
Three flags in the same RAM page decide how much of the developer build the retail disc exposes.
| Flag | JP address | Effect |
|---|---|---|
0x8007B8C2 | shifted by 0x1B90 | Dev / retail loader-path flag. Retail boots it to 1 (the store at 0x80015F08), selecting the PROT-index path; the == 0 path is the h:\PROT\FIELD\<stage>\… developer branch in FUN_800255B8 and its sisters. |
0x8007B9B0 | - | Overlay print flag, separate from the menu enable. The slot-A minigame overlays gate their printf-style readouts on it, several of them also on held pad bit 0x2; in the fishing overlay that pair also swaps the bite cadence for a debug value. |
0x8007B98F | 0x8007D51F | In-game debug menu enable. Read as the high byte of the word at 0x8007B98C: the GameShark byte write 8007B98F 0001 makes that little-endian word non-zero (0x01000000), enabling every debug branch with one check. |
All three have static writers in SCUS_942.54, reached $gp-relative ($gp = 0x8007B318) - which is why a cross-reference sweep that only looks for lui pairs reports none. Published GameShark codes also prove all three are writable at runtime.
| Cell | Writer(s) |
|---|---|
0x8007B8C2 | sh at 0x80015F08 (gp+0x5AA) - the retail boot-to-1 store |
0x8007B98C | sw at 0x8001D444 (clear), 0x8001D490, 0x8001D4B0 (gp+0x674) |
0x8007B9B0 | sw zero at 0x8001D448 (gp+0x698) |
Only the byte 0x8007B98F has no accessor of its own; it is reached as the top byte of the word at 0x8007B98C.
JP addresses are not one shift away
The 0x1B90-byte shift between the JP and NA debug-menu byte is what Region::translate_addr applies, and it holds for the cells it was derived from (the published cheat pair), not for the build as a whole. SCPS_100.59 is a separate compile, and no single shift maps NA addresses onto it:
| What | JP | NA |
|---|---|---|
| Inventory bag | 0x801CBFC8 | 0x80085958 |
| Gold | 0x801CAC0C | 0x8008459C |
| Coins | 0x801CAC14 | 0x800845A4 |
| Overlay slot A (PROT 0897 / 0898 / 0899) | 0x801D05C8 | 0x801CE818 (shift 0x1DB0) |
| Slot-B cast modules (PROT 0903..0966) | 0x801F9DB0 | 0x801F69D8 (shift 0x33D8) |
| Scripted-fight flag | ctx[+0x1E7] | ctx[+0x287] |
| Cast phase | ctx[+0x1D9] | ctx[+0x279] |
| Round counter | ctx[+0x1EA] | ctx[+0x28A] |
The battle-context fields sit 0xA0 lower in JP. The French SCES_019.44, by contrast, is the NA code relocated, with slot A at 0x801CF0A8 and slot B at 0x801F7400.
Debug pad chords
Once 0x8007B98F is set, these chords are live. The dispatcher is FUN_8001822C.
| Chord | Effect |
|---|---|
| SELECT + △ | Open the debug menu (item give, map change, stats, event flags, …) |
| SELECT + START | Start the game in Debug Mode - the full-screen configuration tester in PROT 0971, reached as game mode 0 / CONFIG INIT (see boot) |
| R1 + R2 + ✕ | Coordinates debug overlay + free camera |
| ○ (in coordinates mode) | Dim lighting |
| ▢ (in coordinates mode) | Toggle the verbose overlay |
Each frame FUN_8001822C reads the BIOS pad data at 0x800840F8 and builds a 32-bit button mask, _DAT_8007B850. If the debug word _DAT_8007B98C is zero it strips the upper 16 bits - the controller-2 / debug half - and that is the master gate. A large block guarded by _DAT_8007B98C != 0 then handles the chords.
Two consequences matter when driving the menu externally:
- The chords are port-2 bindings. The same chord on port 1 is ignored.
- The gate does not latch for the session. The debug word's only
swwriter is the shared menu / title / save-init routine, which scene transitions run, so entering a scene can clear_DAT_8007B98Cmid-session. Re-assert it rather than setting it once.
Globals behind GameShark D-codes
0x8007B7C0- Previous-frame button mask, so
D007B7C0 XXXXmeans "wait for the player to press XXXX". _DAT_8007B874mask & ~prev- newly pressed this frame.0x8007B7C4mask ^ prev- buttons that changed.
Camera control axes
The coordinates debug overlay names its camera axes in film-crew terms - a handy string-search anchor for finding the camera-debug renderer.
| Label | Axis | Label | Axis | Label | Axis |
|---|---|---|---|---|---|
VX | truck | WX | track | AX | crane |
VY | pedestal | WY | - | AY | tongue / pan |
VZ | zoom | WZ | dolly | AZ | roll |
SC | field of view |
The labels live in the field overlay (PROT 0897), not in SCUS_942.54. The block starts at 0x801CF1E4 and runs VX VY VZ AX AY AZ WX WZ SC WY, then DCX / DCY / DCZ, MX0 / MY0 / MX1 / MY1, and PLAYER_STAT / HEIGHT_STAT / FREEZE_STAT / ANM_FREEZE_FLAG. Search the extracted PROT entry, not the executable.
CDNAME subsystem semantics
The block labels of CDNAME.TXT past the per-scene blocks. The numbers are the file's own #define values, which are raw in-RAM TOC indices: the extraction entry (the NNNN in a "PROT entry NNNN" citation) is the define minus 2 (see CDNAME). A label is a hint, not a verdict - several blocks hold something other than their name suggests.
#define | Label | Extraction | What the entries hold |
|---|---|---|---|
| 0..864 | per-scene names | - | Stage / field blocks (towns, dungeons, world maps, cutscenes), one block per scene name - named on scene names |
| 865..868 | battle_data | 863..866 | The four player battle files PLAYER1..4 (battle data pack) |
| 869 | monster_data | 867 | Monster archive: stat records, meshes, animations |
| 870..871 | sound_data | 868..869 | Sound-driver data |
| 872..875 | befect_data | 870..873 | Battle effects etim / etmd / vdf / efect (effect bundle) |
| 876 | player_data | 874 | Player character pack (character mesh) |
| 877..890 | sound_data2 | 875..888 | Sound-driver data |
| 891..892 | level_up | 889..890 | Level-up block; entry 890 is the title TIM |
| 893 | monster_se | 891 | Monster sound effects |
| 894 | card_data | 892 | Memory-card screen kanji font |
| 895..896 | bat_back_dat | 893..894 | summon.dat / readef.DAT battle side-band (summon / readef) |
| 897..971 | xxx_dat | 895..969 | Code overlays: boot init.pak (895), the field / battle / menu images (897..899), the slot-B band (900..966) and the battle stage modules (967..969) |
| 972..973 | move_program_no | 970..971 | STR / MDEC movie player (970) and the debug-menu overlay (971) |
| 974..979 | other_game | 972..977 | Mini-game overlays: fishing (972), dev modules (973 / 974), slot machine (975), Baka Fighter (976), Muscle Dome hub (977) |
| 980..989 | monster_test | 978..987 | More overlays, among them FIELD BACK READ (978), dance (980) and the world-map top view (981) |
| 990..1071 | music_test / music_01 | 988..1069 | BGM sequences + banks (music tracks) |
| 1072..1194 | vab_01 | 1070..1192 | VAB instrument banks |
| 1195..1232 | other1 / 4 / 5 / 6 / 7 | 1193..1230 | Mini-game and contest assets (e.g. the ringside stills at 1221 / 1222) |
Dispatch RAM addresses (GameHacking.org)
PSX RAM cells (KSEG0, 0x80000000 base) that published cheats use - useful anchors for runtime tracing.
| Address | Purpose |
|---|---|
0x80084540 | Current map ID (writable; "Map Modifier" and "View Credits" use it) |
0x8007B6F4 | "Small maps" debug mode flag |
0x8007B7C0 | Previous-frame button mask - what D0 / E0 conditional codes compare against. FUN_8001822C loads it, XORs it with the fresh mask into the edge words 0x8007B7C4 / 0x8007B874, then stores the fresh mask back. Not a dispatch selector. |
0x8007B450 | Debug-dispatch parameter slot - the menu-request register the menu overlay polls each frame |
0x800422F4 | Not a RAM cell - a branch inside the executable's inventory-add clamp. The "99 quantity" cheat writes 0001 there, shortening the branch so the clamp always runs (see cheat databases). |
Sample values the cheats write to 0x8007B450:
| Value | Effect |
|---|---|
0x0001 | Open the Status Modifier menu |
0x000D | Open the name modifier for Gala |
0x0011 | Open the name modifier for Vahn |
0x0085 | Show the end-of-game stat page |
0x4097 | "Save Anywhere" prompt |
When the trigger is 0x0003, writing a map ID to 0x80084540 warps there.
Mini-game state regions
Each mini-game is a slot-A overlay image: the mode-24 warp streams its PROT entry (fishing 0972, slot machine 0975, Baka Fighter 0976, Muscle Dome 0977, dance 0980) to 0x801CE818 over whatever was resident. The addresses below name mini-game state only while that mini-game's image is loaded; per-image extents are on the RAM map.
| Address | Mini-game | Purpose |
|---|---|---|
0x801D9168 | Fishing | Tension |
0x801D9274 | Fishing | Casting power |
0x801D9298 | Fishing | Life |
0x801D91CC | Fishing | Fish ID modifier |
0x801D53CC | Dancing | Dance points |
0x801DBFC4 | Baka Fighter | Player life |
0x801DC06C | Baka Fighter | Computer life |
Character struct
Stride 0x414 bytes (1044), confirmed by file-offset deltas in ePSXe save states (Vahn / Noa / Gala). Four slots (Vahn / Noa / Gala / Terra the wolf) make a party block of about 4096 bytes - one PSX RAM page. Offsets are relative to the Level field, all u16 little-endian unless noted.
| Offset | Field |
|---|---|
-0x2C / -0x2A | HP max / HP current |
-0x28 / -0x26 | MP max / MP current |
-0x20..-0x16 | AGL / ATK / UDF / LDF / SPD / INT, current |
-0x14 / -0x12 | HP / MP unequipped (base) |
-0x0E..-0x04 | AGL / ATK / UDF / LDF / SPD / INT, unequipped (base) |
+0x00 | Level |
+0x55 | Moves-learned count (u8) |
+0x56.. | Moves array (u8 IDs, contiguous) |
+0x177 | Name (string) |
"Current" stats are post-equipment; "unequipped" are the base values. The stat order is fixed across both blocks and all four slots. The full record is on per-character save record.
Money and inventory
- Money
- 24-bit (three consecutive
u8bytes, little-endian). Cap0x00FFFFFF= 16,777,215 G. - Inventory
- One shared list, 2 bytes per entry
[item_id, quantity]. Weapons, armor, items and Ra-Seru levels all live in it.
Item ID table
Up to 256 IDs. Canonical NA assignments:
| Range | Class |
|---|---|
0x65..0x9A, 0xA3 | Items (consumables, books, flutes) |
0x01..0x19 | Ra-Seru weapons per character × level (Meta = Vahn 1-9, Terra = Noa 1-8, Ozma = Gala 1-7, plus 0x12 = empty Noa slot) |
0x1A..0x33, 0x52 (empty), 0xBA (Astral Sword) | Normal weapons |
0x34..0x42 | Helmets |
0x43..0x57 | Armors |
0x58+ | Boots |
ID 0x12 is "empty wp. for Noa" and 0x52 is "empty wp. for Vahn" - reserved-but-empty slots.
Move tables (Tactical Arts)
Slot 0x00 is the Miracle Art starter on every character (action constant 0x1B = Vahn's Craze / Noa's Ark / Biron Rage, gated by a story flag). Vahn and Gala carry their 14 regular arts at slots 0x01..0x0E. Noa's table runs to slot 0x10 with holes at 0x02 / 0x03 - her Hurricane Kick covers three on-disc levels through one slot - so her slot 0x0F is the ordinary art Acrobatic Blitz, not a Miracle Art. Mirror: legaia_art::tables.
| Character | Arts |
|---|---|
Vahn (slots 0x01..0x0E) | Burning Flare, Fire Blow, Tornado Flame, Cyclone, Hurricane, PK Combo, Spin Combo, Pyro Pummel, Cross-Kick, Power Punch, Slash Kick, Somersault, Charging Scorch, Hyper Elbow |
| Noa (display order) | Lizard Tail, Acrobatic Blitz, Sonic Javelin, Blizzard Bash, Mirage Lancer, Dolphin Attack, Bird Step, Swan Driver, Tough Love, Rushing Gale, Tempest Break, Frost Breath, Vulture Blade, Hurricane Kick |
| Gala | Flying Knee Attack, Battering Ram, Ironhead, Back Punch, Guillotine, Head-Splitter, Side Kick, Black Rain, Neo Raising, Electro Thrash, Bull Horns, Thunder Punch, Lightning Storm, Explosive Fist |
The field VM's EXEC_MOVE (op 0x22, see script VM) feeds these IDs into the move-table consumer at FUN_800204F8; the file format is on MDT.
Translation notes
Character names that differ between the JP and NA scripts - they matter when comparing MES text across regions:
| NA | JP |
|---|---|
| Gala | Gaara |
| Vahn | Vann |
| Noa | Noah |
| Tetsu | Todd |
Unused content
Useful as fixtures for validating extractors:
- Unused enemies: index 78 ("Comm") and 140 ("Evil Bat") in the monster table.
- Unused items: "Something Good" (sells for 50,000 G) and an unnamed accessory that forces Seru-only encounters.
- Placeholder battle background: a graphic containing ぷろきおん in hiragana, loaded when a real battle background is missing.
- Placeholder music: tracks copied from Alundra (the Zazan battle theme) and Wild ARMs (battle theme) sit in the SEQ / VAB data.