How to read this page
Everything here is read from the USA release's executable, its overlays and the data on the disc. Three of the four cases were also watched in a running game, and each section says exactly how: the dance lock with scripted button presses and nothing written to memory; the War God Icon refusal and the flute's early round end on poked states, meaning some memory values were written by hand to set the situation up, and the section lists which. Side Kick is read from the code and data only. Addresses are for the USA build (SCUS_942.54) unless a table says otherwise; ctx means the battle context block, found through the pointer at 0x8007BD24.

The Spikefish Flute cancels enemy turns (the Koru flute glitch)

Reported as
In a boss fight the flute skips the party's remaining turns, and for every party member who already acted it also cancels an enemy turn, slowest enemy first. Against Koru it can stop Dead End Crisis for good (community report).
Cause
The flute's turn-skip adds one to the round's turn count per living party member instead of per member still waiting, so the round ends early
Where
Spikefish cast module, PROT entry 0925, tail at 0x801F79B8; round-over test in the battle overlay, PROT entry 0898, at 0x801E67C8
Affects
Every fight flagged as scripted (boss fights), on the USA, Japanese and French discs; only Koru's script can be pushed off its end
Status
Explained - from the code and disc data; the early round end and a boss's thrown-away decision were captured on a poked state in the evolved Cort fight; Koru's own fight was not run

A battle round is a count, not a list of turns. One byte counts how many turns have been taken this round, and the round ends when that count reaches the number of fighters. Who goes next is decided fresh after every action: the fighter holding the highest unspent initiative key.

The flute is an escape item. In a fight flagged as scripted it cannot flee, so only the tail of its code runs, and that tail is meant to throw away the party's remaining turns. It does it by adding one to the turn count for every living party member, subtracting one, and zeroing the party's keys. With p party members already done, the count runs p too far and the round ends p turns early. Only monsters still hold keys, and the highest key always goes first, so the turns that fall off the end belong to the slowest enemies.

Turn cursor ctx+0x1A: turns taken this round012345round ends at 4VahnNoaGala: flute, cursor +3Cursor passes 4: Koru never acts, round counter 4 to 5
Flute used third on the round where Dead End Crisis is due. Two normal turns move the turn cursor to 2; the flute moves it three, past the round end at 4. Koru is never reached.
Turn cursor ctx+0x1A: turns taken this round012345round ends at 4Vahn: flute, cursor +3KoruCursor stops at 3: Noa and Gala are skipped, Koru still acts
Flute used first. The same jump of three lands one short of 4, so exactly one more turn is played, and Koru is the only fighter left holding a key.

So a flute used as the round's first action skips nobody: the rest of the party loses its turns and every enemy still acts. The boss's place in the order does not matter, only how many party members went before the flute. A boss that has already acted has nothing left to lose.

Why Koru never recovers

Koru has no timer. His script picks a move from the battle's round number, and only round number 4 means Dead End Crisis. The round number rises at every round end whoever acted. End that round before he moves and the number is 5, which his script has no entry for; it does not come back to 4 until the byte wraps. The on-screen countdown is 4 - round number stored in one byte, which is why it reads 255. Nothing writes 255 anywhere.

CounterCountdown shownSpell id stored
040xA2
130xA3
220xA4
310xA5
400xA1 Dead End Crisis
5 and up255, 254, ...nothing scripted

With nothing scripted, the generic monster picker is all that is left. Koru's record carries no usable spell, so it builds a plain attack from his two costed attack animations. Both list their hit at frame 200, on clips only 64 and 30 frames long, so the hit never fires: the animation plays and nothing lands. His real specials take their damage and effect sprites from his own cast module, which a plain attack never runs.

In an ordinary, non-scripted fight the same item ends the battle: the party walks off and the escape teardown runs.

The boss still decides on a turn it never gets

  1. Flute endsparty keys are zero, the count is already too high
  2. Pickthe boss holds the highest key, so it is picked and its script chooses a move · 0x801E5D58, 0x801DAF48
  3. Round-over testthe count has reached the end; the chosen move is discarded · 0x801E67C8
  4. Next roundround number +1, every key rolled again · 0x801E6810, 0x801DA780

For Koru this changes nothing, because his script keeps no memory. For a boss whose script writes something down at the moment it chooses, that note still changes on the discarded turn. Evolved Cort is the clear case: the game records "Ultra Charge was used" when he decides, not when the move plays, and clears it when he decides on Final Crisis. A thrown-away decision can therefore wipe out a charged Final Crisis, or make him fire one next turn without ever visibly charging.

Keys are rolled fresh every round (speed plus a random amount up to half of it), so a fast party's flute user sometimes rolls first, and then the flute skips nobody. That is the "sometimes" in reports about other bosses.

What each boss loses

Each row is read from that boss's own script in the battle overlay.

