Claim set · data/claims/ff6-av.yaml

Final Fantasy VI battle graphics and sound (everything8215's disassembly)

Game: Final Fantasy VI.

On a town or dungeon map, a battle starts with the battle sound effect, number $C1, and 32 frames of mosaic over the background layers before the field hands over to the battle program. Each frame the routine writes the mosaic size into all eight entries of the field's mosaic HDMA table, which feeds the mosaic register: for the first 15 frames the size counts 1 to 7 and then 0 to 7, for the next 16 it counts 0 to 15, and on the 32nd it is 0 again. A size of n draws blocks n + 1 pixels square, so the screen breaks up twice into blocks up to 8 pixels and then once into blocks up to 16. Two flags can turn the sound or the blur off: a battle started by event command $4E turns both on, the Colosseum turns both off, and a monster-in-a-box battle takes them from the top two bits of its event command's background byte. ff6-av/field-battle-mosaic

About: Final Fantasy VI HDMA

Value
{
 "frames": 32,
 "sfx": 193,
 "sizes": [
  1,
  2,
  3,
  4,
  5,
  6,
  7,
  0,
  1,
  2,
  3,
  4,
  5,
  6,
  7,
  0,
  1,
  2,
  3,
  4,
  5,
  6,
  7,
  8,
  9,
  10,
  11,
  12,
  13,
  14,
  15,
  0
 ]
}
CodeFinal Fantasy VI Disassembly · src/field/battle.asm#L25-L61; [ battle blur/sound ] .proc BattleMosaic lda $078a ; branch if battle sound effect is disabled and #$40 bne :+ lda #SFX::BATTLE_SFX jsr PlaySfx : lda $078a ; return if battle blur is disabled bmi Done stz $46 ; clear frame counter Loop: jsr WaitVblank lda $46 cmp #$10 bcs LastHalf … and #$07 ; increase mosaic size from 0 to 7 twice … and #$0f ; then increase from 0 to 15 once : asl4 ora #$0f ; enable mosaic on all bg layers sta $7e8233 ; store in screen mosaic hdma table ($2106) … sta $7e824f lda $46 ; loop for 32 frames cmp #32 bne LoopFinal Fantasy VI Disassembly · src/field/battle.asm#L65-L68; [ execute battle ] .proc ExecBattle jsr BattleMosaicFinal Fantasy VI Disassembly · src/field/reset.asm#L287inc $46 ; increment vblank counterFinal Fantasy VI Disassembly · src/sound/sfx.inc#L199BATTLE_SFX ; $c1 // 193Final Fantasy VI Disassembly · src/field/event.asm#L1669-L1671EventCmd_4e: @a4f9: inc $56 ; enable battle stz $078a ; enable blur and soundFinal Fantasy VI Disassembly · src/field/event.asm#L1704-L1706 — the Colosseum battle (event command $AF)lda #$c0 sta $078aFinal Fantasy VI Disassembly · src/field/event.asm#L1803-L1805 — the monster-in-a-box battle (event command $8E)lda $ec ; battle blur/sound flags and #$c0 sta $078aChecked by claude-agent, 2026-11-08 — read BattleMosaic and ExecBattle, the field NMI's frame counter, the sound effect's number, and the three event commands that set the flags; the size sequence is computed from the frame counter, which is 1 after the first waitChecked by a second AI model, 2026-11-08.

The mosaic register's high nibble is the size and its low nibble picks the layers; $0F sets BG1 to BG4. The size sequence is computed: the counter is cleared, then incremented by the NMI before the first read, so the first frame reads 1; the frame that reads 32 still writes its size (32 AND 15 = 0) before the loop ends.

Cited by: Battle transition, Mosaic

On the world map, a random battle starts with the battle sound effect and a 34-frame Mode 7 zoom. Each frame takes a pair from a table, the high byte of the zoom level the world map's Mode 7 code reads and the screen brightness. The zoom byte falls from $85 to $18 over the first 8 frames, rises back to $6D by the 16th, eases to $58 by the 24th, and over the last 10 falls to 0 while the brightness steps down from full (15) through 13, 12, 11, 9, 8, 7, 5, 4, 3 to 1. The routine also leaves only BG1 and BG2 on the main screen and clears the sub screen. ff6-av/world-battle-zoom

About: Final Fantasy VI Mode 7

Value
{
 "frames": 34,
 "zoom": [
  133,
  112,
  92,
  58,
  45,
  35,
  25,
  24,
  27,
  41,
  50,
  61,
  83,
  92,
  100,
  109,
  109,
  108,
  105,
  104,
  101,
  95,
  92,
  88,
  78,
  73,
  68,
  56,
  49,
  43,
  29,
  22,
  15,
  0
 ],
 "brightness": [
  15,
  15,
  15,
  15,
  15,
  15,
  15,
  15,
  15,
  15,
  15,
  15,
  15,
  15,
  15,
  15,
  15,
  15,
  15,
  15,
  15,
  15,
  15,
  15,
  13,
  12,
  11,
  9,
  8,
  7,
  5,
  4,
  3,
  1
 ]
}
CodeFinal Fantasy VI Disassembly · src/world/move.asm#L1398-L1433; [ battle zoom and sound effect ] BattleZoom: … lda #SFX::BATTLE_SFX sta hAPUIO1 … lda #$03 sta hTM stz hTS ldx #0 @2228: lda f:BattleZoomTbl,x ; zoom level sta $8c lda f:BattleZoomTbl+1,x ; screen brightness sta hINIDISP phx jsr UpdateMode7Vars … @223e: lda $24 ; wait for vblank beq @223e stz $24 inx2 cpx #$0044 bne @2228Final Fantasy VI Disassembly · src/world/move.asm#L1436-L1442; battle zoom data (2 bytes each, zoom level then screen brightness) BattleZoomTbl: @224e: .word $0f85,$0f70,$0f5c,$0f3a,$0f2d,$0f23,$0f19,$0f18 .word $0f1b,$0f29,$0f32,$0f3d,$0f53,$0f5c,$0f64,$0f6d .word $0f6d,$0f6c,$0f69,$0f68,$0f65,$0f5f,$0f5c,$0f58 .word $0d4e,$0c49,$0b44,$0938,$0831,$072b,$051d,$0416 .word $030f,$0100Final Fantasy VI Disassembly · src/world/move.asm#L880-L898beq @1e1f ; branch if battles are disabled … jsl CheckBattleWorld_ext … beq @1e1c ; branch if no random battle … jsr BattleZoomFinal Fantasy VI Disassembly · src/world/rotate.asm#L884-L886 — the Mode 7 update reads the zoom level as the 16-bit word at `$8B`, whose high byte the battle zoom writes@3ee9: lda $8b sta $97 lda $8dFinal Fantasy VI Disassembly · src/world/move.asm#L587-L590 — in flight the zoom level is the airship's altitude plus $3000@1b7b: lda $2f clc adc #$3000 sta $8b ; set zoom levelFinal Fantasy VI Disassembly · src/world/interrupt.asm#L303-L318; [ world nmi (no vehicle) ] WorldNMI: … inc a:$0024 ; vblank flagFinal Fantasy VI Disassembly · src/world/move.asm#L808-L810 — the random battle check that calls the zoom is in the no-vehicle movement; [ update movement (no vehicle) ] MovePlayer:Checked by claude-agent, 2026-11-08 — read BattleZoom, its table (34 words, $44 bytes), the random battle check that calls it (in the no-vehicle movement), the no-vehicle NMI's vblank flag the loop waits on, and the Mode 7 update's read of $8BRevised after a check by a second AI model, 2026-11-08.

Each table word is little-endian, so its low byte is the zoom and its high byte the brightness. Which way a larger zoom number moves the view is the world map's Mode 7 projection's business, which this claim doesn't read: it gives the numbers, not the direction. TM = $03 is BG1 and BG2.

Cited by: Battle transition

Two more transitions start battles from the world map's other modes, the Magitek train ride (as the disassembly names it) and the world map with a vehicle: each pass of the mode's main loop checks a battle-enabled bit and, when it is set, runs the mode's transition. On the train the routine plays the sound effect the field's battle mosaic plays ($C1) and writes 41 bytes straight to the mosaic register, one a frame: block size 1 up to 13 pixels, back down to 1, and up to 16, all four background layers on. With a vehicle, the effect plays the battle sound and lowers the screen brightness by one a frame for 40 frames, stopping at 0. ff6-av/other-battle-transitions

Value
{
 "trainBytes": 41,
 "trainSizes": [
  0,
  1,
  2,
  3,
  4,
  5,
  6,
  7,
  8,
  9,
  10,
  11,
  12,
  12,
  11,
  10,
  9,
  8,
  7,
  6,
  5,
  4,
  3,
  2,
  1,
  0,
  1,
  2,
  3,
  4,
  5,
  6,
  7,
  8,
  9,
  10,
  11,
  12,
  13,
  14,
  15
 ],
 "vehicleFrames": 40
}
CodeFinal Fantasy VI Disassembly · src/world/move.asm#L233-L270; [ battle blur and sound effect (magitek train) ] TrainBattleMosaic: … lda f:TrainBattleMosaicTbl,x inx sta hMOSAIC @18f9: cmp #$ff beq @1905 … ; battle blur data TrainBattleMosaicTbl: @1907: .byte $0f,$1f,$2f,$3f,$4f,$5f,$6f,$7f,$8f,$9f,$af,$bf,$cf,$cf,$bf,$af .byte $9f,$8f,$7f,$6f,$5f,$4f,$3f,$2f,$1f,$0f,$1f,$2f,$3f,$4f,$5f,$6f .byte $7f,$8f,$9f,$af,$bf,$cf,$df,$ef,$ffFinal Fantasy VI Disassembly · src/world/move.asm#L182-L231; [ vehicle battle effect ] VehicleBattleEffect: … lda #SFX::BATTLE_SFX sta hAPUIO1 … lda #$28 ; wait 40 frames sta $66 … lda $23 ; decrement screen brightness beq @18ba dec @18ba: sta $23 @18bc: lda $24 ; wait for vblank beq @18bc stz $24 dec $66 bne @1891Final Fantasy VI Disassembly · src/world/world_start.asm#L150-L154lda $11f6 bit #$0002 beq @01cb ; branch if battle is not enabled jsr VehicleBattleEffectFinal Fantasy VI Disassembly · src/world/world_start.asm#L8-L10; [ world map (with vehicle) ] VehicleMain:Final Fantasy VI Disassembly · src/world/world_start.asm#L522-L567; [ magitek train ride ] TrainMain: … jsr ExecTrainCmd jsr UpdateTrainGfx lda $11f6 bit #$02 beq @0545 ; branch if battle is not enabled ; battle jsr TrainBattleMosaicFinal Fantasy VI Disassembly · src/world/interrupt.asm#L565-L583; [ magitek train ride nmi ] … inc a:$00fa ; increment 4 frame counterFinal Fantasy VI Disassembly · src/world/interrupt.asm#L16-L31; [ world nmi (w/ vehicle) ] VehicleNMI: … inc a:$0024 ; vblank flagChecked by claude-agent, 2026-11-08 — read both routines, the train's table (41 bytes, the last $FF ending the loop after it is written), the train ride's and the vehicle world map's main loops that call them, and the two NMIs that set the bytes their loops wait onRevised after a check by a second AI model, 2026-11-08.

The sizes are each byte's high nibble; block size in pixels is the size plus 1. The train's loop waits on $fa, which the train ride's NMI increments each time it runs (its comment calls it a 4-frame counter, but the increment is unconditional), and the vehicle effect's loop on $24, which the vehicle NMI increments as its vblank flag; the NMI runs once a frame.

The battle screen opens from a line across the middle of the battlefield. It starts black: every line of an HDMA table that feeds the color math registers subtracts full white from BG1 to BG3 and the sprites. Each frame the clear band grows by two lines up and two down from line 76, the battlefield's middle, and beyond each edge the subtraction rises by one step (of 31) every two lines, so the band's edges are soft gradients 62 lines deep. After 38 frames all 152 battlefield lines are clear and the channel goes back to its window table. Meanwhile the screen brightness rises by one each frame, from 1 to full (15) in 15 frames. ff6-av/battle-fade-in

About: Final Fantasy VI HDMA

Value: frames 38 · middle line 76 · battlefield lines 152 · lines per step 2 · brightness frames 15

CodeFinal Fantasy VI Disassembly · src/btlgfx/init.asm#L638-L646lda #$ff97 ; full subtract, all layers, white @1213: sta near w7eea32,x inx2 cpx #$01c0 bne @1213 shorta0 lda #$80 sta near w7ee9f9Final Fantasy VI Disassembly · src/btlgfx/init.asm#L738-L743; init fade in lda #$4c sta near w7ee9f7 stz near w7ee9f8 lda #1 sta near w7ee9f6 ; enable fade inFinal Fantasy VI Disassembly · src/btlgfx/init_2.asm#L199-L240; [ update screen fade in ] UpdateFadeIn: … ; increment screen brightness lda near w7ee9f9 and #$0f cmp #$0f beq @b8b6 inc sta near w7ee9f9 ; update hdma for fade bars @b8b6: shorti lda near w7ee9f7 asl tay lda near w7ee9f8 asl tax lda #$e0 ; black @b8c4: sta near w7eea32-1,y sta near w7eea32+1,y sta near w7eea32+$99,x sta near w7eea32+$9b,x cmp #$ff beq @b8d5 inc @b8d5: inx4 dey4 bne @b8c4 inc near w7ee9f8 inc near w7ee9f8 dec near w7ee9f7 dec near w7ee9f7 bne @b8f0 stz near w7ee9f6 ; fade in is completeFinal Fantasy VI Disassembly · src/btlgfx/interrupt_2.asm#L57-L62; hdma #5 table (+$2131, color math) ; used for fade in, then replaced with the window position HDMA table HDMA5FadeInTbl: hdma_addr 112 | BIT_7, w7eea32 hdma_addr 112 | BIT_7, w7eea32 + 112 * 2Final Fantasy VI Disassembly · src/btlgfx/interrupt.asm#L1032-L1037 — called from the battle's NMI, so once a frame; [ update running/fade in/timers ] _c10b73: escape_set: @0b73: stz near w7e2f45 ; disable characters running animation jsl UpdateFadeInFinal Fantasy VI Disassembly · src/btlgfx/init.asm#L839-L846; wait for fade in @1404: jsr WaitFrame lda near w7ee9f6 bne @1404 clr_ax stx $10 jsr SetColorMathHDMAChecked by claude-agent, 2026-11-08 — read the table's initial fill, the fade-in's start values, UpdateFadeIn's two write loops (the upper walks up from line f7, the lower down from line 76 + f8, each iteration two lines and one intensity step, capped at $FF), the channel 5 table, and the NMI path that calls it; band widths and frame count computed from f7 = 76 falling by 2 a frameChecked by a second AI model, 2026-11-08.

Each table entry is two bytes, the color math control ($2131) and the fixed color ($2132); $97 subtracts from BG1 to BG3 and sprites, and the fixed color byte's top three bits pick red, green and blue with its low five the intensity, so $E0 is 0 and $FF is 31. The writes land on the odd bytes, the fixed color. Lines 152 on are the menu, whose gradient the same initialisation copies in (init.asm#L700-L705).

Cited by: Color math

A battle's song comes from its battle properties: bits 3 to 5 of the fourth byte index an 8-entry battle song table (in the disassembly's names the battle theme, Decisive Battle, Fierce Battle, Returners, Save Them, and Dancing Mad parts 1 to 3, then two entries that mean keep the song playing); bit 7 set leaves the music alone. A character-AI scene's own song, when it names one, takes the table's place, and a random battle started while an event flag is set keeps the map's music. The same byte's bit 2 turns off preemptive strikes and the four messages that announce a battle's start: back attack, pincer attack, side attack and preemptive strike. When the battle ends, the end command fades the music out unless the battle kept the music playing (bit 7, or the map's song) and no victory fanfare played; the fanfare, which plays only when the map's song wasn't kept, always brings the fade. ff6-av/battle-music

