At a glance

Two front ends
The browser patcher (nothing uploaded; presets or fine-tuning) and the legaia-patcher CLI (scriptable; emits a shareable PPF). Same code, same bytes for the same seed.
Modes
Shuffle permutes what the disc already has (totals preserved); Random draws each slot from the valid pool; none leaves it alone. Sliders and manual edits are seedless.
Editing rule
Same-size in place - the disc layout never moves. Only door retargets and place renames resize a record, through the MAN relocation engine. Anything that cannot re-pack into its footprint is skipped and reported.
Disc
USA only (SCUS-94254); a PAL disc is refused rather than hybridised.
Crate
crates/patcher (legaia_patcher), built on legaia_lzs::compress, legaia_iso::write and DiscPatcher. Internals: randomizer internals.
Sony bytes
None ship. A PPF carries only the deltas between your disc and the patched one.
Engine
Never involved - the disc is edited and retail (or the port) plays it. Exception: Seru trading, whose vendor UI the port draws.

How a patch reaches the disc

A PlayStation disc is not a folder of files. Almost every value the randomizer changes sits inside a compressed block, on a sector whose checksums must be recomputed, at an address nothing else may move. Every feature on this page uses one of six techniques, from “overwrite a byte in a table” up to “host new machine code in space the game never uses”.

The six patch tiers, from static-table edits to code hosted in an overlay's dead region, with the features that use each same-size in place resizes one record new machine code Astatic tables steals, spell costs,equip bonuses Binside LZS slots drops, monster stats,arts, difficulty Cscript operands chests, shops,encounters DMAN relocation doors, place names,starting-bag overflow Erodata-gap code flee EXP, enemy ally,shiny Seru Foverlay dead space Seru trading,Super Arts list
Tier A: static tables · B: LZS slots · C: field-VM operands · D: MAN relocation · E: rodata-gap code · F: overlay dead region.

Three terms recur in the feature blocks below:

  • MAN - a scene's script-and-data bundle: its encounters, chests, shops, doors and dialogue, LZS-compressed with no slack. Re-packing it must land inside its original span.
  • Monster slot - each monster's record in the battle archive (PROT entry 867) has a fixed 0x14000-byte slot, so a re-packed record is zero-padded back to size.
  • Code hook - a two-word jump from a retail routine into hand-assembled MIPS hosted in space the game never reads, which replays the displaced instructions and returns. Several hooks share one small arena and are mutually exclusive.

The patch chain, the checksum math and the two injection traps are on the internals page.

CLI: legaia-patcher

The scriptable path: disc + seed in, a portable PPF out (default <input>.ppf), optionally a patched .bin + .cue (--output) and a spoiler-safe TOML run record (--manifest). Disc arguments take a raw Mode 2/2352 .bin or a .cue. The seed resolves from a number or a hashed string and is always printed, so a run reproduces byte-for-byte.

legaia-patcher randomize --input DISC.bin --seed myrun --drops shuffle \
    --encounters shuffle --chests shuffle --shops shuffle --steals shuffle \
    --doors shuffle --door-coupling coupled --starting-items 3 \
    --patch run.ppf --manifest run.toml
legaia-patcher verify --input DISC.bin --patch run.ppf     # apply to a copy + sanity-check
legaia-patcher chests --input DISC.bin                     # read-only listing
SubcommandDoes
randomizeApplies every flag in the feature blocks below. --dry-run plans without writing; --allow-region-mismatch overrides the USA-disc check.
verifyApplies a PPF to a copy of your disc and confirms it still parses end to end - a recipient's check.
drops, chests, steals, shops, casino, doors, house-doors, map-doors, starting-items, monster-stats, move-powers, affinity, spell-costs, arts, equip-bonuses, weapon-specialty, equipment, fishing, locations, earth-eggRead-only listings of the population each feature edits, with item and scene names read off your disc.
monster-block--dump one monster's decoded record for hex editing; --write re-packs it into its slot. Walkthrough: modding guide.
tim-list, tim-export, tim-replaceTexture replacement.
monster-modelCustom monster models (export / import).
translateLanguage packs.

Mode flags (--drops, --encounters, …) take shuffle / random / none; the rest are toggles or values. Each flag is documented in its feature block.

Loot & economy

What falls out of a monster, what is in the chest, what the shop and the casino sell, what the Evil God Icon steals. Quest and story items always stay put, so a re-rolled game is finishable.

Monster drops

Every monster has one drop slot (item + chance); the pass deals those slots out again across the roster.

FlagValuesNotes
--dropsshuffle / random / noneShuffle preserves the drop economy; random draws from real, named items.
How it is patched

Tier B. The drop is the byte pair at +0x48 (item) / +0x49 (chance) of the decoded monster record; each edit is decompress → mutate → recompress → zero-pad of that monster's slot. A slot too tight to re-pack is skipped and reported. See battle data pack and the tier B write-up.

Equipment drops

Retail never drops gear; with this on, any battle has a small chance of paying out one extra weapon, armor piece or accessory on top of the normal drop - rarer the better the gear and the weaker the enemy.

FlagValuesNotes
--equipment-dropstoggleOn in every browser preset except Vanilla.
--equipment-drop-chancepercent, default 5Per-battle roll for the bonus piece.
How it is patched

Tier E code hook. A record has one drop slot, so no data edit can make a monster drop two things; instead the battle-end reward routine is detoured after it grants the normal drop. The injected routine rolls rand() % 100 < chance with the battle RNG, picks an id from an embedded equipment table, adds it, replays the two displaced instructions and returns. It runs once per battle.

Equipment ids are recovered by name: the curated gamedata weapon / armor / accessory names are matched case-insensitively against the disc's own item-name table, so no Sony bytes ship. The rate is tiered by gear price (early ≤ 3700 G, mid ≤ 17000 G, late above) and by monster EXP (early ≤ 600, mid ≤ 3000, late above), taking the lower tier: 3% / 2% / 1%. Sub-percent rates are unrepresentable because the retail roll is integer.

Treasure chests

