At a glance

Queue
Actor +0x1DF..+0x1F2: a 16-byte build window inside a 19-byte stream
Strike cursor
ctx[+0x15], a battle-context byte (0xFF = parked)
Category
Actor +0x1DE; 3 = Attack, which is also every Tactical Art
Builder
FUN_801EED1C (PROT 0898), called at the action-seed state 0x0C
Super applier
FUN_801EF9E4
Damage
FUN_801EC3E4, called from the animation tick FUN_80047430 once per hit event
Clip bytes
Staged +0x1DA, committed +0x1D9, latched +0x1DB; per-clip hit index +0x1F4
Port
legaia_art::tokenize and the matchers; engine-battle-vm::battle_action (queue applier, attack chain, validator). The port builds byte-identical queues

The queue alphabet

ByteMeaning
0x00terminator (the magic band uses 0xFF)
0x0C / 0x0D / 0x0E / 0x0Fdirection swing: Left / Right / Down (low) / Up (high) - written as 0x0B + direction
0x19art starter, art already known
0x1Aart starter, art learned on this use; also the starter the Super applier stamps
0x1B..0x1Ethe Miracle Art and the three Hyper Arts
0x1F..ordinary arts: art ordinal n is constant 0x1B + n
0x8C..0x8Fon-disc Miracle rows only: direction bytes with bit 7 set, cleared by the builder

For a monster the bytes are action-entry indices from the AI picker, and for a cast they are the spell id followed by clip and shot pairs.

What recognising an art does to the queue

On a match the builder does not collapse the combo into one constant. It overwrites only the last matched arrow with a starter, and inserts the art constant after it, shifting the tail right by one. Every arrow before it stays in the stream and still executes as its own swing - so a three-arrow art is two swings plus the art.

entered 0x0CLeft 0x0FUp 0x0DRight 0x00end built 0x0Cstill a swing 0x0Fstill a swing 0x19 / 0x1Astarter 0x1B + nart constant 0x00end overwritten shifted right
The match against an art record compares stream[i] - 0x0B with the record's command bytes; the commit writes the starter over the last matched arrow and inserts art_id + 0x1B after it.

After the per-art commits come two trigger passes, in this order:

  1. Miracleif the input equals the character's Miracle command string, and the Ra-Seru marker is set, the whole queue is replaced with the Miracle row
  2. MSB clear + reorderbit 7 is swept off the on-disc direction bytes; marked starters are reordered
  3. SuperFUN_801EF9E4 matches each Super “find” pattern against the tail of the queue and replaces it with a tail ending in the finisher constant

A Super triggers only when the last art of its pattern is the last action in the queue and every participating art paid its AP. The Miracle, Super find and Super replace tables are resident in the battle overlay.

How the queue is consumed

The strike loop stages one byte per swing and applies no damage. State 0x1E of the action SM reads the byte at the strike cursor, post-increments the cursor by exactly one, and stages the byte as the actor's next clip. The action SM never calls a damage kernel: the call does not appear anywhere in it.

Damage is one power byte per animation hit event. The animation tick calls the hit resolver with the hit-event frame, and each call consumes exactly one power byte from the art record, indexed by the actor's own hit counter (bounded at four). So one staged art constant produces as many damage applications as its clip has hit events - the art's power list is walked by the animation, not by the stream. A Hyper or Super clip that replays its loop window re-fires its hits each cycle.

The total lands once. Every admitted hit adds to the target's combo word and its HP-bar word; live HP is written by one arm, normally only when the strike cursor is parked and this is the clip's last listed beat. Two exceptions:

  • Nothing left can connect. A look-ahead over every remaining hit of the action finds none whose height class can reach the target's size class (the limb-versus-height “Miss” law): the total lands now.
  • Attack ×2. With the War God Icon's passive, the first action of the pair never applies; its total carries into the second.

A swing entry's first power byte is equipment-spliced, not a property of the command: the swing clips are per weapon, and the same Down swing reads different bytes on different saves.

The Attack ×2 second pass

The refill loop at the end of the strike loop is the War God Icon's second pass, not a Miracle continuation. It rewinds the strike cursor and replays the whole stream once, demoting to 0x19 every starter whose build mark reads exactly 1. The exactness is load-bearing: the Super applier writes mark 4 on the starters it stamps, so a Super's starter is the one the second pass leaves alone - the extra pass performs the Super again rather than a plain swing. The marks cannot be recovered from the finished queue bytes, because both starters read 0x1A.

Why only arts get an attack camera

The clip commit ends with an unconditional copy of the staged byte into the latch byte +0x1DB, which is what the per-art attack camera dispatches on (0x1A..=0x2D). An action whose stream carries only direction swings never puts a value in that range there, so the camera is unreachable for it. The tracks themselves are on the attack-camera table page.

Where a queue comes from

  • The saved chain. Before the gauge opens, FUN_801DA34C preseeds the queue from one of the character's two saved 16-byte arts-input strings (character record +0x76F / +0x77F). The slot pick and its fallback are asymmetric: one leg prefers the first string and falls back to the second; the other reads only the second. After an arts action FUN_801DA59C writes the queue back, which is what the next preseed replays.
  • No input at all. The builder has one arm that produces a whole attack queue itself, selected when the character seated in the slot is roster id 4 - the AI-driven guest. It flips a coin to act at all, picks a living monster, and writes a single low swing against a target of size class 2, otherwise two random Left / Right swings.
  • A monster. Action-entry indices from the AI picker.

The action validator

FUN_8003FB10 (SCUS) is the 18-arm gate the menu and battle UI run against a candidate slot before committing an action: is this a valid heal target, a valid revive target, a stat that can still grow. It reads from the battle-actor table inside a fight and from the character records outside one, and writes a per-slot validity bit. Arms 0x00..=0x0D are target rules (heal, restore MP, status present, dead, alive, stat-cap walker, per-slot match); 0x80..=0x83 are out-of-battle item gates. One quirk is kept by the port: the field branch of the “has a curable status” arm reads the status word signed, so a word with bit 15 set validates even with the tested bits clear.

See also

The full write-up - each commit path's addresses, the per-frame drift flag, the trigger tables, the port's command flow and the validator's arm table - is in docs/subsystems/battle-action-queue.md.