BossMoveWhat a flute skip does
KoruDead End CrisisGone for good; the script runs off its end and the countdown shows 255
Cort, first formMystic ShieldCannot be skipped: on the opening round his key is forced to 30000, so he always moves before any flute. Later picks are fresh rolls; a skipped turn costs only that turn
Cort, evolvedUltra Charge into Final CrisisThe charge is a flag his script flips when it picks, not when the move plays. A discarded Final Crisis pick erases the charge (observed); a discarded Ultra Charge pick (1 in 4 with 200 MP) arms a Final Crisis with no charge shown and no MP spent on it
ZetoCall Wave into Big WaveThe latch is written by the move itself, so a discarded pick changes nothing; a skipped Big Wave is chosen again next turn
XainBull Charge into Terio PunchSame latch as Zeto
Gi, Che, LuBlazing Slash / Megaton Press / Plasma Strike on every round whose counter is 2 mod 3Not made up; the next one is three rounds later
Van SaryuJugger Power (once, at one third HP)A discarded pick spends the one use; it is never cast
RogueElement Change on even roundsA skipped change leaves the old element's attack in use

The flag applies to every fight launched from a formation row whose first byte is non-zero: the two Piura, Caruban and Golem in Rikuroa, the Viguro pair, Zeto, all three Songi, all three Berserkers, Van Saryu, Dohati, Xain, the Kemaro pair, the Puera fights and Zora in the Floating Castle, late Tetsu, both Gaza, Lu / Che / Gi, Koru, Rogue, Jette, Caruban $2 / $3 and both Cort forms. Lapis, the opening Tetsu, Queen Bee and Gold Face are not flagged, so there the flute simply flees.

Watched in the evolved Cort fight

Captured on a poked state. The run starts from a save state of the real evolved Cort fight as reached in play (Vahn, Noa and Gala; the scripted-fight byte reads 4), on the retail disc; that state has an unrelated place-name patch resident in memory. Written by hand: party HP held at 9000; party speed, so that the order is seat 0, seat 1, Cort, seat 2; the queued actions of seats 1 and 2, changed to the Spikefish cast; and, on the opening round only, one random draw in Cort's script so that he takes Ultra Charge. His Final Crisis pick on the next round was not forced.

Turn cursor ctx+0x1A in the captured round (four fighters)012345round ends at 4attackflute tail: cursor +2+1 at endseat 0seat 1 casts the fluteAt cursor 3 Cort's script picks Final Crisis: charge flag 1 to 0Cursor reaches 4: the round is over and Cort, key 184, never acts
The captured round, to the same scale as the diagrams above. The flute tail takes the cursor from 1 to 3, Cort's script runs and clears his charge, and the end of the flute's action takes the cursor to 4. Cort still held a key and was never given the turn.
MomentWhat happenedCharge flag 0x801C8FE4Turn cursor
Opening round, after a party actionCort's script runs and stores at 0x801EBAD40 to 12
Opening round, laterCort is dispatched and Ultra Charge plays13
Next round, seat 0 attacksAn ordinary turn10 to 1
Next round, seat 1 casts the fluteThe tail at 0x801F79E0 runs once per living party seat, three passes, and zeroes the party keys11 to 3
State 0x50 after the fluteCort's script runs, queues Final Crisis and stores at 0x801EBB141 to 03
State 0x5ARound over: cursor 4 equals the fighter count, round counter 1 to 2, keys rolled again04

Three more runs of the same fight show the other case: with the flute user as the first party member to act, the cursor goes to 3 of 4, the other two party turns are dropped and Cort takes his turn.

Not watched: Koru's own fight (the 255 countdown and the attacks that never land rest on the code and his monster record), the Ultra Charge direction of the thrown-away decision, and Van Saryu's one-time Jugger Power.

The Japanese and French discs

The trick is not particular to the USA disc. The Japanese build (SCPS_100.59) is a different compile with its overlays loaded higher and some context fields at other offsets, and every link of the chain is there with the same logic. Koru's monster data is byte-identical from the end of his name onward. The French build (SCES_019.44) is the USA code relocated: its flute tail (0x801F83E0) and round-over step (0x801E70EC) match instruction for instruction. Neither regional disc was run; this is from their code.

LinkUSAJapan
Scripted-fight test in the flute module0x801F73E8, ctx+0x2870x801FA858, ctx+0x1E7
Tail entry0x801F79B80x801FAE58
+1 per living party seat0x801F79D8..0x801F79FC0x801FAE7C..0x801FAEA0
Item refund0x801F7A08..0x801F7A300x801FAEAC..0x801FAED4
-10x801F7A54..0x801F7A600x801FAEF8..0x801FAF04
Party keys zeroed0x801F7A70 / 7A7C / 7A880x801FAF14 / AF24 / AF34
End-of-action step and round-over compare0x801E679C..0x801E67E40x801E96E4..0x801E9730
Round counter and its one writerctx+0x28A, 0x801E6810ctx+0x1EA, 0x801E9760
Koru's script and jump table0x801EB52C, 0x801CF49C0x801EEA10, 0x801D1258
Countdown 4 - counter0x801D0F94..0x801D0FA40x801D2ED0..0x801D2EE8
State 0x50 calls the picker0x801E5D580x801E8C74
Picker calls the monster AI0x801DAF480x801DE304
The instructions

The cast module FUN_801F6A00 (PROT 0925). s4 = ctx + 0x11, so 0x9(s4) is the turn cursor ctx+0x1A:

801f73e8  lbu  v0,0x287(a0)        ; scripted-fight byte
801f73f0  bne  v0,zero,0x801f79b8  ; scripted: skip the escape
801f79e0  lhu  v0,0x14c(v0)        ; seat HP
801f79f0  lbu  v0,0x9(s4)
801f79fc  sb   v0,0x9(s4)          ; cursor += 1 per LIVING party seat
801f7a2c  jal  0x800421d4          ; refund an unspent Item turn
801f7a60  sb   v0,0x9(s4)          ; cursor -= 1
801f7a70  sh   zero,0x16c(v1)      ; party keys = 0 (also 7a7c, 7a88)

The end-of-action gate in FUN_801E295C (PROT 0898):

801e67a4  addiu v0,v0,1            ; cursor += 1
801e67b4  lbu  v1,0(a2)            ; party count
801e67b8  lbu  a0,1(a2)            ; monster count
801e67bc  lbu  a1,0x14(s5)         ; ctx+0x25, dropped without acting
801e67c8  slt  v0,v0,v1            ; cursor < party + monsters - dropped ?

Koru's arm of the monster AI:

801eb538  lbu   v1,0x28a(v0)       ; round counter
801eb540  sltiu v0,v1,5
801eb544  beqz  v0,0x801ebdac      ; 5 or more: nothing scripted

Evolved Cort's arm. Both stores are inside the pick; neither of his cast modules (PROT 0961, 0962) touches the word:

801eba74  lw    v0,4(s0)           ; 0x801C8FE4, the charge flag
801eba7c  bnez  v0,0x801ebae8      ; charged: the Final Crisis arm
801eba8c  andi  v0,v0,3            ; else a 1-in-4 roll, needs 200 MP
801ebab8  sb    v0,0x1df(s4)       ; queue 0xA5 Ultra Charge
801ebad4  sw    v0,4(s0)           ; flag += 1
801ebaec  li    v0,0xb4            ; queue Final Crisis
801ebb14  sw    v0,4(v1)           ; flag -= 1

With P seated party members, L alive, M monsters and c turns taken before the flute user: the cursor is c + L after the flute's turn, and the round continues only while it is below P + M - ctx[+0x25].

Zeto and Xain keep their two-step latch at 0x801C8FF0 + seat*4; their scripts only read it and the cast modules write it, which is why a discarded pick costs them nothing. First-form Cort's key is forced to 30000 by the seeder when the first formation id is 0xB4 and the round counter is 0 (0x801DAAB8..0x801DAAF0).

Addresses

AddressImageWhatEvidence
0x801F6A00PROT 0925Spikefish cast module bodydisassembly
0x801F73E8PROT 0925Reads the scripted-fight byte ctx+0x287disassembly
0x801F78F8PROT 0925Ordinary fight: stores action state 0x65 (escape)disassembly
0x801F79B8..0x801F7A88PROT 0925The tail: cursor +1 per living seat, item refund, -1, party keys zeroeddisassembly, capture
0x800421D4SCUSGive-item routine used for the refunddisassembly
ctx+0x1ARAM (ctx = *0x8007BD24)Turn cursor: turns taken this rounddisassembly, capture
ctx+0x25RAMFighters dropped from the round without actingdisassembly
ctx+0x287RAMScripted-fight byte; reads 4 in boss fights reached in playdisassembly, capture
ctx+0x28ARAMRound counterdisassembly, capture
actor+0x16CRAM (table 0x801C9370)Initiative key, 0 = spentdisassembly
0x801E679C..0x801E67E4PROT 0898End-of-action gate; round-over compare at 0x801E67C8disassembly, capture
0x801E6800..0x801E6810PROT 0898Round counter +1disassembly
0x801DA780PROT 0898Initiative seeder, called every round from 0x801D0ED8disassembly
0x801DAAB8..0x801DAAF0PROT 0898Seeder: formation 0xB4, round 0, seat-3 key = 30000disassembly
0x801DABA4PROT 0898Next-fighter picker; calls monster AI at 0x801DAF48disassembly
0x801E5D58PROT 0898State 0x50 calls the picker before the 0x5A testdisassembly, capture
0x801CF1CCPROT 0898Monster AI jump table, index monster id - 4disc data
0x801EB52CPROT 0898Koru's AI arm; sltiu v0,v1,5 at 0x801EB540disassembly
0x801CF49CPROT 0898Koru's five-entry jump tabledisc data
0x801D0F94..0x801D0FA4PROT 0898Countdown 4 - counter stored at 0x801F6958disassembly
0x801EC468PROT 0898Melee kernel's hit-frame gatedisassembly
monster 0xB6, entries 5 and 6PROT 0867Hit frame 200, cost 200, clips 64 / 30 framesdisc data
0x801C8FE4RAMShared one-word AI latch in the per-battle block 0x801C8FE0 (zeroed at 0x8005601C): evolved Cort's charge, Van Saryu's one-shot, Rogue's elementdisassembly, capture
0x801EBAD4 / 0x801EBB14PROT 0898Evolved Cort: charge flag +1 on the Ultra Charge pick / -1 on the Final Crisis pickdisassembly, capture
0x801EBDA8PROT 0898Van Saryu: one-shot flag +1 on the Jugger Power pickdisassembly
0x801C8FF0 + seat*4RAMTwo-step latch, set and cleared by the cast module (PROT 0946 0x801F6CCC / 0x801F6BEC, PROT 0953 0x801F6DD0 / 0x801F6C90)disassembly
0x801EB7CC..0x801EB81CPROT 0898Gi / Che / Lu: special when round counter % 3 == 2disassembly