About: Final Fantasy VI Music driver

Value: songs BATTLE_THEME, DECISIVE_BATTLE, FIERCE_BATTLE, RETURNERS, SAVE_THEM, DANCING_MAD_1_2_3, NONE, NONE

CodeFinal Fantasy VI Disassembly · src/battle/init_2.asm#L681-L685lda f:BattleProp+2,x ; load auxiliary battle data sta near w7e2f4a lda f:BattleProp,x eor #$00f0 ; toggle battle type flags sta near w7e2f48Final Fantasy VI Disassembly · src/btlgfx/char_ai.asm#L72-L95sta near w7e629d ; special song index … @bd95: lda near w7e2f4b bmi @bdd0 … lda #$10 ; spc command $10 (load song) sta $1300 … lda near w7e629d cmp #$ff bne @bdbf ; branch if a special song from character ai data lda near w7e2f4b and #$38 lsr3 tax lda f:BattleSongTbl,x cmp #$ff beq @bdcd ; branch if continuing same song @bdbf: sta $1301 ; song number lda $11e4 and #$08 bne @bdcd ; branch if continuing current music jsl ExecSound_extFinal Fantasy VI Disassembly · src/btlgfx/char_ai.asm#L266-L275; battle songs BattleSongTbl: .byte SONG::BATTLE_THEME .byte SONG::DECISIVE_BATTLE .byte SONG::FIERCE_BATTLE .byte SONG::RETURNERS .byte SONG::SAVE_THEM .byte SONG::DANCING_MAD_1_2_3 .byte SONG::NONE .byte SONG::NONEFinal Fantasy VI Disassembly · src/field/battle.asm#L426-L429 — the field's random battle; the world map's does the same (field/battle.asm#L207-L210)lda $1ed7 ; and #$10 lsr sta f:$0011e4Final Fantasy VI Disassembly · src/battle/init.asm#L100-L119lda near w7e2f4b bit #$04 bne @24ea … ldx #ATTACK_MSG::BACK_ATTACK … ldx #ATTACK_MSG::PINCER_ATTACK … ldx #ATTACK_MSG::SIDE_ATTACK … ldx #ATTACK_MSG::PREEMPTIVE_ATTACK @24ea: txyFinal Fantasy VI Disassembly · src/btlgfx/main.asm#L102-L114; [ battle graphics command $09: fade out & terminate battle ] … @00af: lda near w7e2f4b bmi @00bb lda $11e4 and #$08 beq @00c0 ; branch if not continuing current music @00bb: lda near w7e6284 beq @00d7 @00c0: inc near wSfxDisabled ; disable sound effects lda #$81 sta $1300Final Fantasy VI Disassembly · src/battle/init_2.asm#L333-L335lda near w7e2f4b bit #$04 bne @2ec0 ; return if preemptive attacks are disabledFinal Fantasy VI Disassembly · src/btlgfx/main.asm#L175-L182 — the victory fanfare sets `w7e6284` only when the map's song isn't keptlda $11e4 and #$08 bne @0163 ; branch if continuing music from map inc near wSfxDisabled ; disable sound effects inc near w7e6284 lda #$10 sta $1300 lda #SONG::VICTORY_FANFAREChecked by claude-agent, 2026-11-08 — read LoadBattleProp, the character-AI scene init's song choice, the song table, the random battle's flag copy, the battle-start message choice, the preemptive strike roll's check, the terminate command's two branches, and the victory fanfare's flagRevised after a check by a second AI model, 2026-11-08.

