diff --git a/src/dusk/rpg/cutscene/CMakeLists.txt b/src/dusk/rpg/cutscene/CMakeLists.txt index a7ced42c..f285af87 100644 --- a/src/dusk/rpg/cutscene/CMakeLists.txt +++ b/src/dusk/rpg/cutscene/CMakeLists.txt @@ -7,6 +7,7 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME} PUBLIC cutscene.c + cutscenerefs.c cutscenesystem.c ) diff --git a/src/dusk/rpg/cutscene/cutscene.c b/src/dusk/rpg/cutscene/cutscene.c index 7e5c16bf..293caee5 100644 --- a/src/dusk/rpg/cutscene/cutscene.c +++ b/src/dusk/rpg/cutscene/cutscene.c @@ -148,26 +148,6 @@ void cutsceneAppendNext( cutsceneAppendAt(scene, (uint8_t)(currentIndex + 1), items, count); } -void cutsceneRemoveFront( - cutscene_t *scene, - const uint8_t count -) { - assertNotNull(scene, "Scene cannot be NULL"); - assertTrue(count <= scene->itemCount, "count exceeds itemCount"); - - const size_t tailCount = (size_t)scene->itemCount - count; - // count == 0 has nothing to shift (and would pass dest == src into - // memoryMove, which asserts against that as a no-op call). - if(count > 0 && tailCount > 0) { - memoryMove( - &scene->items[0], - &scene->items[count], - tailCount * sizeof(cutsceneitem_t) - ); - } - scene->itemCount -= count; -} - errorret_t cutsceneLoadParse( const char_t *path, cutscene_t *scene, @@ -189,7 +169,9 @@ errorret_t cutsceneLoadParse( // cutsceneitem_t field that could reference it owns its string data by // value, so nothing needs to survive past this call and the entry can // just be unlocked like any other asset once parsing finishes. - errorret_t parseResult = cutsceneParseDoc(entry->data.json, scene, items, itemsMax); + errorret_t parseResult = cutsceneParseDoc( + entry->data.json, scene, items, itemsMax + ); assetUnlockEntry(entry); errorChain(parseResult); diff --git a/src/dusk/rpg/cutscene/cutscene.h b/src/dusk/rpg/cutscene/cutscene.h index b6263a9d..07939299 100644 --- a/src/dusk/rpg/cutscene/cutscene.h +++ b/src/dusk/rpg/cutscene/cutscene.h @@ -128,30 +128,13 @@ void cutsceneAppendNext( const uint8_t count ); -/** - * Removes count items from the front of scene->items, shifting the - * remainder down to index 0 and shrinking scene->itemCount to match. Used - * by cutsceneSystemNext/cutsceneGoTo to reclaim already-run items' slots - * instead of leaving them as dead weight forever - see - * CUTSCENE_SYSTEM.currentItem's doc comment, since the currently-running - * item is always scene->items[0] once a cutscene has started. - * - * @param scene Cutscene to remove from. - * @param count Number of items to remove from the front - must be - * <= scene->itemCount. - */ -void cutsceneRemoveFront( - cutscene_t *scene, - const uint8_t count -); - /** * Loads a cutscene JSON asset by path and parses it into scene/items (see * cutsceneParseDoc) - the common "lock the asset, require it loaded, * parse its 'items' array, unlock it again" sequence shared by every * place that resolves a cutscene by file path (cutsceneSystemLoad, * cutsceneCutsceneResolve, cutsceneInsertResolveAndSplice, - * battleStateExecutingInit, cutsceneGoTo's reload). Purely propagates the + * battleStateExecutingInit, cutsceneSystemGoTo's reload). Purely propagates the * error on failure (like cutsceneParseDoc) - this is core cutscene logic, * not UI, so it doesn't reach for uiFatalErrorOpen itself; each caller * decides how to surface the failure (typically errorCatch(errorPrint()) diff --git a/src/dusk/rpg/cutscene/cutscenerefs.c b/src/dusk/rpg/cutscene/cutscenerefs.c new file mode 100644 index 00000000..ebae33bb --- /dev/null +++ b/src/dusk/rpg/cutscene/cutscenerefs.c @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "cutscenerefs.h" +#include "assert/assert.h" + +void cutsceneRefsReset( + cutscenesystemrefs_t *refs, + entity_t *interact, + entity_t *interacted +) { + assertNotNull(refs, "Refs cannot be null"); + + refs->entityInteract = interact; + refs->entityInteracted = interacted; + refs->entityLastCreated = NULL; + refs->entityLastRef = NULL; + refs->areaLastCreated = CUTSCENE_AREA_LAST_CREATED; + refs->textMiniLastCreated = CUTSCENE_TEXT_MINI_LAST_CREATED; +} diff --git a/src/dusk/rpg/cutscene/cutscenerefs.h b/src/dusk/rpg/cutscene/cutscenerefs.h new file mode 100644 index 00000000..86cafe1c --- /dev/null +++ b/src/dusk/rpg/cutscene/cutscenerefs.h @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "dusk.h" + +typedef struct entity_s entity_t; + +#define CUTSCENE_AREA_LAST_CREATED ((uint8_t)0xFF) +#define CUTSCENE_TEXT_MINI_LAST_CREATED ((uint8_t)0xFA) + +/** + * Common cutscene references that should survive a cutsceneRestart - + * grouped into one struct (rather than loose fields on cutscenesystem_t) + * so cutsceneRestart can snapshot/restore all of them in one copy instead + * of field-by-field, and so anything added here later comes along for the + * ride automatically. + */ +typedef struct { + entity_t *entityInteract; + entity_t *entityInteracted; + entity_t *entityLastCreated; + entity_t *entityLastRef; + uint8_t areaLastCreated; + uint8_t textMiniLastCreated; +} cutscenesystemrefs_t; + +/** + * Resets refs to a fresh state: interact/interacted set to the given + * entities, everything else (last-created entity, last-referenced entity, + * last-created map area, last-created mini textbox) cleared back to its + * "nothing yet" sentinel. + * + * @param refs Refs to reset. + * @param interact The entity that initiated the interaction, or NULL. + * @param interacted The entity being interacted with, or NULL. + */ +void cutsceneRefsReset( + cutscenesystemrefs_t *refs, + entity_t *interact, + entity_t *interacted +); diff --git a/src/dusk/rpg/cutscene/cutscenesystem.c b/src/dusk/rpg/cutscene/cutscenesystem.c index 8bd18a4d..2470bef0 100644 --- a/src/dusk/rpg/cutscene/cutscenesystem.c +++ b/src/dusk/rpg/cutscene/cutscenesystem.c @@ -21,16 +21,18 @@ void cutsceneSystemInit() { CUTSCENE_SYSTEM.loadedScene.itemsMax = CUTSCENE_LOADED_ITEMS_MAX; } +void cutsceneSystemUpdate() { + if(CUTSCENE_SYSTEM.scene == NULL) return; + + const cutsceneitem_t *item = cutsceneSystemGetCurrentItem(); + if(cutsceneItemUpdate(item, &CUTSCENE_SYSTEM.data)) cutsceneSystemNext(); +} + void cutsceneSystemDispose() { CUTSCENE_SYSTEM.scene = NULL; - CUTSCENE_SYSTEM.currentItem = 0xFF; + CUTSCENE_SYSTEM.currentItem = CUTSCENE_CURRENT_ITEM_NONE; CUTSCENE_SYSTEM.pause = CUTSCENE_PAUSE_NONE; - CUTSCENE_SYSTEM.entityInteract = NULL; - CUTSCENE_SYSTEM.entityInteracted = NULL; - CUTSCENE_SYSTEM.entityLastCreated = NULL; - CUTSCENE_SYSTEM.entityLastRef = NULL; - CUTSCENE_SYSTEM.areaLastCreated = CUTSCENE_AREA_LAST_CREATED; - CUTSCENE_SYSTEM.textMiniLastCreated = CUTSCENE_TEXT_MINI_LAST_CREATED; + cutsceneRefsReset(&CUTSCENE_SYSTEM.refs, NULL, NULL); CUTSCENE_SYSTEM.textCache[0] = '\0'; CUTSCENE_SYSTEM.onComplete = NULL; CUTSCENE_SYSTEM.loadedFile[0] = '\0'; @@ -45,25 +47,14 @@ void cutsceneSystemPrepare( CUTSCENE_SYSTEM.scene = cutscene; CUTSCENE_SYSTEM.pause = cutscene->pause; - CUTSCENE_SYSTEM.entityInteract = interact; - CUTSCENE_SYSTEM.entityInteracted = interacted; - CUTSCENE_SYSTEM.entityLastCreated = NULL; - CUTSCENE_SYSTEM.entityLastRef = NULL; - CUTSCENE_SYSTEM.areaLastCreated = CUTSCENE_AREA_LAST_CREATED; - CUTSCENE_SYSTEM.textMiniLastCreated = CUTSCENE_TEXT_MINI_LAST_CREATED; + cutsceneRefsReset(&CUTSCENE_SYSTEM.refs, interact, interacted); CUTSCENE_SYSTEM.textCache[0] = '\0'; - CUTSCENE_SYSTEM.currentItem = 0xFF;// Set to 0xFF so Next wraps to 0. CUTSCENE_SYSTEM.onComplete = NULL; - // Only invalidate the known source file when switching away from - // loadedScene entirely. Starting loadedScene itself means - // cutsceneSystemLoad/cutsceneCutsceneResolve just populated it - for - // cutsceneCutsceneResolve (see cutsceneCutsceneStart), that already - // happened before this call, so clearing loadedFile here would - // immediately undo it. cutsceneGoTo needs loadedFile intact to reload - // a marker behind the current position; cutsceneSystemLoad re-stamps - // it itself right after this call anyway, so it's unaffected either - // way. + // cutsceneNext will cause overflow to index 0 (intentional). + CUTSCENE_SYSTEM.currentItem = CUTSCENE_CURRENT_ITEM_NONE; + + // Clear loaded file if cutscene not running from file. if(cutscene != &CUTSCENE_SYSTEM.loadedScene) { CUTSCENE_SYSTEM.loadedFile[0] = '\0'; } @@ -84,9 +75,9 @@ void cutsceneSystemStartCutsceneWith( "Cutscene itemCount exceeds itemsMax" ); + // Prep cutscene, save it to the save slot, and advance, aka overflow to 0. cutsceneSystemPrepare(cutscene, interact, interacted); saveSlotSetCurrentCutscene(CUTSCENE_SYSTEM.loadedFile); - cutsceneSystemNext(); } @@ -96,8 +87,9 @@ void cutsceneSystemStartCutsceneAndGoToMarker( ) { assertNotNull(marker, "Marker cannot be NULL"); + // Restarts the cutscene cutsceneSystemPrepare(cutscene, NULL, NULL); - cutsceneGoTo(marker); + cutsceneSystemGoTo(marker); } void cutsceneSystemInsertItemsNext( @@ -109,7 +101,6 @@ void cutsceneSystemInsertItemsNext( CUTSCENE_SYSTEM.scene, "cutsceneSystemInsertItemsNext called with no cutscene running" ); - cutsceneAppendNext( CUTSCENE_SYSTEM.scene, CUTSCENE_SYSTEM.currentItem, items, itemCount ); @@ -128,31 +119,27 @@ void cutsceneSystemInsertCutscene(const cutscene_t *cutscene) { cutsceneSystemInsertItems(cutscene->items, cutscene->itemCount); } -void cutsceneSystemDiscardQueued(void) { +void cutsceneSystemClearAfter(const uint8_t index) { assertNotNull( CUTSCENE_SYSTEM.scene, - "cutsceneSystemDiscardQueued called with no cutscene running" + "cutsceneSystemClearAfter called with no cutscene running" + ); + assertTrue( + index < CUTSCENE_SYSTEM.scene->itemCount, + "cutsceneSystemClearAfter index out of range" ); - // currentItem is always 0 once a cutscene has started (see its doc - // comment) - keep just that one item, drop everything queued after it. - CUTSCENE_SYSTEM.scene->itemCount = 1; + CUTSCENE_SYSTEM.scene->itemCount = index + 1; } void cutsceneSystemLoad(const char_t *file) { assertNotNull(file, "File cannot be NULL"); - // Copy file out before it can be invalidated - every caller today - // passes a string literal, but file could in principle point into - // CUTSCENE_SYSTEM.loadedItems (a running item's own name field, if the - // running cutscene is loadedScene), which both cutsceneLoadParse and - // cutsceneSystemStartCutscene below overwrite/re-enter (see - // cutsceneCutsceneResolve's matching comment for the exact bug this - // guards against - initial.jsonc's closing CUTSCENE item into - // main_menu.jsonc hit it there). + // Take a copy of file, as it may be a part of the cutscene itself. char_t fileCopy[ASSET_FILE_NAME_MAX]; stringCopy(fileCopy, file, ASSET_FILE_NAME_MAX - 1); + // Load the cutscene asset, parse it, and start it. errorret_t result = cutsceneLoadParse( fileCopy, &CUTSCENE_SYSTEM.loadedScene, CUTSCENE_SYSTEM.loadedItems, CUTSCENE_LOADED_ITEMS_MAX @@ -162,13 +149,8 @@ void cutsceneSystemLoad(const char_t *file) { uiFatalErrorOpen(NULL); return; } - - // Stamped before starting (not after) - cutsceneSystemStartCutsceneWith - // reads loadedFile to persist the in-progress cutscene to the save (see - // saveSlotSetCurrentCutscene), so it must already be correct by then. - // Safe: cutsceneSystemPrepare (called from within Start) only clears - // loadedFile when switching away from loadedScene entirely, which this - // isn't. + + // Store the loaded file so we can restart if needed. stringCopy(CUTSCENE_SYSTEM.loadedFile, fileCopy, ASSET_FILE_NAME_MAX - 1); cutsceneSystemStartCutscene(&CUTSCENE_SYSTEM.loadedScene); } @@ -177,10 +159,14 @@ void cutsceneRestart(void) { assertNotNull( CUTSCENE_SYSTEM.scene, "cutsceneRestart called with no cutscene running" ); - + + // Snapshotted as one struct (rather than field-by-field) so anything + // added to cutscenesystemrefs_t later - entities, map areas, mini + // textboxes, etc - survives a restart automatically instead of needing + // its own line here. cutsceneSystemPrepare (called from within both + // branches below) resets refs to a fresh state, so it's restored after. cutscenecallback_t onComplete = CUTSCENE_SYSTEM.onComplete; - entity_t *entityInteract = CUTSCENE_SYSTEM.entityInteract; - entity_t *entityInteracted = CUTSCENE_SYSTEM.entityInteracted; + cutscenesystemrefs_t refs = CUTSCENE_SYSTEM.refs; if(CUTSCENE_SYSTEM.loadedFile[0] != '\0') { char_t file[ASSET_FILE_NAME_MAX]; @@ -188,13 +174,12 @@ void cutsceneRestart(void) { cutsceneSystemLoad(file); } else { cutsceneSystemStartCutsceneWith( - CUTSCENE_SYSTEM.scene, entityInteract, entityInteracted + CUTSCENE_SYSTEM.scene, refs.entityInteract, refs.entityInteracted ); } CUTSCENE_SYSTEM.onComplete = onComplete; - CUTSCENE_SYSTEM.entityInteract = entityInteract; - CUTSCENE_SYSTEM.entityInteracted = entityInteracted; + CUTSCENE_SYSTEM.refs = refs; } void cutsceneSystemSetOnComplete(cutscenecallback_t onComplete) { @@ -210,28 +195,28 @@ entity_t * cutsceneSystemGetEntity(const uint8_t entityIndex) { if(entityIndex == CUTSCENE_ENTITY_INTERACT) { assertNotNull( - CUTSCENE_SYSTEM.entityInteract, + CUTSCENE_SYSTEM.refs.entityInteract, "CUTSCENE_ENTITY_INTERACT used but no interact entity is set" ); - entity = CUTSCENE_SYSTEM.entityInteract; + entity = CUTSCENE_SYSTEM.refs.entityInteract; } else if(entityIndex == CUTSCENE_ENTITY_INTERACTED) { assertNotNull( - CUTSCENE_SYSTEM.entityInteracted, + CUTSCENE_SYSTEM.refs.entityInteracted, "CUTSCENE_ENTITY_INTERACTED used but no interacted entity is set" ); - entity = CUTSCENE_SYSTEM.entityInteracted; + entity = CUTSCENE_SYSTEM.refs.entityInteracted; } else if(entityIndex == CUTSCENE_ENTITY_LAST_CREATED) { assertNotNull( - CUTSCENE_SYSTEM.entityLastCreated, + CUTSCENE_SYSTEM.refs.entityLastCreated, "CUTSCENE_ENTITY_LAST_CREATED used but no entity has been created" ); - entity = CUTSCENE_SYSTEM.entityLastCreated; + entity = CUTSCENE_SYSTEM.refs.entityLastCreated; } else if(entityIndex == CUTSCENE_ENTITY_LAST_REF) { assertNotNull( - CUTSCENE_SYSTEM.entityLastRef, + CUTSCENE_SYSTEM.refs.entityLastRef, "CUTSCENE_ENTITY_LAST_REF used but no entity has been referenced" ); - entity = CUTSCENE_SYSTEM.entityLastRef; + entity = CUTSCENE_SYSTEM.refs.entityLastRef; } else { assertTrue( entityIndex < ENTITY_COUNT, @@ -240,17 +225,17 @@ entity_t * cutsceneSystemGetEntity(const uint8_t entityIndex) { entity = &ENTITIES[entityIndex]; } - CUTSCENE_SYSTEM.entityLastRef = entity; + CUTSCENE_SYSTEM.refs.entityLastRef = entity; return entity; } uint8_t cutsceneSystemGetAreaId(const uint8_t areaId) { if(areaId == CUTSCENE_AREA_LAST_CREATED) { assertTrue( - CUTSCENE_SYSTEM.areaLastCreated != CUTSCENE_AREA_LAST_CREATED, + CUTSCENE_SYSTEM.refs.areaLastCreated != CUTSCENE_AREA_LAST_CREATED, "CUTSCENE_AREA_LAST_CREATED used but no map area has been created" ); - return CUTSCENE_SYSTEM.areaLastCreated; + return CUTSCENE_SYSTEM.refs.areaLastCreated; } return areaId; } @@ -258,11 +243,12 @@ uint8_t cutsceneSystemGetAreaId(const uint8_t areaId) { uint8_t cutsceneSystemGetTextMiniId(const uint8_t index) { if(index == CUTSCENE_TEXT_MINI_LAST_CREATED) { assertTrue( - CUTSCENE_SYSTEM.textMiniLastCreated != CUTSCENE_TEXT_MINI_LAST_CREATED, + CUTSCENE_SYSTEM.refs.textMiniLastCreated != + CUTSCENE_TEXT_MINI_LAST_CREATED, "CUTSCENE_TEXT_MINI_LAST_CREATED used but no mini textbox has been " "shown" ); - return CUTSCENE_SYSTEM.textMiniLastCreated; + return CUTSCENE_SYSTEM.refs.textMiniLastCreated; } return index; } @@ -282,68 +268,49 @@ void cutsceneSystemSetTextCache(const char_t *text) { void cutsceneSystemNext() { if(CUTSCENE_SYSTEM.scene == NULL) return; - // Pop the just-finished item off the front rather than advancing an - // index further into the array - see CUTSCENE_SYSTEM.currentItem's doc - // comment. The very first call (currentItem still 0xFF) has nothing to - // pop yet; it just marks the cutscene as started. - if(CUTSCENE_SYSTEM.currentItem == 0xFF) { + // Pop the just-finished item off the front. + if(CUTSCENE_SYSTEM.currentItem == CUTSCENE_CURRENT_ITEM_NONE) { CUTSCENE_SYSTEM.currentItem = 0; } else { - cutsceneRemoveFront(CUTSCENE_SYSTEM.scene, 1); + cutscene_t *scene = CUTSCENE_SYSTEM.scene; + const size_t tailCount = (size_t)scene->itemCount - 1; + if(tailCount > 0) { + memoryMove( + &scene->items[0], &scene->items[1], tailCount * sizeof(cutsceneitem_t) + ); + } + scene->itemCount--; } - // End of the cutscene? Note that a CUTSCENE_ITEM_TYPE_INSERT item's - // spliced-in items are physically part of this same array (see - // cutsceneSystemInsertCutscene), so there's no separate "parent scene" - // to fall back into here - itemCount already accounts for them. + // End of the cutscene? if(CUTSCENE_SYSTEM.scene->itemCount == 0) { - // Saved and cleared before firing so a callback that immediately - // starts another cutscene (or sets its own onComplete) isn't clobbered - // by this function's own cleanup running after it - same reentrancy - // hazard as uiFocusPop, see src/dusk/ui/focus/uifocus.c. cutscenecallback_t onComplete = CUTSCENE_SYSTEM.onComplete; CUTSCENE_SYSTEM.scene = NULL; - CUTSCENE_SYSTEM.currentItem = 0xFF; CUTSCENE_SYSTEM.pause = CUTSCENE_PAUSE_NONE; - CUTSCENE_SYSTEM.entityInteract = NULL; - CUTSCENE_SYSTEM.entityInteracted = NULL; - CUTSCENE_SYSTEM.entityLastCreated = NULL; - CUTSCENE_SYSTEM.entityLastRef = NULL; - CUTSCENE_SYSTEM.areaLastCreated = CUTSCENE_AREA_LAST_CREATED; - CUTSCENE_SYSTEM.textMiniLastCreated = CUTSCENE_TEXT_MINI_LAST_CREATED; - CUTSCENE_SYSTEM.textCache[0] = '\0'; - CUTSCENE_SYSTEM.onComplete = NULL; if(onComplete != NULL) onComplete(NULL); return; } - // Start item. + // Start next (now current) item const cutsceneitem_t *item = cutsceneSystemGetCurrentItem(); memset(&CUTSCENE_SYSTEM.data, 0, sizeof(CUTSCENE_SYSTEM.data)); cutsceneItemStart(item, &CUTSCENE_SYSTEM.data); } -void cutsceneGoTo(const char_t *name) { +void cutsceneSystemGoTo(const char_t *name) { assertNotNull(name, "Name cannot be NULL"); assertNotNull( - CUTSCENE_SYSTEM.scene, "cutsceneGoTo called with no cutscene running" + CUTSCENE_SYSTEM.scene, "cutsceneSystemGoTo called with no cutscene running" ); - // A marker behind the current position can't be found in the live - // queue - already-run items are evicted from its front as the - // cutscene advances (see cutsceneSystemNext/cutsceneRemoveFront), so - // the untouched original has to be re-parsed from source instead. Only - // supported when the running cutscene is the one cutsceneSystemLoad/ - // cutsceneCutsceneResolve populated - a C-authored cutscene_t, or - // content spliced in via INSERT/battleStateExecutingInit, has no - // source to reload from, so a backward jump into those isn't supported - // yet. assertTrue( - CUTSCENE_SYSTEM.scene == &CUTSCENE_SYSTEM.loadedScene && - CUTSCENE_SYSTEM.loadedFile[0] != '\0', - "cutsceneGoTo requires the running cutscene to have come from " - "cutsceneSystemLoad/cutsceneCutsceneResolve" + CUTSCENE_SYSTEM.scene == &CUTSCENE_SYSTEM.loadedScene, + "cutsceneSystemGoTo requires the running cutscene file reference (1)" + ); + assertTrue( + CUTSCENE_SYSTEM.loadedFile[0] != '\0', + "cutsceneSystemGoTo requires the running cutscene file reference (2)" ); cutscene_t freshScene = { .items = CUTSCENE_SYSTEM.gotoScratchItems }; @@ -357,6 +324,7 @@ void cutsceneGoTo(const char_t *name) { return; } + // Search for the marker with the given name... for(uint8_t i = 0; i < freshScene.itemCount; i++) { const cutsceneitem_t *item = &freshScene.items[i]; if( @@ -364,10 +332,8 @@ void cutsceneGoTo(const char_t *name) { !stringEquals(item->marker.name, name) ) continue; - // Commit: replace the live queue outright with marker-onward from - // the fresh parse. Nothing before the marker (including whatever was - // running) gets Started - only the marker item itself does, same as - // the old in-place jump's semantics. + // Found, so splice the cutscene at that point and start it, the remaining + // items being the rest of the cutscene after the marker. const uint8_t remaining = freshScene.itemCount - i; memoryCopy( CUTSCENE_SYSTEM.loadedItems, &freshScene.items[i], @@ -383,19 +349,10 @@ void cutsceneGoTo(const char_t *name) { return; } - assertTrue(false, "cutsceneGoTo: no marker found with that name"); -} - -void cutsceneSystemUpdate() { - if(CUTSCENE_SYSTEM.scene == NULL) return; - - const cutsceneitem_t *item = cutsceneSystemGetCurrentItem(); - if(cutsceneItemUpdate(item, &CUTSCENE_SYSTEM.data)) cutsceneSystemNext(); + assertTrue(false, "cutsceneSystemGoTo: no marker found with that name"); } const cutsceneitem_t * cutsceneSystemGetCurrentItem() { if(CUTSCENE_SYSTEM.scene == NULL) return NULL; - - // Always index 0 - see CUTSCENE_SYSTEM.currentItem's doc comment. return &CUTSCENE_SYSTEM.scene->items[0]; } diff --git a/src/dusk/rpg/cutscene/cutscenesystem.h b/src/dusk/rpg/cutscene/cutscenesystem.h index 8fbe0e04..cf1d87ad 100644 --- a/src/dusk/rpg/cutscene/cutscenesystem.h +++ b/src/dusk/rpg/cutscene/cutscenesystem.h @@ -7,15 +7,13 @@ #pragma once #include "cutscene.h" - -typedef struct entity_s entity_t; +#include "cutscenerefs.h" #define CUTSCENE_ENTITY_INTERACT ((uint8_t)0xFE) #define CUTSCENE_ENTITY_INTERACTED ((uint8_t)0xFD) #define CUTSCENE_ENTITY_LAST_CREATED ((uint8_t)0xFC) #define CUTSCENE_ENTITY_LAST_REF ((uint8_t)0xFB) -#define CUTSCENE_AREA_LAST_CREATED ((uint8_t)0xFF) -#define CUTSCENE_TEXT_MINI_LAST_CREATED ((uint8_t)0xFA) +#define CUTSCENE_CURRENT_ITEM_NONE ((uint8_t)0xFF) #define CUTSCENE_TEXT_CACHE_MAX 64 #define CUTSCENE_LOADED_ITEMS_MAX 128 @@ -23,21 +21,10 @@ typedef struct entity_s entity_t; typedef struct { cutscene_t *scene; - - // 0xFF if nothing has started running yet, otherwise always 0 - the - // currently-running item is always scene->items[0]; cutsceneSystemNext - // removes it from the front (see cutsceneRemoveFront) rather than - // advancing an index further into the array, so an item's slot is - // reclaimed the moment it finishes instead of sitting there as dead - // weight for the rest of the cutscene's run. uint8_t currentItem; cutscenepause_t pause; - entity_t *entityInteract; - entity_t *entityInteracted; - entity_t *entityLastCreated; - entity_t *entityLastRef; - uint8_t areaLastCreated; - uint8_t textMiniLastCreated; + + cutscenesystemrefs_t refs; // Free-form text cache for the running cutscene - see // cutsceneSystemGetTextCache/cutsceneSystemSetTextCache. @@ -49,17 +36,12 @@ typedef struct { // See cutsceneSystemSetOnComplete. cutscenecallback_t onComplete; + // Cache and storage used for the dynamically loaded cutscenes. cutsceneitem_t loadedItems[CUTSCENE_LOADED_ITEMS_MAX]; cutscene_t loadedScene; - - // Filename last passed to cutsceneSystemLoad - see cutsceneRestart. char_t loadedFile[ASSET_FILE_NAME_MAX]; - - // Scratch space for cutsceneGoTo's re-parse of loadedFile - a fixed, - // persistent buffer rather than a local one since cutsceneitem_t is - // large (e.g. cutscenemodal_t alone carries a 256-byte message buffer), - // making a CUTSCENE_LOADED_ITEMS_MAX-sized array too big to put on the - // stack on constrained platforms (PSP/GameCube/Wii). + + // Cutscene items scratch, mostly used for CUTSCENE_INSERT items. cutsceneitem_t gotoScratchItems[CUTSCENE_LOADED_ITEMS_MAX]; } cutscenesystem_t; @@ -157,15 +139,19 @@ void cutsceneSystemInsertItems( void cutsceneSystemInsertCutscene(const cutscene_t *cutscene); /** - * Discards every item still queued behind the currently-running one, - * without disturbing that item's own progress - e.g. so a callback that + * Discards every item queued after index (e.g. index 0 keeps only the + * currently-running item and drops everything spliced in behind it), + * without disturbing index's own progress - e.g. so a callback that * decides the rest of a batch-spliced sequence is now moot (a battle * ending mid-round, with other fighters' still-queued move cutscenes and * the round's trailing state transition left behind) can drop it before * splicing in its own follow-up items, instead of leaving it to run * afterward against torn-down state. + * + * @param index Index to keep - everything after it is discarded. Must be + * < the running cutscene's current item count. */ -void cutsceneSystemDiscardQueued(void); +void cutsceneSystemClearAfter(const uint8_t index); /** * Loads and immediately starts a cutscene asset by file name. @@ -235,25 +221,12 @@ void cutsceneSystemSetTextCache(const char_t *text); void cutsceneSystemNext(); /** - * Jumps the running cutscene directly to the marker with the given name - * and starts it immediately. Re-parses the cutscene fresh from its - * source file (see cutsceneLoadParse) and replaces the live queue with - * marker-onward from that fresh parse - items already run may have been - * evicted from the front of the live queue (see - * cutsceneSystemNext/cutsceneRemoveFront), so a marker behind the - * current position can only be found in the untouched original. Nothing - * before the marker gets Started, only the marker item itself. - * - * Requires the running cutscene to be the one cutsceneSystemLoad/ - * cutsceneCutsceneResolve populated (i.e. CUTSCENE_SYSTEM.scene == - * &CUTSCENE_SYSTEM.loadedScene) - asserts otherwise. A C-authored - * cutscene_t, or content spliced in via INSERT/battleStateExecutingInit, - * has no source file to reload from, so backward jumps into those - * aren't supported yet. + * Jumps to a cutscene marker directly. If the cutscene is a loaded cutscene, + * this will result in it being reloaded (due to unshift nature of cutscenes). * * @param name Marker name to search for. */ -void cutsceneGoTo(const char_t *name); +void cutsceneSystemGoTo(const char_t *name); /** * Update the cutscene system for one frame. diff --git a/src/dusk/rpg/cutscene/item/battle/cutscenebattlepostmove.c b/src/dusk/rpg/cutscene/item/battle/cutscenebattlepostmove.c index 965369c3..ba7e1b26 100644 --- a/src/dusk/rpg/cutscene/item/battle/cutscenebattlepostmove.c +++ b/src/dusk/rpg/cutscene/item/battle/cutscenebattlepostmove.c @@ -39,7 +39,7 @@ void cutsceneBattlePostMoveStart( // still-pending move cutscenes, the trailing BATTLE_SET_STATE(PRE_ROUND) - // see battleStateExecutingInit) - the battle is over, so none of that // should run against the WON/LOST/ENDING transition about to replace it. - cutsceneSystemDiscardQueued(); + cutsceneSystemClearAfter(CUTSCENE_SYSTEM.currentItem); const cutsceneitem_t items[] = { { diff --git a/src/dusk/rpg/cutscene/item/control/cutsceneidle.h b/src/dusk/rpg/cutscene/item/control/cutsceneidle.h index d819084e..b230e186 100644 --- a/src/dusk/rpg/cutscene/item/control/cutsceneidle.h +++ b/src/dusk/rpg/cutscene/item/control/cutsceneidle.h @@ -11,7 +11,7 @@ /** * Updates an idle item. Never completes on its own - the cutscene blocks * here indefinitely until something external (e.g. a UI callback) calls - * cutsceneGoTo to jump elsewhere. + * cutsceneSystemGoTo to jump elsewhere. * * @param item The cutscene item. * @param data Runtime data storage. diff --git a/src/dusk/rpg/cutscene/item/control/cutscenemarker.h b/src/dusk/rpg/cutscene/item/control/cutscenemarker.h index 8da1dc9b..0dc10e16 100644 --- a/src/dusk/rpg/cutscene/item/control/cutscenemarker.h +++ b/src/dusk/rpg/cutscene/item/control/cutscenemarker.h @@ -19,7 +19,7 @@ typedef struct { /** * Starts a marker item. A marker does nothing on its own - it exists - * purely as a named position for cutsceneGoTo to jump to. + * purely as a named position for cutsceneSystemGoTo to jump to. * * @param item The cutscene item. * @param data Runtime data storage. diff --git a/src/dusk/rpg/cutscene/item/cutsceneitem.c b/src/dusk/rpg/cutscene/item/cutsceneitem.c index 123c7357..558b810a 100644 --- a/src/dusk/rpg/cutscene/item/cutsceneitem.c +++ b/src/dusk/rpg/cutscene/item/cutsceneitem.c @@ -481,9 +481,9 @@ cutscene_t * cutsceneCutsceneResolve(const char_t *name) { } // Shares loadedScene/loadedItems with cutsceneSystemLoad, so track the - // source the same way it does - cutsceneGoTo needs this to reload the + // source the same way it does - cutsceneSystemGoTo needs this to reload the // untouched original when jumping to a marker behind the current - // position (see cutsceneGoTo's doc comment). + // position (see cutsceneSystemGoTo's doc comment). stringCopy(CUTSCENE_SYSTEM.loadedFile, nameCopy, ASSET_FILE_NAME_MAX - 1); return &CUTSCENE_SYSTEM.loadedScene; diff --git a/src/dusk/rpg/cutscene/item/entity/cutsceneentityadd.c b/src/dusk/rpg/cutscene/item/entity/cutsceneentityadd.c index 75992fe6..af8cca35 100644 --- a/src/dusk/rpg/cutscene/item/entity/cutsceneentityadd.c +++ b/src/dusk/rpg/cutscene/item/entity/cutsceneentityadd.c @@ -25,8 +25,8 @@ void cutsceneEntityAddStart( entityInit(entity, item->entityAdd.entityType); entityPositionSet(entity, item->entityAdd.position);// Also assigns chunk. - CUTSCENE_SYSTEM.entityLastCreated = entity; - CUTSCENE_SYSTEM.entityLastRef = entity; + CUTSCENE_SYSTEM.refs.entityLastCreated = entity; + CUTSCENE_SYSTEM.refs.entityLastRef = entity; } bool_t cutsceneEntityAddUpdate( diff --git a/src/dusk/rpg/cutscene/item/maparea/cutscenemapareaadd.c b/src/dusk/rpg/cutscene/item/maparea/cutscenemapareaadd.c index 7cbd2f19..8b408a0b 100644 --- a/src/dusk/rpg/cutscene/item/maparea/cutscenemapareaadd.c +++ b/src/dusk/rpg/cutscene/item/maparea/cutscenemapareaadd.c @@ -12,7 +12,7 @@ void cutsceneMapAreaAddStart( const cutsceneitem_t *item, cutsceneitemdata_t *data ) { - CUTSCENE_SYSTEM.areaLastCreated = mapAreaAdd( + CUTSCENE_SYSTEM.refs.areaLastCreated = mapAreaAdd( item->mapAreaAdd.min, item->mapAreaAdd.max, item->mapAreaAdd.callback, diff --git a/src/dusk/rpg/cutscene/item/maparea/cutscenemapareaadd.h b/src/dusk/rpg/cutscene/item/maparea/cutscenemapareaadd.h index f100051f..b4135a65 100644 --- a/src/dusk/rpg/cutscene/item/maparea/cutscenemapareaadd.h +++ b/src/dusk/rpg/cutscene/item/maparea/cutscenemapareaadd.h @@ -21,7 +21,7 @@ typedef struct { /** * Starts a map area add step (adds the area immediately, storing its ID - * in CUTSCENE_SYSTEM.areaLastCreated). + * in CUTSCENE_SYSTEM.refs.areaLastCreated). * * @param item The cutscene item. * @param data Runtime data storage. diff --git a/src/dusk/rpg/cutscene/item/save/cutscenesavedevicecheck.c b/src/dusk/rpg/cutscene/item/save/cutscenesavedevicecheck.c index 9d6e4813..76d3a3fa 100644 --- a/src/dusk/rpg/cutscene/item/save/cutscenesavedevicecheck.c +++ b/src/dusk/rpg/cutscene/item/save/cutscenesavedevicecheck.c @@ -12,7 +12,7 @@ void cutsceneSaveDeviceCheckCallback(savedevice_t *device, void *user) { const cutsceneitem_t *item = cutsceneSystemGetCurrentItem(); - cutsceneGoTo( + cutsceneSystemGoTo( device != NULL ? item->saveDeviceCheck.successMarker : item->saveDeviceCheck.failureMarker diff --git a/src/dusk/rpg/cutscene/item/save/cutscenesavedevicecheck.h b/src/dusk/rpg/cutscene/item/save/cutscenesavedevicecheck.h index 7bd0f1cd..3998dd4c 100644 --- a/src/dusk/rpg/cutscene/item/save/cutscenesavedevicecheck.h +++ b/src/dusk/rpg/cutscene/item/save/cutscenesavedevicecheck.h @@ -31,7 +31,7 @@ void cutsceneSaveDeviceCheckStart( * Updates a save-device-check item. Like a CUTSCENE_MODAL_OPTIONS item, * this never completes on its own - once saveFindAvailableDevice's * callback fires, it jumps straight to the item's successMarker or - * failureMarker via cutsceneGoTo. + * failureMarker via cutsceneSystemGoTo. * * @param item The cutscene item. * @param data Runtime data storage. diff --git a/src/dusk/rpg/cutscene/item/save/cutscenesaveloadallslots.c b/src/dusk/rpg/cutscene/item/save/cutscenesaveloadallslots.c index 06745331..1b368723 100644 --- a/src/dusk/rpg/cutscene/item/save/cutscenesaveloadallslots.c +++ b/src/dusk/rpg/cutscene/item/save/cutscenesaveloadallslots.c @@ -17,11 +17,11 @@ void cutsceneSaveLoadAllSlotsStart( errorret_t result = saveLoadAllSlots(); if(errorIsNotOk(result)) { errorCatch(errorPrint(result)); - cutsceneGoTo(item->saveLoadAllSlots.failureMarker); + cutsceneSystemGoTo(item->saveLoadAllSlots.failureMarker); return; } - cutsceneGoTo(item->saveLoadAllSlots.successMarker); + cutsceneSystemGoTo(item->saveLoadAllSlots.successMarker); } bool_t cutsceneSaveLoadAllSlotsUpdate( diff --git a/src/dusk/rpg/cutscene/item/save/cutscenesaveloadallslots.h b/src/dusk/rpg/cutscene/item/save/cutscenesaveloadallslots.h index fc237b47..18b32b9d 100644 --- a/src/dusk/rpg/cutscene/item/save/cutscenesaveloadallslots.h +++ b/src/dusk/rpg/cutscene/item/save/cutscenesaveloadallslots.h @@ -17,7 +17,7 @@ typedef struct { /** * Starts a save-load-all-slots item: calls saveLoadAllSlots() and jumps * straight to the item's successMarker or failureMarker via - * cutsceneGoTo, depending on the result. + * cutsceneSystemGoTo, depending on the result. * * @param item The cutscene item. * @param data Runtime data storage. diff --git a/src/dusk/rpg/cutscene/item/ui/cutscenemodal.h b/src/dusk/rpg/cutscene/item/ui/cutscenemodal.h index d7f74c19..78df7bc6 100644 --- a/src/dusk/rpg/cutscene/item/ui/cutscenemodal.h +++ b/src/dusk/rpg/cutscene/item/ui/cutscenemodal.h @@ -75,7 +75,7 @@ void cutsceneModalStart( * CUTSCENE_MODAL_OPTIONS) always blocks regardless of the blocking * field - it's dismissed by the player picking one of them, and the * option callback is responsible for moving the cutscene on from there - * (typically via cutsceneGoTo or cutsceneRestart). + * (typically via cutsceneSystemGoTo or cutsceneRestart). * * @param item The cutscene item. * @param data Runtime data storage. diff --git a/src/dusk/rpg/cutscene/item/ui/cutscenemodaloptionsmarkers.c b/src/dusk/rpg/cutscene/item/ui/cutscenemodaloptionsmarkers.c index 37961926..f0390a92 100644 --- a/src/dusk/rpg/cutscene/item/ui/cutscenemodaloptionsmarkers.c +++ b/src/dusk/rpg/cutscene/item/ui/cutscenemodaloptionsmarkers.c @@ -23,7 +23,7 @@ void cutsceneModalOptionsMarkersCallback( // the modal directly (uiModalClose) before an option is picked. const uint8_t index = optionIndex < options->optionCount ? optionIndex : options->optionCount - 1; - cutsceneGoTo(options->markers[index]); + cutsceneSystemGoTo(options->markers[index]); } void cutsceneModalOptionsMarkersStart( diff --git a/src/dusk/rpg/cutscene/item/ui/cutscenemodaloptionsmarkers.h b/src/dusk/rpg/cutscene/item/ui/cutscenemodaloptionsmarkers.h index bfdc7813..9a46f178 100644 --- a/src/dusk/rpg/cutscene/item/ui/cutscenemodaloptionsmarkers.h +++ b/src/dusk/rpg/cutscene/item/ui/cutscenemodaloptionsmarkers.h @@ -22,7 +22,7 @@ typedef struct { char_t message[CUTSCENE_MODAL_MESSAGE_MAX_CHARS]; // Each option's display text/locale message ID, and the marker to - // cutsceneGoTo when that option is selected. Copied by value at parse + // cutsceneSystemGoTo when that option is selected. Copied by value at parse // time (see cutsceneModalOptionsMarkersLoad), so they stay valid // regardless of the backing JSON doc's lifetime. char_t options[CUTSCENE_MODAL_OPTIONS_MARKERS_MAX][UI_MODAL_OPTION_TEXT_MAX]; @@ -47,7 +47,7 @@ void cutsceneModalOptionsMarkersStart( * the cutscene blocks here indefinitely. Back/cancel input is disabled * while it's open (see uiMenuSetDisableBack), so it must be dismissed * by picking an option, which jumps straight to that option's marker - * via cutsceneGoTo. + * via cutsceneSystemGoTo. * * @param item The cutscene item. * @param data Runtime data storage. diff --git a/src/dusk/rpg/cutscene/item/ui/cutscenetextmini.c b/src/dusk/rpg/cutscene/item/ui/cutscenetextmini.c index 53e511b4..08bd27e9 100644 --- a/src/dusk/rpg/cutscene/item/ui/cutscenetextmini.c +++ b/src/dusk/rpg/cutscene/item/ui/cutscenetextmini.c @@ -23,7 +23,7 @@ void cutsceneTextMiniStart( NULL, NULL ); - CUTSCENE_SYSTEM.textMiniLastCreated = index; + CUTSCENE_SYSTEM.refs.textMiniLastCreated = index; } bool_t cutsceneTextMiniUpdate( diff --git a/src/dusk/ui/screen/mainmenu/uimainmenu.c b/src/dusk/ui/screen/mainmenu/uimainmenu.c index 2e5b972d..168a1d63 100644 --- a/src/dusk/ui/screen/mainmenu/uimainmenu.c +++ b/src/dusk/ui/screen/mainmenu/uimainmenu.c @@ -81,7 +81,7 @@ void uiMainMenuStartGame(void) { if(cutscene == NULL) return; cutsceneSystemStartCutsceneAndGoToMarker(cutscene, "NEW_GAME"); } else { - cutsceneGoTo("NEW_GAME"); + cutsceneSystemGoTo("NEW_GAME"); } cutsceneSystemSetOnComplete(uiMainMenuOpenSelectSave); @@ -93,7 +93,7 @@ void uiMainMenuOptions(void) { if(cutscene == NULL) return; cutsceneSystemStartCutsceneAndGoToMarker(cutscene, "OPTIONS"); } else { - cutsceneGoTo("OPTIONS"); + cutsceneSystemGoTo("OPTIONS"); } } @@ -103,7 +103,7 @@ void uiMainMenuQuit(void) { if(cutscene == NULL) return; cutsceneSystemStartCutsceneAndGoToMarker(cutscene, "QUIT"); } else { - cutsceneGoTo("QUIT"); + cutsceneSystemGoTo("QUIT"); } } diff --git a/test/rpg/cutscene/test_cutscenesystem.c b/test/rpg/cutscene/test_cutscenesystem.c index c8dbf5ea..6b15d80a 100644 --- a/test/rpg/cutscene/test_cutscenesystem.c +++ b/test/rpg/cutscene/test_cutscenesystem.c @@ -111,8 +111,8 @@ static void test_cutsceneSystemStartWithSetsInteractEntities(void **state) { &CUTSCENE_TEST_SINGLE_WAIT, &ENTITIES[0], &ENTITIES[1] ); - assert_ptr_equal(CUTSCENE_SYSTEM.entityInteract, &ENTITIES[0]); - assert_ptr_equal(CUTSCENE_SYSTEM.entityInteracted, &ENTITIES[1]); + assert_ptr_equal(CUTSCENE_SYSTEM.refs.entityInteract, &ENTITIES[0]); + assert_ptr_equal(CUTSCENE_SYSTEM.refs.entityInteracted, &ENTITIES[1]); assert_ptr_equal( cutsceneSystemGetEntity(CUTSCENE_ENTITY_INTERACT), &ENTITIES[0] ); @@ -122,8 +122,8 @@ static void test_cutsceneSystemStartWithSetsInteractEntities(void **state) { TIME.delta = 2.0f; cutsceneSystemUpdate();// ends the cutscene - assert_null(CUTSCENE_SYSTEM.entityInteract);// reset on end - assert_null(CUTSCENE_SYSTEM.entityInteracted); + assert_null(CUTSCENE_SYSTEM.refs.entityInteract);// reset on end + assert_null(CUTSCENE_SYSTEM.refs.entityInteracted); } static void test_cutsceneSystemGetEntitySentinelsRequireBeingSet( @@ -158,26 +158,26 @@ static void test_cutsceneSystemGetAreaId(void **state) { cutsceneSystemInit(); // cutsceneSystemInit() zero-inits the field -- only actually starting a // cutscene sets it to the "nothing created yet" sentinel. - CUTSCENE_SYSTEM.areaLastCreated = CUTSCENE_AREA_LAST_CREATED; + CUTSCENE_SYSTEM.refs.areaLastCreated = CUTSCENE_AREA_LAST_CREATED; expect_assert_failure(cutsceneSystemGetAreaId(CUTSCENE_AREA_LAST_CREATED)); assert_int_equal(cutsceneSystemGetAreaId(5), 5);// direct IDs pass through - CUTSCENE_SYSTEM.areaLastCreated = 3; + CUTSCENE_SYSTEM.refs.areaLastCreated = 3; assert_int_equal(cutsceneSystemGetAreaId(CUTSCENE_AREA_LAST_CREATED), 3); } static void test_cutsceneSystemGetTextMiniId(void **state) { cutsceneSystemInit(); - CUTSCENE_SYSTEM.textMiniLastCreated = CUTSCENE_TEXT_MINI_LAST_CREATED; + CUTSCENE_SYSTEM.refs.textMiniLastCreated = CUTSCENE_TEXT_MINI_LAST_CREATED; expect_assert_failure( cutsceneSystemGetTextMiniId(CUTSCENE_TEXT_MINI_LAST_CREATED) ); assert_int_equal(cutsceneSystemGetTextMiniId(4), 4); - CUTSCENE_SYSTEM.textMiniLastCreated = 1; + CUTSCENE_SYSTEM.refs.textMiniLastCreated = 1; assert_int_equal( cutsceneSystemGetTextMiniId(CUTSCENE_TEXT_MINI_LAST_CREATED), 1 ); @@ -195,15 +195,15 @@ static void test_cutsceneSystemDisposeResetsState(void **state) { assert_null(CUTSCENE_SYSTEM.scene); assert_int_equal(CUTSCENE_SYSTEM.currentItem, 0xFF); assert_int_equal(CUTSCENE_SYSTEM.pause, CUTSCENE_PAUSE_NONE); - assert_null(CUTSCENE_SYSTEM.entityInteract); - assert_null(CUTSCENE_SYSTEM.entityInteracted); + assert_null(CUTSCENE_SYSTEM.refs.entityInteract); + assert_null(CUTSCENE_SYSTEM.refs.entityInteracted); } // --- loadedFile survival across cutsceneSystemPrepare ------------------- // // cutsceneCutsceneResolve (and cutsceneSystemLoad) stamp // CUTSCENE_SYSTEM.loadedFile with what they just parsed loadedScene from -// - cutsceneGoTo needs that to survive so it can reload the same source +// - cutsceneSystemGoTo needs that to survive so it can reload the same source // later. cutsceneCutsceneResolve's caller stamps it BEFORE calling // cutsceneSystemStartCutscene(&CUTSCENE_SYSTEM.loadedScene), so // cutsceneSystemPrepare must not blindly clear loadedFile on every @@ -212,7 +212,7 @@ static void test_cutsceneSystemDisposeResetsState(void **state) { // regression-tests the exact bug hit via initial.jsonc's CUTSCENE item // into main_menu.jsonc: cutsceneCutsceneResolve stamped loadedFile, then // the immediately following cutsceneSystemStartCutscene call wiped it -// straight back out, so a later cutsceneGoTo on the still-running +// straight back out, so a later cutsceneSystemGoTo on the still-running // cutscene had nothing to reload from. static void test_cutsceneSystemPrepareKeepsLoadedFileWhenReenteringLoadedScene( void **state @@ -551,8 +551,8 @@ static void test_cutsceneInsertDoesNotResetPauseOrInteractEntities( // been popped off the front, only the snippet's one item is left. assert_ptr_equal(CUTSCENE_SYSTEM.scene, &CUTSCENE_TEST_INSERT_PERSIST_OUTER); assert_int_equal(CUTSCENE_SYSTEM.scene->itemCount, 1); - assert_ptr_equal(CUTSCENE_SYSTEM.entityInteract, &ENTITIES[3]); - assert_ptr_equal(CUTSCENE_SYSTEM.entityInteracted, &ENTITIES[4]); + assert_ptr_equal(CUTSCENE_SYSTEM.refs.entityInteract, &ENTITIES[3]); + assert_ptr_equal(CUTSCENE_SYSTEM.refs.entityInteracted, &ENTITIES[4]); // The snippet declares ALL, but INSERT doesn't apply it -- the outer // cutscene's NPC pause, already in effect, stands. assert_int_equal(CUTSCENE_SYSTEM.pause, CUTSCENE_PAUSE_NPC);