Verifying it

The Koru half is the part still to be run. Break on 0x801F79F0 and 0x801E67C8. Watch the byte at ctx+0x1A, the byte at ctx+0x28A, the byte at 0x801F6958, and the halfword +0x16C of all four fighters. With the flute used second or third on the round where the counter reads 4, the three party keys drop to zero together, the cursor jumps by (living party - 1), and the counter goes 4 to 5 while Koru's key is still non-zero. Repeat with the flute used first: Koru acts.

For a thrown-away decision, add a write watch on 0x801C8FE4 and a breakpoint on the action dispatch at 0x801E2CDC: the word changes in state 0x50 and no dispatch for the boss follows before the round counter moves.

Open: whether a member who is alive but cannot act (petrified or captured) shifts the overshoot by one, since the flute's loop tests HP only; the two uncaptured rows above (evolved Cort's Ultra Charge direction, Van Saryu); and which of the flagged Rikuroa rows belongs to which of Caruban, the Golem and the Piura.

The War God Icon sometimes gives only one attack string

Reported as
The accessory should make the wearer attack twice in a row, but it randomly fails to; players describe it in solo Muscle Dome Master Course fights (community report).
Cause
The "second pass used" byte doubles as the Low command's AP cost, so typing commands sets it; only an attacker stepping up to a target clears it
Where
Battle action state machine FUN_801E295C and the arts gauge build FUN_801D388C, PROT entry 0898; byte at ctx+0x16
Affects
Every wearer, plain attacks, Arts and counterattacks; in practice one-on-one fights with hand-typed commands
Status
Explained - read from the code, and the refusal captured on a poked state (the wearer was nudged into reach); a refusal with nothing nudged, and how often Noa or Gala hit it, are not measured

There is no dice roll. At the end of the first attack string the game grants the replay only if a one-byte pass counter reads zero.

That byte is shared with something unrelated: the AP cost of the Low command on the arts-entry screen. Every time a fighter's command gauge is built for typing commands by hand, the byte is set to that cost, 30. A doubled attack also leaves it at 2 or more. The game clears it in exactly one place: at the end of the short "step up to the target" phase of an attack.

So the marker reads "second pass already used" at the start of every round whose commands were typed, and stays that way until some attacker, party or monster, has to close the distance to a target. If the wearer swings before anyone has done that and is already within reach, the step-up phase is skipped, nothing has cleared the byte, and the replay is refused. The single pass that does run deals its damage normally.

state 0x14range checkstate 0x19step up: byte = 0state 0x1Estrike loopout of reachalready in reach: byte not clearedThe byte ctx+0x16 through one round, commands typed by handThe wearer attacks first and is already in reachcommands typedbyte set to 30wearer swingsin reach: no cleartwo strikes30, 31, 32string end: 32second pass refusedAny attacker, party or monster, has to step up before the wearercommands typedbyte set to 30someone steps upbyte = 0wearer swingsbyte stays 0string end: 0second pass granted
Only the step-up state clears the byte, and typing commands sets it to 30. A wearer who swings first while already in reach meets a non-zero byte at the end of the string; once anyone has stepped up, the same attack doubles.

Fighters are not walked back after an action. A monster that has just hit the wearer is left standing at the very edge of the wearer's reach, and which side of the edge depends on the knock-back of the move it used and on who the wearer is: Vahn's reach is 43 units shorter than Noa's and 96 shorter than Gala's. The failing round is: the wearer is the first to attack, types commands by hand, and targets the monster that hit them last round while it is still within reach. In a crowded fight the other attackers shove the target away and clear the byte, so it almost never lines up. In a one-on-one fight, which is where players report it, it can.

Avoiding it: choose Auto instead of typing commands, attack a different monster, or let anyone else attack first.

Sets the byte non-zeroClears itLeaves it as it is
Typing commands (the Low cost, 30)A party attacker who has to step upA party attacker already in reach
A granted second pass (one plus its strikes)A monster attack that starts out of reach, for all but six monstersA monster already in reach, and the six that walk in: the three Caruban, Evil Shadow, Shade, Nightmare
Magic, items, Spirit