Which battles use each index is counted in [ff6-tables/tracks](#ff6-tables/tracks). SONG::NONE is $FF, which the code reads as keep the song. Command $81 to the sound driver is the fade (sound_main.asm); this claim doesn't read its rate.

A battle's background is picked before the battle starts. On a town or dungeon map it is the map's own battle background. On the world map the terrain under the party gives an index 0 to 7, and a table of eight backgrounds for each world turns it into one (field, forest, desert, a second forest, Zozo's interior, the World of Ruin's field, the Veldt, and clouds in the World of Balance; the World of Ruin swaps in its own desert and its field twice). The Colosseum sets its own, and a monster-in-a-box battle takes its event command's background unless that is $3F, which falls back to the map's. A character-AI scene can name a special one. ff6-av/battle-background

BalanceRuin
FIELD_WOBFIELD_WOB
FOREST_WORFOREST_WOR
DESERT_WOBDESERT_WOR
FOREST_WOBFOREST_WOB
ZOZO_INTFIELD_WOR
FIELD_WORFIELD_WOR
VELDTVELDT
CLOUDSCLOUDS
CodeFinal Fantasy VI Disassembly · src/field/battle.asm#L413-L419lda $0522 ; battle bg and #$7f sta f:$0011e2Final Fantasy VI Disassembly · src/world/move.asm#L876-L882jsr GetWorldTileProp shorta bit #$40 beq @1e1f ; branch if battles are disabled xba sta $11f9 ; battle bg indexFinal Fantasy VI Disassembly · src/field/battle.asm#L98-L109lda $1f64 ; map index asl3 sta $1a lda $11f9 ; battle bg index from world map and #$07 ora $1a tax lda f:WorldBattleBGTbl,x sta f:$0011e2Final Fantasy VI Disassembly · src/field/battle.asm#L225-L246; world map battle backgrounds (8 per map) WorldBattleBGTbl: ; world of balance .byte BATTLE_BG::FIELD_WOB .byte BATTLE_BG::FOREST_WOR .byte BATTLE_BG::DESERT_WOB .byte BATTLE_BG::FOREST_WOB .byte BATTLE_BG::ZOZO_INT .byte BATTLE_BG::FIELD_WOR .byte BATTLE_BG::VELDT .byte BATTLE_BG::CLOUDS ; world of ruin .byte BATTLE_BG::FIELD_WOB .byte BATTLE_BG::FOREST_WOR .byte BATTLE_BG::DESERT_WOR .byte BATTLE_BG::FOREST_WOB .byte BATTLE_BG::FIELD_WOR .byte BATTLE_BG::FIELD_WOR .byte BATTLE_BG::VELDT .byte BATTLE_BG::CLOUDSFinal Fantasy VI Disassembly · src/field/event.asm#L1692-L1695lda #$001c sta f:$0011e2 ; set battle background to colosseumFinal Fantasy VI Disassembly · src/field/event.asm#L1806-L1810lda $ec ; battle bg and #$3f cmp #$3f bne @a5db lda $0522 ; map's default battle bgFinal Fantasy VI Disassembly · src/btlgfx/char_ai.asm#L64-L68lda f:CharAI+1,x ; special battle background cmp #$ff beq @bd84 ; branch if no special background sta near w7eecb8 ; set battle backgroundChecked by claude-agent, 2026-11-08 — read the field's random battle setup, the world map's tile property read and CheckBattleWorld's table lookup, the table, the two event commands, and the character-AI scene initChecked by a second AI model, 2026-11-08.

The table's names are the disassembly's constants; "the World of Ruin's field" is FIELD_WOR, which the World of Balance's sixth slot also uses. The same index picks the world map's battle rate and group (BattleBGRateTbl, BattleBGGroupTbl), as [ff6/encounter-rate](#ff6/encounter-rate) reads.

A damage or healing number is drawn as two 16-pixel-wide sprites over the target, built each time from digit tiles: the value's low 14 bits are turned into decimal digits by counting off thousands, hundreds and tens, leading zeros are dropped, and each digit is 8 pixels wide, so the number is shifted left by half its width (4, 8, 12 or 16 pixels) to center it. Damage uses sprite palette 4, which the source calls white, and healing palette 5, green; a miss draws a "miss" graphic instead, shifted by 8. Four number slots serve single targets, and a new number for a target that already shows one waits 8 frames first; a spell over several targets draws its numbers with a command that runs over 10 entries, one for each character and monster. The conversion has no ten-thousands place: a value over 9999 would count 10 to 16 into the thousands digit, which this claim doesn't follow to the screen, nor whether the battle program keeps damage below it. A number is hidden on any frame its sprite is on line 151 or lower, where the menu begins. ff6-av/damage-numerals

Value: slots 4 · multi slots 10 · digit width 8 · max digits 4 · value bits 14 · damage palette 4 · heal palette 5 · miss offset 8 · same target wait 8 · hide from line 151

CodeFinal Fantasy VI Disassembly · src/btlgfx/gfx_cmd.asm#L2907-L2914; [ graphics script command $0b: display damage numerals (single) ] ; b1: numeral target ; +b2: gm?vvvvvv vvvvvvvv ($ffff = hide numerals) ; g: green numeral ; m: display "miss" ; v: numeral valueFinal Fantasy VI Disassembly · src/btlgfx/gfx_cmd.asm#L2925-L2931lda near w7e631a,x ; branch if numeral is not enabled … lda #$08 jsr WaitA ; wait 8 frames while the existing numeral finishesFinal Fantasy VI Disassembly · src/btlgfx/gfx_cmd.asm#L2955-L3007@a510: sta $1e ; $1e = hi byte of numeral value and #$40 beq @a531 ; branch if not displaying "miss" … lda #$08 ; x offset … lda (z76),y ; numeral value and #$3fff … jsr HexToDec16 … lda #$0010 sta $14 lda z69 ; thousands digit and #$00ff bne @a572 ; branch if not zero (show digit) lda #$000c … lda #$0008 … lda #$0004 … @a581: lda z69 + 3 ; ones digitFinal Fantasy VI Disassembly · src/btlgfx/gfx_cmd.asm#L3018-L3023sta near w7e6326,x ; numeral graphics x offset (width / 2) … lda $1e ; green numeral flag and #$80 ora #$01 ; enable numeralFinal Fantasy VI Disassembly · src/btlgfx/sprite.asm#L946-L951lda near w7e631a,x ; branch if numeral is green and #$80 bne @2d27 lda #$38 ; use palette 4 (white numerals) bra @2d29 @2d27: lda #$3a ; use palette 5 (green numerals)Final Fantasy VI Disassembly · src/btlgfx/sprite.asm#L953-L987lda $36 sta $0300,y ; x position … lda $36 ; next tile, x += 16 … lda $38 ; y position cmp #$97 bcc @2d7a ; hide sprite if y position < $97Final Fantasy VI Disassembly · src/btlgfx/sprite.asm#L683-L700; [ update damage numeral sprites ] DrawDmgNumSprites: … lda near w7e7b3f,x ; branch if damage numeral is disabledFinal Fantasy VI Disassembly · src/btlgfx/gfx_cmd.asm#L701-L704; [ graphics script command $03: display damage numerals (multiple) ] array_label GFX_CMD, GFX_CMD::DMG_NUMERALS_MULTI @9609: jsr _c1a5faFinal Fantasy VI Disassembly · src/btlgfx/gfx_cmd.asm#L3075-L3089; [ init damage numerals (multiple) ] … lda #$0a sta $10Final Fantasy VI Disassembly · src/btlgfx/gfx_cmd.asm#L3197-L3200inc $20 ; next character/monster iny2 dec $10 beq @a701Final Fantasy VI Disassembly · src/btlgfx/decimal.asm#L103-L136; [ convert hex to decimal (16-bit) ] … @1b36: sec sbc #1000 bcc @1b41 inc $22 ; +$22 = thousands digit jmp @1b36 … sbc #100 … sbc #10 … sta $28 ; +$28 = ones digitChecked by claude-agent, 2026-11-08 — read command $0B whole (slot choice, the same-target wait, the miss branch, the digit and width code), command $03's entry and its init's 10-entry loop, the decimal conversion (thousands counted with no upper limit), and the sprite writer's palette, tile pair and line checkRevised after a check by a second AI model, 2026-11-08.

The source's comment on the line check reads "hide sprite if y position < $97", but the code keeps the sprite when the line is below $97 and moves it off screen (line $E0) otherwise. The width offsets are half of 8 pixels times the digit count. Healing is the green flag, bit 15 of the value word; the battle program sets it. The several-target command is graphics command $03, whose loop counts 10 entries with $10 and fills w7e7b3f one per character or monster; it converts with the same routine.

A damage or healing number lives 64 frames and moves by a 65-byte table of heights above its start: it rises to 16 pixels by its 10th frame, holds there to the 14th, falls back to its start on the 24th, bounces once to 8 pixels around frames 31 and 32, lands on the 39th, and sits still for the last 25 frames. Numbers over a single target and over several targets read the same table. ff6-av/damage-number-bounce

Value
{
 "frames": 64,
 "heights": [
  3,
  6,
  8,
  10,
  11,
  13,
  14,
  15,
  15,
  16,
  16,
  16,
  16,
  16,
  15,
  15,
  14,
  13,
  11,
  10,
  8,
  6,
  3,
  0,
  3,
  4,
  5,
  6,
  7,
  7,
  8,
  8,
  7,
  7,
  6,
  5,
  4,
  3,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0
 ],
 "peak": 16,
 "bounce": 8
}
CodeFinal Fantasy VI Disassembly · src/btlgfx/sprite_data.asm#L704-L710; y offsets for bouncing damage numerals DmgNumBounceTbl: @cf93: .byte 3,6,8,10,11,13,14,15,15,16,16,16,16,16,15,15 .byte 14,13,11,10,8,6,3,0,3,4,5,6,7,7,8,8 .byte 7,7,6,5,4,3,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0Final Fantasy VI Disassembly · src/btlgfx/sprite.asm#L897-L913; [ update damage numeral sprite ] _c12cc2: @2cc2: pha lda near w7e6322,x ; damage numeral frame counter cmp #$40 ; branch after 64 frames (a little over 1 second) … lda f:DmgNumBounceTbl,x ; $3c = y offset for bouncing damage numerals sta $3c plx inc near w7e6322,x ; increment frame counterFinal Fantasy VI Disassembly · src/btlgfx/sprite.asm#L925-L928lda $38 ; +$38 = y position sec sbc $3c sta $38Final Fantasy VI Disassembly · src/btlgfx/sprite.asm#L698-L708lda near w7e7b49,x ; damage numeral frame counter cmp #$40 bne @2b57 ; branch after 64 frames (a little over 1 second) … lda f:DmgNumBounceTbl,x ; $3c = y offset for bouncing damage numeralsFinal Fantasy VI Disassembly · src/btlgfx/sprite.asm#L212-L216; [ update sprites ] ; called directly from nmi UpdateSprites:Checked by claude-agent, 2026-11-08 — read the table, both sprite updaters (the frame counter indexes the table, the height is subtracted from the line, and the number is turned off when the counter reaches 64), and the NMI note on the sprite updateChecked by a second AI model, 2026-11-08.

Frame numbers count from 1 for the table's first entry. The table's 65th byte is never read, since the counter stops at 64. Heights are subtracted from the sprite's line, so they lift the number.

When ordinary monsters die, each dying monster's sprites switch to sprite palette 3, which is loaded with a 16-color death palette: after the transparent color and a near-black, 14 shades of magenta from full red and blue (31, 0, 31) down to (3, 0, 3), so the monster turns into a magenta figure that keeps its own shading. The monster-death sound, number $2D, plays, and for 32 frames every color of that palette loses one step of red, green and blue (of 31), stopping at black, so the figure is black from the 31st frame. Color math is set for the time to add the sub screen, which holds only sprites, to BG2. Then the dead monsters leave the shown set and color math goes back to off. ff6-av/monster-death

About: Final Fantasy VI Palette swap

Value: frames 32 · sfx 45 · palette 3 · colors 12684, 1025, 31775, 29725, 25625, 23575, 21525, 19475, 17425, 15375, 13325, 11275, 9225, 7175, 5125, 3075 · cgwsel 2 · cgadsub 2 · sub screen 16

CodeFinal Fantasy VI Disassembly · src/btlgfx/gfx_cmd.asm#L405-L489; [ execute monster death animations ] ; called once per frame, also updates visible monsters and monster ; facing directions … @9418: lda f:MonsterDeathPal,x sta near w7e7e00::_11,x … ldx #$0202 ; add bg2 stx $10 lda #$10 ; affect sprites jsr SetColorMathHDMA … lda near w7e80db,x ; set palette to 3 and #$c1 ora #$06 sta near w7e80db,x … lda #SFX::MONSTER_DEATH jsr PlayAnimSfx lda #$20 ; animation takes 32 frames ; start of frame loop @9473: pha jsr WaitFrame jsr UpdateMonsterDeathPal pla dec ; next frame bne @9473 lda near w7e2f2f ; monsters that are not dead sta near w7e201e ; monsters shown clr_ax stx $10 jsr SetColorMathHDMAFinal Fantasy VI Disassembly · src/btlgfx/gfx_cmd.asm#L511-L528; [ update monster death palette ] UpdateMonsterDeathPal: @94c0: clr_ay longa ldx #16 ; 16 colors lda #$00e1 ; subtract 1 (red, green, and blue) … @94d3: lda near w7e7e00::_11,y jsr DecColor sta near w7e7e00::_11,yFinal Fantasy VI Disassembly · src/btlgfx/anim_cmd_2.asm#L193-L197; monster death animation palette MonsterDeathPal: @b05d: .word $318c,$0401,$7c1f,$741d,$6419,$5c17,$5415,$4c13 .word $4411,$3c0f,$340d,$2c0b,$2409,$1c07,$1405,$0c03Final Fantasy VI Disassembly · src/btlgfx/anim_cmd.asm#L1822-L1834; [ set color add/sub data ] ; +$10: shbo4321 mmss--cd (+$2130) ; s: 0 = add, 1 = subtract ; h: 0 = full add/sub, 1 = half add/sub ; bo4321: layers affected by add/sub … ; c: 0 = fixed color add/sub, 1 = subscreen add/sub ; d: 0 ; A: ---o4321 subscreen designation ($212d)Final Fantasy VI Disassembly · src/btlgfx/anim_cmd.asm#L11211-L11227; [ subtract from color ] … DecColor: … sbc $22 ; +$28 = resulting red value sta $28 and #$7fe0 bne @fcb6 ; branch if the red value was less than zeroFinal Fantasy VI Disassembly · src/sound/sfx.inc#L51MONSTER_DEATH ; $2d // 45Checked by claude-agent, 2026-11-08 — read MonsterDeathAnim whole, UpdateMonsterDeathPal, DecColor's floor at 0, the palette's 16 words, and SetColorMathHDMA's bit notes; the colors' components are decoded from the words (blue in bits 10-14, green 5-9, red 0-4)Checked by a second AI model, 2026-11-08.

The palette words decode to red = blue = 31, 29, 25, 23, 21, 19, 17, 15, 13, 11, 9, 7, 5, 3 with no green: there is no 27. In flashback mode (wEnableFlashback) the palette is first filtered (FilterColors). How the add to BG2 combines with the dying monster on screen depends on the main screen's layers, which this pass didn't read; see the gap below.

A boss dies with a script of its own, about 490 frames (8 seconds) long, which the boss's AI script asks for (43 AI scripts do, among them those the disassembly names Vargas, Dadaluma, Ghosttrain, Atmaweapon and eight dragons). The background flashes white with a thunder sound and fades back over 8 frames, then holds 65; a second thunder flash whitens the background and the boss together, the boss fading back over 32 frames with color math adding the sprites to BG2, then a 32-frame hold. With a second sound the boss shakes for 32 frames, a pixel aside and back on alternate frames. Then at two frames a step it drains its color: blue goes in 32 steps over 127 frames (the first step still at one frame) while green loses half; green finishes and red loses half over the next 128 frames with the shake at 2 pixels; red finishes over 64 frames at 3 pixels. Then the monsters are hidden and the sound stops. ff6-av/boss-death

Value
{
 "frames": 490,
 "aiScripts": 43,
 "phases": [
  {
   "what": "first flash",
   "frames": 73
  },
  {
   "what": "second flash",
   "frames": 64
  },
  {
   "what": "shake",
   "frames": 32
  },
  {
   "what": "blue",
   "frames": 127
  },
  {
   "what": "green",
   "frames": 128
  },
  {
   "what": "red",
   "frames": 64
  },
  {
   "what": "hide",
   "frames": 2
  }
 ]
}
CodeFinal Fantasy VI Disassembly · src/btlgfx/attack_anim_script.asm#L762-L856; [ Animation Script $027B: Monster Exit $0C: Boss Death (bg1) ] … anim_script BG1 ; first flash mod_pal BG2, ADD, WHITE, 31 sfx SEALED_GATE_THUNDER loop 8 mod_pal BG2, ADD, WHITE, -4 blank_frame end_loop loop 65 blank_frame end_loop ; second flash mod_pal BG2, ADD, WHITE, 31 mod_pal MONSTER, ADD, WHITE, 31 sfx SEALED_GATE_THUNDER wait_scanline color_math {ADD, SUBSCREEN}, BG2, SPRITE sprite_priority 0 char_priority 3 loop 8 mod_pal BG2, ADD, WHITE, -4 mod_pal MONSTER, ADD, WHITE, -1 blank_frame end_loop loop 24 mod_pal MONSTER, ADD, WHITE, -1 blank_frame end_loop mod_pal MONSTER, SUB, WHITE, 0 loop 32 blank_frame end_loop ; start shaking sfx BOSS_DEATH_B loop 16 monster_x_offset +1 blank_frame monster_x_offset -1 blank_frame end_loop ; subtract blue and green anim_speed 3 loop 16 mod_boss_death_pal BLUE, +1 … mod_boss_death_pal BLUE, +1 mod_boss_death_pal GREEN, +1 … ; subtract green and red loop 16 mod_boss_death_pal GREEN, +1 monster_x_offset +2 … mod_boss_death_pal RED, +1 … ; subtract red loop 8 mod_boss_death_pal RED, +1 monster_x_offset +3 … hide_monsters blank_frame sfx NONEFinal Fantasy VI Disassembly · src/btlgfx/monster_anim.asm#L150-L153array_label MONSTER_EXIT_SCRIPT, 12 @e5b8: .byte $00,$03 .word attack_anim_prop_offset BOSS_DEATHFinal Fantasy VI Disassembly · src/battle/ai_script.mac#L217.define boss_death kill_monsters ALL, BOSS_DEATHFinal Fantasy VI Disassembly · src/btlgfx/anim_cmd.asm#L2957-L2968; [ battle animation command $80/$80: subtract from monster color palettes ] ; used for boss death ; b1: rgbscccc ; r: affect red components ; g: affect green components ; b: affect blue components ; s: subtract if 1, add if 0 ; c: amount to subtract from each color (intensity)Final Fantasy VI Disassembly · src/btlgfx/anim_cmd.asm#L10434-L10442; [ battle animation command $84: set animation speed ] ; b1: speed (frames per update) … sta near wAnimThread::AnimRate,x ; animation speedFinal Fantasy VI Disassembly · src/btlgfx/anim_script.mac#L943-L945.mac anim_speed val _a_cmd_byte $84, val - 1Final Fantasy VI Disassembly · src/battle/ai_script.asm#L6795 — one of the three dragon scripts (Skull, Blue and Red Dragon in the disassembly's names) that write the macro's command for themselveskill_monsters SELF, BOSS_DEATHFinal Fantasy VI Disassembly · src/btlgfx/anim_cmd.asm#L2532-L2535 — the counter is reloaded from the rate before the step's commands rundec near wAnimThread::AnimFrameCounter,x ; decrement animation frame counter bne @c708 ; branch if it didn't reach 0 (next thread) lda near wAnimThread::AnimRate,x ; animation speed sta near wAnimThread::AnimFrameCounter,x ; reset frame counterChecked by claude-agent, 2026-11-08 — read the script whole, the exit script table's entry 12, the AI macro and a dragon's own line, the palette command, the speed command with the macro that writes its byte, and the interpreter's counter reload; frame counts computed: one frame a step until the step after anim_speed 3, then two; the 43 AI scripts counted by a scratch script over battle/ai_script.asmRevised after a check by a second AI model, 2026-11-08.

The count of 43 is the AI scripts in battle/ai_script.asm with a boss_death line (40) or the line kill_monsters SELF, BOSS_DEATH (3), computed; a script can hold several. The dragons among them are the disassembly's White, Ice, Storm, Dirt, Gold, Skull, Blue and Red. anim_speed 3 assembles to the byte 2, and the interpreter's frame counter makes that a step every 2 frames (anim_cmd.asm#L2532-L2535). Command $84 sets only the rate, and the counter was reloaded with the old rate of 1 before the step that holds it ran, so that step lasts one frame and the 2-frame steps start with the next. The phases' frames are computed from the loop counts: 8 + 65, 32 + 32, 16 × 2, then 16 × 4 × 2 − 1, 16 × 4 × 2, 8 × 4 × 2, and the last step at two frames. Each palette step subtracts 1 of 31 from the monster sprite palettes 0 to 2, so 32 steps empty a component. The sounds are SEALED_GATE_THUNDER and BOSS_DEATH_B in the disassembly's names.

Every spell, attack and effect animation is a set of scripts, one per layer it draws on (sprites, BG1, BG3), named with its graphics, palettes, sound effect and an init function in the attack's animation properties. A script opens with two bytes, its speed (a step every 1 to 16 frames) and how it lines up on its target, then runs as a byte stream: a byte below $80 shows that frame of the animation and ends the step, $FF ends the script, and $80 to $FE are commands, $80 taking a second byte that picks one of a second set. Commands run at once, as many as come before the next frame byte, so palette changes, moves and register writes take no time of their own. Up to 85 threads run side by side, each counting down its own speed, and the effect lasts until none is left. ff6-av/anim-script-format

Value: threads 85 · speeds 1, 16 · frame bytes 0, 127 · end 255 · extended 128

CodeFinal Fantasy VI Disassembly · src/btlgfx/anim_script.mac#L222-L243.mac anim_script layer, speed, align set_script_mode BATTLE_ANIM set_anim_layer layer … .ifnblank speed .assert speed > 0 .and speed <= 16, error, "Invalid animation speed" .byte (speed - 1) << 4 .else .byte 0 .endif .ifnblank align .byte ANIM_ALIGN::align .else .byte ANIM_ALIGN::CENTERFinal Fantasy VI Disassembly · src/btlgfx/anim_cmd.asm#L1513-L1516lda [$22] ; animation speed lsr4 inc sta near wAnimThread::AnimRate,xFinal Fantasy VI Disassembly · src/btlgfx/anim_cmd.asm#L2521-L2535; start of frame loop for animation execution … dec near wAnimThread::AnimFrameCounter,x ; decrement animation frame counter bne @c708 ; branch if it didn't reach 0 (next thread) lda near wAnimThread::AnimRate,x ; animation speed sta near wAnimThread::AnimFrameCounter,x ; reset frame counterFinal Fantasy VI Disassembly · src/btlgfx/anim_cmd.asm#L2561-L2578lda [zAnimScriptPtr] ; animation command bpl @c714 ; branch if a frame cmp #$ff bne @c70a ; branch if not end of script stz near wAnimThread::ThreadIsActive,x ; deactivate attacker thread … ; animation command (sprite thread) @c70a: jsr ExecAnimCmd ldy zAnimScriptPtr ; increment animation script pointer iny sty zAnimScriptPtr bra @c6d1 ; show frame (sprite thread)Final Fantasy VI Disassembly · src/btlgfx/anim_cmd.asm#L2616-L2623cpx #$0550 ; 85 threads total jne @c6a9 jsr WaitFrame … lda near w7e7b14 ; continue if there are no more active threads jne @c6a4Final Fantasy VI Disassembly · src/btlgfx/anim_cmd.asm#L2761-L2779; [ battle animation command $80 ] … lda [zAnimScriptPtr] ; next byte … jsr (near AnimCmd_00_Tbl,x) … ; battle animation command $80 jump table AnimCmd_00_Tbl: ptr_tbl ANIM_CMD_00Final Fantasy VI Disassembly · src/data/attack_anim_prop.asm#L671-L682; 55: IFRIT attack_anim_prop IFRIT sprite_gfx IFRIT_SPRITE sprite_pal 10 bg1_script IFRIT_BG1 bg1_pal 83 bg3_script IFRIT_BG3 bg3_pal 83 extra_gfx IFRIT_SPRITE sfx IFRIT init_fn 51 end_attack_anim_propChecked by claude-agent, 2026-11-08 — read the script header macro, the thread setup that turns the speed nibble into frames per step, ExecAnimScript's frame loop (countdown, command or frame, end byte, the 85-thread pass and its WaitFrame), the $80 dispatcher, and one attack's propertiesChecked by a second AI model, 2026-11-08.

The BG1 and BG3 threads take the same countdown before their own update routines; each layer has its own blank frame byte ($1F for sprites, $0F for BG1, $09 for BG3, in the macro file). A step ends when a frame byte is shown, so a script's length in frames is its frame bytes times its speed.

The animation scripts' commands, as the disassembly lists them: 127 one-byte commands, $80 to $FE, and 141 more behind $80, each with the macro the disassembly's scripts write it as and what its handler's header comment says it does, the rows compiled from those headers (52 say nothing). The two jump tables are built by a macro from the handlers' labels, so the labels are the list. Moving threads along lines, vectors, circles and arcs; loops and calls; palette adds, subtracts and cycles per layer; the scroll waves; color math, the main screen's layers, mosaic and the screen mode; Mode 7 moves, zooms, flips and rotation; window shapes; sound effects; and one-off commands for single spells and bosses. ff6-av/anim-commands

BytesMacro (disassembly)Handler's header (disassembly)
$80extended command: the next byte picks one of the $80 commands
$81attacker_frameset attacker graphical action
$82target_frameset target graphical action
$83movemove thread
$84anim_speedset animation speed
$85move_to_attackermove to attacker position
$86move_attackermove attacker
$87move_targetmove target
$88fight_animmove attacker forward (fight)
$89looploop start
$8aend_looploop end
$8banim_loopanimated loop start
$8cend_anim_loopanimated loop end
$8dmove thread if animation is flipped horizontally
$8eanim_draw_order
$8fmove_if_flippedmove thread if animation is flipped horizontally
$90anim_priorityset sprite layer priority
$91move_to_weapon_attackermove to weapon attacker position
$92move_vecmove thread along vector
$93vec_offsetset position on vector
$94calc_vec_randset vector from attacker to target (random location on target)
$95calc_vecset vector from attacker to target
$96move_vec_boomerangmove thread along vector (boomerang)
$97calc_vec_boomerangset vector from attacker to target (boomerang)
$98auto_frameupdate frame offset auto-increment
$99anim_sprite_palset thread sprite palette
$9amatch_target_dirset thread facing direction to match target
$9bblock_draw_orderchange thread sprite priority
$9cmove_if_block_flippedmove thread if facing left
$9dset sprite frame
$9eflip_target_dir
$9fanim_loop_per_threadanimated loop start (loop count = number of active threads)
$a0move_vec_jumpjump forward along vector
$a1move_vec_jumpjump backward along vector
$a2hflip_animtoggle horizontal flip
$a3cycle_palcycle palette right
$a4cycle_palcycle palette left
$a5init_circleset circle parameters
$a6move_circle, zoom_circlemove circle and change size
$a7update_circleupdate circle
$a8move_circle_to_attackermove circle to attacker
$a9move_circlemove circle
$aaset bg3 animation palette subtraction (absolute)
$abmod_palset bg3 animation palette addition (absolute)
$acinit_scroll_waveinit bg scroll hdma
$adset_scroll_hdmaset bg hdma scroll type
$aeupdate_scroll_waveupdate bg scroll hdma
$afset battle bg palette subtraction (absolute)
$b0mod_palset battle bg palette addition (absolute)
$b1set sprite animation palette subtraction (absolute)
$b2mod_palset sprite animation palette addition (absolute)
$b3set bg3 animation palette addition (relative)
$b4set bg3 animation palette subtraction (relative)
$b5set battle bg palette addition (relative)
$b6set battle bg palette subtraction (relative)
$b7set sprite animation palette addition (relative)
$b8set sprite animation palette subtraction (relative)
$b9set monster palette subtraction (absolute)
$bamod_palset monster palette addition (absolute)
$bbset monster palette addition (relative)
$bcset monster palette subtraction (relative)
$bdshow_bg1_thread, show_bg3_thread, hide_bg1_thread, hide_bg3_threadhide/show bg1/bg3 animation thread graphics
$bemosaicset screen mosaic
$bfcalljump to subroutine
$c0returnreturn from subroutine
$c1move_vec_arc
$c2unpause_layerunpause animation
$c3move_circle_to_targetmove circle to target
$c4move_bg1_here, move_bg3_heremove bg1/bg3 thread to this thread's position
$c5jump_quadjump based on swdtech hit
$c6move_vec_spiral
$c7attacker_char_dir, reset_char_vec_offset, save_attacker_char_pos, restore_attacker_char_pos, vec_to_attacker_char_pos, char_pos, update_char_vec_dir_walk, calc_vec_rel, update_char_vec_dir_jump, play_song, event_sfx, set_sound_vol, set_song_vol, set_sfx_vol, change_char_gfx, tritoch_sparkle, shake_bg, show_char, disable_runanimation commands for battle events
$c8attacker_actionset secondary attacker action
$c9sfx
$canormal_action_speed, double_action_speedset character action animation speed
$cbenable_echo_sprites, disable_echo_spritesenable/disable echo sprites
$ccset bg1 animation palette subtraction (absolute)
$cdmod_palset bg1 animation palette addition (absolute)
$cedecrement bg1 animation palette
$cfset bg1 animation palette addition (relative)
$d0sprite_priorityset sprite tile priority for all characters/monsters
$d1normal_draw_order, fixed_draw_orderchange draw order update frequency
$d2set_vec_targetset target position
$d3move_circle_to_attacker_charmove circle to attacking character
$d4color_mathset color math HDMA
$d5flip_monsterflip target monster
$d6scroll_bgscroll background
$d7update_fire_danceupdate fire dance sprites
$d8update_bum_rush
$d9attacker_priorityset attacker sprite tile priority
$damove_tornado
$dbjump_stepbranch if character needs to step back
$dcupdate_triangle_2dupdate triangle (2d)
$ddinit_triangleinit triangle
$demove_triangle_to_attackermove triangle to attacker position
$dfmove_triangle_to_targetmove triangle to target position
$e0move_triangle, zoom_triangle, rotate_triangle
$e1hide_attacker_monster, hide_attacker_char, show_attacker_monster, show_attacker_charshow/hide attacker
$e2move_vec_monstermove monster forward along vector
$e3move_vec_monstermove monster back along vector
$e4calc_vec_jumpset vector from attacker to target (jump)
$e5move_vec_charmove character forward along vector
$e6move_vec_charmove character backward along vector
$e7calc_vec_charset vector from attacker to target
$e8move_polarmove in polar coordinates
$e9move_randmove randomly
$eabg_screen_posset bg tile data location
$ebjump_threadjump based on thread index
$ecchange_anim_layerchange thread layer
$edmove_vec_grav_bombmove along ??? vector
$eetarget_priority
$efmove_ellipsemove in flattened polar coordinates
$f0jump_targetjump based on target
$f1hide_target_monsters, hide_target_chars, show_target_monsters, show_target_charsshow/hide target
$f2calc_vec_reverseset vector from target to attacker
$f3jump_attackerjump based on attacker
$f4front_sprite, back_spriteset sprite layer priority
$f5loop end (loop until no sprite/bg1 threads are active)
$f6update_triangle_3dupdate triangle (3d)
$f7wait_scanlinewait for scanline
$f8jump_magitekjump based on magitek mode
$f9magitek_action, magitek_target_actionset magitek armor action
$fajumpjump
$fbset character palette subtraction (absolute)
$fcmod_palset character palette addition (absolute)
$fdset character palette addition (relative)
$feset character palette subtraction (relative)
$80 $00set_target_char_returnset target position to attacking character position
$80 $01clear_pos_offsetclear attacking character and thread x/y offset
$80 $02save_attacker_dirsave attacker facing direction
$80 $03restore_attacker_dirrestore attacker facing direction
$80 $04rand_vecrandomize vector angle and position
$80 $05init_bum_rush_posinit thread position (bum rush)
$80 $06reset_tornado_posinit tornado variables
$80 $07move_tornado_to_animmove tornado to thread position
$80 $08move_anim_to_vecmove thread to vector position
$80 $09update_priority_tornadoupdate character/monster sprite tile priority for tornado
$80 $0aupdate_white_pre_animupdate vector for white/effect pre-attack animation
$80 $0bupdate_genju_pre_animupdate esper pre-animation balls position
$80 $0cmove_to_first_threadmove to first thread position
$80 $0d
$80 $0einit_monster_jump_posinit thread position for monster jump
$80 $0fcalc_vec_grav_bombinit ??? vector
$80 $10move_to_target
$80 $11rand_anglerandomize polar angle
$80 $12init_polarinit polar movement
$80 $13target_imptoggle imp graphics for target
$80 $14target_vanishmake target vanish
$80 $15move circle to thread position
$80 $16reset_ellipse
$80 $17bg_target_draw_orderupdate sprite layer priority based on target
$80 $18load_sketch_palload sketched monster palette
$80 $19update_sketch_pos
$80 $1avalidate_monster_entry, invalidate_monster_entryvalidate/invalidate monster entry
$80 $1bignore_char_vec_offset
$80 $1cdec_brightnessdecrement screen brightness
$80 $1dupdate_orbit_32update orbit (radius 32)
$80 $1eupdate_bg3_scroll_holyscroll bg3 for pearl
$80 $1finit_bg3_hscroll_holyinit bg3 hdma scroll data for pearl (horizontal)
$80 $20init_bg3_vscroll_holyinit bg3 hdma scroll data for pearl (vertical)
$80 $21update_ellipse_priorityupdate sprite layer priority based on polar angle
$80 $22init_white_wind_scroll
$80 $23update_white_wind_scroll
$80 $24reset_scroll_hdmaclear bg3 scroll hdma data
$80 $25reset_scroll_hdmaclear bg1 scroll hdma data
$80 $26enable_char_pal_update, disable_char_pal_updateenable/disable character palette updates
$80 $27show_chars, hide_charshide/show characters for esper attack
$80 $28char_priorityset layer priority for all character
$80 $29show_char_indicator, hide_char_indicatorhide/show cursor sprites (during esper attack)
$80 $2aload animation palette (sprite)
$80 $2bload_bg1_palload animation palette (bg1)
$80 $2cload_bg3_palload animation palette (bg3)
$80 $2djump_battle_typejump based on battle type
$80 $2emove_xymove thread
$80 $2f
$80 $30load animation palette for character 1
$80 $31update_vec_wave_widemove in vertical sine wave (wide)
$80 $32jump_dir
$80 $33update_rainbow_gradientupdate rainbow gradient lines
$80 $34copy_monster_pal_color_mathcopy monster palettes to character palettes
$80 $35enable_monster_color_mathuse character palettes for monster sprites
$80 $36disable_monster_color_mathrestore palettes for monster sprite data
$80 $37reset_gradientclear fixed color value hdma data
$80 $38hi_priority_bg3use high priority bg3
$80 $39update_blue_gradientupdate narrow blue gradient lines
$80 $3ainit_blue_gradientset gradient line intensity
$80 $3banim_target_palswap target's palette w/ animation palette
$80 $3crestore_target_palreturn target's palette to normal
$80 $3dcalc_vec_spiral
$80 $3emainscreen_layersset main screen layers
$80 $3fwait_bg1_reach_targetwait until bg1 thread reaches target
$80 $40screen_modeset screen mode ($2105)
$80 $41mode7_move, mode7_zoomzoom/move bg1 (mode7)
$80 $42mode7_flipset mode7 settings register ($211a)
$80 $43init_moon_song_effect, update_moon_song_effectmoon song effect
$80 $44move_to_prev_threadcopy position from previous thread
$80 $45bg1_window
$80 $46bg1_tilemap_locationchange bg1 tilemap vram location
$80 $47bg1_gfx_locationchange bg1/bg2 graphics vram location
$80 $48invisible_monstermake monster invisible
$80 $49rand_sprite_palload a random color sprite palette
$80 $4adisable_step_backcharacters don't step back after attack
$80 $4bupdate_megazerk_gradientupdate red/yellow gradient lines
$80 $4cmove_triangle_heremove triangle to thread position
$80 $4dcalc_vec_triangleset vector from triangle to target
$80 $4ereset_frame_offsetclear frame offset
$80 $4fmove_to_attacker_charmove thread to attacking character position
$80 $50rand_bg3_hscrollrandom bg3 h-scrolling
$80 $51disable_vertical_image, enable_vertical_image
$80 $52update_orbit_16update orbit (radius 16)
$80 $53move_char_rowmove character to other row
$80 $54toggle_char_rowtoggle character row
$80 $55init_quasar_scroll, update_quasar_scroll
$80 $56bg1_scroll_goner
$80 $57bg3_windowset bg3/bg4 window mask settings
$80 $58circle_shapeset circle shape
$80 $59window2_size
$80 $5aupdate_mind_blast_scroll
$80 $5binit_mind_blast_scroll
$80 $5creset_mind_blast_scroll
$80 $5dupdate_vec_wave
$80 $5emode7_rotaterotate and zoom mode 7
$80 $5fupdate_wide_blue_gradient
$80 $60toggle_attacker_statustoggle attacker status
$80 $61update_eyedrop
$80 $62update_evil_toot
$80 $63update_vec_wave_narrowmove in vertical sine wave (narrow)
$80 $64use_8x8_bg1_tiles
$80 $65update_rainbow_pal
$80 $66reset_pos_offset
$80 $67load_crusader_pal
$80 $68load_crusader_gfx
$80 $69bg_attacker_draw_orderupdate sprite layer priority based on attacker
$80 $6arealign_to_target_bottom
$80 $6brealign_to_target_center
$80 $6cclear_bg_frames
$80 $6ddisable_menu
$80 $6e
$80 $6fupdate_window_hdmaenable HDMA #5 update (window position)
$80 $70align_bg3_vscroll
$80 $71restore_char_palrestore character palettes
$80 $72jump_hit
$80 $73dice_roll
$80 $74
$80 $75update_super_ballupdate super ball graphic
$80 $76update_seize_stretch
$80 $77save_seize_char_pos
$80 $78restore_seize_char_pos
$80 $79chars_run_leftcharacters run to left side of screen
$80 $7achars_run_rightcharacters run to right side of screen
$80 $7bflip_charsflip all characters
$80 $7cswap_attacker_and_targetswap target and attacker
$80 $7djump_dragon_hornbranch if dragon horn is active
$80 $7evflip_target_charflip target character vertically
$80 $7fhide_monstershide all monsters
$80 $80mod_boss_death_palsubtract from monster color palettes
$80 $81
$80 $82monster_x_offsetset x-offset for all monsters
$80 $83save_chadarnook_pos
$80 $84restore_chadarnook_posrestore chadarnook position during exit
$80 $85load_chadarnook_bg_pal
$80 $86play sound effect (pan to attacker horizontal position)
$80 $87play sound effect (pan to attacker vertical position)
$80 $88move_blockmove thread for block graphics
$80 $89disable_kefka_head_shake, enable_kefka_head_shake
$80 $8amonster_target_priority_zeroset target monster sprite priority to 0
$80 $8bunknown_sfxplay ??? sound effect
$80 $8cplay sound effect (pan center)
CodeFinal Fantasy VI Disassembly · src/btlgfx/anim_cmd.asm#L5726-L5741ExecAnimCmd: set_magic_code: @d9d7: and #$7f asl stx near wAnimThreadPtr tax ldy zAnimScriptPtr iny sty zAnimScriptPtr jmp (near AnimCmdTbl,x) … ; battle animation command jump table ($80-$fe) AnimCmdTbl: ptr_tbl ANIM_CMDFinal Fantasy VI Disassembly · src/btlgfx/anim_cmd.asm#L2776-L2779; battle animation command $80 jump table AnimCmd_00_Tbl: ptr_tbl ANIM_CMD_00Final Fantasy VI Disassembly · src/btlgfx/anim_cmd.asm#L10434-L10442 — one handler, as each sits under its header; `array_label ANIM_CMD, $04` places it in the table's slot 4, command $84; [ battle animation command $84: set animation speed ] ; b1: speed (frames per update) array_label ANIM_CMD, $04Final Fantasy VI Disassembly · src/btlgfx/anim_script.mac#L943-L945 — one macro; the table's macro column pairs each command with the macros that emit its byte.mac anim_speed val _a_cmd_byte $84, val - 1 .endmacFinal Fantasy VI Disassembly · src/common/macros.inc#L333-L335 — the jump tables' macro; each handler names its slot with `array_label ANIM_CMD, $xx` or `array_label ANIM_CMD_00, $xx`.mac ptr_tbl label, count _ptr_tbl .addr, label, count .endmacroChecked by claude-agent, 2026-11-08 — read both dispatchers and their tables, which `ptr_tbl` builds from the handlers' `array_label` lines (127 `ANIM_CMD` and 141 `ANIM_CMD_00` in anim_cmd.asm, counted); the rows were compiled by a scratch script from every handler's header comment in src/btlgfx (the battle-event set behind $C7 left out) and every macro in anim_script.mac that emits a command byte; spot-read the headers for $84, $89, $8A, $AC, $AE, $B0, $D4, $80 $41, $80 $42, $80 $5E, $80 $7F and $80 $80 against their codeRevised after a check by a second AI model, 2026-11-08.

The descriptions are the disassembly's own and unchecked line by line, except the commands the other ff6-av claims quote. Command $C7 runs a separate set of battle event animation commands (event_anim.asm), not listed. A command with no macro is one the disassembly's scripts don't write by name. The scratch script is a framework candidate (reported). The $80 row's text and the split of the header for $8D and $8F are ours.

Five attack animations switch the battle to Mode 7 for part of their run, drawing BG1 as a rotating and scaling plane: Atom Edge and True Edge (one script; Atom Edge's init loads Odin's graphics), Purifier, H-Bomb, Overcast and S. Cross. The battle's shared Mode 7 init, which six attack init functions call (Atom Edge's among them), takes BG1 off the main screen and sets the matrix to 1.0 (A = D = $0100); script commands then change the zoom and position by signed steps, flip the plane, and write the screen mode. In Atom Edge the plane zooms by −8/256 a frame in both axes for 32 frames, down to 0 from 1.0, before the screen goes back to Mode 1. Overcast spins it: each frame the matrix is a rotation by −2 × the value the source comments as the frame counter whose size starts at 255 and drops by 2, for 127 frames. ff6-av/mode-7-effects

About: Final Fantasy VI Mode 7

Value: scripts 5 · unit 256 · atom edge zoom step -8 · atom edge frames 32 · overcast frames 127 · overcast radius step -2

CodeFinal Fantasy VI Disassembly · src/btlgfx/anim_init.asm#L1043-L1072; [ init mode 7 animation ] InitMode7: … lda near w7e898d ; disable bg1 in main screen and #$fe sta near w7e898d ldx #$0100 stx near w7ee9c4 stx near w7ee9ca clr_ax stx near w7ee9c6 stx near w7ee9c8 stx near w7ee9cc stx near w7ee9ceFinal Fantasy VI Disassembly · src/btlgfx/interrupt.asm#L1110-L1125lda near w7ee9c4 sta f:hM7A lda near w7ee9c4+1 sta f:hM7A lda near w7ee9c6 sta f:hM7B … lda near w7ee9ca sta f:hM7DFinal Fantasy VI Disassembly · src/btlgfx/anim_cmd.asm#L4141-L4159; [ battle animation command $80/$41: zoom/move bg1 (mode7) ] ; b1 = x zoom change ; b2 = y zoom change ; b3 = x position change ; b4 = y position change … lda near w7ee9c4 ; x zoom clc adc $10 sta near w7ee9c4Final Fantasy VI Disassembly · src/btlgfx/anim_cmd.asm#L4203-L4214; [ battle animation command $80/$40: set screen mode ($2105) ] ; b1 = -----mmm ; m: screen mode … lda near w7e896f and #$f8 ora [zAnimScriptPtr],y sta near w7e896fFinal Fantasy VI Disassembly · src/btlgfx/anim_cmd.asm#L3490-L3527; [ battle animation command $80/$5e: rotate and zoom mode 7 ] ; used by overcast … lda z0e asl neg_a sta $12 lda near w7ee9f0 ; init $ff when mode 7 graphics loaded sta $24 lda $12 jsr CalcSine16 longa lda $28 sta near w7ee9c4 ; x zoom sta near w7ee9ca ; y zoom … adc #$40 jsr CalcSine16 longa lda $28 sta near w7ee9c6 neg_a sta near w7ee9c8 … lda near w7ee9f0 sec sbc #2 sta near w7ee9f0Final Fantasy VI Disassembly · src/btlgfx/attack_anim_script.asm#L643-L709; [ Animation Script $011F: Atom Edge, True Edge (bg1) ] … mode7_move {96, 0} wait_scanline mainscreen_layers {SPRITE, BG1} screen_mode 7 sprite_priority 3 wait_scanline loop 16 mode7_zoom {-8, -8} update_blue_gradient 0 blank_frame end_loop sprite_priority 0 loop 16 mode7_zoom {-8, -8} … mainscreen_layers {SPRITE, BG2, BG3} screen_mode 1Final Fantasy VI Disassembly · src/btlgfx/attack_anim_script.asm#L7766-L7813; [ Animation Script $01B7: Overcast (bg1) ] … mainscreen_layers SPRITE screen_mode 7 mod_pal BG1, SUB, WHITE, 31 sfx OVERCAST loop 32 mod_pal BG1, SUB, WHITE, -1 mode7_rotate blank_frame mainscreen_layers {BG1, SPRITE} end_loop loop 95 mode7_rotate blank_frame end_loop wait_scanline mainscreen_layers {BG2, SPRITE} screen_mode 1Final Fantasy VI Disassembly · src/btlgfx/anim_init.asm#L1079-L1081 — the Atom Edge init loads Odin's graphics@f070: jsr InitMode7 ldx #GENJU_GFX::ODINFinal Fantasy VI Disassembly · src/btlgfx/anim_cmd.asm#L3240 — `z0e` named as the frame counter, in another command's initlda z0e ; frame counterChecked by claude-agent, 2026-11-08 — read InitMode7, the NMI's matrix writes, commands $80/$40, $80/$41 and $80/$5E, and the Atom Edge and Overcast scripts; six `jsr InitMode7` lines in anim_init.asm, counted, Atom Edge's read; the five scripts are those whose body holds `screen_mode 7` (counted over attack_anim_script.asm); both scripts run at one frame a stepRevised after a check by a second AI model, 2026-11-08.

The five, by their script headers: $011F Atom Edge, True Edge; $021A Purifier; $021E H-Bomb; $01B7 Overcast; $01AD S. Cross. The matrix's size and the plane's on-screen size go opposite ways (a smaller matrix samples less of the map per pixel), so Atom Edge's falling zoom value enlarges the plane, and a value of 0 would stretch one texel over the screen; Overcast's shrinking size also enlarges it as it turns. Sine is read through CalcSine16 with the size as amplitude; this claim doesn't read its scaling.

73 of the 565 attack animation scripts set color math with command $D4, more than cycle a palette (64) or set a scroll wave (47), counting as one script everything from a script's header in the disassembly to the next header, so a subroutine set after a script counts with it. The command writes the color math control for every line of an HDMA table and the sub screen's layers. One setting adds the sub screen, holding sprites, to a background, as the summons do while the party is hidden; others add a fixed color, which the disassembly's blue and rainbow gradients change from line to line. In Atom Edge the battle background fades out over 32 frames, a step of white subtracted each frame, while a blue gradient is added to it and the backdrop. ff6-av/color-math-effects

About: Final Fantasy VI HDMA

Value: scripts 73 · of 565 · gradient scripts 14

CodeFinal Fantasy VI Disassembly · src/btlgfx/anim_cmd.asm#L7605-L7621; [ battle animation command $d4: set color math HDMA ] … lda [zAnimScriptPtr] sta $10 lda [zAnimScriptPtr],y sta $11 iny lda [zAnimScriptPtr],y ; main screen layers jsr SetColorMathHDMAFinal Fantasy VI Disassembly · src/btlgfx/anim_cmd.asm#L1822-L1858; [ set color add/sub data ] ; +$10: shbo4321 mmss--cd (+$2130) … SetColorMathHDMA: … lda $10 @c243: sta near w7e8993+1,x ; set hdma data sta near w7e8993+101,x … sta near w7e898e ; set subscreen designationFinal Fantasy VI Disassembly · src/btlgfx/attack_anim_script.asm#L14716-L14744; [ hide characters for esper attack (bg1) ] _d05516: set_blank_frame 15 sfx PRE_GENJU_B hide_bg1_thread disable_char_pal_update blank_frame wait_scanline color_math {ADD, SUBSCREEN}, BG2, SPRITE … loop 16 mod_pal CHAR, SUB, WHITE, +1 hide_chars blank_frame mod_pal CHAR, SUB, WHITE, +1 show_chars blank_frame end_loopFinal Fantasy VI Disassembly · src/btlgfx/attack_anim_script.asm#L668-L683_d003d0: mod_pal BG2, SUB, WHITE, 0 init_blue_gradient 15 wait_scanline color_math {ADD, FIXED_CLR, OUTSIDE_SUB}, {BACK, BG2} loop 15 mod_pal BG2, SUB, WHITE, +1 update_blue_gradient -1 blank_frame end_loop loop 17 mod_pal BG2, SUB, WHITE, +1 update_blue_gradient 0 blank_frame end_loopFinal Fantasy VI Disassembly · src/btlgfx/anim_script.mac#L1533-L1541.mac color_math math_flags, main_layers, sub_layers _a_cmd_impl $d4 make_bitmask .word, 0, COLOR_MATH_FLAGS, math_flags, main_layersFinal Fantasy VI Disassembly · src/btlgfx/attack_anim_script.asm#L5-L22054 — the first header, the one without a number, and the last; 566 headers, 565 numbered (counted); [ Animation Script $00E9: W Wind (bg1) ] … ; [ Animation Script XX: most weapons ] … ; [ Animation Script $0028: Heal Rod, Mithril RodChecked by claude-agent, 2026-11-08 — read command $D4, SetColorMathHDMA, its macro, the esper hide subroutine and Atom Edge's fade; the counts are scripts (by header) whose body holds `color_math` (73; the header "XX: most weapons" is not one of the 565 and holds none) or a gradient command (14), counted over attack_anim_script.asmRevised after a check by a second AI model, 2026-11-08.

The table SetColorMathHDMA fills is channel 4's, which writes $212F-$2132 per line (interrupt_2.asm#L44-L47). The esper hide subroutine flickers the party, hiding and showing them on alternate frames, while their palettes darken by 32 steps of white subtracted; 9 scripts call it, Inferno among them.

Cited by: Color math

Backgrounds ripple through the battle's scroll HDMA: command $AC sets a layer's wave, its amplitude (one of eight sine tables built when the battle starts) and its speed, for the horizontal or vertical scroll of BG1, BG2 or BG3, and each $AE copies 32 words of that sine table, from the wave's phase on, into the layer's scroll HDMA table and advances the phase by the speed. 47 of the 565 attack scripts set a wave. Ifrit's Inferno runs one horizontal wave at the script's amplitude setting 4 and one vertical at 3 on the battle background through the whole summon while the background loses cyan, then over 16 frames at the end sets both to 3, 1 and 0. The copy picks the sine table from bits 1 to 3 of the setting only, so 4 picks the third of the eight tables, 3 the second, and 1 and 0 both the first. ff6-av/scroll-wave-effects

About: Final Fantasy VI HDMA

Value
{
 "scripts": 47,
 "of": 565,
 "words": 32,
 "sineTables": 8,
 "infernoAmplitudes": {
  "horizontal": 4,
  "vertical": 3
 }
}
CodeFinal Fantasy VI Disassembly · src/btlgfx/anim_cmd.asm#L8868-L8878; [ battle animation command $ac: init bg scroll hdma ] ; b1: 123fffff ; 1: affect bg1 ; 2: affect bg2 ; 3: affect bg3 ; f: frequency ; b2: vhaaaaaa ; v: affect vertical scroll hdma ; h: affect horizontal scroll hdma ; a: amplitude (--aaa- only these 3 bits have an effect)Final Fantasy VI Disassembly · src/btlgfx/anim_cmd.asm#L8720-L8727; [ battle animation command $ae: update bg scroll hdma ] ; b1: vh---123 ; v: affect vertical scroll hdma ; h: affect horizontal scroll hdma ; 1: affect BG1 ; 2: affect BG2 ; 3: affect BG3Final Fantasy VI Disassembly · src/btlgfx/anim_cmd.asm#L8744-L8752jsr _c1ef34 lda near w7e6098 clc adc near w7e609a sta near w7e6098Final Fantasy VI Disassembly · src/btlgfx/anim_cmd.asm#L8961-L8980; [ copy sine data to bg1/bg2 hdma scroll table ] ; +$10: hdma table start offset ; $16: phase ; $24: amplitude _c1ef34: bg_laster_set: @ef34: lda $24 and #%1110 tax longa lda f:_c1ef24,x ; pointer to sine wave data … lda #$0020 ; 32 iterationsFinal Fantasy VI Disassembly · src/btlgfx/attack_anim_script.asm#L14832-L14909; [ Animation Script $00EF: Inferno (bg1) ] … mod_pal BG2, SUB, CYAN, 0 init_scroll_wave BG2, 4, 1, HORZ init_scroll_wave BG2, 3, 1, VERT … loop 16 mod_pal BG2, SUB, CYAN, -2 update_scroll_wave BG2, {HORZ, VERT} frame 11 end_loop init_scroll_wave BG2, 3, 1, {HORZ, VERT} call _d05677 init_scroll_wave BG2, 1, 1, {HORZ, VERT} call _d05677 init_scroll_wave BG2, 0, 1, {HORZ, VERT}Final Fantasy VI Disassembly · src/btlgfx/anim_cmd.asm#L8740-L8741 — the amplitude setting $AC stored goes to $24 for the copylda near w7e6096 sta $24Final Fantasy VI Disassembly · src/btlgfx/anim_cmd.asm#L8956-L8957_c1ef24: @ef24: .addr w7ee7bf,w7ee7ff,w7ee83f,w7ee87f,w7ee8bf,w7ee8ff,w7ee93f,w7ee97fChecked by claude-agent, 2026-11-08 — read commands $AC and $AE (BG1's vertical branch whole, the other five alike), the amplitude's path to the copy, the sine copy with its table of eight pointers, and Inferno's BG1 script; the tables are picked by the setting AND %1110 as a byte offset into the pointers (4 → offset 4, the third; 3 → 2, the second; 1 and 0 → 0); the count is scripts (by header) whose body holds `init_scroll_wave`Revised after a check by a second AI model, 2026-11-08.

The source notes that only three of the amplitude's bits matter, picking one of the eight sine tables (_c1ef24) that battle init fills (btlgfx/init.asm, "init sine wave tables"). Inferno's closing steps are two 8-frame waits (_d05677) between the amplitude changes. How many lines each scroll table entry covers is the scroll HDMA tables' business (interrupt_2.asm), not read here.

Spell effects animate by palette cycling: commands $A3 and $A4 rotate a run of up to 15 colors in one battle palette one place right or left, once every n calls, where n is the command's speed. 64 of the 565 attack scripts cycle a palette. In Ifrit's Inferno the BG1 flames rotate colors 1 to 7 of the BG1 animation palette one place right every 2 frames for 66 frames, then every frame for 33 as the flames rise. ff6-av/palette-cycle-effects

About: Final Fantasy VI Palette cycling

Value
{
 "scripts": 64,
 "of": 565,
 "infernoColors": [
  1,
  7
 ],
 "infernoPhases": [
  {
   "framesPerShift": 2,
   "frames": 66
  },
  {
   "framesPerShift": 1,
   "frames": 33
  }
 ]
}
CodeFinal Fantasy VI Disassembly · src/btlgfx/anim_cmd.asm#L9391-L9419; [ battle animation command $a3: cycle palette right ] ; aaaabbbb ccccdddd ; a: offset color ; b: number of colors ; c: palette index ; d: speed (number of loops per shift) … lda near w7e6085,x bne @f211 … jsr CyclePalRight ldy #1 lda [zAnimScriptPtr],y and #$0f sta near w7e6085,x @f211: dec near w7e6085,xFinal Fantasy VI Disassembly · src/btlgfx/anim_script.mac#L1091-L1099.mac _cycle_pal_range range_begin, range_end .byte (range_end - range_begin + 1) | (range_begin << 4) .endmac .mac cycle_pal pal_id, rate, color_range .if rate >= 0 _a_cmd_impl $a3 _cycle_pal_range color_range .byte rate | BATTLE_CGRAM_PAL::pal_id << 4Final Fantasy VI Disassembly · src/btlgfx/attack_anim_script.asm#L14862-L14897show_bg1_thread loop 8 frame 11 cycle_pal BG1_ANIM, 2, {1, 7} … loop 13 … cycle_pal BG1_ANIM, 2, {1, 7} … frame 11 … loop 16 … cycle_pal BG1_ANIM, 2, {1, 7} … frame 11 … loop 33 move UP, 4 cycle_pal BG1_ANIM, 1, {1, 7} update_scroll_wave BG2, {HORZ, VERT} frame 11 end_loopChecked by claude-agent, 2026-11-08 — read command $A3's countdown (a shift when it reaches 0, then reloaded with the speed and decremented, so a shift every speed calls), its macro, and Inferno's BG1 loops; frames computed at one frame a step: 8 + 13 × 2 + 16 × 2 = 66, then 33; the count is scripts (by header) whose body holds `cycle_pal`Revised after a check by a second AI model, 2026-11-08.

$A4 is the same leftward. BG1_ANIM is battle palette 3 in the macro file's numbering (anim_script.mac#L1082). The run's length is the low four bits of the command's first byte, which the macro packs as range_end - range_begin + 1 under range_begin << 4, so 15 is the most.

When a battle is won, the victory command closes the battle menus and, unless the battle turns the fanfare off, queues battle event 1 and plays song $2F, the Victory Fanfare, at full volume, skipping the song when the map's music carries through the battle. Battle event 1 gives every character the same animation: a spin through four jump frames at one frame every 4 video frames, so 16 frames, and then the jumping-forward action. Dead and petrified characters get an empty script and stay as they are. ff6-av/victory-fanfare

About: Final Fantasy VI Music driver

Value: song 47 · spin frames 16 · frames per step 4

CodeFinal Fantasy VI Disassembly · src/btlgfx/main.asm#L159-L201array_label BTL_GFX, BTL_GFX::VICTORY @0117: inc near wPauseNotAllowed ; disable pause … jsr _c10105 ; force close all battle menus … lda near w7e2f49 and #$02 bne @016a ; return if fanfare is disabled … lda $11e4 and #$08 bne @0163 ; branch if continuing music from map … lda #$10 sta $1300 lda #SONG::VICTORY_FANFARE sta $1301 lda #$ff sta $1302 jsl ExecSound_ext … ; battle script command $0f/01: execute battle event 1 (victory) _c1016b: @016b: .byte GFX_CMD::BATTLE_EVENT .byte BATTLE_EVENT_SCRIPT::VICTORY_FANFAREFinal Fantasy VI Disassembly · src/sound/song_script.inc#L56VICTORY_FANFARE ;= $2f ; 47Final Fantasy VI Disassembly · src/btlgfx/battle_event_script.asm#L9343-L9410; [ battle event 1: victory fanfare ] … all_chars_event_anim .addr CharVictoryAnim ; terra … .addr DeadCharVictoryAnim ; dead/petrified characters … CharVictoryAnim: anim_script SPRITE, 4, CENTER call VictorySpin attacker_action JUMPING_FORWARD end_anim_script … VictorySpin: attacker_frame JUMPING_DOWN, JUMPING_FORWARD blank_frame attacker_frame JUMPING_FORWARD_FLIP, JUMPING_UP blank_frame attacker_frame JUMPING_UP, JUMPING_FORWARD_FLIP blank_frame attacker_frame JUMPING_FORWARD, JUMPING_DOWN blank_frame attacker_frame NONE anim_speed 2 return … DeadCharVictoryAnim: anim_script SPRITE end_anim_scriptChecked by claude-agent, 2026-11-08 — read the victory command, its queued graphics script, the song constant, and battle event 1 with both animations; the spin's frames computed from the script's speed of 4 and its four blank-frame stepsChecked by a second AI model, 2026-11-08.

attacker_frame takes two frames, which the disassembly's names suggest are for the two facings. After the spin, anim_speed 2 writes the byte 1, a step every frame, before the pose. "Victory Fanfare" is the disassembly's song name; the track listing is [ff6-tables/tracks](#ff6-tables/tracks).

After the fanfare the battle program shows the results as battle messages, in this order: a Colosseum win shows only its prize item. Otherwise come the experience each living character gets (the defeated monsters' total, none on the Veldt, divided among the living, counted twice for one wearing the relic that doubles experience, the Exp. Egg in the source's comment); the magic points for espers, behind a check on Terra's Morph; then, character by character, one level-up message however many levels are gained, followed by each spell learned; then the Lores, a Dance Mog learns from the battle's background, a cursed shield's lifting, each item dropped (with a count when more than one), and the gil, doubled by the relic that doubles it, the cat hood in the source's comment. Sword techniques and Blitzes learned at a level come with the level up. ff6-av/victory-messages

CodeFinal Fantasy VI Disassembly · src/battle/win.asm#L8-L36WinBattle: … lda #BTL_GFX::VICTORY jsr ExecBtlGfx … beq @5d91 ; branch if not a colosseum battle ; colosseum victory … lda #ATTACK_MSG::WIN_ITEM jsr ShowMsg plp rtsFinal Fantasy VI Disassembly · src/battle/win.asm#L47-L89lda near w7e3eb0 + 12 ; $f1 set if morph is available … bne @5dcf ; branch if on the veldt clc lda near wTargetProp2::_4::MonsterExp,x ; monster experience … ldx near w7e3a76 ; number of allies alive … lda #ATTACK_MSG::WIN_EXP jsr ShowMsgFinal Fantasy VI Disassembly · src/battle/win.asm#L96-L120and #RELIC_EFFECT5::DOUBLE_GP … jsr AddExp lda near wTargetProp2::RelicEffect5,y bit #RELIC_EFFECT5::DOUBLE_EXP beq @5e59 ; branch if exp. egg not equipped jsr AddExpFinal Fantasy VI Disassembly · src/battle/win.asm#L134-L160lda $f1 ; and $f0 beq @5e8f lda $fb ; magic points … lda #ATTACK_MSG::WIN_MAGIC_POINTS jsr ShowMsg … lda #ATTACK_MSG::GAIN_LEVEL sta $f2 jsr CheckLevelUp … jsr ShowLearnedMagicMsgFinal Fantasy VI Disassembly · src/battle/win.asm#L180-L198lda #ATTACK_MSG::LEARN_LORE … lda f:BattleBGDance,x ; dance index for each battle background … lda #ATTACK_MSG::LEARN_DANCE … lda #ATTACK_MSG::CURSED_SHIELDFinal Fantasy VI Disassembly · src/battle/win.asm#L250-L267lda #ATTACK_MSG::WIN_ITEM … beq @5f72 ; branch if only 1 was obtained inc ; change to battle message $21 "got <i> x <v1>" @5f72: jsr ShowMsg … lda #ATTACK_MSG::WIN_GILFinal Fantasy VI Disassembly · src/battle/win.asm#L455-L470@60a8: lda $f2 beq @60b1 ; branch if no battle message for level up stz $f2 jsr ShowMsg @60b1: jsr DoLevelUp … jsr LearnAbilities plx bra CheckLevelUpFinal Fantasy VI Disassembly · src/battle/win.asm#L547-L548lda #ATTACK_MSG::LEARN_MAGIC jsr ShowMsgFinal Fantasy VI Disassembly · src/battle/win.asm#L676-L690lda #ATTACK_MSG::LEARN_BUSHIDO … lda #ATTACK_MSG::LEARN_BLITZChecked by claude-agent, 2026-11-08 — read WinBattle from the victory command to the gil, CheckLevelUp's loop (the message flag is cleared after its first use), the learned-spell messages, and the ability messages at level upChecked by a second AI model, 2026-11-08.

The magic points message needs $F1, set when Morph is available, and a bit of $F0, which the loop sets from more than one cause (Terra with Morph, the gil relic); this claim doesn't untangle which. The message texts are in the ROM's battle message table (text/attack_msg.asm), which this pass didn't decode; the names are the disassembly's constants.

Final Fantasy VI's sound effects are numbered $00 to $FC in the disassembly's list, 253 names (18 of them a bare number, unnamed), in a driver table of 256 slots that each point at two channel scripts. The effects have eight samples of their own, apart from the instruments'. In battle a sound is queued and sent once a frame from the NMI as sound driver command $18 with the effect's number and a pan value; the animation scripts' sound command pans by the animation's target position across the screen, and a monster death by the last dying monster's, in formation order. ff6-av/sound-effects

About: Final Fantasy VI Sound effects

No.Name (disassembly)
0PRE_LORE
1PRE_BLACK
2PRE_WHITE_EFFECT
3PRE_GENJU_A
4ESCAPE
5ULTIMA
6QUAKE
7HASTE
8PALIDOR
9SCAN
10RASP_A
11RASP_B
12SHIVA
13MISS
14RAMUH
15SIREN
16BUM_RUSH
17ALEXANDR_A
18ALEXANDR_B
19FLARE_B
20PHOENIX
21THUNDAGA
22FIRE
23BLIZZARD
24DRAIN
25FIRAGA
26METEOR
27TREASURE_POT
28AIR_ANCHOR
29SMOKE_BOMB
30FENIX_DOWN
31DEMI
32POISON
33PUMMEL
34BIO
35ESUNA
36DEZONE
37TERRATO
38IFRIT
39STARLET
40EVENT_JUMP
41CURE_B
42CURE_A
43TORNADO
44DOOR_OPEN
45MONSTER_DEATH
46SWORD
47ARISE
48GRAND_TRAIN
49FLARE_A
50SOUL_OUT
51PUNCH
52SFX_34
53DISPEL
54BLIZZARA_A
55BLIZZARA_B
56SLOW
57CONFUSE
58KIRIN
59CARBUNKL
60SHOAT
61THUNDARA
62HOLY
63MELTDOWN
64PRE_BUSHIDO
65CALMNESS
66FIRA
67THUNDER
68RUNIC
69SHELL
70PRE_GENJU_B
71QUICK_A
72SAFE
73WRENCH
74CHAINSAW
75RAISE_A
76WARP
77BLIZZAGA
78DOOM
79LAGOMORPH
80SHOCK_B
81XFER
82SHOCK_A
83BREAK_A
84CLEAVE
85KITTY
86SHRAPNEL
87MANTRA
88SLEEP
89VANISH
90RUNIC_ABSORB
91STEAL
92REFLECT
93FENRIR
94EL_NINO
95CLEANSWEEP
96EVENT_HIT
97SKETCH
98MAGITEK_BEAM
99BIO_BLASTER
100FIRE_DANCE
101RETORT
102SUN_BATH
103BERSERK
104LIFESHAVER
105PLASMA
106JUMP
107PEARL_LORE
108MAGITEK_BARRIER
109MAGICITE
110ACID_RAIN
111SLASH
112SLIMER
113DELTA_HIT
114SURGE
115SAND_STORM
116GONER
117LAND_SLIDE
118RAGE_DANCE
119HASTE_2
120MAGITEK_STEP
121AQUA_RAKE
122PHANTOM
123FLASH_RAIN
124AURA_BOLT
125CURA
126SNARE
127ODIN
128BAHAMUT
129BISMARCK
130DRILL
131CHOCOBOP
132QUASAR
133L4_FLARE
134CRUSADER
135RIPPLER
136DIFFUSER
137BURNING_HOUSE
138AUTOCROSSBOW
139CLAW
140ROD
141MAGICITE_PICKUP
142CARDS
143CONFUSER
144MAGITEK_MISSILE
145NEEDLES
146TRAIN_WHISTLE
147STONE_A
148THROW
149NET
150WALL_SWITCH
151DOG_BARK
152SFX_152
153SNOW_FOOTSTEP
154SFX_154
155SHOCK_WAVE_A
156ATOMIC_RAY_A
157STEP_MINE
158REGEN
159FLASH
160SHIELD_BLOCK
161IMP_SONG
162GRAVITY_BOMB
163BLASTER
164SWORD_SLASH
165RUMBLE
166TREASURE_CHEST
167SFX_167
168SPEAR
169UMARO_TACKLE
170WHITE_WIND
171FLARE_C
172QUADRA_SLAM
173SFX_173
174OVERCAST
175TENTACLE
176FORCE_FIELD
177SNOWSTORM
178MIND_BLAST
179TRITOCH_EVENT
180S_CROSS
181JUMP_LAND
182WILL_O_THE_WISP
183FLARE_STAR
184WHISTLE
185ESPER_TERRA_SCREAM
186FALLING
187FLOOR_SWITCH
188REVENGE
189MADUIN
190ODIN_DEATH
191CASH_REGISTER
192BIRD_CHIRP
193BATTLE_SFX
194PARRY
195ESPER_TERRA_ZOZO
196SFX_196
197MENU_CURE
198PRE_BLITZ
199SFX_199
200SFX_200
201REVERSE_POLARITY
202STRAY_CAT
203CURAGA_B
204SECURITY_CHECKPOINT
205KEFKA_LAUGH
206SPLASH
207GOLEM
208APPLAUSE
209SAVE_POINT
210WAVE_CANNON
211TEK_LASER
212BLUE_MAN
213BIG_GUARD
214BLIZZARD_FIST
215BUBBLES
216NOISEBLASTER
217CHOCOBO
218FLAIL
219SFX_219
220PRE_DANCE_A
221OPERA_FAIL
222MINE_CART_BRAKE
223ELEVATOR
224SFX_224
225AUCTION_HOUSE
226SFX_226
227SEALED_GATE_THUNDER
228SFX_228
229REVIVIFY
230DOOR_KNOCK
231SFX_231
232BIG_FOOTSTEP
233RECOVERY_SPRING
234DRAINING_WATER
235FILLING_WATER
236POISON_DMG
237SFX_237
238BLIZZARD_B
239BOSS_DEATH_A
240CAVE_IN
241SFX_241
242HORZ_FADE_ENTRY
243SFX_243
244ENGULF
245SFX_245
246BOSS_DEATH_B
247FIRE_DMG
248SHADOW_EDGE
249PRE_DANCE_B
250SFX_250
251SCREAMS
252CONTROL
CodeFinal Fantasy VI Disassembly · src/sound/sfx.inc#L5-L263.enum SFX PRE_LORE ; $00 // 0 PRE_BLACK ; $01 // 1 … SCREAMS ; $fb // 251 CONTROL ; $fc // 252 DEFAULT = 0 NONE = $ff ; $ff .endenumFinal Fantasy VI Disassembly · src/sound/sfx_data.asm#L59-L66; c5/205e SfxPtrs: spc_block .repeat 256, i .addr .ident(.sprintf("SfxScript_%04x_1", i)) - SfxStart + $3000 .addr .ident(.sprintf("SfxScript_%04x_2", i)) - SfxStart + $3000 .endrepFinal Fantasy VI Disassembly · src/sound/sfx_data.asm#L3-L13; c5/1ec9 SfxBRR: … .incbin "assets/sound/sfx_brr/sfx_0000.brr" … .incbin "assets/sound/sfx_brr/sfx_0007.brr"Final Fantasy VI Disassembly · src/btlgfx/sfx.asm#L60-L89; [ play animation sound effect ] ; A: sound effect number ; $10: pan value PlayAnimSfx: … lda #$18 sta near w7ee9e8 ; spc command $18 inc near w7ee9ec ; enable animation sound effect … ; [ update sound effects ] UpdateSfx: nmi_effect_set: … lda near w7ee9ea ; play animation sound sound effect sta f:hAPUIO2 lda near w7ee9e9 sta f:hAPUIO1 lda near w7ee9e8 sta f:hAPUIO0Final Fantasy VI Disassembly · src/btlgfx/anim_cmd.asm#L5745-L5755; [ battle animation command $c9: ] … lda near wAnimThread::TargetPosX,x sta $10 lda [zAnimScriptPtr] jne PlayAnimSfx lda near w7ee9e7 jmp PlayAnimSfxFinal Fantasy VI Disassembly · src/btlgfx/gfx_cmd.asm#L455-L468lda near w7e80c3,x ; $14 = x position sta $14 … lda $14 sta $10 lda #SFX::MONSTER_DEATH jsr PlayAnimSfxChecked by claude-agent, 2026-11-08 — read the enum whole (253 entries, numbered in order; 18 named SFX_ and a number, counted by a scratch script), the pointer table's repeat, the effect samples, PlayAnimSfx and UpdateSfx, command $C9 and the monster death's callChecked by a second AI model, 2026-11-08.

The names are the disassembly's; PRE_ names are the sounds before a kind of spell, as the first entries show (Lore, black, white and effect magic, espers). The scripts themselves are generated from MML files the build reads (assets/mml/sfx), so their ROM region starts from an offset (data/rommaps/final-fantasy-vi.yaml, sfx-scripts). Command $C9 with a 0 byte plays the attack's own sound (w7ee9e7). Slots $FD and $FE have no name; $FF means none.

What an ordinary monster's death and a boss's look like on screen, as the color math composes them, is not settled: both set color math to add the sub screen, which holds only sprites, to BG2, and the dying monster's sprites are in palettes 0 to 3; whether the monster shows on the main screen as a darkening figure or only through the add, as a fade into the background, depends on the main screen's layers at the time, which this set hasn't read. ff6-av/death-look

UnsourcedRevised after a check by a second AI model, 2026-11-08.