General
| Offset | Sections | Section Size |
|---|---|---|
| 0x48B8 | 10 | 32 bytes |
Sections
| Offset | Ability |
|---|---|
| 0x48B8 | Punch Rush |
| 0x48D8 | Booya |
| 0x48F8 | Heel Drop |
| 0x4918 | Mach Kick |
| 0x4938 | Dolphin Blow |
| 0x4958 | Meteor Strike |
| 0x4978 | Burning Rave |
| 0x4998 | Meteor Barret |
| 0x49B8 | Different Beat |
| 0x49D8 | My Final Heaven |
Section Structure
| Offset | Length | Description |
|---|---|---|
| 0x0000 | 2 bytes | Offset to limit name |
| 0x0002 | 2 bytes | Offset to limit description |
| 0x0004 | 2 bytes | Magic ID |
| 0x0006 | 1 byte | Attack type |
| 0x0007 | 1 byte | Attack power |
| 0x0008 | 1 byte | Target hit animation — the hit/impact animation byte. Duel swaps the flags/animation byte order vs. Magic/Enemy-attack layouts (Battle_applyDamage) |
| 0x0009 | 1 byte | Padding (unused; IDA: 0 xrefs) |
| 0x000A | 1 byte | Target Info |
| 0x000B | 1 bytes | Attack flags — behavior bitfield (low 2 bits also stored as the last-attacker ATTACK_FLAG) |
| 0x000C | 1 byte | Hit count |
| 0x000D | 1 byte | Element Attack |
| 0x000E | 1 byte | Element Attack % |
| 0x000F | 1 byte | Status attack accuracy |
| 0x0010 | 2 bytes | Sequence Button 1 — also carries the finisher flag in bit 0x0100 |
| 0x0012 | 2 bytes | Sequence Button 2 |
| 0x0014 | 2 bytes | Sequence Button 3 |
| 0x0016 | 2 bytes | Sequence Button 4 |
| 0x0018 | 2 bytes | Sequence Button 5 |
| 0x001A | 2 bytes | Status 1 (statuses 0-15) |
| 0x001C | 4 bytes | Status 2 (statuses 16-47) |
Sequence buttons
Each of the five slots is a u16, but it is never used raw — the engine masks it with 0xF0FF everywhere, and bit 0x0100 of button 1 only is not a button at all but a finisher flag.
The button bits
BattleMenu_ZellDuel_Update (0x4AF840) builds the recorded input as (unsigned __int8)read_pad_pressed_raw(...) | (ctx+20 & 0xF000) — the low byte from the engine pad mask plus the D-pad nibble — and compares it against stored & 0xF0FF. BuildZellDuelMenu (0x4B0280) picks the on-screen glyph from the index of the lowest set bit of the same masked value (icon id = bit index + 0x80).
Each bit is a remappable slot, not a fixed key: the value stored in the kernel never changes, but which key or pad button performs it depends on the player’s controls. The table gives the slot’s default gamepad button and the ff8input.cfg line that rebinds it — Create_ff8input_cfg (0x498CB0) writes the fourteen commands in order and sub_498550 maps each one to its pad bit.
| Value | Default pad button | ff8input.cfg command |
|---|---|---|
0x0001 | L2 | 7. RotLt |
0x0002 | R2 | 8. RotRt |
0x0004 | L1 | 5. Toggle |
0x0008 | R1 | 6. Trigger |
0x0010 | Triangle | 4. Menu |
0x0020 | Circle | 1. Select |
0x0040 | Cross | 2. Exit |
0x0080 | Square | 3. Misc |
0x1000 | Up | 11. Up |
0x2000 | Right | 14. Right |
0x4000 | Down | 12. Down |
0x8000 | Left | 13. Left |
0xFFFF | unused slot |
Two more commands exist but cannot appear in a Duel input: 9. Start (0x0800) and 10. Select (0x0100) are above the low byte the matcher reads — which is exactly why 0x0100 was free to be reused as the finisher flag below.
This corrects an earlier version of this page, which listed the raw PSX hardware button word (directions at
0x0010-0x0080, face buttons at0x1000-0x8000, finisher at0x0001). The kernel stores the engine pad mask instead, whose two halves are swapped relative to the hardware word. The give-away is Dolphin Blow, whose four inputs are0x0004 0x0008 0x0004 0x0008: those are L1/R1 in the engine mask, but R3/Start in the hardware word — and the PC input layer can never emit R3 or Start (sub_498550emits0x0001-0x0100,0x0800and0x1000-0x8000, never0x0200or0x0400). No vanilla entry sets0x0001at all.
The pad-button names match the engine pad mask documented for the button-remap table (bits 0-11 = L2, R2, L1, R1, Triangle, Circle, Cross, Square, Select, L3, R3, Start). The direction bits are confirmed the same way, through Create_ff8input_cfg’s command order, and corroborated by My Final Heaven reading as a full clockwise circle.
Bits 0x0200 and 0x0400 (L3/R3) are masked off and unreachable anyway — sub_498550 never emits them, which is why the Controls menu greys those rows out without an analog pad. Bits 8-11 of buttons 2-5 are likewise masked off and read by nothing.
0xFFFF marks an unused slot. The matcher counts a move’s inputs by walking back from button 5 while the slot reads 0xFFFF, so the used slots must be packed from button 1 with no gap in the middle.
The finisher flag (bit 0x0100 of button 1)
BuildZellDuelMenu reads it from button 1 alone (v8 = *SequenceButton1 & 0x100) and turns it into bit 0x40 of the menu row byte; BattleMenu_ZellDuel_Update then selects the state that closes the Duel window (BattleUI_CloseWindow(6)) instead of returning to the input loop. In other words, a move with this bit set ends the limit break. Both the matched-input path and the auto-limit path use it.
Vanilla sets it on exactly the four five-input moves.
Vanilla sequences
Decoded from kernel.bin with the mask applied:
| Move | Inputs | Ends Duel |
|---|---|---|
| Punch Rush | ○ ✕ | |
| Booya | → ← | |
| Heel Drop | ↑ ↓ | |
| Mach Kick | ← ← ○ | |
| Dolphin Blow | L1 R1 L1 R1 | |
| Meteor Strike | ↓ ○ ↑ ○ | |
| Burning Rave | ↓ ↓ ↓ ↓ ○ | yes |
| Meteor Barret | ↑ ✕ ↓ △ ○ | yes |
| Different Beat | △ □ ✕ ○ ↑ | yes |
| My Final Heaven | ↑ → ↓ ← △ | yes |
The four raw words carrying the finisher bit are Burning Rave 0x4100, Meteor Barret 0x1100, Different Beat 0x0110 and My Final Heaven 0x1100 — always in button 1.