Being in reach is not enough on its own: a wearer who starts in reach with a clean byte still doubles. A counterattack by the wearer is decided the same way, since the counterer takes over inside the strike loop and inherits whatever the byte holds. Nothing else cuts the second string: the target cannot die between the passes (the first pass's damage is held back until the second ends), there is no AP check, and monsters never counter.

Watched in play

Two fights were run on the retail disc: three-on-one against Gaza and one-on-one against a Gobu Gobu. No available save has the Icon equipped, so in every run the ability bit was written onto Vahn by hand (bit 0x2000 set in the word at 0x800847FC). The Gaza state has an unrelated arts-AP patch resident in the battle overlay; the Gobu Gobu state is retail apart from four data bytes.

WhatHow it was set upWhat was seen
A normal doubleAbility bit poked, nothing elseOut of reach, state 0x19, clear at 0x801E35B4, strikes with the byte at 0, the check at 0x801E3A18 reads 0, grant, the second pass bumps the byte to 6. No HP is written until the second pass ends
In reach with a clean byteAbility bit poked; Vahn's position not touchedThe monster steps up to hit Vahn, which clears the byte, and stays beside him. Vahn takes the in-reach bypass and the check still reads 0: granted
The refusalCaptured on a poked state: ability bit; HP 9000 on both sides; Vahn's maximum HP raised each round so that he acts first; Vahn moved 49 to 78 units toward the target at the range testBypass taken, two strikes bump the byte from 30 to 32, the check reads 32, recovery, no second pass. One string, damage 84 to 88 committed normally. Three rounds running
The controlThe same run, with the byte also poked to 0 at 0x801E3A10Second pass runs, 178 committed instead of 88. The next round, with no such poke, is refused again
Every store to the byteA write breakpoint over ctx+0x14..0x17 through both fights: about sixty attacks, a monster's magic cast, manual and Auto entryOnly the four stores listed below write ctx+0x16. No summon, cast-module action or item use ran under the watch; for those the list rests on a reference sweep of every code image
Battle setupA save taken at the first prompt of the Gaza fightctx+0x14..0x17 read 00 00 00 00
The gauge storeManual entry, both fightsOpening directional entry sets ctx+0x15 and ctx+0x16 to 30 every time; under Auto the byte keeps its old value

How close an unassisted wearer gets. With his position left alone, Vahn attacking the Gobu Gobu that had just hit him was 0 to 49 units outside reach in eleven rounds and inside it in one. In ten of those eleven the margin is smaller than his own 43-unit handicap, so Noa or Gala standing in the same spot would have been in reach; that is an inference from Vahn's numbers, not a capture with them wearing the Icon. Against Gaza with three attackers, every start was far out of reach.

The instructions

s5 = ctx + 0x11: 5(s5) is the pass counter ctx+0x16, 4(s5) the strike cursor, 2(s5) the acting seat. The grant, at the end of the string:

801e39bc  sltiu v0,v0,3            ; party seat
801e39fc  lw    v0,0x6bc(v0)       ; character record +0xF4
801e3a04  andi  v0,v0,0x2000       ; War God Icon bit
801e3a10  lbu   v0,5(s5)           ; pass counter
801e3a18  bnez  v0,0x801e3a74      ; NON-ZERO: no second pass
801e3a38  sb    zero,4(s5)         ; rewind the strike cursor
801e3a40  sb    v0,5(s5)           ; counter += 1

The one clear, on leaving state 0x19, and the bypass in state 0x14:

801e35b0  sb    v0,7(v1)           ; state = 0x1E
801e35b4  sb    zero,5(s5)         ; pass counter = 0

801e31f4  jal   0x8004e2f0         ; range check
801e3200  bnez  v0,0x801e3230      ; out of reach: approach
801e3210  sb    v0,7(v1)           ; in reach: state = 0x1E, counter untouched

The store outside the attack loop, in the arts gauge build (case 9 of FUN_801D388C, s4 = ctx + 0x11):

801d3b3c  sb    v0,3(a2)           ; a2 = s4 + i, i = 0..3: ctx+0x14+i
801d3bc8  sltiu v0,a3,4            ; Left, High, Low, Right

i = 2, the Low command, is ctx+0x16. Four stores cover the byte and no others: the gauge cost (0x801D3B3C), the clear (0x801E35B4), a per-strike bump that only fires when it is already non-zero (0x801E37BC) and the grant (0x801E3A40). Reading the counter as private to the attack loop misses the first of these. The list comes from a reference sweep of the executable and every overlay that follows the context pointer through both its lui-relative and gp-relative loads.

Battle setup zeroes the byte: FUN_80055B6C clears the whole battle block (0x80055F14..0x80055F24). So in a fight entered with Auto the first attack always doubles, and with typed commands the byte is already 30 before the first swing.

Reach: a party attacker is in reach of a monster when reach_bias[character] + distance < size * 16, with the bias table at 0x80078878 (+43 Vahn, 0 Noa, -53 Gala) and size the monster record's byte +0x1F. The walk chain (states 0x15..0x18) needs an action entry tagged 0x20; six of the 186 monster records have one.

The damage kernel withholds the HP write only while the counter is below 2 (0x801EE114), so a refused pass, whose byte is 2 or more, still applies its damage. The per-strike bump is a one-byte increment: a byte left stale long enough wraps through zero and the next string is granted again.

Addresses

AddressImageWhatEvidence
ctx+0x16RAM (ctx = *0x8007BD24)Attack x2 pass counter, and the Low command's AP cost on the arts-entry screendisassembly, capture
0x80084140 + (id-1)*0x414 + 0x6BCRAMCharacter record +0xF4; bit 0x2000 is the War God Icondisassembly
0x801E39BC..0x801E3A64PROT 0898Second-pass grant and its guards; zero test at 0x801E3A18disassembly, capture
0x801E3768..0x801E37BCPROT 0898Per-strike counter bumpdisassembly, capture
0x801E35B4PROT 0898The only clear, on the state 0x19 exitdisassembly, capture
0x801D3B3CPROT 0898Gauge build in FUN_801D388C: per-command AP cost into ctx+0x14+i; i = 2 is the counterdisassembly, capture
0x801E31F4..0x801E3210PROT 0898State 0x14: in reach goes straight to 0x1Edisassembly, capture
0x801E3260PROT 0898Looks up the tag-0x20 walk entry that selects the walk chaindisassembly
0x801E3548..0x801E3558PROT 0898State 0x18 into 0x1E, no cleardisassembly
0x801E3664..0x801E36DCPROT 0898Counterattack swap inside the strike loopdisassembly
0x801DAF74..0x801DB050PROT 0898Counter latch 0x801F6970: armed only against a party seat with the Counterattack bitdisassembly
0x801EE0F8..0x801EE120PROT 0898Damage kernel carry test, counter below 2 (twin at 0x801EE954)disassembly, capture
0x8004E2F0SCUSRange metric, 0 = in reach; party-on-monster test at 0x8004E344..0x8004E36Cdisassembly, capture
0x80078878SCUSReach bias per character: +43, 0, -53disc data
monster record +0x1FPROT 0867Size byte; the reach threshold is size * 16disc data
0x80055F14..0x80055F24SCUSBattle init FUN_80055B6C zeroes the battle block, context includeddisassembly
0x801DA850..0x801DA8C4PROT 0898Seeder's wound bonus for a party seat, from max HP - HPdisassembly
0x801CEDA4 / 0x801CEDA8PROT 0898Jump-table slots of states 0x18 / 0x19disc data

Verifying it

Watch the byte at ctx+0x16. Break on 0x801E3A18: a non-zero read there is a refused second pass. Break on 0x801E320C with ctx+0x13 < 3 to catch the in-reach bypass, and on 0x801E31FC to log the range result. Writing zero to the byte at 0x801E3A10 restores the double.

The run that would close the remaining gap: a memory-card save with the Icon on Noa or Gala in a one-on-one Muscle Dome fight, commands typed by hand, the wearer faster than the opponent, logging the range result and the string-end read over ten rounds. The prediction is "in reach" and a non-zero read on most rounds that follow the opponent's attack.

Open: a refusal with nothing nudged; how often a Noa or Gala wearer starts in reach; the wearer's own counterattack and the one-byte wrap are read from the code, not captured.

Side Kick's first hit misses floating enemies even with War God Boots

Reported as
War God Boots let Gala's low kick hit floating enemies, but Side Kick still misses its first hit against them (community report).
Cause
Reach is a property of each hit's power byte. The boots swap in a different low-kick record; Side Kick is an art with its own fixed bytes
Where
Melee kernel FUN_801EC3E4, PROT entry 0898, test at 0x801EC488; bytes in Gala's battle file, PROT entry 0865
Affects
One art hit in the whole game; the floating monsters listed below
Status
Explained - from the code and disc data, no capture

Whether a hit can reach a floating enemy is decided by the hit's own power byte, not by anything on the attacker. Low hits come in two encodings: one that cannot reach a floater and one that always connects.

Power byte of one hit, 0x0C to 0x1Fhigh, restricted0C..10low, restricted11..15high, free16..1Alow, free1B..1FSide Kick hit 1: 12hit 2: 17Low kick, other boots: 13Low kick, War God Boots: 1DA floating enemy (class 2) cannot be hit by bytes 11..15
The twenty power-byte values in their four bands. Side Kick's first hit sits in the same restricted band as an ordinary low kick; only the War God Boots' own kick record moves out of it.

The boots grant no ability. Every pair of shoes ships its own Low and High kick, and the War God Boots' Low kick simply carries the always-connects byte where Gala's other shoes carry the restricted one.

FootwearLow kickHigh kick
none / Power Shoes / Fighting Boots13 restricted0E restricted
War God Boots1D free18 free
Ra-Seru Thongs13 restricted18 free

Side Kick is not a shoe's kick. It is an art, stored in Gala's art bank with the fixed power run 12 17. The first byte is the restricted kind, so the first hit misses a floater; the second connects. Changing boots never touches an art record. Across all three characters' art banks it is the only hit encoded this way.

The instructions
801ec488  sltiu v0,a3,3            ; party attacker only
801ec494  lbu   a0,0(a1)           ; this hit's power byte
801ec49c  sltiu a1,a0,0x16         ; 0x16 and up always connects
801ec4c0  lbu   v1,0x1e(v0)        ; target monster record +0x1E
801ec4cc  sltiu v0,a0,0x11         ; class 2: bytes 0x11..0x15 miss
801ec53c  sltiu v0,v0,0x11         ; class 3: bytes below 0x11 miss
801ec554  sb    v0,0x263(v1)       ; miss flag, no roll, no damage

Direction commands play swing records spliced from the equipped items (the footwear section's first record is the Low kick, its second the High kick; the power run is the record's first bytes). Arts play a record from the art bank, selected as record constant - 0x10, power run at +0x24. Side Kick is Gala's action constant 0x23.

Who and what it applies to

Floating monsters (height class 2): Evil Fly, Death Wings, Demon Fly, Drake Ghost, Guardian, Ghost Knight, the Theeder, Vera, Nighto, Viguro, Gola Gola, Slippery, Puera and Gilium families, Pump Bat, Devil Pump, Boogie Pump, Hornet, Killer Bee, Queen Bee, Spikefish, Mad Bird, Wailing Bird, Mage, Sorcerer, Thermo, Amethyst, Garnet, Topaz, the Evil Bat records, Lapis, Rogue and Zora.

Short monsters (class 3, missed by restricted High kicks): Mushroom, Mushrin, Mush Mush, Frog, Gel Frog, King Frog.

CharacterReaches floatersRestricted
VahnTriumph Boots, Ra-Seru Bootsnone, Warrior, Ironman, Master, Expert, Hero Boots
Noanothingevery shoe, Ra-Seru Shoes included
GalaWar God Bootsnone, Power Shoes, Fighting Boots, Ra-Seru Thongs

Addresses

AddressImageWhatEvidence
0x801EC488..0x801EC554PROT 0898Limb-versus-height miss test in the melee kernel FUN_801EC3E4disassembly
0x801F64ECPROT 0898Power multiplier table 0C 12 14 16 1Cdisc data
monster record +0x1EPROT 0867Height class: 2 floating, 3 shortdisc data
ctx+0x263RAMMiss strobedisassembly
0x80052FA0 / 0x800557B8SCUSBattle-file assembler and swing-record copyrepo doc
footwear section +0x04 / +0x08PROT 0863..0865Offsets of the Low / High swing records; power run at record +0disc data
art bank record (0x23-0x10), +0x24PROT 0865Side Kick's power run 12 17, hit frames 7 and 16disc data
Side Kick = action constant 0x23-Gala's learned-art slot 8repo doc

Verifying it

Fight an Evil Fly with Gala in War God Boots and break on 0x801EC494. A plain Low reads 0x1D and connects. Side Kick reads 0x12 on its first hit, branches to 0x801EC548 and sets the miss flag; its second reads 0x17 and connects. Changing the art record's first power byte from 0x12 to 0x1C (same multiplier, free range) makes the first hit land.

Open: whether 0x12 is a deliberate low sweep or an authoring slip cannot be told from the data.

The level-3 dance special swallows the next special

Reported as
In the dance minigame, the level-3 special animation "eats" the next special if two level-3 specials are done in a row (community report). The special is the Triangle move, the lesson's "groovy move". An early fan guide gives the same warning: used at level 3, it lasts so long that you miss the next move.
Cause
Presses are only judged while the idle or dance loop plays; the level-3 Triangle move runs 6.83 beats, past the next scoring slot and the next combo's first note
Where
Dance overlay, PROT entry 0980: per-dancer tick FUN_801D1358, gate at 0x801D168C
Affects
Every dancer and every triggered move; worst at level 3
Status
Explained - read from code and data, and captured in the running game with scripted button presses and nothing written to memory

A dancer's button presses are judged only while its body is playing the idle or the basic dance loop. Every triggered move, whether a combo finisher, the Triangle "groovy move" or the flinch after a wrong press, is a one-shot animation, and until it reaches its last frame the judge is not called at all. A press made during it is not stored, not counted as a miss, and for Triangle does not use up one of the three per song. It vanishes.

The level-3 animations are the longest. The level-3 Triangle move lasts 6.83 beats. The next scoring slot closes at most 4.75 beats after the press, so a second Triangle there is always lost. The next level-3 combo starts 6 beats after the press, so its first note is lost too and that combo cannot be completed. A Triangle on the last note of that combo, 8 beats on, does register.

Holding the button does not help: the game only sees a button on the frame it goes down.

Beats after a Triangle press that was judgedeach box is one beat's timing window, 0.75 of a beat; dashed ones carry no level-3 notepressnext slotnext combo: notes 1, 2, 3012345678level 1: 2.56 beatslevel 2: 4.91 beatslevel 3: 6.83 beatsnext slot: Triangle not judged, not spent (levels 2 and 3)first note of the next combo: not judged (level 3)notes 2 and 3 are judged; Triangle on note 3 pays in full
Input locks after a Triangle press, drawn to scale on the beat ruler. The level-2 and level-3 locks cover the whole of the next scoring slot; the level-3 lock also covers the first note of the next combo.
MoveFrames of animationLock, game framesLock, delta unitsLock, beats
wrong-press flinch30401204.27
level-1 combo15 / 2020 / 2760 / 812.14 / 2.88
level-2 combo26351053.74
level-3 combo30401204.27
level-1 Triangle1824722.56
level-2 Triangle34461384.91
level-3 Triangle48641926.83

Triangle pays its real reward only on a combo slot (every fourth beat) inside the timing window. A press made up to 0.75 beat into one slot can be followed on the next slot no later than 4.75 beats afterwards:

First moveLock, beatsWhat it costs afterwards
level-1 Triangle2.56nothing: a press on the next slot is judged
level-2 Triangle4.91the whole next slot, every time
level-3 Triangle6.83the whole next slot, and the first note of the next level-3 combo, 6 beats on. A press 8 beats on is judged
level-3 combo finisher4.27a next-slot press is judged only if it comes at least 4.27 beats (40 game frames) after the finishing press
wrong-press flinch4.27as for a level-3 finisher

The level-3 chart places one three-note combo per eight beats, so two combo finishers in a row never collide. A Triangle dropped inside the lock does not reduce the stock. A Triangle pressed after the lock ends but outside a combo-slot window does spend one, for only a few points, which is the other way a second special can feel swallowed. Triangle pressed together with Square or Circle is judged as Triangle alone, so "with the last command of a combination" means "instead of it".

The code also has a per-dancer "queued move" flag that would start a follow-up move when the current one ends. The move number is written on every completed combo, but the flag itself is only ever written zero: nothing else on the disc that can be loaded with the dance hall refers to it, and a write watch during the runs saw only the two zero stores. The follow-up never fires. It reads as an unfinished "chain the next move" path, which is an inference.

Watched in play

The qualifier (Noa and two rivals) was run in the retail dance hall. Every input went through the emulator's controller; level 3 was reached by pressing the chart's own notes; nothing was written to memory. The run starts from a save state taken on the way into the hall, which then loads the dance code from the retail disc. That state has an unrelated patch resident in the main executable: four code sites differ from the disc, none in the frame-timing or animation code, and the dance overlay's code is byte-identical to the disc's.

Triangle on consecutive combo slots at level 3:

Game frameBeatAnimation boundJudge calledTriangles leftScore
54351loop to 17yes3 to 2180 to 255
5815517no, though the press is in the pad word2255
60757loop againyes2255
61859loop to 17yes2 to 1255 to 330
6566317no1330
69367loop to 17yes1 to 0330 to 405

The gate stayed shut for exactly 64 game frames after each judged level-3 Triangle. Other runs: from the start of a song, the level-1 Triangle reopens the gate after 24 frames and the next press is judged, the level-2 Triangle holds it for 46 and the press on the next slot is neither judged nor spent. With the next combo played normally after a level-3 Triangle, its first note is not judged, the other two score as plain hits and the combo does not close. With Triangle pressed on that combo's last note instead, it is judged and pays in full. A dropped Triangle held down for 80 frames, through the end of the lock, shows in the pad word on one frame only and never fires.

The instructions
801d168c  lw   v0,0x10(s1)         ; idle clip id
801d1690  lh   v1,0x5c(s0)         ; clip bound right now
801d1698  beq  v1,v0,0x801d16b4    ; idle: judge
801d16a0  lw   v0,0x18(s1)         ; dance-loop clip id
801d16ac  bne  v1,v0,0x801d1750    ; anything else: skip the judge
801d16b4  jal  0x801d1af4          ; judge / award routine

The clip driver FUN_800204F8 steps the cursor by (rate * 2 + div - 1) / div times the frame-delta byte at 0x1F800393 and raises the end flag at frames * 16 - 1. Noa's moves all run at rate 8 with divisor 4, a step of 4. The hall runs at a frame delta of 3: the dance init writes the frame-step floor (0x801CF070) and the frame driver FUN_80016B6C applies it, and it read 3 on every play frame. So the cursor moves 12 per game frame and the gate is shut for exactly ceil((frames * 16 - 1) / 12) game frames after the judged one. There is no extra frame for the release: the driver call at the end of the tick that binds the clip is already its first step.

The beat clock advances by the same frame delta times ten, with a beat of 0x119 units, so one beat is 28.1 delta units or 9.37 game frames. A level-2 Triangle reopens the gate 1380 beat-clock units after the press; the next slot's window has closed by 1333.

Addresses

AddressImageWhatEvidence
0x801D1358PROT 0980Per-dancer tickdisassembly
0x801D168C..0x801D16B4PROT 0980Judging gate: bound clip must be idle or dance loopdisassembly, capture
0x801D14C8PROT 0980Clip end-flag test (+0x62 & 0x100)disassembly
0x801D1AF4PROT 0980Judge / award routinedisassembly
0x801D1C9CPROT 0980Triangle clip pick, lane*2 + 0x10disassembly
0x801D1CA8..0x801D1CCCPROT 0980Combo-slot and window test for Triangledisassembly
0x801D1C98PROT 0980Triangle stock decrementdisassembly
0x801D1E5C / 0x801D1F9CPROT 0980Direction arms skip when the hit latch 0x801D548C is set, so Triangle pre-empts themdisassembly
0x801D534CRAMTriangle stock, one word per dancerdisassembly, capture
0x801D55CC / 0x801D560CRAMQueued-move flag (only ever written zero) and move numberdisassembly, capture
0x801D4E1CPROT 0980Dancer descriptor table; move pairs from +0x28disc data
0x801D509CPROT 0980Step chart, three rows of 0x20 beatsdisc data
0x801CF070PROT 0980Dance init writes the frame-step floor, 3disassembly
0x8007B9D8RAMFrame-step floordisassembly, capture
0x80016B6CSCUSFrame driver that rebuilds 0x1F800393 and applies the floordisassembly
0x800204F8SCUSClip driverdisassembly
0x1F800393RAMFrame-delta byte both clocks scale by; 3 in the halldisassembly, capture
0x8007B874RAMPad word of newly pressed buttons; Triangle is 0x0010capture
clip records 7..17PROT 1229Frame counts of Noa's movesdisc data
beat 0x119, window 0xD2-Beat clock constantsrepo doc

Verifying it

Break on 0x801D16B4 for dancer 0 and log the frame number. After a level-3 Triangle the next hit comes 64 game frames later at the hall's frame delta of 3. Or watch the bound clip id at actor +0x5C: presses made while it reads 0x11 show in the pad word at 0x8007B874 but never reach 0x801D1AF4, and the stock word at 0x801D534C does not change.

The capture ran the qualifier only; the gate is the same code in every mode of the minigame.

See also

Battle action state machine · damage formulas · art data · player battle files · accessory passives · the arts command gauge · the endless camera orbit