A chest's item and the message announcing it are reassigned together, so the text always names what you got; keys, quest tools, letters and every other progression item stay where they are.

FlagValuesNotes
--chestsshuffle / random / noneGlobal across every chest on the disc.
--keep-static-itemsid list, or ""Overrides the protected set; empty string randomizes everything.
How it is patched

Tier C. A chest grants its item through the field VM's GIVE_ITEM opcode 0x39, a single inline operand byte in the scene's script. The sites are found by an opcode-aware walk that skips inline dialogue segments (a byte scan would false-hit a 0x39 inside text) and is bounded to each record. The chest's announcement names the item again through a separate dialogue token 0xC2 <id>; both bytes are rewritten together (display vs grant) so the flavour text matches the grant. Scenes arrive as either a bundle MAN or a raw streaming chunk; both carriers are walked, so the streamed dungeons (Mt. Rikuroa, Mt. Balden) join the pool. A scene too tight to re-pack keeps its items and its ids leave the shuffle pool.

Keep-static items. The protected set is derived from the disc, not a hand list: every named item the item table prices at 0 (the game's own “never sold” marker) minus the chest-found gear that is merely unsold (the Ra-Seru set and the Astral Sword). A protected chest keeps its item and its id never enters another chest.

Town shops (what stores sell)

Each store's stock list is rewritten across every shop on the disc; quest items never appear, and gear that is normally chest-only is given a price so it can.

FlagValuesNotes
--shopsshuffle / random / noneRandom draws from the sellable (priced > 0) pool.
How it is patched

Tier C. A gold merchant's stock is inline in the scene MAN, in the payload of field-VM op 0x49 sub-op 0: [u8 count][count × u8 item_id][ASCII name\0]. Sites are found by a signature scan rather than an opcode walk, because a confirm-picker ahead of the op desyncs a linear walk; strict validation (sub-op byte, small count, non-zero ids, printable name, id names a real item) rules out false hits. Item ids are rewritten same-size and the MAN recompressed. The chest-only Ra-Seru gear and Astral Sword ship at price 0, so the pass first prices them (approximated from the nearest priced gear of the same type) with a same-size SCUS edit.

Casino prize exchange

The casino counter's prizes move around; each keeps its coin price and the progression gate that unlocks it, so the counter still fills in as you play.

FlagValuesNotes
--casinoshuffle / random / noneWhole records move, so price + gate stay with the prize.
How it is patched

Tier A. The prize list is a static table in the menu overlay's data segment (PROT entry 899, stored raw): four 0x60-byte blocks of 8-byte [u16 item][u16 story-gate][u32 coin-price] records. It debits the casino coin bank, not gold, which is how it is told apart from a merchant. Same-size raw edit, no LZS.

Steal items (Evil God Icon)

What each monster carries for the Evil God Icon changes; the odds of stealing it never do.

FlagValuesNotes
--stealsshuffle / random / noneChance byte preserved per monster.
How it is patched

Tier A. The steal table is a static SCUS_942.54 table of [chance, item] per 1-based monster id - not part of the monster record. The item byte is overwritten straight into the executable; nothing can overflow, so nothing is ever skipped.

Fishing prize prices

Reprice any prize at the Buma and Vidna fishing exchanges; a prize only appears once you can afford it, so the price also moves when it shows up.

FlagValuesNotes
--fishing-priceITEM=POINTS, repeatablee.g. 0x6F=500. A prize sold at both venues is one row.
How it is patched

Tier A. Each prize is a raw 12-byte row [u32 limit][u32 price][u32 item] in the fishing-exchange table (parser legaia_asset::fishing_exchange); rows can be repriced, not added, removed or swapped. See the fishing minigame and the spirit fish write-up.

Earth Egg coin threshold

Set how many casino coins the Sol Tower Prize Counter demands for the Earth Ra-Seru Egg (retail 100,000); the game debits exactly that many.

FlagValuesNotes
--earth-egg-price1 – 8,388,608A hidden scripted exchange, not a casino-table row.
How it is patched

Tier C. The threshold is a script literal in the Sol Tower scene MAN, rewritten same-size and recompressed.

Fights

What jumps you on the road, how tough it is, how hard its specials hit and which element beats which. The shuffles move values between monsters; the sliders scale every monster together, ignore the seed, and compose with the shuffles.

Random encounters

Each area's random formations are refilled from its own roster, from anywhere in its kingdom, or from the whole disc; bosses and story fights are never touched, and an over-strong monster dropped into an early area arrives alone.

FlagValuesNotes
--encountersshuffle / random / noneShuffle conserves the scope-wide monster census.
--encounter-scopescene (default) / kingdom / worldKingdoms are read off CDNAME.TXT, anchored on the three overworld maps.
--no-solo-strong-encounterstoggleOpts out of the solo pass (on by default).
--solo-strong-thresholdpercent, default 200A pack whose strongest member exceeds this share of the area's norm collapses to one enemy.
How it is patched

Tier C. Formations are encounter records [3 reserved][u8 count][u8 ids] inside the scene MAN; monster id bytes are rewritten and the stream recompressed. Both MAN carriers are walked (bundle MAN and raw streaming chunk), so the v12-family dungeons are covered.

Boss protection. A formation is random only if some region with a non-zero encounter rate reaches it; formations the script starts by index (bosses, story fights) stay byte-identical and never enter a donor pool. An explicit id guard pins Gimard, whose tutorial formation a rate>0 region happens to span.

Solo-strong pass. Each monster is scored by its combat-stat budget; each scene's baseline is the mean of its original random monsters. Any multi-monster random formation whose strongest member clears the threshold is cut to that monster alone (same-size: count set to 1, rest zeroed). Wider scopes work because the battle loader streams any monster's slot by id on demand.

Monster combat stats

Each stat column is dealt out again across the roster, so the total difficulty budget is unchanged but nobody is where you remember; tutorial enemies and story bosses keep their numbers.

FlagValuesNotes
--monster-statsshuffle / random / noneHP / MP / ATK / DEF↑ / DEF↓ / INT / SPD; AGL untouched.
How it is patched

Tier B. Stats are u16 halfwords at fixed offsets of the decoded monster record (HP +0x0C, MP +0x10, then ATK / DEF↑ / DEF↓ / INT / SPD). The pass is column-wise: shuffle permutes one stat across the roster (multiset preserved), random draws each cell from that column. The AGL action gauge (+0x0E) is excluded because it gates the AI's action economy. Protected ids (the Rim Elm sparring partner, the first wild Piura, every story-boss form) are neither source nor target. Each slot re-packs to 0x14000.

Enemy difficulty scale

One dial that makes every enemy - bosses included - tougher or gentler without moving anything between monsters; random encounters and bosses can get their own dial, and so can each stat.

FlagValuesNotes
--enemy-stat-scale0.1 – 5 (retail 1)Whole roster. Seedless; applied after --monster-stats.
  stat=mult listhp=3, attack=2,defense=0.5Scales only the named stats.
  regular: / boss: split'regular:0.75|boss:2'Each half may itself be a stat list.
How it is patched

Tier B, same seven halfwords as the stat shuffle. Integer permille arithmetic ((v * permille + 500) / 1000), zero stays zero, non-zero floors at 1, saturates at u16. Bosses are scaled - a difficulty knob that skipped the set-pieces would miss the hardest fights - except the unwinnable Rim Elm sparring partner, pinned in both directions. AGL is left alone so a 5x run is harder, not a slideshow of enemy turns; EXP, gold and drops never move.

Which enemies are bosses is read off the disc through the encounter randomizer's mask (a monster seen only in script-started formations), unioned with the curated story-boss list for the mid-battle forms no formation names, and with the tutorial enemies forced back to regular. The loader's own fixed ATK / DEF / INT boost applies on top when a record becomes a live actor.

Experience multiplier

Every monster pays a multiple of its usual experience, on wins and on escapes alike; gold and drops are untouched.

FlagValuesNotes
--exp-scale0.1 – 5 (retail 1)Seedless. Browser: Experience multiplier slider.
How it is patched

Tier B. One field is the whole feature: the base EXP halfword at decoded-record +0x46, which the victory-spoils routine (×3/4, split among living members) and the run-away EXP hook both read. Same permille arithmetic and clamps as the difficulty scale.

Seru catch rate

Replace the per-monster absorb odds with one flat chance - from “every kill absorbs” to “never”, for a run without Seru magic.

FlagValuesNotes
--seru-catch-rate0 – 100 percentOnly the 63 capturable records change; the Ivory Book's +30 still applies.
How it is patched

Tier B. A killing physical blow rolls a d100 against the record's catch byte (+0x3F) when its Seru id (+0x3E) is non-zero; retail rates run from 80% (Gimard) to 1%. The byte is overwritten and the slot re-packed. Seedless.

Enemy attack count

Enemies swing more (or fewer) times per attack turn without changing how hard each hit lands; nothing drops below one hit.

FlagValuesNotes
--enemy-attack-count0.1 – 5 (retail 1)Seedless. Movesets never change, only counts.
How it is patched

Tier B. The hit count is not stored: the AI queues strikes while a per-round AGL budget (the record's AGL stat) affords each attack move's AGL-cost byte, bounded at 15. The dial divides each retail-affordable cost byte by the multiplier (round half up) and clamps it to the budget, so an attacker always keeps at least one hit. Sentinel, overpriced and zero-cost entries and spell casts are byte-identical; AGL itself never moves, so this composes with the difficulty scale.

Special-attack power

How hard enemy specials and Seru magic hit is redistributed across the moves; animations, effects and sounds stay with their move, and party Tactical Arts are a separate table.

FlagValuesNotes
--move-powershuffle / random / nonePopulated records only.
How it is patched

Tier A. Only the +0x00 power halfword of each 26-byte move-power record moves (the roll modulus the damage kernel reads); the other 24 bytes - geometry, timing, effect and sound cues - are untouched. PROT entry 898 is stored raw, so the write is same-size in place.

Element-affinity matrix

The 8×8 grid of which element hurts which is scrambled; shuffle keeps the same number of weaknesses and resistances, between different pairs.

FlagValuesNotes
--element-affinityshuffle / random / nonePer-character elements and summon rows untouched.
How it is patched

Tier A. Cells are damage-scale percentages (100 neutral, >100 weak, <100 resist, 0 immune) in matrix[attacker][defender] inside PROT entry 898 (raw). Shuffle permutes the 64 cells; random draws from them. See battle formulas.

Spell MP costs

Every named spell's MP cost is dealt out again; free enemy-only entries never gain a cost.

FlagValuesNotes
--spell-costshuffle / random / noneNamed, non-zero-cost spells only.
How it is patched

Tier A. The cost byte at record +3 of the static spell table in SCUS_942.54; names and target shapes untouched.

Your party

Tactical Arts, the AP gauge that pays for them, gear, and how a new game starts. Most of these are targeted edits aimed at one art or one item rather than seeded shuffles.

Arts button combos

The arrow combo that fires each Tactical Art is reassigned; every art keeps its input count, the menu's arrows always match the real trigger, and Miracle Arts are left alone.

FlagValuesNotes
--artsshuffle / random / noneCombos permute within each length class.
How it is patched

Tiers A + B. A combo lives in two files that must change together: the matcher records in each character's player battle file (LZS, rewritten in place) and the SCUS arts-name table's menu-arrow glyph string. Display strings are deduplicated across characters, so the assignment permutes distinct combo strings per length class. See art records.

Arts damage power

Tune how hard any single Tactical Art hits - power a favourite down for a challenge run, or turn its damage off.

FlagValuesNotes
--arts-powerCOMBO=VALUE; tier 0x0C..=0x1F or 0e.g. RDLDL=0x16. Lower = weaker; 0 disables the hits. Browser: Tactical-Art overrides picker.
How it is patched

Tier B. An art's 1–4 per-strike power bytes sit at +0x24 of its 0xD0-stride record in the character's player battle file; a byte is a tier, mult = [12,18,20,22,28][(v-0xC)%5]. Every active byte of the matched record is set (hit count preserved; a spirit-only art with no damage byte is skipped) and the record recompressed. There is no menu copy to sync. A combo shared by two characters edits both files.

Super Art damage power

Super Arts - the finishers a chain of ordinary arts triggers - have no button combo and no AP of their own, so their damage is edited by name; their AP is the AP of the arts that trigger them.

FlagValuesNotes
--super-art-powerNAME=VALUE; tier 0x0C..=0x1F or 0e.g. "Tri-Somersault"=0x1A. Names match ignoring case and punctuation.
How it is patched

Tier B. A Super Art has its own 0xD0-stride record (name at +0x10, power bytes at +0x24) indexed by action constant: base + (c - 0x10) * 0xD0. The finisher constants are known, so the address is derived and self-checked against the record's name; an unrecognised build yields nothing. To make a Super cheaper to set up, retune its chain arts with the AP override - the browser's Super Art row names them and offers an Add rows button. No per-Super AP field is injected.

Show Super Arts on the move list

Retail never lists a Super Art anywhere; with this on, a Super Art you have performed appears on the in-battle Triangle arts list and on the pause menu's Moves page, sorted by AP, with its name, the AP its chain costs and the arrows you type.

FlagValuesNotes
--show-super-artstoggleArena feature: exclusive with --shiny-seru, --super-arts-pack, --arts-ap-grant / --arts-ap-cost, --delilas-challenge. Terra has no Super Arts.
How it is patched

Tiers E + F. Performed is a per-character bitfield in the one free, save-persistent byte of the character record (+0x75D, the sixteenth learned-id slot no fifteen-art character reaches), set by a two-word detour at the Super applier's match arm. It rides in the save block, so rows survive a save/load.

A row's AP is the chain's sum, read off the arts-name table at patch time; its name is chased from the live art record; its arrows are the Super's physical input derived by the byte-exact retail tokenizer (arts overlap, so Tri-Somersault is seven arrows). The battle list synthesises a 20-byte arts-table record in dead space and jumps the list renderer past its scan into its own hit arm, so retail draws every field; the pager is replaced in place so pages step. The pause-menu half detours the menu overlay's panel renderer with routines hosted in that overlay's dead runs. Both halves are verified live under PCSX-Redux. Known cosmetic gap: the Triangle prompt's page caption can still read “View Hyper Arts list” on a later page.

The battle-list half needs 613 bytes of the 652-byte verified-dead SCUS arena - hence the exclusivity; the arena budget explains why it cannot move into the battle overlay.

Super Arts Pack (by ZetaPhoenix)

A community mod by ZetaPhoenix that gives each character five more Super Arts - each with its own banner, hit count, animation and trigger chain - installed as a disc patch so it works from a cold boot instead of a cheat device.

FlagValuesNotes
--super-arts-packtoggleOff by default, in no preset. Arena feature (exclusive with --show-super-arts and its siblings). The retail five per character are untouched.
How it is patched

ZetaPhoenix authored the payload as a GameShark-style RAM patch: a 3764-byte block at 0x801FD000 holding trigger tables, fifteen names, four MIPS routines and seventeen animation edit-lists. It is installed unmodified: parked in the DMY.DAT annex and streamed in by a twelve-instruction stub entered from battle init, one instruction after the battle overlay's own CD read finishes. That address is free RAM in every state of the project's save library, with no overlay covering it.

Fourteen same-size word edits across ten sites point the game at it - ZetaPhoenix's own hook set, supplied by him and installed verbatim: seven retarget the retail Super-Art applier onto the pack's wider tables (doubling one register turns the 5-row strides into the pack's 10-row strides, and the match arm's exit seed widens with the loop bound so a match still ends the scan), the rest jump into his routines. The one addition is the battle-load stub and its hook, this project's by construction - his RAM patch had nothing to load. New arts: Vahn - Ultra Elbow, Somersault Duo, Searing Rush, Criss-Cross, Blazing Typhoon; Noa - Double Lizard, Falcon Talons, Chilling Smash, Zephyr Swipes, Grand Maelstrom; Gala - Ground Pound, Storm Kick, System Shock, Skyvolt Knee, Raging Bull. The pack also ships the author's fix for retail's mis-centred art name banner (the banner is measured against a placeholder name and only re-measured for regular/Hyper arts), its routine parked behind the battle-load stub - his instruction stream verbatim, relocated out of the SsAPI zero-padding window to read-watch-verified arena space. His licence is to be confirmed before a tagged release ships it.

Arts AP override

Make any Tactical Art cheaper, dearer, or turn it into one that pays you AP each time it lands in a combo.

FlagValuesNotes
--arts-ap-grant[CHAR:]COMBO=1..100Grants AP (capped at 100), castable at any AP level. Menu AP shows 0.
--arts-ap-cost[CHAR:]COMBO=1..100Flat cost in place of retail's computed one. Without a prefix, every character holding the combo.
How it is patched

Tier E. Retail has no per-art AP number - it computes the cost from the art's position in the character's list - so one code hook into the party arts queue-builder (PROT 0898; party slots only) reads a 4 × 32 i8 config table keyed by (character, arts row) hosted in the verified-dead SCUS arena, which is why it is exclusive with the other arena features. Each targeted art's menu AP byte (+2 of the arts-name record) is rewritten to match. Sites and AP math: arts command gauge. Disc-verified; a live battle playtest is what would make it runtime-verified.

AP gauge tuning

The AP gauge that pays for Super and Miracle Arts fills two ways - pressing Spirit and getting hit - and each gets a slider, including negative values that turn the fill into a drain.

FlagValuesNotes
--spirit-ap-100 – 100 (retail 32)0 = pure defensive stance; 100 fills the gauge in one press; negative drains.
--damage-ap-200 – 200 (retail 100)AP per 100% of max HP lost; 0 also drops the min-1 floor; negative drains.
How it is patched

Same-size immediates inside the battle overlay (PROT 0898), no arena. Spirit is the per-action accrual the battle-action state machine adds in its state-0x50 cleanup (8 per action, 0x20 for Spirit) plus the three gauge-widget ramp targets that mirror it, so the animation stays honest. Damage is pct = max(1, damage * 100 / max_hp); the 100 is a shift/add chain, restated as an explicit multiply for any other factor, and it is inlined twice (the closed-form finisher for magic / specials, the arms resolver for physical hits) - the patch writes both and refuses an image whose copies disagree.

The signed accrual tail

The gauge is a u16 and every retail site clamps only against the 100 ceiling, so a negative value needs a floor the consumer honours. On the damage site the dead ceiling words host a bgez floor. The Spirit tail is shared with the +8 every action grants, so the floor and the surviving ceiling do not both fit; they fit because a negative setting makes the AP-Boost-1 arm dead, and its head hosts the relocated over-100 clamp. Consequence: while a slider is negative, the AP-Boost accessory arm is inert. Negative modes are statically verified only. The assembled tail is listed on the internals page.

Equipment stat bonuses

Gear stat bonuses are dealt out again within each slot type - a weapon's numbers only land on another weapon - so the best sword might be an early one.

FlagValuesNotes
--equip-bonusshuffle / random / noneMasks, passives and slot types stay with their row.
How it is patched

Tier A. The [INT, ATK, UDF, LDF, SPD] tuples of the static equipment table in SCUS_942.54, permuted within slot category. Rows are edited, not item ids (several items can share a row), and unreferenced rows are left alone. Composes with the mask pass, which edits the disjoint +6 byte.

Equip mask (who can equip what)

Who can wear what is reshuffled within each slot type; each character keeps exactly as many equippable weapons, body, head and footwear pieces as in retail, just different ones.

FlagValuesNotes
--equip-maskshuffle / random / noneNobody is ever left with zero gear in a slot under shuffle.
How it is patched

Tier A. The +6 equip-character mask (1 Vahn, 2 Noa, 4 Gala, 7 any) of the same table, permuted within slot category (+7 & 0x60). The engine's equip picker reads the same byte, so a patched disc re-gates it there too.

Weapon specialty

Vahn favours blades, Noa claws, Gala clubs - and an off-class weapon makes that character's Arms command wider on the arts bar, so fewer commands fit; this permutes who favours what.

FlagValuesNotes
--weapon-specialtytoggleSeeded bijection: each class keeps one specialist. The Astral Sword stays always-wide.
How it is patched

Tier B. The arm cost is not a runtime class check but a per-(character, weapon) byte baked into the player battle files; each weapon section is decompressed, the byte rewritten for the new relationship, and recompressed in place. See arts command gauge.

Equipment editor (command costs and equip owners)

Two manual edits: set exactly what any weapon costs on the arts bar for any character, and set who can equip any item - give someone a weapon their battle file never had and the patcher carries the model over.

FlagValuesNotes
--swing-costCHAR:ITEM[:up]=COSTRetail tiers 30 favored / 42 off / 54 far; minimum 7. default, raseru, feet[:up] address a section's default record.
--equip-ownerITEM=V|N|G|any|noneRows shared by several items move together (reported).
--no-model-transplanttoggleNew owner keeps the default look.
--allow-relayouttoggle, --output onlyWhole-disc relayout when the DMY.DAT annex is unavailable; no PPF.
How it is patched

Command cost (tier B): each of the four commands is priced by the equipment section that fills it in the character's player battle file - Left and Right by the weapon and the Ra-Seru arm, Down and Up by the footwear's two records (:up). The cost byte is the AP a press charges and the pennant width plus 6. An item the file has no section for falls to the section's default record. Applied after --weapon-specialty, so a named cost wins.

Equip owner (tier A + B): rewrites the item's mask in the SCUS table, then for a weapon cuts the model out of the donor file's record, re-seats it into the new owner's grip (calibrated per weapon class from the weapons both files carry) with the donor's texture tile, palettes and arm cost. Room comes first from re-packing the three player files (PROT 863..865) with the optimal LZS parse, then from parking the rebuilt records in the DMY.DAT annex the loader reaches by descriptor offsets alone - same-size image, still a PPF. Ra-Seru forms, body, head and footwear are never carried over. Details: battle data pack.

Starting bag and starting level

A vanilla New Game begins with five Healing Leaves and a level-1 party; these flags seed a different bag, named extras, warps everywhere, and a higher starting level with real level-N stats.

FlagValuesNotes
--starting-itemsN (0 = vanilla)N distinct random consumables replace the leaves.
--start-withid[:count],…Explicit picks of any kind, additive.
--door-of-wind / --incense[N], default 10Convenience consumables.
--speed-chain / --chicken-heart / --good-luck-bell[N], default 1Convenience accessories.
--all-warpstoggleDoor of Wind reaches every town from the start.
--starting-level2 – 14Whole starting party.
How it is patched

Tiers A + D. There is no starting-inventory table: the new-game init routine builds the bag in code, so the seed code is rewritten in a reclaimable 40-byte region, one packed halfword store per slot (cap 7, or 5 with all-warps). Overflow is granted by splicing a guarded run of silent GIVE_ITEM ops into the opening scene's entry script through the MAN relocation engine.

The starting level is three coordinated SCUS edits: the level literal on every roster slot (magic rank kept at 1); each growth character's cumulative XP seeded to the midpoint of level N's band and the next threshold to reach(N+1) from the disc's own thresholds; and each stat template recomputed from the disc's growth curves (Terra has none). See new-game table, save record, level-up.

Location names

Rename a town or dungeon everywhere the game shows it: the quick-travel list, the world-map label and the on-entry banner each read their own copy off the disc.

FlagValuesNotes
--rename-locationTARGET=NAME, repeatableTARGET = quick-travel index or exact current name; ASCII, up to 23 characters.
How it is patched
DisplayCarrierEdit
quick-travel list16 fixed 0x20-byte SCUS cellssame-size
world-map label29-record table trailing every kingdom MANsame-size
entry banner (+ save-screen row)scene MAN section-2 name, unpaddedtier D relocation

Places with a label but no quick-travel cell (Hunter's Spring, Sol Tower, …) are addressed by name; matching is exact, so Conkram leaves Conkram (Past) alone. The rename runs in the door randomizer's slot, after a language pack. See place names.

New mechanics and fixes

Things retail has no table for. Each is hand-assembled MIPS hosted in space the executable never uses; several share one small arena of dead bytes, so only one arena feature can be on at a time.

Run-away EXP

A successful escape banks a slice of the fight's experience; it shows on the status screen at once and counts toward the next level-up.

FlagValuesNotes
--flee-exptoggleOn in the Balanced / Full Chaos presets.
--flee-exp-pctpercent, default 5Share of the fled formation's EXP.
How it is patched

Tier E. The battle-action state machine's successful-escape teardown state runs once per escape, after party HP has been floored to 1; its first two instructions are detoured to a routine in the SCUS rodata gap that sums each live enemy's EXP halfword, scales it, adds it to every member's cumulative-experience cell (capped at 9,999,999) and returns. The grant is banked, never a level-up mid-fade. The routine shares the gap with the equipment-drop hook, clear of it, so both battle hooks coexist.

Enemy ally (charm)

Some battles open with one enemy already on your side, attacking its former friends - a charmed enemy for that fight, not a fourth party member; never in one-enemy fights.

FlagValuesNotes
--enemy-allytoggleMulti-enemy fights only.
--enemy-ally-pctpercent, default 20Per-battle chance.
How it is patched

Tier E. A battle-setup hook sets the game's own AI-delegated confuse/charm flag (+0x16E |= 0x380) on the frontmost enemy, and a one-word widen of the victory check stops the ally counting as an enemy left. A bundled charm_fix guard closes the hard-freeze the widen otherwise arms: a living ally can be the acting actor at victory, and the win-pose staging would index the 3-byte party roster with a monster slot; a single-word detour keeps the acting slot only when it is a living party slot. See the battle action SM.

Shiny Seru

Now and then a capturable enemy spawns translucent and 35% stronger; absorb it and the Seru keeps a permanent +35% damage boost, shown in a caption every cast.

FlagValuesNotes
--shiny-serutoggleArena feature (exclusive with the Super Arts list / pack, AP override, Delilas Challenge). Applies to Seru captured after patching.
--shiny-pctpercent, default 2Per-battle chance on the frontmost capturable enemy.
How it is patched

Tier E: nine same-size detours into SCUS regions verified dead and outside every live indexed table (618 of the arena's 652 bytes). “Capturable” is an allowlist built at patch time from the disc's monster names matching the player Seru-magic names; the permanent flag is a parallel per-spell byte inside the saved character record, so it survives a memory-card save. See spell table.

Seru trading

Every shop gains a Trade row: swap one of a party member's learned Seru-magic for a different one at a set level; offers rotate with play time and differ per vendor.

FlagValuesNotes
--seru-tradetoggleComposes with every gap-based hook.
--seru-trade-offerscount, default 4Offers listed per vendor at once.
How it is patched

Tier F. Hand-assembled MIPS hosted entirely in the menu overlay's (PROT 0899) reference-free dead region: a fourth Buy / Sell / Trade / Quit row, a Wants / Offers screen, and a “No <want> available” message when nobody holds the wanted Seru. Levels are curved low (1-3 common, 7-9 very rare); offers rotate on a play-time bucket, phased per vendor by an offset summed from its shop record, all deterministic from the seed (kernel legaia_asset::seru_trade).

Jewel fix

A few boss cinematic casts - Xain's Bloody Horns and Terio Punch, Cort's Guilty Cross, the Delilas signature moves - bypass the elemental resist ladder in retail, so a Jewel or All Guard does nothing against them; this makes elemental guards apply.

FlagValuesNotes
--jewel-fixtoggle, seedlessIn every browser preset above Vanilla.
How it is patched

Same-size retargets of those casts' damage path onto the ordinary elemental route. See battle formulas and cast modules.

Approach-softlock fix

Retail can freeze a boss fight forever - the boss walks toward you, its walking animation dies, and the camera circles the party for eternity; this makes the boss start walking again.

FlagValuesNotes
--approach-softlock-fixtoggle, seedlessOn in the Balanced / Full Chaos presets. Healthy fights are byte-identical.
How it is patched

A monster approaching an out-of-reach target waits in a range poll with no movement code and no timeout while its staged Move clip carries it; when a summon's staging round-trip precedes the melee, that clip dies and nothing re-stages it. The fix is a nine-word rewrite of the poll's redundant per-frame facing recompute: when the clip reads dead while the poll still fails, the state bounces back to staging and retail's own code resumes the walk. Runtime-verified on both live-caught park states. Full story: the endless camera orbit.

Delilas Challenge

The Muscle Dome clerk gains a fourth course: Che and Lu Delilas together, then Gi with two borrowed tricks; a full clear pays 5,000 coins and, with custom items on, three items retail never shipped.

FlagValuesNotes
--delilas-challengetoggle, seedlessUnlocks after the Koru event in Nivora Ravine. Arena feature. On in Balanced / Full Chaos.
How it is patched

A koin1 script edit grows the enrollment picker to its four-option ceiling, plus a small arena/SCUS code injection. The 1v2 fits the battle heap by streaming slim clones of Che and Lu from two unreferenced archive slots; the real records, the ravine duels and the Master course are untouched. The pair fire their specials once every four turns, staggered two apart. Gi borrows two streamed capture-class casts - Divide below half HP (after which Blazing Slash is locked out and the clone only melees) and Spore Gas from turn 3. Losing returns you to the Sol venue; the course repeats.

With custom items on, a clear also hands out Nature's Elixir, the Ra-Seru Tear and the Fury Bloom in place of the Honey reward.

Custom items

Three items the game never had, built into the item table's only free slots: Nature's Elixir (full HP and MP, field or battle), the Ra-Seru Tear (a free cast of the user's own Ra-Seru summon, castable by anyone) and the Fury Bloom (a party-wide Fury Boost).

FlagValuesNotes
--custom-itemstoggle, seedlessObtained through random drop / chest / steal fills or the Delilas Challenge reward; with neither, they exist but nothing hands them out.
How it is patched

Tier A + E: name, description and effect-descriptor rows written into the three free slots of the item table and item effect table, with the effects hosted as code hooks.

Delilas party swap

Play as Gi, Lu and Che: the siblings take the heroes' place in battle, in the field, on the save screen and in dialogue, while Vahn, Noa and Gala step into the siblings' story duels; each sibling brings their signature special in place of a Hyper Art.

FlagValuesNotes
--delilas-partyany permutation of gi,lu,cheMaps onto Vahn, Noa, Gala in order. Seedless; in no preset. Composes with the Challenge.
--delilas-moveshybrid (default) / delilasMove set.
--delilas-arts-voiceoriginal (default) / adjusted / removedArts voices.
--delilas-che-hammertoggleChe keeps his welded hammer instead of the mirrored fist; --allow-kept-hammer waives the audit's radius check.
How it is patched

Each character keeps their animations, arts, magic, stats and story but wears the mapped sibling's battle model; each sibling's monster block is rebuilt around the mapped hero's model, and because the animation streams pose parts by index, a same-part-count model inherits every move. The swap is an anatomy permutation plus a per-part rest-pose bake between the rigs and a bit-exact 4bpp texel re-layout between the monster page and the party texture band, applied to every equipment variant of the player files. Field models rebuild from the siblings' Nivora Ravine NPC meshes; battle grunts resample from their voice banks; save-select faces, memory-card icons and load-screen portraits follow the mapping; every dialog line naming a sibling is rewritten. Pause-menu portraits and battle HUD faces stay retail.

The signature special lands when it connects

The reskinned Hyper Art plays the sibling's multi-stage signature chain, and its damage frames and visual burst are re-derived onto the frames the chain actually connects on: a stage with authored contact beats (Lu's strikes) uses them; one without (Gi's and Che's, damaged by cast modules as enemies) takes the frame the whole body arrests hardest. Anchoring on the final stage's start instead lands the first hit 1–3 seconds late, because that stage opens with its own approach.

Each slot fights in its sibling's element

Retail keeps one element byte per character in the battle overlay (Vahn fire, Noa wind, Gala thunder), read by both affinity readers. The swap copies each sibling's element from their monster record - Gi fire, Che earth, Lu thunder - into the slot, so Lu's Plasma Strike deals thunder out of Vahn's slot. It is per character, not per art.

Move set

Hybrid changes nothing but the one reskinned Hyper Art. Delilas rebuilds the character's whole battle-animation archive from the sibling's monster clips (the signature, the locomotion clip and one entry per distinct swing), repoints and re-times every art, renames each surviving art after the clip it plays, and blanks the combos of arts neither a Super Art nor the Miracle Art needs - a blanked combo is never performed, so never learned. The archive is rebuilt rather than extended because retail leaves too little free space (Noa's slot has room for no extra clip); repeated names are also what keeps the art bank inside its compressed footprint. Result: 12 / 16 / 12 performable arts, 3 / 1 / 3 hidden; Super and Miracle Arts remain reachable.

Arts voices

Original leaves the retail XA arts shouts untouched. Adjusted re-voices them toward the mapped sibling through a tuned pitch/formant map. Removed silences the XA2/4/6 arts banks and the party's three swing-grunt channels, routing intact, leaving the resampled battle grunts. The grunt resample is SPU-side and rides with the swap in every mode.

Two traps in the MIPS injection features

  • The R3000 load-delay slot. A just-loaded register is not ready for the very next instruction; every injected routine keeps a filler between a load and its first use.
  • “Zero is not dead.” A run of zero bytes is safe to host code only if no code reads it. A region qualifies when it is zero in the clean image, constant across states, outside every known table, and read-watch-verified unreferenced on a live session.

The three times the second trap bit, and the arena arithmetic behind the mutual exclusions, are on the internals page.

Getting around

Three kinds of door live on the disc, each a different edit: a scene-transition door names its destination scene inline; a house door inside a town is a scripted teleport of the player; and most house exits are a bare trigger tile in the map data with no script at all.

Doors (scene transitions)

Walk through the Rim Elm gate and come out somewhere else; doors are re-paired two-way by default so turning around still takes you back, and the big overworld hubs keep theirs because their data cannot grow in place.

FlagValuesNotes
--doorsshuffle / random / none160 doors across 48 scenes on the retail disc.
--door-couplingcoupled (default) / decoupledTwo-way pairs via a random involution, or fully independent one-way destinations.
How it is patched

Tier D - the only randomizer that resizes an asset. The field VM's 0x3F named-scene-change op carries [i16 index][u8 name_len][name][entry_x][entry_z][dir] inline in partition-2 MAN records; the destination name is variable length, so the op is rewritten through the relocation engine, the MAN recompressed and the descriptor's size word updated. The whole destination (scene + entry tile + facing) moves as one unit, so a re-pointed door always lands somewhere valid. Doors with no reverse partner fall back to one-way and are reported; a scene whose MAN cannot grow in its footprint keeps its doors.

House doors (intra-town)

Inside a town the front doors lead to different houses; entries stay entries and exits stay exits, so you can never be trapped indoors.

FlagValuesNotes
--house-doorsshuffle / nonePer-scene, class-preserving. Also drives map doors.
How it is patched

Tier C. Entering a house is an intra-scene reposition: the cross-context player move 0xA3 0xF8 xb zb (opcode 0x23 | 0x80 into the player channel), in partition-0 records paired by a fullwidth naming convention (IN/OUT, 入口/出口, A/B elevator endpoints). 56 warps across 12 scenes; a same-size 2-byte operand edit, recompressed in place. A record carrying several player warps is choreography (the tower's multi-stop elevator), not a door, and stays vanilla.

Map doors (.MAP intra-scene teleports)

Most house exits are not a script at all: crossing the tile just inside the doorway repositions the player outright - by far the largest door population on the disc, rewired only when the scene's walk geometry proves nothing becomes unreachable.

FlagValuesNotes
--house-doorsshuffle2319 records across 72 scenes. legaia-patcher map-doors lists them with walk-component classes.
How it is patched

Same-size 2-byte writes into the raw .MAP sectors - the per-scene field map's trigger block carries a kind-0 sub-table of [tile_x][tile_z][dest_x][dest_z] records with no object, record or name; landing is (dest_x*64 + 64, (dest_z+1)*64). Records have no entry/exit class, so the softlock policy is reachability verification: the walkable surface (walk-visible floor minus collision wall bits) partitions into 4-connected components, each record is a directed edge, and a permutation is accepted only if the component graph keeps every retail reachability pair and adds no one-way trap - retried deterministically, vanilla when nothing verifies. Endpoints that cannot be attributed on the base grid stay vanilla. See field locomotion.

Cut content and custom art

Unused content

The disc ships two monsters and two items the finished game never uses; these toggles put them back into play.

FlagValuesNotes
--unused-enemiestoggle“Comm” (id 78) and the Evil Bat clones (176-178) join the encounter pool. Needs --encounters random.
--unused-itemstoggleSomething Good (0x6B) and the unnamed accessory (0xFD, named “Seru Bell”) join the random-fill pool.
How it is patched

The battle loader streams a monster's slot by id on demand with no per-scene preload list, so a formation byte alone makes a cut monster spawn. The unnamed accessory's name string is written into preserved rodata padding of SCUS_942.54 and only 0xFD's name pointer is repointed; the region is chosen by its flanking rodata surviving file→RAM byte-for-byte, since the data segment's trailing zero-fill is scratch the game overwrites every frame. The accessory's documented effect (only Seru-class random encounters) is never exercised in retail, so treat it as experimental.

Texture replacement

Swap any texture on the disc - a town's ground, a monster's skin, the party's in-battle art, the save-slot portraits - for your own PNG, in the browser or with three CLI subcommands.

SubcommandArgsNotes
tim-listBoth catalogs: raw (standalone entries, timpack members, the system-UI gap) and lzs (inside compressed sections).
tim-export--entry N --offset K -o out.pngDecode one texture.
tim-replace--entry N --offset K --png in.png [--quantize]Same pixel size required; colours must fit the palette (or be quantized).
  --tier battle --battle-slotrecord / header0 / header1The battle-equipment upload block, which is not a TIM.
How it is patched

The encoder copies the original's pixel mode, CLUT layout and VRAM placement fields (TIM); alpha maps to the semi-transparency bit. A raw-tier texture always applies; an lzs-tier one only when its section re-compresses into the original footprint - the battle-equipment art is the tightest, with as little as two spare bytes in one record. A monster sheet is shown through the palettes its model uses and its palettes are never rewritten. Browser change packs carry your images plus a fingerprint of each retail texture, never the game's pixels. See also NPC palettes and save icons.

Custom monster models

Replace a monster's whole 3D model - mesh, texture page and baked vertex shading - with one authored in Blender, and it performs every retail move with zero animation work. CLI only.

SubcommandArgsNotes
monster-model --export--id N --export nameWrites .obj / .mtl / .png; one o part_NN per TMD object, baked colours as v x y z r g b.
monster-model --obj--id N --obj m.obj --texture m.png [--allow-grow]Part count must match retail; may not grow past the retail decoded size without the flag.
How it is patched

The part-count law: battle animations pose TMD objects rigidly by index with no skeleton (monster animation), so a replacement with the retail object count inherits every move; the importer rejects any other count. Material names carry render state (skin_pNN, skin_semi_abrN_pNN, flat) so a round trip reproduces the palette partition; faces without a hint are re-palettized greedily into at most 15 sixteen-colour CLUTs. The block is re-packed into its 0x14000 slot and the patched image re-decoded before success is reported. Two worked examples ship in the repo. See TMD and the bestiary.

How we know

The retail routines each family of edits is pinned against. Per-function dumps live in ghidra/scripts/funcs/<addr>.txt.

FunctionAddressWhat it proves
LZS decoderFUN_8001A55CThe stream shape legaia_lzs::compress must produce.
PROT entry sizeFUN_8003E68CEntry span = gap to the next TOC entry; the re-pack budget.
Battle-end rewardFUN_8004E568, join 0x8004F610Where the normal drop is granted; the equipment-drop hook site; the integer rand() % 100 roll.
Battle RNGFUN_80056798The roll every hook reuses.
Field-VM dispatcherFUN_801DE840 cases 0x23, 0x39, 0x3F, 0x49House-door warp, GIVE_ITEM, scene change, shop payload - all inline operands.
Encounter rollFUN_801D9E1COnly rate_increment > 0 regions trigger; the boss-protection mask.
Kind-0 teleport armFUN_801D1EC4FUN_801D5630Map-door records and their half-tile landing formula.
Battle-action SMFUN_801E295CEscape teardown state (flee EXP hook), Spirit accrual, state-0x19 approach poll.
Damage finisher / arms resolverFUN_801DDB30 / FUN_801EC3E4The twice-inlined damage-AP fill; arts power tiers; the Seru catch roll.
Party arts queue-builderFUN_801EED1CAP override hook site.
Super-Art applierFUN_801EF9E4, arm 0x801EFBCCFind/replace over the action queue; the performed-flag writer and the pack's retarget words.
Arts list renderer / pagerFUN_80034358 / FUN_801D3748Where the Super-Art rows are merged into the battle list.
Menu panel rendererFUN_801D33D8The pause-menu Moves page half.
New-game initFUN_80034A6C, seed 0x80034B04The bag is built in code; the starting-item rewrite site.
Actor loader boostFUN_80054CB0The fixed ATK / DEF / INT boost applied on top of scaled records.
Static tablesDAT_80077828 steals, DAT_800754C8 spells, DAT_80074F68 equipment, DAT_801E4518 casino, 0x801F4F5C move powerTier A targets, each verified against the curated gamedata tables.
Rodata gap0x8007AB38 (1028 bytes)Tier E host; flanking rodata survives file→RAM, proving it is not boot-cleared scratch.

Under the hood

The crate's module map, the per-feature test inventory and the no-Sony-bytes rules are on randomizer internals: modules · tests · hygiene.

See also