Author: HobbitDur
Camera sequence
The camera sequences reuse the same byte-code VM as animation sequences (arithmetic C0-E5 and jumps E6-F3 behave identically), with camera-specific callbacks (CameraSeq_DispatchActionOpcode at 0x509810, driver BS_UpdateCameraSequence at 0x509610).
Who starts a camera sequence
A camera data blob starts with a small header containing two relative offsets: one to the camera sequence (the VM byte-code interpreted here) and one to the camera animation collection (the actual key-framed camera motions that opcodes 00/05 play).
A camera sequence is started by calling Battle_PlayCameraAnimation (0x5099A0) with a pointer to such a blob, which registers both pointers (CURRENT_CAMERA_SETTING_ADDR / CURRENT_CAMERA_ANIMATION_COLLECTION_HEADER_ADDR). In practice this is called:
- at battle start by
BS_CameraInit(the battle stage’s idle camera), - by every spell/ability effect routine (the
MAG_xxxfunctions in magic.fs and the monster-attack effect inits) when the action’s visual effect begins — each effect embeds/points to its own camera data. For monster abilities the camera comes from this section.
A camera sequence can adapt its framing to the monster it is filming through the camera category (information & stats byte 246): that per-monster value is converted at battle start into the entity’s camera variable, which camera sequences read back via camera-C3 0x15 (see the table below).
From then on, the battle camera update (updateBattleCamera at 0x504060, every frame unless battle is paused) calls BS_UpdateCameraSequence, which interprets the sequence: it runs until opcode 01 (yield, one frame), and stops when it reaches 02 (or any unknown opcode), releasing the camera back to the default behaviour.
Camera opcodes < 0xC0:
| Opcode | Params | Description |
|---|---|---|
| 00 XX | 1 | Play camera animation XX from the current camera animation collection |
| 01 | 0 | Yield (pause for this frame, resume next frame) |
| 02 | 0 | End the camera sequence and clear the camera pointer |
| 03 | 0 | Capture the current camera pose as the idle/rest pose (0x503300 copies the live position/look-at into the default-pose registers at 0xB8B800) + clear flag bit 15 |
| 04 XX | 1 | Start a camera oscillation (wobble) task with param XX |
| 05 XX | 1 | Play camera animation whose id is read through the camera special-value reader (XX) |
| 06 | 0 | Set camera flag bit 15 |
| 07 | 0 | Clear camera flag bit 15 |
| 08 | 0 | Reset the wobble factor (4096) and the camera flag |
| 09 XX | 1 | Nop (parameter skipped) |
| other | - | Reset wobble factor and end the sequence |
Camera C3-family special reads (CameraSeq_ReadSpecialVar_C3 at 0x509640):
| Param | Value read |
|---|---|
| 0x00-0x07 | Camera animation local variables |
| 0x10 | Camera flag variable |
| 0x11 | Random value |
| 0x13 | Count of party members in a specific animation state |
| 0x15 | Target entity’s camera var: its camera category (information & stats byte 246), also overridable at runtime by entity sequences via E5 0x2B |
| 0x16 | Target’s animation status (with dead-flag fixup) |
| 0x17 | Battle task value |
| 0x18 | Attacker slot id |
| 0x19 | Target slot id |
| 0x1A | Number of affected targets |
| 0x1B | Count of party members with animation status 0 |
| 0x1C-0x22 | Random value modulo 2..8 |
| > 0x77 | Camera stack (same principle as the entity stack) |
Camera E5 writes: params < 8 write the camera animation local variables, 0x10 writes the camera flag variable, > 0x77 writes the camera stack.