At a glance

Where
record[0] of each player battle file (PROT 0863 Vahn / 0864 Noa / 0865 Gala), resident in RAM at 0x80160EFC / 0x80176998 / 0x8018BA54. Display names, arrows and AP: the SCUS arts-name table at DAT_80075EC4.
Stride
0xD0 bytes per record, indexed by action constant: record = base + (c − 0x10) × 0xD0. Name-table rows are 20 bytes.
Parser
crates/art (parse_record, arts_table, tokenize, Miracle / Super matchers); editors legaia_arts_patch::arts_power / super_art_power.
Confidence
Command prefix, stride, power byte at +0x24, effect class at +0x7A and the name table are Confirmed; the variable-field tail offsets are Inferred from external RE work.
Used by
Battle action SM, Arts gauge, Arts page, Randomizer (arts shuffle).
The button combos live in two places

The matcher - what fires an art - reads the player-file record's command bytes. The menu draws its arrows from the SCUS name table. Editing one without the other makes the menu lie: the art still fires on the old combo. The arts randomizer edits both.

what fires the art - player file player file record0extraction 0863..0865 art block0xD0 stride matcher / tokenizerFUN_801EED1C action queueactor+0x1DF +0 combo anim commitFUN_8004AD80 materialized recordactor+0x4C damage kernelFUN_801EC3E4 cue playoutFUN_801DEA50 +0x24 power hit run what the menu draws - SCUS arts-name tableSCUS DAT_80075EC4 Arts menu display +8 glyphs, +2 AP, +0xC name
The two places an art lives. The matcher fires off the player-file record and the damage and cues come from the record it materializes; the menu's arrows, AP and name come from the separate SCUS table - which is why editing one without the other makes the menu lie.

Art record layout

One 0xD0-byte record per action constant. Solid cells are byte-pinned; the hatched span is schema-then-walk - its fields are known in order but their exact offsets vary per art.

The second row is not to scale. The 0x24-byte matcher head is followed by a standard battle action entry (see player files § battle animations).

