# Cutscenes Two distinct layers: a low-level engine sequencer (`src/dusk/cutscene/`) and a higher-level RPG wrapper (`src/dusk/rpg/cutscene/`). Almost all game code works with the RPG layer. --- ## Engine sequencer (`src/dusk/cutscene/`) `cutscene_t CUTSCENE` is a minimal event runner with up to `CUTSCENE_EVENT_COUNT_MAX` (16) `cutsceneevent_t` slots. Each event has three callbacks: ```c typedef struct { errorret_t (*onStart)(void); errorret_t (*onUpdate)(void); errorret_t (*onEnd)(void); } cutsceneevent_t; ``` API: ```c cutscenePlay(events, count); // copy events array and start from index 0 cutsceneAdvance(); // end current event, start next (deactivates after last) cutsceneStop(); // abort immediately cutsceneIsActive(); // bool ``` This layer is primarily used by the RPG cutscene system — game code doesn't normally touch it directly. --- ## RPG cutscene layer (`src/dusk/rpg/cutscene/`) ### Data structures A `cutscene_t` is just a pointer to an item array and a count: ```c typedef struct cutscene_s { const cutsceneitem_t *items; uint8_t itemCount; } cutscene_t; ``` A `cutsceneitem_t` is a tagged union of all item types: ```c typedef struct cutsceneitem_s { cutsceneitemtype_t type; union { cutscenetext_t text; // display text in textbox cutscenecallback_t callback; // call a void(*)(void) function cutscenewait_t wait; // pause for a fixed_t duration (seconds) const cutscene_t *cutscene; // nest another cutscene }; } cutsceneitem_t; ``` ### Item types | Type constant | Payload | Behaviour | |---|---|---| | `CUTSCENE_ITEM_TYPE_TEXT` | `cutscenetext_t` — `text[256]` + `rpgtextboxpos_t position` | Shows textbox; advances on player confirm input | | `CUTSCENE_ITEM_TYPE_CALLBACK` | `cutscenecallback_t` (function pointer) | Calls the function once, then immediately advances | | `CUTSCENE_ITEM_TYPE_WAIT` | `cutscenewait_t` (a `fixed_t` in seconds) | Counts down `animTime` each frame, then advances | | `CUTSCENE_ITEM_TYPE_CUTSCENE` | `const cutscene_t *` | Plays the nested cutscene before continuing | ### Runtime state `cutscenesystem_t CUTSCENE_SYSTEM` tracks: - `scene` — pointer to the active `cutscene_t` - `currentItem` — index into `scene->items[]` - `data` — per-item runtime data (`cutsceneitemdata_t`, currently just `cutscenewaitdata_t`) - `mode` — the current `cutscenemode_t` API: ```c cutsceneSystemStartCutscene(cutscene); // begin playing a cutscene cutsceneSystemNext(); // advance to next item cutsceneSystemUpdate(); // called each frame from rpgUpdate cutsceneSystemGetCurrentItem(); // inspect active item ``` ### Cutscene mode (`cutscenemode.h`) Each item can run in one of three modes: ```c CUTSCENE_MODE_NONE // no cutscene active CUTSCENE_MODE_FULL_FREEZE // pause everything (not yet used) CUTSCENE_MODE_INPUT_FREEZE // player input blocked (default: CUTSCENE_MODE_INITIAL) CUTSCENE_MODE_GAMEPLAY // player can still move during cutscene ``` `cutsceneModeIsInputAllowed()` is checked by `entityUpdate()` before invoking the movement callback — the player cannot walk when in INPUT_FREEZE mode. ### Defining a cutscene Cutscenes are defined as `static const` arrays in header files under `rpg/cutscene/scene/`. Example (`testcutscene.h`): ```c static const cutsceneitem_t MY_CUTSCENE_ITEMS[] = { { .type = CUTSCENE_ITEM_TYPE_TEXT, .text = { .text = "Hello!", .position = RPG_TEXTBOX_POS_BOTTOM } }, { .type = CUTSCENE_ITEM_TYPE_WAIT, .wait = FIXED(1.5f) }, { .type = CUTSCENE_ITEM_TYPE_CUTSCENE, .cutscene = &ANOTHER_CUTSCENE }, }; static const cutscene_t MY_CUTSCENE = { .items = MY_CUTSCENE_ITEMS, .itemCount = sizeof(MY_CUTSCENE_ITEMS) / sizeof(cutsceneitem_t) }; ``` Attach to an NPC via its interact component: ```c entity->interact.type = ENTITY_INTERACT_CUTSCENE; entity->interact.data.cutscene = &MY_CUTSCENE; ``` --- ## Textbox (`src/dusk/rpg/rpgtextbox.h`) `rpgtextbox_t RPG_TEXTBOX` is the global textbox state: ```c typedef struct { rpgtextboxpos_t position; // RPG_TEXTBOX_POS_TOP or RPG_TEXTBOX_POS_BOTTOM bool_t visible; char_t text[RPG_TEXTBOX_MAX_CHARS]; // 256 chars } rpgtextbox_t; ``` API: ```c rpgTextboxShow(position, text); // copies text, sets visible = true rpgTextboxHide(); // sets visible = false rpgTextboxIsVisible(); // bool ``` The textbox state is read by `ui/uitextbox.c` during the UI render pass to draw the dialogue box on screen. `rpgtextbox.c` itself does no rendering.