Expansion packs: cutscenes
cutscenes.toml holds an expansion pack's scripted scenes: a camera rising up a hall, an NPC walking to meet the party, a line, a choice that branches, a fade, a fight. Each is a list of named steps that a small deterministic sequencer runs frame by frame, with named tracks running beside the main one. Every hook is the identity with no pack active: no cutscene can start, nothing locks the player, and the camera, the screen layer and the save gates read as before.
At a glance
- File
cutscenes.tomlat the pack root; optional.- Parser
legaia_expansion_format::cutscene(the step shapes, the reachability and spin checks, the validator rules).- Runtime
- The sequencer
legaia_engine_expansion::cutscene(CutsceneRun, its camera and screen layer, the workbench'spreview);engine-core'sworld::expansion_cutsceneruns its commands on theWorld. - Hosts
- Both play hosts frame the shot through
camera_view::pack_cutscene_viewand draw the fades and letterbox throughscreen_layers::expansion_cutscene_prims; nothing of a cutscene is host-side. - Ids
- Declares
cutscene; referencesline,formation,boss,quest,map. - Seen flag
cutscene.<id>, a pack flag saved with the pack's progress.
Why a step list, not field-VM bytecode
Retail's own cutscenes are field-VM records (cutscenes): camera beats through op 0x45, actor moves, inline dialogue, flag ops. A pack cutscene is a list of named steps on a sequencer of its own instead, for three reasons:
- A pack never writes a retail story flag. Field-VM bytecode reaches the flag bank, the scene control block and every placement's script state; a step list has no op for any of them, and its flags are pack flags, exactly as a pack dialogue line's are.
- It is checked as a whole. Every actor, line, label, track, flag, fight and tile is known before the cutscene runs, so the validator refuses a broken one.
- It is written by hand and edited in the workbench. A step reads as what it does; the workbench's step-list editor is a form over the same shape.
cutscenes.toml
[cutscenes.tower_intro]
title = "The Tower Wakes"
map = "genesis_1f"
letterbox = true
[[cutscenes.tower_intro.steps]]
do = "camera"
focus = { tile = [7, 11] }
pitch = -14.0
zoom = 0.55
[[cutscenes.tower_intro.steps]]
do = "start_track"
track = "crane"
[[cutscenes.tower_intro.steps]]
do = "say"
line = "intro_hall"
[[cutscenes.tower_intro.tracks.crane.steps]]
do = "camera"
focus = { tile = [7, 1] }
zoom = 2.3
frames = 300
| Key | Meaning |
|---|---|
title | Display title. |
map | The pack map it plays on: its tiles and NPCs, and the engine refuses it elsewhere. Without it, tiles are the scene's field-grid tiles and actors the player and retail:<slot>. |
skippable | Start skips it once seen (default on). |
lock_player | The player is held throughout (default on). |
letterbox | Cinematic bars while it runs. |
steps | The main track; the cutscene ends when it does. |
tracks.<name>.steps | Tracks a start_track step runs beside it. |
Steps
A step's do key names it. Frames are display frames, 60 a second; a step that takes time accepts wait = false to let the next one start at once.
do | What it does |
|---|---|
wait | Waits frames. |
say | Shows a line and waits for it to close; on_choice names a label per option. |
move | Walks an actor through to / path tiles (optional speed, run, clip); a leg that would cross a wall goes round it on the collision grid. |
face, clip, teleport | Turn an actor (sector or toward another), play a clip, put it on a tile. |
show, hide | Bring a pack NPC on or take it off. |
camera, camera_reset, shake | Move the shot, ease it back, shake it. |
fade, flash, tint | The screen layer: fade to black / white / clear, a dying flash, a held colour. |
banner | A title across the lower screen in the place-name banner's balloon: a dialog line's first page. |
set_flag, clear_flag, counter | Pack flags and counters. |
label, goto, branch | Jump targets and jumps; a branch reads the quest gate shape and a counter. |
start_track, join | Start a track; wait for one. |
lock, unlock | Hold or free the player midway. |
battle, boss | End on a battle.toml fight. |
give_item, take_item, gold, give_card | Rewards. |
start_quest | Start a quest. |
sfx, bgm | A sound effect from the static table; switch the music. |
sound, music, music_release | A retail cue or pack sound; a held music pick (a pack track too) cross-fading over fade frames; the music back to the map (audio). |
end | End here. |
Actors and walks
An actor is "player", a pack NPC of the cutscene's map, or "retail:<slot>". The player walks at the pad walk's pace (8 world units a frame, 12 running) and plays its walk clip; an NPC walks each leg on the motion VM. A walk goes straight from stop to stop where that keeps to open ground, and round a wall on the collision grid where it would not; a leg with no way round walks straight. A pack NPC's present gate keeps it off the map until it holds; hide parks it on retail's own off-map hide box, out of every draw, the talk probe and the collision boxes.
Camera
A camera step moves the shot from the follow camera's own: focus replaces the follow focus (a tile, or an actor followed while it moves), yaw and pitch are degrees added to the follow shot's, and zoom scales the eye-space translation so the shot pulls straight back along its line of sight. A glide eases still at both ends; frames = 0 cuts. A cutscene that never moves the camera looks exactly like the field.
Hooks
| Hook | Plays |
|---|---|
A map trigger, kind = "cutscene" | When the player steps into the zone (once, requires as usual). |
A map's enter_cutscenes | On arrival: the first unseen entry whose gate holds, or one with repeat. |
A pack NPC's cutscene | When the player talks to it, in place of its line. |
A quest's start_cutscene / complete_cutscene | After the quest's line, once back in the field. |
A boss's intro / outro | As its fight is called (the fight follows), and back on the field after a win. |
A hook queues the cutscene; it starts on the first field frame with no box open, no fight waiting and no scene change in flight.
Runtime
The sequencer is a deterministic interpreter: each frame it advances its clocks, clears the waits that are over and runs each track to its next wait. It reads the world only through a narrow environment (is this actor walking, is the box closed, which option was picked, does this gate hold) and writes it only through commands, so the same answers give the same commands frame for frame. Each command uses a path the world already has - the faithful dialogue runner for a line, the motion VM for an NPC leg, the pack's queued fight for a battle. While a cutscene holds the player, the one predicate the walk, the talk probe, the menu button and the encounter roll already read answers that the player is engaged; the map's zones and exits fire nothing under it and its patrols pause.
Skipping and saves
A cutscene seen to the end once raises cutscene.<id>; from then on Start skips it: walks land, glides arrive, unshown lines are skipped, and every flag, item and quest step still happens. A line ending on a menu stops the skip, since the choice is the player's. A cutscene is never a save state: a host save is refused while one runs and the pause menu cannot open; a loaded save starts outside any cutscene.
Validation
- Errors: an actor or tile the cutscene's map does not have; a line, fight, quest or card that does not exist;
on_choiceon a line without a menu or with more labels than options; a jump to an undefined label, a label defined twice; a step no flow reaches; a loop that never waits a frame; an unknown track; a malformedface; a zoom, pitch, frame count or shake out of range; a hook naming a missing cutscene, or an arrival cutscene bound to another map. - Warnings: a track nothing starts.
The workbench's Cutscenes tab edits the step lists and shows a text timeline of each cutscene played on the engine's own sequencer against a stand-in world (workbench).
Gaps
- The field draws the party leader only, so the other members cannot be moved.
- The path round a wall is the collision grid's: a prop with no wall bits under it is walked through.
- A scene change ends a cutscene, so no step changes map midway.
- A player
clipnames a clip base of the party bank, not a free animation.