FieldMeaning
command sequence1=L 2=R 3=D 4=U, 0-terminated. A Super Art record's field is a one-byte stub (no combo).
action constant0x1B..=0x32 (below).
anim_index, anim_extraPrimary animation slot; extras chain multi-stage arts (Noa's Hurricane Kick).
nameFixed-width name slot; populated for Super, Miracle and some Hyper Arts.
power runPer-strike damage tier bytes (encoding). Confirmed; editor legaia_arts_patch::arts_power.
impact-effect class1..=5, 0 = none. Selects the element spark and afterimage tint - this byte, not the cue script, makes an art read as its element.
Variable-field tail (Inferred positions)
FieldEncoding
Damage timing (×4)One byte per power byte: the animation frame at which that hit fires.
Special effect cues (×2)2 words each: half-word effect id, then XYZ half-words. Active iff non-zero.
Hit effect cues (×4)One word each: high half = frame, low half = cue code.
IdentifierByte; some values trigger special animations (0x67 in Heaven's Drop = Thunderbolt).
Anim speedByte; lower = slower.
Effect on enemyStatus byte, the entry +0x7A selector: 1 / 2 tint only, 3 sets status bit 0x1, 4 bit 0x2, 5 one of bits 0x08 / 0x10 / 0x20 on a party target, 6 bit 0x1000; 7 and up write nothing (FUN_801EC3E4). No party art carries a value above 2; Tough Love and Love You carry 0 and get their status from the clip-key arm of FUN_8004CE2C instead.
Repeat frames3 bytes: count, start, end. Replays a frame range and any hits inside it (Super Tempest: 4 power bytes, 8 hits).
Background0 regular, 2 black (Super Arts, Tornado Flame).
Runtime addressWord written after first use; always zero on disc.

The runtime hit run the per-frame cue player walks sits at record + 0x14 + cursor × 8 (8-byte entries: timing, cue code, XYZ). Cue-code high bit = spawn an efect.dat billboard; a plain code selects a 3D move-VM prototype. Target-group codes: < 8 one actor, 8 the party, 9 the enemy row, 0xA everyone.

Power encoding

Each power byte names a defence target and a multiplier. Retail authors the run ascending; weak arts carry one byte, Hyper and Super Arts four.

Byte rangeTargetMultipliersNote
0x16-0x1AUDF (upper defence)12, 18, 20, 22, 28Standard high hit.
0x1B-0x1FLDF (lower defence)12, 18, 20, 22, 28Standard low hit.
0x0C-0x10UDFsameMisses short enemies.
0x11-0x15LDFsameMisses floating enemies.
other--No damage.

Indexed by action constant, not by combo

  • Constants 0x19 / 0x1A (the two Art Starters) land on the two "Starter" records, 0x1B on the Miracle Art, regular arts at 0x1B + display index.
  • Super Art finishers have records too - 0x2B..0x2F (Vahn, Gala), 0x2E..0x32 (Noa) - with real power tiers, so Super damage is ordinary record data.
  • Some records are reachable by neither route (Vahn's and Gala's 0x2A, Noa's 0x2C/0x2D): named, powered, but no menu row and no combo.

Action constants

Every entry in the battle action queue is one of these bytes:

ByteMeaning
0x00-0x05Nothing, Item, Magic, Attack, Spirit, Escape
0x07 / 0x08Faint animations 1 / 2
0x0A / 0x0BItem-or-magic animation / block animation
0x0C-0x0FLeft, Right, Down, Up
0x10Spirit animation
0x11-0x18Empty slots (never in static data)
0x19 / 0x1ARegular / Special Art Starter
0x1B-0x32Per-character arts - the same constant is a different art per character (crates/art/src/tables.rs)
Learned-art slots and animation slots per character

A per-character byte (0x8008488D Vahn, 0x80084CA1 Noa, 0x8008506C Gala) tracks the highest learned slot; slots resolve to constants through a table with holes (Noa skips 0x02/0x03 because one learned slot covers all three Hurricane Kick levels). API: legaia_art::learned_art_action(character, slot).

SlotVahnNoaGala
0x00Vahn's CrazeNoa's ArkBiron Rage
0x01Burning FlareHurricane KickExplosive Fist
0x02Fire Blow-Lightning Storm
0x03Tornado Flame-Thunder Punch
0x04CycloneVulture BladeBull Horns
0x05HurricaneFrost BreathElectro Thrash
0x06PK ComboTempest BreakNeo Raising
0x07Spin ComboRushing GaleBlack Rain
0x08Pyro PummelTough LoveSide Kick
0x09Cross-KickSwan DriverHead-Splitter
0x0APower PunchBird StepGuillotine
0x0BSlash KickDolphin AttackBack Punch
0x0CSomersaultMirage LancerIronhead
0x0DCharging ScorchBlizzard BashBattering Ram
0x0EHyper ElbowSonic JavelinFlying Knee Attack
0x0F-Acrobatic Blitz-
0x10-Lizard Tail-

Slot constants run 0x1B + slot. The record's anim_index indexes a separate per-character animation table (slot 0 = Spirit, 3 = Art Starter, with holes); API legaia_art::art_anim_name(character, anim_index).

AnimVahnNoaGala
0x01Power PunchTempest BreakBull Horns
0x02Slash KickTough LoveHead-Splitter
0x04Tornado FlameHurricane Kick 1Lightning Storm
0x05HurricaneHurricane Kick 2Back Punch
0x06Charging ScorchRushing GaleIronhead
0x07PK ComboSwan DriverBattering Ram
0x08Fire BlowFrost BreathFlying Knee Attack
0x09SomersaultLizard Tail-
0x0ACycloneJurassic Blow 2Thunder Punch
0x0BHyper ElbowBird StepGuillotine
0x0C-Dolphin AttackExplosive Fist
0x0DBurning FlareVulture BladeBlack Rain
0x0ESpin ComboMirage Lancer-
0x0FPyro PummelBlizzard Bash-
0x10Cross-KickSonic JavelinSide Kick
0x11Acrobatic BlitzElectro Thrash-
0x12--Neo Raising

Miracle Arts

Each character has one. When the exact sequence is entered, the runtime clears the whole action queue and writes the art's replacement string: four directionals, the Special Starter, then the finisher constants. On disc the four directionals carry the high bit (0x8C..0x8F); the copy masks them to 0x0C..0x0F.

CharacterArtInput
VahnVahn's CrazeR D L U L U R D L
NoaNoa's ArkL U R D U L U D R
GalaBiron RageR R D U D U D L L

Super Arts

A Super Art is never matched against the raw input. The game first tokenizes the arrows into arts, then looks for a registered Find pattern at the tail of the queue and replaces it with the Super's finisher.

  1. Input arrowsThe player types 7-9 directions, e.g. ↑↓↑↑↑↓↑.
  2. TokenizeTail-first: each matched art overwrites its last arrow with a Starter (0x19) and inserts its constant; leading arrows stay, so one arrow can belong to two arts. Restarts after every match.
  3. Queue19 27 0F 19 1F 0E 19 27 in actor[+0x1DF] - Somersault, Cyclone, Somersault overlapping.
  4. Find at tailTable 0x801F6524: the pattern must end the queue and every chain art must have paid its AP.
  5. ReplaceTable 0x801F65E8: … 1A 2B 2B 2B - Special Starter + Tri-Somersault × 3 hits. AP is the chain's sum; the Super charges none of its own.

Because the Find pattern is what the physical input tokenizes to, laying the chain arts end to end does not trigger it. Every retail Super derives to a unique shortest input; fourteen of fifteen agree with the public walkthrough table (Dragon Fangs' printed six-arrow input drops one arrow and never performs Swan Driver).

CharacterSuper ArtChainInputAP
VahnTri-SomersaultSomersault, Cyclone, Somersault↑↓↑↑↑↓↑60
VahnMaximum BlowCharging Scorch, Slash Kick, Power Punch↓→↑↓←←↓54
VahnFire TackleHyper Elbow, Power Punch, Charging Scorch←→←←↓→↑54
VahnPower SlashCharging Scorch, Somersault, Slash Kick↓→↑↓↑↓←54
VahnRolling ComboSpin Combo, Power Punch, PK Combo↑↓→←←↓↑↑←66
NoaTriple LizardBird Step, Swan Driver, Lizard Tail↓↓↓↑↑↑↓↑66
NoaSuper JavelinRushing Gale, Sonic Javelin↑↑←↓→↓→48
NoaSuper TempestDolphin Attack, Tempest Break→→←→→←↑↑↑60
NoaLove YouMirage Lancer, Lizard Tail, Tough Love→→↑↑↓↑↓←→72
NoaDragon FangsLizard Tail, Swan Driver, Acrobatic Blitz↑↓↑↑↑↓↓60
GalaBack Punch x3Ironhead, Flying Knee Attack, Back Punch↑↓↓↑←→←54
GalaSuper IronheadFlying Knee Attack, Head-Splitter, Ironhead↓↑←↑↑↓↓54
GalaRushing CrushBattering Ram, Flying Knee Attack, Head-Splitter←→↓↑←↑↑54
GalaHeaven's DropFlying Knee Attack, Head-Splitter, Black Rain↓↑←↑↑←↓↓60
GalaNeo Static RaisingBack Punch, Guillotine, Neo Raising←→←↑←←→↑←66

Tables: crates/art/src/super_art.rs, miracle.rs.

Arts-name table (SCUS)

Display names, arrows and AP costs live in a static 20-byte-stride table in SCUS_942.54, sorted by character and terminated by a (99, 99) "End" row. Each character's index 0 is the Miracle Art (AP byte 99). This is also the table the MES 0xC5 substitution reads.

OffsetTypeField
+0u8character: 0 Vahn, 1 Noa, 2 Gala
+1u8art display index
+2u8AP cost - a display mirror; the battle path computes multiplier × command count from code immediates and retail keeps the two consistent by authoring (arts gauge)
+4u16per-art tier constant with no reader anywhere on the disc - see below
+8u32pointer to the arrow-glyph string: [count] then two-byte glyphs 0x81A9 L, 0x81A8 R, 0x81AB D, 0x81AA U; a 0xFF06 / 0xFF09 marker is not a direction
+0xCu32pointer to the name string
+0x10u32aux string pointer

The +4 halfword is authored data the runtime never consults. Eight sites materialise the table base (addiu rX, rY, 0x5EC4); walking every load whose base descends from one of them, with the displacement tracked through the addiu/addu/sll chain, reaches the record only at +0, +1, +2, +8, +0xC and +0x10 - never +4 or +6 - and a five-form sweep for 0x80075EC8 finds no reference in any image. The values are a per-art tier ladder keyed to the art’s position in its character’s list: 60000 for the Miracle Art, 50000/40000/30000 for the three elemental arts, 20000 for Noa’s Tempest Break, then 15000/10000/5000 for the six-, five- and four-input arts, and 1 on the terminator. It is not an AP mirror (Noa’s 70-AP and Vahn’s 50-AP index-1 arts share 50000) and not the input count (five-input arts appear at both 40000 and 10000).

The glyph string stores the physical direction (Noa's Arms / Ra-Seru are swapped) and is the oracle for both the record parser and the curated gamedata arts table - every AP agrees, and one walkthrough error surfaces (Vahn's Hyper Elbow is L R L on disc). Decoder legaia_art::arts_table::parse_from_scus; dump with art arts-table.

How we know

The fixed fields are read off the overlay damage kernel, queue builder and cue player's disassembly; the Super tables are validated against a captured resident queue, and every record's command bytes agree with the SCUS name table's glyph strings.

Provenance: functions and tables
FunctionAddressWhat it provesDump
Damage kernelFUN_801EC3E4 (overlay 0898)Reads the strike's power byte at art_record[+0x24 + cursor], cursor at actor+0x1F4; bounds +0x7A to < 6.-
Art materialiserFUN_8004AD80actor[+0x4C] = DAT_801C9360[char][slot] - the runtime copy of record[0]; fires the CD-XA shout and Hyper fanfare.-
Queue builder / tokenizerFUN_801EED1C (0x801EF2EC..0x801EF858)Emits a matched art's constant as row +0x18; Starter over the last arrow, leading arrows kept, tail-first restart.-
Super tablesfind 0x801F6524, replace 0x801F65E815 entries, capture-validated against a resident queue.-
Cue playoutFUN_801DEA50, FUN_801E22C8, FUN_801E09F8Per-frame hit-cue walk at +0x14 + cursor×8; per-art cue list at 0x801F6470; special-attack sibling.ghidra/scripts/funcs/overlay_battle_action_801dea50.txt
Element renderersFUN_8004998C, FUN_80049348Spark along the swing path and afterimage tint keyed on actor[+0x21F] (the +0x7A class); neither reads the cue records.-
Name-table expanderFUN_80036514Scans DAT_80075EC4 rows by (character, index); returns the +0xC name pointer.-
AP display read0x801D4524 in FUN_801D33D8 (overlay 0899)The only reader of the name table's +2 byte is the status-panel renderer.-

See also