GF cinematic script and mag files
The seven summons of the GF cinematic engine (Ifrit, Leviathan, Bahamut, Cerberus, Alexander, the Brothers, Eden) keep their whole choreography as byte code in their mag files. This page is the file-format and instruction-set reference; the engine that runs it is on the engine page. The FF8UltimateEditor tool Laguna (and cli.py laguna) disassembles, simulates and patches these scripts with the tables below.
Files
| GF | Effect id | Files | Streamed parts (battle/) |
|---|---|---|---|
| Ifrit | 201 | magic/MAG200_B.00, .01 | mag200_b.02-.12 |
| Leviathan | 6 | magic/MAG005_B.00, .01 | mag005_b.02-.17 |
| Bahamut | 202 | magic/MAG201_B.00, .01 | mag201_b.02-.39 |
| Cerberus | 203 | magic/MAG202_B.00, .01 | mag202_b.02-.12 |
| Alexander | 204 | magic/MAG203_B.00, .01 | mag203_b.02-.15 |
| Brothers | 205 | magic/MAG204_B.00, .01 | mag204_b.02-.11 |
| Eden | 206 | magic/MAG205_B.00, .01 | mag205_b.02-.56 |
The engine keeps up to 64 file slots. Slot 0 is the .00 and slot 1 the .01, both loaded when the summon starts; slot k (2 and up) is battle/magNNN_b.0k, loaded during the summon by script opcode 0x006 (battle file id = a per-GF base + k). The .00 holds the script, the sound effects, the voice bank and some resources; the .01 holds most textures and meshes and, at its header offset 0x1C, a zero-filled area that the engine uses as RAM for the bone array and the bump allocator. Streamed parts are either packed files with the same header or raw VRAM page dumps.
Header
Every packed file starts with twelve u32 offsets:
| Offset | Content |
|---|---|
0x00 | 0 |
0x04 | Script: root program (.00 only). The script region runs to the sound-effect table |
0x08 | CLUT table (= end of the texture table) |
0x0C | Object table: u32 count, then u32 offset[count] relative to the table start, 0 = not in this file |
0x10 | Sound-effect table (.00 only), one FF8 sound block per entry |
0x14 | Texture table, always 0x30 |
0x18 | Music-stream table |
0x1C | End of the tables. In the .01: start of the engine RAM area |
0x20 | Stage camera animation (unused: 0 in all seven GFs) |
0x24 | Voice bank (.00 only) |
0x28, 0x2C | 0 |
Resource tables are global-index tables shared by the files of a GF: resource i has a non-zero entry only in the file that holds it. Which file slot holds each texture, CLUT, object and music entry, and the VRAM rectangle of each texture and CLUT, come from a per-GF descriptor block in the executable (see Addresses). Textures and CLUTs reach VRAM only through script opcodes (0x027, 0x029, 0x04B…).
Objects
The opcode that uses an object id decides what it is; the data itself is recognisable:
-
Mesh: a
0x30-byte header (+0x00flags: bit 0 has a primitive list, bit 1 has vertices, bit 2 has normals;+0x08primitive list offset;+0x14/+0x18vertex offset/count;+0x1C/+0x20normal offset/count), 8-byte vertices (s16 x, y, z, pad) and a primitive list of{u16 type, u16 count}groups ending at a count of0xFFFF. Vertex fields in a primitive are byte offsets into the vertex array (index x 8). A mesh with flag bit 0 clear is a vertex-only morph target.Type Size Primitive Vertex fields Other fields 2 20 lit Gouraud triangle +14, +16, +18 colours +0/+4/+8, normal +12 6 12 flat triangle +4, +6, +8 colour +0 7 20 Gouraud triangle +12, +14, +16 colours +0/+4/+8 8 20 flat textured triangle +10, +12, +14 colour +0, uv +4/+6/+8, clut +16, tpage +18 9 28 Gouraud textured triangle +18, +20, +22 colours +0/+4/+8, uv +12/+14/+16, clut +24, tpage +26 12 28 lit Gouraud quad +20, +22, +24, +26 colours +0..+12, normal +16 16 12 flat quad +4, +6, +8, +10 colour +0 17 24 Gouraud quad +16, +18, +20, +22 colours +0..+12 18 24 flat textured quad +12, +14, +16, +18 colour +0, uv +4..+10, clut +20, tpage +22 19 36 Gouraud textured quad +24, +26, +28, +30 colours +0..+12, uv +16..+22, clut +32, tpage +34 Quads use the PlayStation vertex order (triangles 0-1-2 and 1-3-2). The other type numbers (0-19) have a record size in the engine but no renderer in any of the seven GFs.
- Embedded battle model (the creature): seven
u32{size, skeleton, geometry, animation, 0, 0, size - 4}, the three offsets pointing at standard battle.datsections 1, 2 and 3. Opcode0x03Finstantiates it and draw handler 3 renders it. - Sprite frame list: 8-byte entries
{s32 frame offset from the object table, s16 duration, s8 code}(code 0 = next entry, 1 = end, 2 = loop to the start); a frame isu32 quadCountand 20-byte quads.
Particle pools are not in the files: opcode 0x058 allocates them at run time.
Script format
A script is a stream of little-endian 16-bit words. The first word of an instruction is the opcode word:
| Bits | Meaning |
|---|---|
| 0-8 | Opcode (0x000-0x146) |
| 9-15 | Modifier, meaning depends on the opcode: wait length (0x009), component mask (generic writes), sub-operation (0x005, 0x039…), flags |
Operands follow as 16-bit words. The length is variable (2 to 10 bytes, more for the inline data blocks of 0x01A, 0x043, 0x044, 0x04E) and is decided by the opcode, sometimes by its modifier bits or by an operand. Each handler advances the cursor itself; an instruction that does not advance the cursor re-executes on the next tick (the “wait until” opcodes use this on purpose).
Every code reference - jump, call, loop, spawn, start of another channel, particle script, inline data block - is a signed 16-bit byte offset relative to the opcode word of the instruction (0x059 with bit 12 set is relative to its first operand word instead). The scripts of all bones therefore form one position-independent block from the root program to the sound-effect table, and nothing outside it points into it: an edit that keeps every instruction’s length needs no relocation.
Execution
A channel runs instructions back to back until one requests a wait; the wait is counted in units of the wait speed of the bone (128 = one battle tick at the default speed), so Wait n (0x009 with modifier n) resumes the channel n ticks later. A bone has three channels; 0x026/0x08B start the other two, 0x032 and its variants create a new bone running a program, 0x000 ends a channel (and kills the bone on channel 0). 0x003/0x004 are a two-level call stack per channel, 0x01E/0x01F a loop counter per bone and 0x0A7/0x0A8 loop counters shared by the scene. Bones synchronise through a shared 16-bit flag word (0x005: set, clear, jump if any/none, wait while any/until any) and a per-bone flag word (0x10C, 0x10D). 0x001 ends the summon.
Replayed without the game (random opcodes seeded, battle-dependent branches not taken), the scripts end after 322 ticks for Ifrit (324 measured in game), 578 for Leviathan, 604 for Bahamut, 279 for Cerberus, 553 for Alexander, 460 for the Brothers and 1253 for Eden (15 ticks per second).
Generic writes
Opcodes 0x00A-0x017 write the motion values of the current bone. Modifier bits 15..10 select the components RotX, RotY, RotZ, PosX, PosY, PosZ (in that order); there is one operand per selected component, except the “all” forms (0x00D-0x00F, 0x016) which take one value for every selected component and 0x017 which takes a base and a spread per component. The value 0x7654 leaves a component unchanged.
| Opcode | Mode | Field |
|---|---|---|
0x00A / 0x00D / 0x010 | set / set all / add | accumulator (value « 16: whole units) |
0x00B / 0x00E | set / set all | velocity (value « 8) |
0x011 | set | velocity (value « 16: whole units per tick) |
0x00C / 0x00F | set / set all | acceleration (value » 4) |
0x012 / 0x013 / 0x014 / 0x015 | add random 0..value | accumulator / velocity « 8 / acceleration (« 4) / velocity « 16 |
0x016 / 0x017 | add random (all) / base +- random spread | accumulator |
Every tick the integrator adds acceleration to velocity and velocity to the accumulator; the integer part of the accumulator is the output angle and position of the bone.
Opcode reference
Lengths are Python expressions of op (the opcode word) and w (the following words, signed). The table lists the implemented opcodes; the names are those of the IDA database.
| Op | Name | Length (bytes) | Operands | Meaning |
|---|---|---|---|---|
0x000 | EndChannel | 2 | - | If channel!=0: StreamCursor=0 (channel pointer stored as 0 = channel unused), wait 0x8000. If channel 0: KILL BONE: clear the 3 chanStreamPtr + chanWait, free its node-matrix slot (B651E0/B65270; key table 0x2797204 entry = bone id cleared), –sceneHeader+0x18 (live bone count), rt->boneCursor– (order list shifted), wait=chanWaitSpeed. |
0x001 | LoopSequenceOrFinish | 4 | restartTarget | If ctx+0xD0 (loop count) < ctx+0xD1 (loop max): ++count, GF_Ifrit_InitBones(), cursor = opcode+param0, boneCursor=0 (whole summon restarts). Else: bone order list filled with 0xFF, SequenceState+8=0, all channels cleared, wait=-1, sceneHeader+0x18=0, sceneHeader+0x1A=4 (sequence finished). |
0x002 | Jump | 4 | target | StreamCursor += param0 (byte offset relative to the opcode word). |
0x003 | Call | 4 | target | Per-channel return stack: bone[+0x24 + 8chan + 4depth] = ¶m1 (= opcode+4), depth byte bone+0x44+chan ++ (2 levels per channel); cursor = opcode + param0. |
0x004 | Return | 2 | - | –depth byte bone+0x44+chan; cursor = saved return address from bone+0x24+8chan+4depth. |
0x005 | FlagOp | 4 + (2 if (op >> 12) in (2, 3) else 0) | mask, target (sub-op 2/3 only) | Operates on the shared 16-bit sequence flag word *(rt+0x10)+2 (inter-bone synchronisation flags). Sub-ops 4/5 yield wait=chanWaitSpeed and leave the cursor on the instruction. Modifier: op»12 = sub-op: 0 (and 6..15) flags|=mask; 1 flags&=~mask; 2 if (flags&mask)!=0 jump opcode+param1 else fall through; 3 if (flags&mask)==0 jump; 4 wait (retry same instr next tick) while (flags&mask)!=0; 5 wait until (flags&mask)!=0. Bits 9..11 unused. |
0x006 | LoadFile | 4 if (op & 0x8000) == 0 else 2 | source (only when bit15 clear) | Starts an async battle-file load (pre_LoadBattleFile, callback B2BB40) of file ctx->frameLimit+ctx[0xA2]+slot into dest, records Magic_b_00[ctx[0xA2]+slot]=dest, ctx+0xB4=dest, sets busy flag byte_2798219. If a load is already busy: wait chanWaitSpeed and retry the same instruction. Modifier: bit15 clear: slot=op»9 (0..63); param0 = source: lo byte 0xFF -> dest ctx+0xB8; lo<0x80 -> dest=Magic_b_00[lo] (+ sub-table offset via dword_1874894/dword_18748B0 indexed by hi byte unless hi==0xFF); lo&0x80 -> dest=Magic_b_00[lo&0x7F]+(hi«12). bit15 set: slot=(op»9)&0x3F, dest=ctx+0xB8; if slot&0x20 the file id = (slot&0x1F)+363 and Magic_b_00 is not updated. |
0x007 | SetFreezeOthers | 2 | - | Freeze/unfreeze other bones; marks current bone 0x80 in the bone order list (keeps running). Modifier: bit15 -> rt->boneSkipFlag=0xFF; bit14 -> boneSkipFlag=0 |
0x008 | WaitLoadDone | 2 | - | If a file load is busy (byte_2798219) or not completed (byte_2798218==0): wait chanWaitSpeed and retry; else advance. |
0x009 | Wait | 2 | - | vmWaitRequest = (op»9)«7 (128 = one tick at the default chanWaitSpeed). Modifier: op»9 = tick count |
0x00A | SetAccum | 2 + 2*popcount((op >> 10) & 0x3F) | one value per set mask bit, bit15 first | Generic write (attrib 0x00: mode 0 Set, field desc 0): target accum (accumRotXYZ +0x50..0x58, accumPosXYZ +0x5C..0x64), encoding s32 16.16, value«16; postAction 1: run BoneHandlerTable[bone->handlerId] then outAngle=HIWORD(accumRot) (B2C440). Operands: one s16 per set mask bit, 0x7654 = leave component unchanged. Modifier: Component mask = bits 15..10, walked from bit 15: 15=RotX 14=RotY 13=RotZ 12=PosX 11=PosY 10=PosZ (6 components, not 3). Bit 9 ignored. |
0x00B | SetVel | 2 + 2*popcount((op >> 10) & 0x3F) | one value per set mask bit, bit15 first | Generic write (attrib 0x01: mode 0 Set, field desc 1): target vel (velRotXYZ +0x68..0x70, velPosXYZ +0x74..0x7C), encoding s32, value«8; no post action. Operands: one s16 per set mask bit, 0x7654 = leave component unchanged. Modifier: Component mask = bits 15..10, walked from bit 15: 15=RotX 14=RotY 13=RotZ 12=PosX 11=PosY 10=PosZ (6 components, not 3). Bit 9 ignored. |
0x00C | SetAccel | 2 + 2*popcount((op >> 10) & 0x3F) | one value per set mask bit, bit15 first | Generic write (attrib 0x02: mode 0 Set, field desc 2): target accel (accelRotXYZ +0x80..0x84, accelPosXYZ +0x86..0x8A), encoding s16, set: value»4 / add+random: value«4; postAction 2: recompute bone->flags (bit0 if any accelRot!=0, bit3 if any accelPos!=0) = integrator enable (B2D460). Operands: one s16 per set mask bit, 0x7654 = leave component unchanged. Modifier: Component mask = bits 15..10, walked from bit 15: 15=RotX 14=RotY 13=RotZ 12=PosX 11=PosY 10=PosZ (6 components, not 3). Bit 9 ignored. |
0x00D | SetAllAccum | 4 | value/range (applied to all masked components) | Generic write (attrib 0x10: mode 1 SetAll, field desc 0): target accum (accumRotXYZ +0x50..0x58, accumPosXYZ +0x5C..0x64), encoding s32 16.16, value«16; postAction 1: run BoneHandlerTable[bone->handlerId] then outAngle=HIWORD(accumRot) (B2C440). Operands: one s16 written to every masked component. Modifier: Component mask = bits 15..10, walked from bit 15: 15=RotX 14=RotY 13=RotZ 12=PosX 11=PosY 10=PosZ (6 components, not 3). Bit 9 ignored. |
0x00E | SetAllVel | 4 | value/range (applied to all masked components) | Generic write (attrib 0x11: mode 1 SetAll, field desc 1): target vel (velRotXYZ +0x68..0x70, velPosXYZ +0x74..0x7C), encoding s32, value«8; no post action. Operands: one s16 written to every masked component. Modifier: Component mask = bits 15..10, walked from bit 15: 15=RotX 14=RotY 13=RotZ 12=PosX 11=PosY 10=PosZ (6 components, not 3). Bit 9 ignored. |
0x00F | SetAllAccel | 4 | value/range (applied to all masked components) | Generic write (attrib 0x12: mode 1 SetAll, field desc 2): target accel (accelRotXYZ +0x80..0x84, accelPosXYZ +0x86..0x8A), encoding s16, set: value»4 / add+random: value«4; postAction 2: recompute bone->flags (bit0 if any accelRot!=0, bit3 if any accelPos!=0) = integrator enable (B2D460). Operands: one s16 written to every masked component. Modifier: Component mask = bits 15..10, walked from bit 15: 15=RotX 14=RotY 13=RotZ 12=PosX 11=PosY 10=PosZ (6 components, not 3). Bit 9 ignored. |
0x010 | AddAccum | 2 + 2*popcount((op >> 10) & 0x3F) | one value per set mask bit, bit15 first | Generic write (attrib 0x20: mode 2 Add, field desc 0): target accum (accumRotXYZ +0x50..0x58, accumPosXYZ +0x5C..0x64), encoding s32 16.16, value«16; postAction 1: run BoneHandlerTable[bone->handlerId] then outAngle=HIWORD(accumRot) (B2C440). Operands: one s16 per set mask bit added, 0x7654 = skip. Modifier: Component mask = bits 15..10, walked from bit 15: 15=RotX 14=RotY 13=RotZ 12=PosX 11=PosY 10=PosZ (6 components, not 3). Bit 9 ignored. |
0x011 | SetVelInt | 2 + 2*popcount((op >> 10) & 0x3F) | one value per set mask bit, bit15 first | Generic write (attrib 0x03: mode 0 Set, field desc 3): target vel (velRotXYZ +0x68..0x70, velPosXYZ +0x74..0x7C), encoding s32, value«16; no post action. Operands: one s16 per set mask bit, 0x7654 = leave component unchanged. Modifier: Component mask = bits 15..10, walked from bit 15: 15=RotX 14=RotY 13=RotZ 12=PosX 11=PosY 10=PosZ (6 components, not 3). Bit 9 ignored. |
0x012 | AddRandomAccum | 2 + 2*popcount((op >> 10) & 0x3F) | one value per set mask bit, bit15 first | Generic write (attrib 0x30: mode 3 AddRandom, field desc 0): target accum (accumRotXYZ +0x50..0x58, accumPosXYZ +0x5C..0x64), encoding s32 16.16, value«16; postAction 1: run BoneHandlerTable[bone->handlerId] then outAngle=HIWORD(accumRot) (B2C440). Operands: one s16 range per set bit, adds rand(range) (0 = skip, word still consumed). Modifier: Component mask = bits 15..10, walked from bit 15: 15=RotX 14=RotY 13=RotZ 12=PosX 11=PosY 10=PosZ (6 components, not 3). Bit 9 ignored. |
0x013 | AddRandomVel | 2 + 2*popcount((op >> 10) & 0x3F) | one value per set mask bit, bit15 first | Generic write (attrib 0x31: mode 3 AddRandom, field desc 1): target vel (velRotXYZ +0x68..0x70, velPosXYZ +0x74..0x7C), encoding s32, value«8; no post action. Operands: one s16 range per set bit, adds rand(range) (0 = skip, word still consumed). Modifier: Component mask = bits 15..10, walked from bit 15: 15=RotX 14=RotY 13=RotZ 12=PosX 11=PosY 10=PosZ (6 components, not 3). Bit 9 ignored. |
0x014 | AddRandomAccel | 2 + 2*popcount((op >> 10) & 0x3F) | one value per set mask bit, bit15 first | Generic write (attrib 0x32: mode 3 AddRandom, field desc 2): target accel (accelRotXYZ +0x80..0x84, accelPosXYZ +0x86..0x8A), encoding s16, set: value»4 / add+random: value«4; postAction 2: recompute bone->flags (bit0 if any accelRot!=0, bit3 if any accelPos!=0) = integrator enable (B2D460). Operands: one s16 range per set bit, adds rand(range) (0 = skip, word still consumed). Modifier: Component mask = bits 15..10, walked from bit 15: 15=RotX 14=RotY 13=RotZ 12=PosX 11=PosY 10=PosZ (6 components, not 3). Bit 9 ignored. |
0x015 | AddRandomVelInt | 2 + 2*popcount((op >> 10) & 0x3F) | one value per set mask bit, bit15 first | Generic write (attrib 0x33: mode 3 AddRandom, field desc 3): target vel (velRotXYZ +0x68..0x70, velPosXYZ +0x74..0x7C), encoding s32, value«16; no post action. Operands: one s16 range per set bit, adds rand(range) (0 = skip, word still consumed). Modifier: Component mask = bits 15..10, walked from bit 15: 15=RotX 14=RotY 13=RotZ 12=PosX 11=PosY 10=PosZ (6 components, not 3). Bit 9 ignored. |
0x016 | AddRandomAllAccum | 4 | value/range (applied to all masked components) | Generic write (attrib 0x40: mode 4 AddRandomAll, field desc 0): target accum (accumRotXYZ +0x50..0x58, accumPosXYZ +0x5C..0x64), encoding s32 16.16, value«16; postAction 1: run BoneHandlerTable[bone->handlerId] then outAngle=HIWORD(accumRot) (B2C440). Operands: one range; ONE rand(range) added to every masked component. Modifier: Component mask = bits 15..10, walked from bit 15: 15=RotX 14=RotY 13=RotZ 12=PosX 11=PosY 10=PosZ (6 components, not 3). Bit 9 ignored. |
0x017 | AddRandomPairAccum | 2 + 4*popcount((op >> 10) & 0x3F) | (base,range) pair per set mask bit | Generic write (attrib 0x50: mode 5 AddRandomPair, field desc 0): target accum (accumRotXYZ +0x50..0x58, accumPosXYZ +0x5C..0x64), encoding s32 16.16, value«16; postAction 1: run BoneHandlerTable[bone->handlerId] then outAngle=HIWORD(accumRot) (B2C440). Operands: two s16 (a,b) per set bit: adds ((b<0 ? -a : a) + rand(b)); a first rand(a) call is made and discarded. Modifier: Component mask = bits 15..10, walked from bit 15: 15=RotX 14=RotY 13=RotZ 12=PosX 11=PosY 10=PosZ (6 components, not 3). Bit 9 ignored. |
0x01A | SetBoneHandler | 4 + 2*(w[0] & 0xF) | hi byte = boneHandlerId, lo nibble = N extra words, N handler parameter words | bone->handlerId(+0x18) = param0»8; bone+0xA0 = pointer to param1 (inline handler parameter block of N words, read later by the bone handler). |
0x01B | Nop4 | 4 | ignored | No effect, skips one operand word. |
0x01C | PokeBoneField | 6 | boneOffset, value | *(bone + param0) = param1 (byte or word). Raw field poke on the current bone. Modifier: op»9 == 1 -> write s16, otherwise write u8 |
0x01D | WaitBoneGoneThenEnd | 4 | boneRef | Resolve bone ref param0 (GfCinematic_GetRotationVector @0xB65370 = find bone by id in the order list; 0xFFF0+ = relative refs via self/parent ids at +0x14/+0x16, bit14 = id relative to bone[0x1B]). While it exists: wait 128 (1 tick) and retry. When not found (returns bones[0]): executes op 0x00 (end channel / kill bone). |
0x01E | SetLoopCounter | 4 | count | bone byte[+0x20 + (op»14)] = param0 (loop counter for op 0x1F). Modifier: op»14 = counter index (0..3) |
0x01F | LoopDecJump | 4 | target | –bone[+0x20+(op»14)]; if nonzero cursor = opcode+param0 (backward loop) else fall through. Modifier: op»14 = counter index |
0x020 | SetFadeLayers | 2 | - | RGB = clamp(outPosX/Y/Z,0..255) packed (B66A90); intensity = clamp(16*outAngleX,0..4096); writes intensity+colour into the 4 entries of stru_1D9898C (global colour/fade layers, 44 bytes each; op 0x6D toggles their bit1). |
0x021 | SetDataPointer | 8 | offset, size | Sets engine work-buffer pointers inside the magic texture buffer. Modifier: bit15: base = Magic_b_01+(Magic_b_01+0x1C) else MAGIC_TEXTURE_BUFFER_PTR. sub=(op»12)&7: 1 -> ctx+0xB8 = base+offset; 2 -> ctx+0x212 = base+offset, half=(size«8)/2 stored, ctx+0x216 = ptr + halfpingPong (double buffer); other -> ctx+0x74 and ctx+0x70 = base+offset (bump arena base/cursor). |
0x022 | ApplyActionResult | 2 | - | Applies the GF action result (ctx+0xCC -> action: target array +8, count +16): all targets (ApplyActionResultToTargets) or only the target whose TargetSlotId == bone+0x1B (ApplyActionResultToTarget). Modifier: (op & 0xF000)==0x8000 -> all targets |
0x023 | SetBlendMode | 2 | - | <=3: bone+0xCC |= 0x02000000 (semi-trans), bone+0x92 bits5-6 = abr; >3: clear semi-trans bit, bits5-6 = 1. Modifier: op»9 = abr 0..3 (semi-transparent); >3 = opaque |
0x024 | SetOptionBits | 2 | - | Sets the bone’s draw option byte +0xDE (OT bias / blending variants). Modifier: v=op»9: if (v&3)!=0 bone+0xDE = v else bone+0xDE |= v |
0x025 | SetSpriteOriented | 4 | spriteRef | Same as op 0x36 (sprite setup, draw handler 5) then orientation byte bone+0x1E = 9. |
0x026 | StartChannel | 6 | channel (0 = first free of 1..2), program | bone->chanStreamPtr[ch] = opcode + param1, chanWait[ch]=0, return-stack depth[ch]=0 (B2D8A0). Starts a parallel script on the SAME bone. If param0==0 and channels 1,2 are busy the scan reaches index 3 (overflows into chanWait); if that is nonzero too the instruction is skipped. |
0x027 | UploadAltTexAndImage | 4 | textureId | If a file load is busy: wait+retry. Else upload alternative texture param0 (isGF_Ifrit_AltTextureLoader @B2E700: Magic_ReadAlternativeTexture + GF_AlternativeTexture_UNK), then rewinds 4 and uploads image param0 from the loaded-file table (B2E750, as op 0x28). Each step waits chanWaitSpeed and retries the whole instruction if the VRAM queue is full. |
0x028 | UploadImage | 4 | imageId | Thunk to B2E750: if load busy wait; else B66560(param0) resolves image data (ctx+0xA8 index -> Magic_b_00 file) + RECT (ctx+0x9C table) and queues the VRAM upload; queue full -> wait+retry, success -> advance 4. |
0x029 | VramUpload | 4 if (op & 0x8000) else (8 if (op & 0x4000) else (10 if (op & 0x2000) else 4)) | rectIndex / textureId / inline RECT x, (bit14) file index / (bit13) RECT y, (bit14) 4KB page / (bit13) RECT w, (bit13) RECT h | Queues Battle_QueueVramUpload_Type0_RectData. Waits+retries while a file load is busy. Modifier: bit15: rect=ctx+0x98 table[param0] (8-byte RECTs), data=ctx+0xB4 (last loaded file) len 4; else bit14: rect=table[param0], data=Magic_b_00[param1&0x7F]+(param2«12) len 8; else bit13: inline RECT {x,y,w,h}=param0..3, data=ctx+0xB4 len 10; else: alt-texture upload of param0 (as op 0x27 first half) len 4. |
0x02A | StopChannels | 2 | - | bone->chanStreamPtr[ch]=0 (kills parallel channel scripts on the current bone). Modifier: op»14 = channel (1..3); 0 = channels 1 and 2 |
0x02B | PlaySE | 4 | attr | BdPlaySE(ctx+0xC4 table[op»9], attr=param0, pos=0x80 centre). Modifier: op»9 = sound index in the table at ctx+0xC4 |
0x02C | StopSoundChannels | 2 | - | sub_46B450(0, mask): stops the masked sound channels. Modifier: (op»9)&0xF = channel mask (bit n -> sound channel n+1) |
0x02D | SetCameraFlag | 2 | - | BYTE1(CAMERA_FLAG_RELATED) |= 0x80. |
0x02E | SetBoneIdShort | 2 | - | bone id (+0x12) = the NEXT stream word (param0), but the cursor only advances 2, so that word is then executed as an opcode. |
0x02F | StopMotion | 2 | - | Zero velRot/velPos/accelRot/accelPos (+0x68..+0x8B), recompute integrator flags (B2D460). |
0x030 | PlaySummonStream | 2 | - | BdPlaySummonStream(0x80, 1, op»9). Modifier: op»9 = stream argument |
0x031 | TransSummonStream | 2 | - | If file load busy wait+retry; else BdTransSummonStream(B25DB0(slot), &ctx+0xA3 ready flag). Pair with 0x34. Modifier: (op»9)&0xF = stream slot; bit15 -> byte_1D96DC4=0 |
0x032 | SpawnBone | 4 | program | If the bone order list has room (list[sceneHeader+0x38 - 1]==0xFF): take the first free bone slot (chanStreamPtr[0]==0), append it to the order list, its chan0 = opcode+param0, ++sceneHeader+0x18, init (B65160), copy accumRot/accumPos, handlerId, renderListOffset, +0x1B target slot and +0xB0..0xB7 from the current bone; new+0x14 = parent id, new+0x16 = parent+0x14, new id = sceneHeader[0]++; run its bone handler; workspace+0xFC = new bone. Else skip. |
0x033 | SetBoneId | 4 | id | bone id (+0x12) = param0 (key for node matrices and bone refs). |
0x034 | WaitStreamReady | 2 | - | If ctx+0xA3 (summon-stream ready flag set by 0x31) == 0: wait chanWaitSpeed and retry; else advance. |
0x035 | NullNoAdvance | 2 | - | nullsub: does not advance the cursor nor set a wait -> infinite loop if executed. Unused. |
0x036 | SetSprite | 4 | spriteRef (bit15: hi7=group, lo8=frame) | B66270: semi-trans bits in +0xCC, frame-script pointers +0xD0/+0xD4/+0xD8 and descriptor +0xE4 from the sprite table (param0 bit15 selects group/frame form), sets draw handler 5 (B65320 also appends the bone to the draw order list); orientation +0x1E = 1. |
0x037 | ResetAccum | 2 | - | Zero accumRot/accumPos (+0x50..+0x67), run the bone handler, outAngle = HIWORD(accumRot). |
0x038 | SetTargetModelColor | 2 | - | RGB = clamp(base colour bytes at CURRENT_BS_MODEL_PALETTE + src - 128) packed, stored at ((sceneHeader+0x60+4bone[0x1B]))+0x28: tints the battle model of the target slot. Modifier: (op & 0xFE00) != 0 -> source outAngleXYZ, else outPosXYZ |
0x039 | CameraAndSound | 4 | lookAtBoneRef / voice (lo=slot, hi=sound-1) | Camera / sound opcode (existing name kept). Modifier: op»12 sub-op (see IDA comment) |
0x03A | NullNoAdvance | 2 | - | nullsub: no advance, no wait (hang if executed). Unused. |
0x03B | SequenceFlags | 4 | bits (bit15 = clear) | param0>=0: SequenceState+8 |= param0; else SequenceState+8 &= ~(param0&0x7FFF). |
0x03C | SetMeshScaled | 4 | meshId | B2F380: clear semi-trans, +0xBC=0, mesh ptr +0xD8 = B657E0(meshId), draw handler 1 registered; then drawHandlerId=2 (mesh with outAngle*16 XYZ scale). |
0x03D | SetMeshTexParam | 8 | drawHandler, meshRes, texParam | colour(+0xCC)=0x808080 keeping bit25; meshPtr(+0xD8)=MagResource(w1); +0xB8=16*w2; +0xBC=0; SetDrawHandler(w0 & 0xFF) (also adds the bone to the draw order list). |
0x03E | SetInlineDescriptor3 | 8 | data0, data1, data2 | bone+0xBC = pointer to the 3 inline words following the opcode (&w0); data read by the draw handler. |
0x03F | CreateEmbeddedModel | 4 | modelRes | Allocates (bump arena, 0x80 bytes) an embedded battle-model instance from mag resource w0 (skeleton/anim/geometry, BattleAnimHeader+Cmd, pre_Battle_ReadAnimation), stores it at bone+0xBC and selects draw handler 3 (the creature). |
0x040 | ColourFromBoneOutPos | 4 | srcBone | bone colour(+0xCC) RGB = clamp(0..255) of srcBone outPos X/Y/Z, top byte kept. |
0x041 | EmbeddedModelFlags | 6 if (op >> 12) == 1 else 4 | bits_or_data0, data1 (sub-op 1 only) | Flag/override operations on the embedded model instance at bone+0xBC (created by 0x3F). Modifier: op»12 sub-op: 0 = clear bits w0 in instance word +2; 1 = set flag 0x400 in instance word +2 and instance+0x7C = &w0 (2 inline words); 8 = set bits w0; any other sub-op does NOT advance the cursor (hang, never used). |
0x042 | EntityAnimSeq (Bahamut, Brothers only) | 4 | seqIndex_or_target | Entity = SceneHeader entity ptr [bone+0x1B] (bone’s battle-entity slot, SceneHeader+0x60+4*slot). Sub 0: QueueChainTransformation(entity, p0) = start that entity’s section-5 AnimSeq p0 (multi-part chain aware; bit 0x1000 forces). Sub 2: if entity.anim_cmd.current_frame (+0x72) == total_frames (+0x73) jump rel p0. Modifier: op»9 = sub-op: 0 = start anim seq; 2 = test anim finished. Any other value returns without advancing the cursor (would hang; unused). |
0x043 | SetDrawHandlerInlineData | 6 + 2*w[1] | drawHandler, wordCount, data[wordCount] | SetDrawHandler(w0); bone+0xB8 = pointer to the inline block of w1 words; bone+0xBC=0; cursor skips the block. |
0x044 | SetDrawHandlerInlineDataReset | 6 + 2*w[1] | drawHandler, wordCount, data[wordCount] | As 0x43 and also clears bone+0xC0 and bone+0xC4 (handler frame/timer state). |
0x045 | EntityFlagBits | 4 | bits | Sets/clears bits in the first u16 (entity_flags/status_flags) of the FF8BattleEntitySlotData of bone->slotId (sceneHeader+0x60 table). Modifier: op»12: 0 = set bits w0; 1 = clear bits only if (sceneHeader+0x4E[slot] & w0)==0; 8 = clear bits; others = no-op. |
0x046 | JumpIfTargetResult | 4 | target | Conditional jump to opcode address + w0 on the action-result state of the bone’s target slot; else falls through (4 bytes). Modifier: op»9 condition on the target record (ctx+0xCC list, 24-byte entries, entry[0]==bone slot): 1 = jump if entry[3]&4; 2 = jump if entry[2]&8; 3 = jump if entry[3]&2; 4 = jump if BATTLE_SLOT_DATA[slot].status_2 & 0x2000; other (0,5..127) = jump if !(entry[3]&4). |
0x047 | CameraShakeFromOutPos | 2 | - | BATTLE_CAMERA_SHAKE_OFFSET_X/Y/Z = current bone outPos X/Y/Z. |
0x048 | OverrideEntityTransform | 2 | - | Drives the battle entity of bone->slotId from the bone outputs. Modifier: (op»9)&0xF: 0 = entity based_position(+0x1C..+0x20) = outPos, and if bit15 also entity+0x24 = outPosY; 1 = entity based_rotation(+0x0C..+0x10) = outAngle; others = flag only. Always entity status_flags |= 0x10. |
0x049 | JumpIfEntitySize | 6 | value, target | Compares entity+0x26 (s16; IDB name animation_speed_factor, used as size/radius by 0x60/0x75) with w0, jumps to opcode address + w1. Modifier: op & 0xFE00 != 0: fall through if entity+0x26 >= w0 else jump; == 0: fall through if entity+0x26 <= w0 else jump. |
0x04A | SetMeshDrawHandler | 4 | meshRes | colour &= 0x2FFFFFF; +0xBC=0; meshPtr(+0xD8)=MagResource(w0); SetDrawHandler(op»9). Modifier: op»9 = draw handler id |
0x04B | TintPaletteUpload | 10 if (op >> 12) == 1 else (8 if (op >> 12) == 2 else 6) | clutRes (lo=res id, hi=dest bank), firstColour, colourCount (sub-op 1/2), rgbSrcBone (sub-op 1) | Copies CLUT resource (w0&0xFF) from colour w1, adds a 5-bit RGB delta (outAngle X/Y/Z, <32) to each 15-bit colour into bank 0x279822C+512*(w0»8), uploads it as alternate texture palette. Modifier: op»12: 0 = 256 colours, delta from own outAngle; 1 = w2 colours, delta from bone w3 outAngle; 2 = w2 colours, own outAngle. |
0x04C | SetBoneHandler | 4 | boneHandler | boneHandlerId(+0x18) = w0; runs BoneHandlerTable[w0] immediately. |
0x04D | SetupScreenTint | 2 | - | boneHandlerId=0, renderListOffset=0, SetDrawHandler(4) (full-screen tint). |
0x04E | SetDescriptorInlineData | 6 + 2*w[1] | slot, wordCount, data[wordCount] | (u32)(bone+0xB8+4*w0) = pointer to inline block of w1 words; cursor skips the block. |
0x04F | Nop4F | 8 | unused0, unused1, unused2 | No-op, skips 3 words. |
0x050 | FreeArenaBlock | 2 | - | Arena top (ctx+0x74) -= bone+0xC4 bytes (4-aligned): releases the bone’s pool. |
0x051 | SetOptionBitsAndC0 | 4 | valueC0 | bone+0xDE |= op»9; bone+0xC0 (u16) = w0. Modifier: op»9 ORed into option bits +0xDE |
0x052 | SetTexture | 4 | texRes | w0 == -1: clear tpage(+0x92), uv(+0x9A), clut(+0x9E); else set them from texture resource w0 (tpage keeps bits 0x60). |
0x053 | MusicVolume | 4 | volume | Sets music volume w0 (low byte), no transition. Modifier: bit15: 1 = Music_SetVolumeTrans(channel 0); 0 = sub_47E3C0 (credits/intro channel, skipped if ENCOUTER_BATTLE_FLAG&2) |
0x054 | SetMesh | 4 | meshRes | colour &= 0x2FFFFFF; +0xBC=0; meshPtr(+0xD8)=MagResource(w0); SetDrawHandler(1). |
0x055 | JumpIfSummonState | 4 | target | Conditional jump to opcode address + w0 on summon-wide state. Modifier: op»9: 1 = jump if ctx+0xD0 != ctx+0xD1; 2 = jump if (rec.byte1 & 3)==1; 3 = jump if rec.byte1 & 2; other = jump if ctx+0xD0 != 0 (rec = *(ctx+0xC0)). |
0x056 | SetClippedMesh | 6 | meshRes, clipMode | As 0x54, then draw handler 9 (Y-plane clipped mesh) and +0xC2 = w1. |
0x057 | Nop57 | 2 | - | No-op. |
0x058 | CreateParticlePool | 4 | count | Allocates 80*w0+16 bytes (arena) as particle pool at +0xB8, clears it, SetDrawHandler(6). |
0x059 | EmitParticle | 6 if op & 0x1000 else 4 | poolBone (bit12 only), particleScript | Takes next ring slot of the pool, starts its particle mini-script at (bit12: address of w0 + w1; else opcode address + w0); particle pos = current bone outPos«8, tpage/uv/colour from pool bone. Modifier: bit12 = emit into the pool of bone w0 (else own pool). |
0x05A | SetBoneHandlerParam | 6 | boneHandler, paramB0 | boneHandlerId=w0, bone+0xB0=w1, runs the handler. |
0x05B | AttachToModelJoint | 8 if op & 0x800 else 4 | modelBone, joint(lo)/nodeOfs(hi), scaleX16 | Attaches the bone to a joint of an embedded or battle model (BattleModel_BuildBoneMatricesFromPose + sub_B66B80). Modifier: bit10 = use the battle entity of bone->slotId (w0 ignored); bit11 = explicit joint w1 & scale 16w2 (else joint = own outAngleX, scale 4096, matrix scaled by modelBone outAngle16); op»12: 0 = accumPos = joint pos + run bone handler; 1 = own node = Cam x joint matrix; 2 = write joint matrix to bone+0x20+(w1»8) (if nonzero) or own node. |
0x05C | SnapToBoneVertex (Leviathan, Brothers, Eden only) | 8 if (op & 0x8000) else 6 | targetBone, vertexIndex, matrixParam (only when bit15 set) | Sets the CURRENT bone’s accumPos («16) to the position of vertex vertexIndex of another bone’s model, then calls the current bone’s BoneHandlerTable[handlerId]. bit15 clear: vertex = lerp(modelA.v, modelB.v, weightBone.outPos/256 per axis) from morph descriptor (target+0xBC) = {weightBone, modelA, modelB}, scaled by target.outAngle (16x/4096), + parent(target).outPos. bit15 set: matrix from parent(target).outAngle + matrixParam (sub_B65590), scaled by target.outAngle, transform target.outPos and vertex of target’s model (*(target+0xD8)). Modifier: bit15 (curOpcode < 0) selects mode: clear = morph-lerp vertex path (3 words); set = model-vertex transform path (4 words). Other bits ignored. |
0x05D | SpawnPerTarget | 4 | program | For each target (count sceneHeader+0x41, slots at sceneHeader+0x48+i) spawns a clone bone via op 0x32’s routine (0xB2D610) running program at opcode address + w0, and sets the clone’s slotId(+0x1B). |
0x05E | PosFromSlotHome | 2 | - | accumPos = s16 xyz at sceneHeader+0x84+8*slot «16; runs bone handler, refreshes outAngle. |
0x05F | PosFromEntityOffset | 8 | dx, dy, dz | accumPos = entity based_position + w (component skipped if w == 0x7654); boneHandlerId=1, runs handler 1. |
0x060 | PosFromEntityJoint | 8 if op & 0x8000 else 4 | joint, radiusMul, angle | accumPos = world position of joint w0 of the slot entity (+ orbit offset); runs bone handler. Modifier: bit15 = orbit: X += w1(entity+0x26)sin(16*w2)»…, Z += …cos. |
0x061 | CopyAccumFromBone | 6 | mask, srcBone | For mask bits 0..5 (rotXYZ,posXYZ) copies srcBone accumRot/accumPos; refreshes outAngle, runs bone handler. Modifier: shared with 0x62: only op word == 0x0061 exactly copies accumulators; any other word copies velocities |
0x062 | CopyVelFromBone | 6 | mask, srcBone | Same as 0x61 with velRot/velPos. Modifier: see 0x61 |
0x063 | PosFromBoneViaParent | 6 | srcBone, rotOrder | Transforms srcBone outPos by its parent bone’s (parentNodeId as bone ref) rotation (order w1: 0,1,2,3) + outPos; result to own accumPos; runs bone handler. |
0x064 | SetBoneSlot | 4 if (op & 0x9000) == 0x1000 else 2 | slot (bit12 only) | Sets bone->slotId(+0x1B), the battle slot used by every entity opcode. Modifier: bit15 = slot of *(ctx+0xC0) (caster/primary); else bit12 = slot w0; else sceneHeader+0x48 (first target). |
0x065 | NodeCamRotFromPos | 4 | unused | Node = Cam x Rot(outPos as angles), translation = camera translation. |
0x066 | NodeCamTranslate | 4 | unused | Node = camera rotation, translation = Cam x outPos, projection = ctx+2. |
0x067 | NodeCamRotTranslate | 4 | unused | Node = Cam x Rot(outAngle), translation = Cam x outPos. Modifier: op»12 = rotation order (0 default,1,2,3=ZYX) |
0x068 | SetParentNode | 4 | parentNodeId | parentNodeId(+0x9C) = w0 (param0, wiki says param1: wrong). |
0x069 | NodeChildOfParent | 6 | unused, parentBone | Node = Rot(outAngle) x Cam x parent node (w1), translation = outPos. |
0x06A | NodeCamRotLocalPos | 4 | unused | Node = Cam x Rot(outAngle), translation = raw outPos, projection = ctx+2. Modifier: op»12 = rotation order |
0x06B | SetFlagCA | 2 | - | bone+0xCA |= 0x8000 (sprite frame-set mode flag, see sprite setup sub_B66270). |
0x06C | ClearFlagCA | 2 | - | bone+0xCA &= ~0x8000. |
0x06D | PartyRecordFlag | 2 | - | Sets/clears bit1 of byte +5 in 4 records of 44 bytes at 0x1D9898C. Modifier: bit15: 1 = clear bit1, 0 = set bit1 |
0x06E | PosFromTargetsJointAvg | 4 | joint | accumPos components = average position of joint w0 over all targets; runs bone handler. Modifier: op bits 12/13/14 = write X/Y/Z |
0x06F | Nop6F | 6 | unused0, unused1 | No-op. |
0x070 | Unused70 | 2 | - | nullsub, does not advance (would hang); never valid. Modifier: n/a |
0x071 | DrawEntityInCinematic | 2 | - | entity_flags |= 0x20 on the slot entity and renders its battle model into the cinematic render list (sub_5088A0); bit15 undoes the flag. Modifier: bit15: 1 = clear entity_flags 0x20; 0 = set it and draw the entity now |
0x072 | RotFromEntity | 2 | - | accumRot = slot entity based_rotation(+0x0C) «16; refreshes outAngle. |
0x073 | SetSpriteOrient2 | 6 | spriteRes, paramB8 | Sprite setup (sub_B2DA00: sprite res w0, draw handler 5, orientation 1), then orientation(+0x1E)=2 and bone+0xB8 = w1 (s16). |
0x074 | DrawFlagBits | 4 | bits | drawFlags(+0x4C) |= w0; with bit15 code does flags &= ~w0 then flags |= ~w0 => flags = ~w0. Modifier: bit15: 1 = ‘clear’ (buggy), 0 = set |
0x075 | AccumFromEntitySize | 4 | mul | Selected accumulators = (entitySize * w0) « 8; runs bone handler, refreshes outAngle. Modifier: bits15..10 = mask rotX,rotY,rotZ,posX,posY,posZ; bit9 = size = max(entity+0x26, joint0 height extents) |
0x076 | AccumAddRandom | 4 | rangeBone | Per masked component accum += rand(range)«16, range = rangeBone outAngle (rot) / outPos (pos); runs bone handler. Modifier: bits15..10 = mask rotX,rotY,rotZ,posX,posY,posZ |
0x077 | Nop77 | 6 | unused0, unused1 | No-op. |
0x078 | SetTexPage | 4 | page | bone+0x9A (tpage/uv base) = sceneHdr[+0x1C] + (page & 0xF) + 4*(page & 0x1F0) (X page bits 0-3, Y page bits 4-8 moved to the PSX tpage layout). |
0x079 | CompareFieldJump | 6 | value, target | bit15=0: if field < value fall through (+6) else jump; bit15=1: if field > value fall through else jump. Jump = cursor += target (relative to the opcode word). Used to loop until an accumulator crosses a value. Modifier: bits 12-14 = field index f: tested value = hi16 of dword at bone+0x50+4*f (0-2 accumRot XYZ, 3-5 accumPos XYZ, 6-7 velRot X/Y); bit 15 = comparison direction |
0x07A | NodeFromParentAndMatrix | 6 | parentBone, matrixOffset | Node builder: own node slot (sub_B65480, keyed by bone id) = ComposeAffineTransform(parentNode, M) where parentNode = node of parentBone (camera node 0 if parentBone==0) and M = 3x3 matrix at curBone+matrixOffset (or the own node’s current matrix if 0). Modifier: bit 15: node projection value (matrix +0x12) = word ctx+0x02, else 0 |
0x07B | WaitThenReloadA8defTim | 2 | - | If byte_2798218 (a8def.tim loader-idle flag) != 0: queue a load_aA8defTim task (sub_508630(dword ctx+0xB8, &flag); clears the flag) and continue (+2). Else vmWaitRequest = bone->chanWaitSpeed without advancing: the same instruction re-executes next tick (wait-until). |
0x07C | RandomOffsetXZ | 10 | radiusZBase, radiusZRand, radiusXBase, radiusXRand | a=rand(4096); accumPosZ += 16(radiusZBase+rand(radiusZRand))cos(a); accumPosX += 16(radiusXBase+rand(radiusXRand))sin(a) (random point on an ellipse in the XZ plane). Consumes rand(). |
0x07D | SetBoneCount | 4 | count | If count > sceneHdr[+0x38] (bones in use): clears chanStreamPtr[0] of bones [old..count) and sets sceneHdr[+0x38]=count (grow only). |
0x081 | SetSpriteAnimOriented | 4 | frameScript | Same as op 0x80 (sub_B2DA00 -> sub_B66270(frameScript): sprite frame script at bone+0xD0.., colour code 0x2C, draw handler 5; frameScript bit15 = bank (p»8)&0x7F + index p&0xFF), then bone+0x1E (orientation) = op»12. Modifier: bits 12-15 = sprite orientation type written to bone+0x1E |
0x082 | VelocityTowardBone | 6 | targetBone, frames | velPos XYZ = (target.accumPos - cur.accumPos)/frames (linear move onto another bone’s position in N ticks). |
0x083 | ColorFromOutAngle | 2 | - | bone+0xCC colour RGB (low 24 bits) = clamp(outAngle X/Y/Z, 0, 255); top byte (GPU code / semi-trans) kept. |
0x084 | CopyMatrix | 8 | srcBone, srcOffset, dstOffset | Copies a 32-byte matrix (3x3 + proj + translation) from srcBone+srcOffset (srcBone’s node slot if 0) to curBone+dstOffset (cur’s node slot if 0) via sub_B656A0. |
0x087 | VelocityScaleAccum | 6 | scale256, frames | For each masked component: vel = ((accum»16)(scale256-256)«8)/frames, so after frames ticks accum = accumscale256/256 (scale toward/away from the origin). Modifier: bits 15..10 = component mask (bit15 velRotX .. bit10 velPosZ) |
0x089 | StepEmbeddedModelAnim | 2 | - | sub_B269B0(bone+0xBC model block): SetupParentXformScaled, clear bit1 of block+2, GF_201Ifrit_StepEmbeddedModelAnim (advance creature keyframes), set bit1 again. |
0x08A | BattleScreenFx | 6 if (op >> 12) not in (1, 2, 3) else (4 if (op >> 12) in (1, 2) else 2) | value, value2 | sub-op 1: sub_501F30(value) (retarget the existing battle fx task dword_1D96EBC: +0xE=value); 2: sub_501E40(value) (create that fx task if none, param=value); 3: sub_4A8480(0) (battle state: set bit 2 at +943, clear 0x100 at +942), no operand; other: byte +0xB = value+1 and byte +9 = value2 of the struct pointed by ctx+0xC0 (action/command context). Modifier: bits 12-15 = sub-op |
0x08B | StartChannel | 6 | channel, target | Starts a script on the SAME bone: channel = channel (1-3) or, if 0, first free of chanStreamPtr[1..3] (none free -> no-op). chanStreamPtr[ch] = (opcodeAddr + target) & 0x7FFFFFFF (positive = runs in the Pos phase); chanWait[ch]=0 and per-channel byte bone+0x44+ch = 0 (sub_B2D8A0). Current stream continues. |
0x08D | ModelFlagsSetClear | 4 | bits | Object entry = dword sceneHdr[0x60 + 4*byte bone+0x1B]; its dword +0x7C |= bits (or &= ~bits). Modifier: bit 15: 0 = OR bits, 1 = AND NOT bits |
0x08E | RemoveFromDrawList | 2 | - | Removes the current bone id from g_GfCinematic_DrawOrderList (MAG_006_sub_B65270). |
0x090 | Nop10 | 10 | unused0, unused1, unused2, unused3 | No-op that just skips 10 bytes (stub in the Ifrit copy; probably a real opcode in another GF of the family). |
0x091 | AccumFromBoneOutputs | 6 | mask, srcBone | For mask bits 0..5 (LOW bit first: rotX,rotY,rotZ,posX,posY,posZ): cur.accum[i] = src.out[i]«16 (outAngle XYZ / outPos XYZ); then recompute outAngle (B2C440) and run BoneHandlerTable[handlerId] (snap to another bone’s pose). |
0x092 | SetField92And9A | 6 | value92, value9A | bone+0x92 (word after outAngleZ) = value92, bone+0x9A (tpage/uv base) = value9A. |
0x093 | BuildLightMatrices (Ifrit, Leviathan only) | 10 | lightSlot, lightBoneA, lightBoneB, lightBoneC | Builds a light set in BoneMatrixTable[slot]: +0 light-direction matrix = M(cols = 16outPos of bones A/B/C, zero when -1) * Rot(16lowbyte(cur.outPos)); +0x20 light-colour matrix (16outAngle of A/B/C); +0x40 back colour = 16cur.outAngle. Used when drawing bones with matrixSlotId != 0. |
0x095 | Nop4 | 4 | unused0 | No-op that just skips 4 bytes (stub in the Ifrit copy; probably a real opcode in another GF of the family). |
0x096 | CaptureScreenToVram (Cerberus, Eden only) | 6 | vramX, vramY | workspace.altTexParamA = vramX, workspace+0xF4 = vramY, then inserts into the render list a MoveImage of the current display buffer (5 strips of 64 px = 320 wide) to VRAM (vramX, vramY): screen grab for later distortion effects. Cerberus sub 0xB0EB60 (renamed GF_203Cerberus_QueueScreenCaptureMoveImage) = Eden GF_206Eden_Draw26_QueueScreenCaptureMoveImage 0xAEA2F0. |
0x09B | ClearOptionBits | 2 | - | bone+0xDE (option bits: OT bias/blending) &= ~((op»9)&0x7F). Modifier: bits 9-15 = bits to clear in bone+0xDE |
0x09C | SpawnBoneChained | 4 | target | Same as op 0x32 (sub_B2D610): if the bone order list has room, take the first bone with chanStreamPtr[0]==0, append it to the bone order list and draw list, its chanStreamPtr[0] = opcodeAddr+target, clone accumPos/accumRot, handlerId, renderListOffset, +0x1B, +0xB0..0xB7, owner (+0x14/+0x16 = cur +0x12/+0x14), id = sceneHdr[0]++; run its bone handler; ws->parentMatrixPtr = new bone. 0x9C then overwrites new+0x14/+0x16 with id/+0x14 of the PREVIOUS bone in the array (chain). |
0x09D | RecenterModelOffsetBone (Brothers only) | 10 | modelId, scaleX, scaleY, scaleZ | Computes the bounding-box centre c of model modelId’s vertices (count at model+0x18, verts at model+(model+0x14), 8-byte stride); cur.accumPos += (cscale/256)«16 per axis; calls the current bone handler; then subtracts c from every vertex (mesh re-centred IN PLACE, so later calls see c ~ 0). |
0x09E | JumpIfCtxFlag15Clear | 4 | target | If (ctx->flags & 0x8000)==0 jump cursor += target, else continue (+4). |
0x09F | JumpIfCtxFlag15Set | 4 | target | If (ctx->flags & 0x8000)!=0 jump cursor += target, else continue (+4). Decoded from raw bytes (no IDA function there). |
0x0A0 | JumpIfCtxFlag13Clear | 4 | target | If (ctx->flags & 0x2000)==0 jump cursor += target, else continue (+4). |
0x0A1 | RandomJump | 6 | threshold, target | r=|rand(256)|; if r <= threshold jump cursor += target, else continue (+6). Probability (threshold+1)/256. |
0x0A2 | Nop4 | 4 | unused0 | No-op that just skips 4 bytes (stub in the Ifrit copy; probably a real opcode in another GF of the family). |
0x0A4 | SetBoneHandler | 6 | handlerId, refBone | bone->boneHandlerId (+0x18) = handlerId, word bone+0xB0 = refBone; if handlerId==3, converts current outPos to polar around refBone: accumPosZ = angle«16, accumPosX = XZ distance«16, accumPosY = (cur.outPosY-ref.outPosY)«16; then runs the bone handler. |
0x0A5 | Nop4 | 4 | unused0 | No-op that just skips 4 bytes (stub in the Ifrit copy; probably a real opcode in another GF of the family). |
0x0A6 | Nop4 | 4 | unused0 | No-op that just skips 4 bytes (stub in the Ifrit copy; probably a real opcode in another GF of the family). |
0x0A7 | SetCounter | 6 | counterIdx, value | byte sceneHdr[0x14 + counterIdx] = value (loop counter for op 0xA8). |
0x0A8 | DecCounterJumpNZ | 6 | counterIdx, target | if (–byte sceneHdr[0x14+counterIdx]) != 0 jump cursor += target, else continue (+6) (DJNZ loop). |
0x0AA | SetLightSlot | 4 | slot | bone->lightSlot (+0xE1, matrixSlotId) = slot (-1 = 0 = unlit). |
0x0AC | AccelerateToTarget | (4 + 2*popcount((op >> 10) & 0x3F)) if (op & 0x200) else 6 | frames, targetBone, targets | For each masked component, accel = (target - accum - framesvel) / (frames(frames+1)) (fixed point) so the bone reaches target after frames ticks; target = targetBone.accum or immediate«16. Then recomputes bone->flags (bit0 rot accel / bit3 pos accel). Modifier: bits 15..10 = component mask (accel rotX,rotY,rotZ,posX,posY,posZ); bit 9 = immediate targets instead of a target bone |
0x0AE | NextTargetOrJump | 4 | doneTarget | Target iterator: if byte ctx+0xD0 (index) < byte ctx+0xD1 (count): ++index, load that target entry (ctx+0xCC = entries+20*index; sceneHdr +0x44/+0x48/+0x4E.. entity lists; bone+0x1B = first entity) and continue (+4); else jump cursor += doneTarget. |
0x0B0 | RandomWait | 4 | maxTicks | vmWaitRequest = rand(maxTicks)*chanWaitSpeed; if that is 0, execution continues without yielding. |
0x0B1 | SetSeqStateByte6 | 4 | value | byte g_GfCinematic_SequenceStatePtr+6 = value. |
0x0B2 | SetCtxByteA2 | 4 | value | byte ctx+0xA2 = value. |
0x0B6 | QueueVramBlit (Eden only) | 4 | blockOffset | QueueBlitCommand(&block.rect, block.x2, block.y2): queues a type-3 VRAM rect copy command in g_command_bffer. Modifier: unused (scripts encode 0x80B6) |
0x0B7 | SdStreamingVolume (Eden only) | 6 | a, b | SdStreamingVolumeTranslation(a, b): PSX streamed-audio volume change. On PC it is a stub that only prints a warning, so this is effectively a no-op. Modifier: op»12 = sub-op; only 1 is implemented (script word 0x10B7). |
0x0B8 | Nop8 | 8 | unused0, unused1, unused2 | No-op that just skips 8 bytes (stub in the Ifrit copy; probably a real opcode in another GF of the family). |
0x0B9 | NegateField | 4 | fieldIdx | If fieldIdx > 0: dword at bone+0x50+4*fieldIdx = -itself (1-2 accumRot Y/Z -> recompute outAngle; 3-5 accumPos -> run bone handler; >=6 vel/acc, no recompute). fieldIdx 0 (accumRotX) is a no-op (>0 test). |
0x0BA | NegateFieldNeg | 4 | fieldIdx | If fieldIdx < 0: dword at bone+0x50+4*fieldIdx (before accumRot: -1 = +0x4C drawFlags …) = -itself, then recompute outAngle. Else no-op. |
0x0BC | SetSpriteFrameSpeed | 4 | speed | bone+0xCA (sprite frame speed) = speed. |
0x0C0 | VelPosTowardSpawner | 4 | frames | Target = bone whose id is cur+0x14 (the spawner/parent bone id, set by the spawn ops 0x32/0x135); velPos XYZ = (target.accumPos - cur.accumPos) / frames (16.16), i.e. ‘move onto the spawner in N frames’ (follow with a wait). |
0x0C1 | Nop | 2 | - | No-op (skips the opcode word only). |
0x0C3 | PauseResumeSounds | 2 | - | bit15 clear -> sub_46B3A0(2),(3) (runs sub_46A740 on all 32 DirectSound instances = pause/stop); bit15 set -> sub_46B3E0(2),(3) (sub_46A7E0 on all 32 = resume). Modifier: bit15: 0 = pause, 1 = resume |
0x0C4 | NodeLocalNoCamera | 4 | unused | Node builder: this bone’s node slot (sub_B65480 find-or-alloc) = rotation matrix from outAngle (order op»12), translation = raw outPos (NOT multiplied by node 0/camera), projection word (+0x12) = (u16)(ctx+2). Modifier: bits12-15 (op»12) = Euler rotation order passed to sub_B65590 |
0x0C5 | JumpIfBattleStage (Brothers only) | 6 | stageId, target | If COMBAT_SCENE_ID (current battle stage) == stageId, jump to opcode_addr + target; otherwise fall through. |
0x0C6 | SetFogColorAndNear | 2 | - | Depth cue/fog: GTE far colour RFC/GFC/BFC = outAngleX/Y/Z*16 (someCameraWork_45DD60); fog near = outPosX (sub_56CCC0 stores dword_209AB64 and recomputes GTE_DQA/DQB via sub_56CC50(near, far, outPosY)). |
0x0C7 | InitSpriteAnimH22 | 4 | spriteAnimId | Runs op 0x36’s handler sub_B2DA00: sub_B66270(id) sets up the sprite frame script (bit15 set: table (id»8)&0x7F entry id&0xFF; else table id), colour code bits, draw handler 5 + draw-list add, bone+0x1E = 1; then overrides drawHandlerId = 22. |
0x0CB | NodeLookAt | 6 | eyeBone, targetBone | Node builder: look-at matrix from eyeBone.outPos toward targetBone.outPos (sub_B66E50), translation = outPos of the chosen bone, composed with node 0 (camera); projection word = 0. Modifier: bit12: translation from targetBone (1) or eyeBone (0) |
0x0CC | SetBoneHandler7 | 4 | value | bone+0xB0 = value; boneHandlerId = 7; runs BoneHandler 7 immediately (handler 7: outPos = bone[(u16)(bone+0xA0)].outPos + hi(accumPos), i.e. position relative to another bone). |
0x0CD | SetRenderListOffset | 4 | otBucket | bone->renderListOffset (+0x48) = param0 (OT depth bucket of this bone’s packets). |
0x0CE | SetBoneId | 4 | id | bone->id (+0x12) = param0 + bone+0x1B (per-bone battle-slot / id base byte). Changes the key used by node slots and bone lookups by id. |
0x0CF | RetargetToMultiPartRoot (Brothers, Eden only) | 2 | - | Entity = SceneHeader entity[bone+0x1B]. If it is part of a multi-part chain (entity+0x8C): sub 0 saves the bone slot at hdr+372 and sets hdr+378 = 1; sub 1 first backs up the target count (hdr+65) to hdr+378 and the target list hdr+72.. to hdr+372… Both then retarget bone.entitySlot and hdr target[0] (+72) to the chain root (compare_com_127_501FF0 = lowest slot in the chain) and set the target count to 1. Not multi-part: hdr+378 = 0. Modifier: op»12 = sub-op 0 or 1; any other value returns without advancing (unused). |
0x0D0 | RemoveFromDrawList | 2 | - | Removes the current bone from g_GfCinematic_DrawOrderList (MAG_006_sub_B65270); bone stops being drawn. |
0x0D1 | JumpIfModelSlot0FileId (Brothers only) | 6 | fileId, target | If battle model slot 0 (stru_1D9898C[0].battle_file_id) == fileId, jump to opcode_addr + target; otherwise fall through. |
0x0D2 | NegateMotionComponent | 4 | index | Negates dword #index of the block at bone+0x50 (0-2 accumRot XYZ, 3-5 accumPos, 6-8 velRot, 9-11 velPos), then runs the bone handler and outAngle = hi(accumRot) (sub_B2C440). Bounce / mirror. |
0x0D3 | ColorFromBoneOutPos | 4 | srcBone | colour (+0xCC, low 24 bits) = clamp(src.outPos XYZ * src.outAngleX / 256, 0..255) as R,G,B; top byte (code/semi-trans) kept. Animated colour through a helper bone. |
0x0D4 | SetColor | 4 if op & 0x8000 else 8 | r_or_grey, g (only if bit15 clear), b (only if bit15 clear) | colour (+0xCC) low 24 bits = R | G«8 | B«16, top byte kept. Modifier: bit15: 1 = grey, one word (R=G=B=param0); 0 = three words R,G,B |
0x0D5 | NorgBossTargetFixup (Brothers only) | 4 | target | Active only when COMBAT_SCENE_ID == COMBAT_SCENE_NORG_BOSS_MASTERS_ROOM. Sub 0: if the first target (hdr+72) != slot 3, set flag byte 0x2796D30 = 1 and force the target list (hdr+65 = 4, hdr+75 = 3, copy a position to hdr+156, hdr+84/+108); otherwise flag = 0. Sub 1: if flag && bone.entitySlot == 3, jump to opcode_addr + target. Modifier: op»12 = sub-op 0 or 1. Outside the Norg room every value skips 4; inside it, other values hang. |
0x0D7 | Nop2 | 4 | unused | No-op skipping one operand word (stub of a feature of another GF copy). |
0x0DA | RenderEntityToVram (Brothers only) | 2 if (op & 0x1000) else 10 | x, y, w, h | bit12 set: bone.scalePacked (colour) = (scalePacked & 0x2000000) | 0x808000 | ((2*byte(dword_1D98A4C) - 160)/3 + 127). bit12 clear: if the RenderCtx[1] flag word == 0, stores the rect in workspace+0xD0.., allocates a 23532-byte scratch buffer (sub_B656E0) and calls sub_B65F30, which renders battle model slot 1 (stru_1D9898C[1]) off-screen at the current bone’s outPos/outAngle into VRAM rect (x, y, w, h). The cursor always advances 10. Modifier: bit12 selects the mode. |
0x0DF | SetupDrawHandler29 | 10 | a, b, c, d | bone+0xB8 = 2a, +0xBC = 2b, +0xC0 = 0x279822C + 2*c (pointer into a global table), +0xC4 = d; drawHandlerId = 29 (0x1D) and bone added to the draw list (sub_B65320). |
0x0E7 | WaitUntilFieldGreater | 6 | fieldByteOffset, value | If (s16)(bone+0x8C+off) > value: continue (cursor += 6); else vmWaitRequest = chanWaitSpeed and cursor stays (re-test next tick). off 0/2/4 = outAngle XYZ, 8/10/12 = outPos XYZ. |
0x0EB | AddToDrawList | 2 | - | Adds the current bone to g_GfCinematic_DrawOrderList if absent (sub_B652E0), drawHandlerId unchanged. |
0x0F1 | Nop2 | 4 | unused | No-op skipping one operand word. |
0x0F2 | BakeOutPosToAccum | 2 | - | accumPos XYZ = outPos XYZ « 16 and boneHandlerId = 0: freezes the current (possibly derived) position into the accumulators and returns to the plain handler. |
0x0FB | WaitUntilFieldLess | 6 | fieldByteOffset, value | If (s16)(bone+0x8C+off) < value: continue (cursor += 6); else yield chanWaitSpeed and re-test next tick. |
0x0FD | JumpIfFieldInRange | 10 | fieldByteOffset, min, max, target | If min <= (s16)(bone+0x8C+off) <= max: cursor += target (relative to the opcode word); else fall through (cursor += 10). |
0x104 | BuildBillboardSlot | 4 | slot | Aux/billboard matrix slot (32-byte table at 0x2798B68 + 32*slot): rotation = CamMatrixAlt x Rot(outAngle), translation = CamMatrixAlt * outPos; projection word = 0. |
0x105 | NodeFromBillboardSlot | 6 | slot, unused | Node builder: this bone’s node = slot[slot] (0x2798B68 table) x Rot(outAngle, order op»12), translation = slot * outPos; projection word = 0. Modifier: bits12-15 = Euler rotation order for sub_B65590 |
0x106 | WaitUntilFieldLessThanBone | 6 | fieldByteOffset, otherBone | If cur.field(off) < other.field(off): continue (cursor += 6); else yield chanWaitSpeed and re-test next tick. |
0x10C | BoneFlagOps | 6 if ((op >> 12) & 0xF) in (2, 3) else 4 | mask, target (sub 2/3 only) | Same as op 0x05 but on the per-bone flag word bone+0x4A. Sub 2/3: taken jump = cursor += target (relative to opcode word), else cursor += 6. Sub 4/5: while the condition holds, yield chanWaitSpeed and re-test (length 4 once passed). Modifier: op»12 = sub-op: 0 (and 6..15) set bits; 1 clear bits; 2 jump if (flags&mask)!=0; 3 jump if ==0; 4 wait while (flags&mask)!=0; 5 wait while ==0 |
0x10D | WaitOtherBoneFlags | 6 | otherBone, mask | Tests another bone’s +0x4A flag word against mask&0x3FFF; continues (cursor += 6) when satisfied, else yield chanWaitSpeed and re-test next tick. Cross-bone synchronisation. Modifier: bit12: 1 = wait until (other.flags4A & mask)==0; 0 = wait until !=0 |
0x110 | PlaceAtMidpoint | 6 | boneA, boneB | cur.boneHandlerId = A.boneHandlerId; cur.accumPos = midpoint of A.accumPos and B.accumPos; runs the bone handler. |
0x116 | NodeCamPosLocalRot | 4 | unused | Node builder: translation = node 0 (camera) * outPos, rotation = Rot(outAngle) alone (NOT multiplied by the camera); projection word = 0. Screen-aligned object at a world position. |
0x117 | SetRotRelativeToRoot | 8 | angleX, angleY, angleZ | accumRot XYZ = (angle - g_GfCinematic_RootAngleXYZ) « 16, then outAngle = hi(accumRot) (sub_B2C440). Absolute angle compensated by the root orientation. |
0x11B | SetFogColorAndFar | 2 | - | Same as 0xC6 but sets fog FAR = outPosX (dword_C78BF0 via sub_56CCA0): GTE far colour = outAngle*16, DQA/DQB recomputed with outPosY. |
0x120 | SetCtx74FromCtx70 | 4 | offset64k | ctx+0x74 = ctx+0x70 + (param0 « 16). ctx+0x70/+0x74 are the pointers set by op 0x21 (sub-op 0/3+: base in the magic buffer + u32); this rewinds/sets the second pointer (bump arena top per the wiki) to base + N*64KB. |
0x127 | Nop4 | 6 | unused, unused | No-op skipping two operand words. |
0x135 | SpawnBoneWithId | 6 | program, newBoneId | Same as op 0x32 (sub_B2D610): if the bone order list has room, take the first free bone (chanStreamPtr[0]==0), append it to the bone order list, chanStreamPtr[0] = opcode word address + program, copy accumPos/accumRot/handlerId/renderListOffset/+0x1B/+0xB0..B7 from the current bone, +0x14 = current id, +0x16 = current +0x14, id = hdr[0]++, run its bone handler; then this op overwrites the new bone’s id (+0x12) with newBoneId. |
0x13D | BattleEntityVisibility | 4 | mode | Hide/restore battle entities (bit 2 of the 156-byte entity records at 0x1D96FC0; restore keeps entities flagged hidden in sceneHdr+78): mode 0 restore caster’s side, 1 hide caster’s side, 2 restore opposite side, 3 hide opposite side, 4 restore all 7, 5 hide all 7. Caster side from bones[0]+0x1B (<3 = party). |
0x140 | WaitScaledBySlot | 4 | frames | vmWaitRequest = (frames * u8 sceneHdr[204 + bone+0x1B]) « 7: wait scaled by a per-battle-slot factor. |
The other table entries (0x094, 0x09A, 0x0A3, 0x0AB, 0x0AD, 0x0AF, 0x0B3, 0x0B4, 0x0B5, 0x0BB, 0x0BD, 0x0BE, 0x0CA, 0x0DB, 0x0E2, 0x0ED, 0x0F0, 0x0F4, 0x0F9, 0x109, 0x10B, 0x112, 0x113, 0x11A, 0x12E, 0x134, 0x136, 0x144, 0x145, 0x146) are empty handlers in every GF: they never advance the cursor, so a script using one hangs.
Addresses
| Op | Name | Handler (Ifrit module unless noted) |
|---|---|---|
0x000 | EndChannel | 0xB2FEB0 |
0x001 | LoopSequenceOrFinish | 0xB2FB20 |
0x002 | Jump | 0xB2AE30 |
0x003 | Call | 0xB2AE50 |
0x004 | Return | 0xB2AEB0 |
0x005 | FlagOp | 0xB2C030 |
0x006 | LoadFile | 0xB2BA10 |
0x007 | SetFreezeOthers | 0xB2BC10 |
0x008 | WaitLoadDone | 0xB2BBD0 |
0x009 | Wait | 0xB2FE80 |
0x00A | SetAccum | 0xB2C480 |
0x00B | SetVel | 0xB2C480 |
0x00C | SetAccel | 0xB2C480 |
0x00D | SetAllAccum | 0xB2C480 |
0x00E | SetAllVel | 0xB2C480 |
0x00F | SetAllAccel | 0xB2C480 |
0x010 | AddAccum | 0xB2C480 |
0x011 | SetVelInt | 0xB2C480 |
0x012 | AddRandomAccum | 0xB2C480 |
0x013 | AddRandomVel | 0xB2C480 |
0x014 | AddRandomAccel | 0xB2C480 |
0x015 | AddRandomVelInt | 0xB2C480 |
0x016 | AddRandomAllAccum | 0xB2C480 |
0x017 | AddRandomPairAccum | 0xB2C480 |
0x01A | SetBoneHandler | 0xB2D070 |
0x01B | Nop4 | 0xB2BE10 |
0x01C | PokeBoneField | 0xB2BDC0 |
0x01D | WaitBoneGoneThenEnd | 0xB2FF70 |
0x01E | SetLoopCounter | 0xB2AF00 |
0x01F | LoopDecJump | 0xB2AF80 |
0x020 | SetFadeLayers | 0xB2E2F0 |
0x021 | SetDataPointer | 0xB2B450 |
0x022 | ApplyActionResult | 0xB2B530 |
0x023 | SetBlendMode | 0xB2DFA0 |
0x024 | SetOptionBits | 0xB2DAF0 |
0x025 | SetSpriteOriented | 0xB2DAA0 |
0x026 | StartChannel | 0xB2D4C0 |
0x027 | UploadAltTexAndImage | 0xB2E540 |
0x028 | UploadImage | 0xB2E530 |
0x029 | VramUpload | 0xB2E440 |
0x02A | StopChannels | 0xB2D590 |
0x02B | PlaySE | 0xB25BB0 |
0x02C | StopSoundChannels | 0xB25CD0 |
0x02D | SetCameraFlag | 0xB2BC60 |
0x02E | SetBoneIdShort | 0xB2D5E0 |
0x02F | StopMotion | 0xB2C8D0 |
0x030 | PlaySummonStream | 0xB25CA0 |
0x031 | TransSummonStream | 0xB25C00 |
0x032 | SpawnBone | 0xB2D610 |
0x033 | SetBoneId | 0xB2B020 |
0x034 | WaitStreamReady | 0xB25C70 |
0x035 | NullNoAdvance | 0xB2E6C0 |
0x036 | SetSprite | 0xB2DA00 |
0x037 | ResetAccum | 0xB2C400 |
0x038 | SetTargetModelColor | 0xB2E230 |
0x039 | CameraAndSound | 0xB2B750 |
0x03A | NullNoAdvance | 0xB2FFB0 |
0x03B | SequenceFlags | 0xB2B980 |
0x03C | SetMeshScaled | 0xB2F3E0 |
0x03D | SetMeshTexParam | 0xB2F430 |
0x03E | SetInlineDescriptor3 | 0xB2F530 |
0x03F | CreateEmbeddedModel | 0xB26820 |
0x040 | ColourFromBoneOutPos | 0xB2DD30 |
0x041 | EmbeddedModelFlags | 0xB26900 |
0x042 | EntityAnimSeq | Bahamut 0xB24BB0, Brothers 0xAFEF60 |
0x043 | SetDrawHandlerInlineData | 0xB2B220 |
0x044 | SetDrawHandlerInlineDataReset | 0xB2B1B0 |
0x045 | EntityFlagBits | 0xB2BC80 |
0x046 | JumpIfTargetResult | 0xB2B290 |
0x047 | CameraShakeFromOutPos | 0xB2B9D0 |
0x048 | OverrideEntityTransform | 0xB2C9E0 |
0x049 | JumpIfEntitySize | 0xB2BD10 |
0x04A | SetMeshDrawHandler | 0xB2F4C0 |
0x04B | TintPaletteUpload | 0xB2E080 |
0x04C | SetBoneHandler | 0xB2C3D0 |
0x04D | SetupScreenTint | 0xB26DF0 |
0x04E | SetDescriptorInlineData | 0xB2B950 |
0x04F | Nop4F | 0xB2E580 |
0x050 | FreeArenaBlock | 0xB300E0 |
0x051 | SetOptionBitsAndC0 | 0xB2DB40 |
0x052 | SetTexture | 0xB2E5C0 |
0x053 | MusicVolume | 0xB25D10 |
0x054 | SetMesh | 0xB2F380 |
0x055 | JumpIfSummonState | 0xB2B380 |
0x056 | SetClippedMesh | 0xB2F3F0 |
0x057 | Nop57 | 0xB2AE20 |
0x058 | CreateParticlePool | 0xB29D70 |
0x059 | EmitParticle | 0xB29DE0 |
0x05A | SetBoneHandlerParam | 0xB2D8D0 |
0x05B | AttachToModelJoint | 0xB2F090 |
0x05C | SnapToBoneVertex | Leviathan 0xB64090, Brothers 0xAFEBF0, Eden 0xAF3660 |
0x05D | SpawnPerTarget | 0xB2D7F0 |
0x05E | PosFromSlotHome | 0xB2C870 |
0x05F | PosFromEntityOffset | 0xB2C780 |
0x060 | PosFromEntityJoint | 0xB2CE00 |
0x061 | CopyAccumFromBone | 0xB2CCC0 |
0x062 | CopyVelFromBone | 0xB2CCC0 |
0x063 | PosFromBoneViaParent | 0xB2EF70 |
0x064 | SetBoneSlot | 0xB2B0E0 |
0x065 | NodeCamRotFromPos | 0xB2E7D0 |
0x066 | NodeCamTranslate | 0xB2E830 |
0x067 | NodeCamRotTranslate | 0xB2E950 |
0x068 | SetParentNode | 0xB2ECB0 |
0x069 | NodeChildOfParent | 0xB2E9E0 |
0x06A | NodeCamRotLocalPos | 0xB2E8C0 |
0x06B | SetFlagCA | 0xB2DB90 |
0x06C | ClearFlagCA | 0xB2DBB0 |
0x06D | PartyRecordFlag | 0xB2BD70 |
0x06E | PosFromTargetsJointAvg | 0xB2CF70 |
0x06F | Nop6F | 0xB2E590 |
0x070 | Unused70 | 0xB26810 |
0x071 | DrawEntityInCinematic | 0xB2DCC0 |
0x072 | RotFromEntity | 0xB2C820 |
0x073 | SetSpriteOrient2 | 0xB2DA40 |
0x074 | DrawFlagBits | 0xB2C360 |
0x075 | AccumFromEntitySize | 0xB2D0B0 |
0x076 | AccumAddRandom | 0xB2D170 |
0x077 | Nop77 | 0xB2BE20 |
0x078 | SetTexPage | 0xB2E040 |
0x079 | CompareFieldJump | 0xB2BE30 |
0x07A | NodeFromParentAndMatrix | 0xB2EB90 |
0x07B | WaitThenReloadA8defTim | 0xB2BB80 |
0x07C | RandomOffsetXZ | 0xB2D210 |
0x07D | SetBoneCount | 0xB2BE90 |
0x081 | SetSpriteAnimOriented | 0xB2DA80 |
0x082 | VelocityTowardBone | 0xB2C900 |
0x083 | ColorFromOutAngle | 0xB2DF10 |
0x084 | CopyMatrix | 0xB2EC40 |
0x087 | VelocityScaleAccum | 0xB2D2B0 |
0x089 | StepEmbeddedModelAnim | 0xB26980 |
0x08A | BattleScreenFx | 0xB2BEF0 |
0x08B | StartChannel | 0xB2D520 |
0x08D | ModelFlagsSetClear | 0xB2BFA0 |
0x08E | RemoveFromDrawList | 0xB2DBD0 |
0x090 | Nop10 | 0xB2E5A0 |
0x091 | AccumFromBoneOutputs | 0xB2CD50 |
0x092 | SetField92And9A | 0xB2E670 |
0x093 | BuildLightMatrices | Ifrit 0xB2F590, Leviathan 0xB64420 |
0x095 | Nop4 | 0xB2EB80 |
0x096 | CaptureScreenToVram | Cerberus 0xB16F60, Eden 0xAF2760 |
0x09B | ClearOptionBits | 0xB2DAB0 |
0x09C | SpawnBoneChained | 0xB2D860 |
0x09D | RecenterModelOffsetBone | Brothers 0xAFEFF0 |
0x09E | JumpIfCtxFlag15Clear | 0xB2FFC0 |
0x09F | JumpIfCtxFlag15Set | 0xB2FFF0 |
0x0A0 | JumpIfCtxFlag13Clear | 0xB30030 |
0x0A1 | RandomJump | 0xB2B080 |
0x0A2 | Nop4 | 0xB30020 |
0x0A4 | SetBoneHandler | 0xB2D920 |
0x0A5 | Nop4 | 0xB2AF30 |
0x0A6 | Nop4 | 0xB2AF40 |
0x0A7 | SetCounter | 0xB2AF50 |
0x0A8 | DecCounterJumpNZ | 0xB2AFD0 |
0x0AA | SetLightSlot | 0xB2F7D0 |
0x0AC | AccelerateToTarget | 0xB2D340 |
0x0AE | NextTargetOrJump | 0xB2FBE0 |
0x0B0 | RandomWait | 0xB30060 |
0x0B1 | SetSeqStateByte6 | 0xB2B150 |
0x0B2 | SetCtxByteA2 | 0xB2BB50 |
0x0B6 | QueueVramBlit | Eden 0xAF27C0 |
0x0B7 | SdStreamingVolume | Eden 0xAE3350 |
0x0B8 | Nop8 | 0xB26BF0 |
0x0B9 | NegateField | 0xB2CA80 |
0x0BA | NegateFieldNeg | 0xB2CAD0 |
0x0BC | SetSpriteFrameSpeed | 0xB2DC60 |
0x0C0 | VelPosTowardSpawner | 0xB2C970 |
0x0C1 | Nop | 0xB2C3B0 |
0x0C3 | PauseResumeSounds | 0xB25D60 |
0x0C4 | NodeLocalNoCamera | 0xB2EA70 |
0x0C5 | JumpIfBattleStage | Brothers 0xAFB240 |
0x0C6 | SetFogColorAndNear | 0xB2F820 |
0x0C7 | InitSpriteAnimH22 | 0xB2DA30 |
0x0CB | NodeLookAt | 0xB2ECE0 |
0x0CC | SetBoneHandler7 | 0xB2CB70 |
0x0CD | SetRenderListOffset | 0xB2B170 |
0x0CE | SetBoneId | 0xB2B050 |
0x0CF | RetargetToMultiPartRoot | Brothers 0xAFCBE0, Eden 0xAF1830 |
0x0D0 | RemoveFromDrawList | 0xB2DC00 |
0x0D1 | JumpIfModelSlot0FileId | Brothers 0xAFB270 |
0x0D2 | NegateMotionComponent | 0xB2CB20 |
0x0D3 | ColorFromBoneOutPos | 0xB2DE30 |
0x0D4 | SetColor | 0xB2DDD0 |
0x0D5 | NorgBossTargetFixup | Brothers 0xAFB630 |
0x0D7 | Nop2 | 0xB2C240 |
0x0DA | RenderEntityToVram | Brothers 0xAFDB00 |
0x0DF | SetupDrawHandler29 | 0xB2E3A0 |
0x0E7 | WaitUntilFieldGreater | 0xB2C250 |
0x0EB | AddToDrawList | 0xB2DC30 |
0x0F1 | Nop2 | 0xB2F8C0 |
0x0F2 | BakeOutPosToAccum | 0xB2CBD0 |
0x0FB | WaitUntilFieldLess | 0xB2C290 |
0x0FD | JumpIfFieldInRange | 0xB2C320 |
0x104 | BuildBillboardSlot | 0xB2EDB0 |
0x105 | NodeFromBillboardSlot | 0xB2EE40 |
0x106 | WaitUntilFieldLessThanBone | 0xB2C2D0 |
0x10C | BoneFlagOps | 0xB2C100 |
0x10D | WaitOtherBoneFlags | 0xB2C1D0 |
0x110 | PlaceAtMidpoint | 0xB2CC20 |
0x116 | NodeCamPosLocalRot | 0xB2EB10 |
0x117 | SetRotRelativeToRoot | 0xB2EF00 |
0x11B | SetFogColorAndFar | 0xB2F870 |
0x120 | SetCtx74FromCtx70 | 0xB2B420 |
0x127 | Nop4 | 0xB2E430 |
0x135 | SpawnBoneWithId | 0xB2D7C0 |
0x13D | BattleEntityVisibility | 0xB2B5D0 |
0x140 | WaitScaledBySlot | 0xB300A0 |
0x1874F10 | Ifrit VmOpcodeTable | 0x147 entries; the table of every GF = its DrawHandlerTable + 0x1A4 |
0x1874ED6 / 0x1874EF0 | Ifrit VmOpcodeAttribTable / VmFieldDescTable | generic writes |
0x1874894 | GF_201Ifrit_MagDescriptor | per-GF resource descriptor (VRAM rectangles, file slots) |
0x2798A68 | g_GfCinematic_MagFileSlot | 64 file slot base pointers |