diff --git a/src/dusk/rpg/cutscene/cutscenesystem.c b/src/dusk/rpg/cutscene/cutscenesystem.c index db1a7092..08541258 100644 --- a/src/dusk/rpg/cutscene/cutscenesystem.c +++ b/src/dusk/rpg/cutscene/cutscenesystem.c @@ -36,6 +36,7 @@ void cutsceneSystemDispose() { CUTSCENE_SYSTEM.textMiniLastCreated = CUTSCENE_TEXT_MINI_LAST_CREATED; CUTSCENE_SYSTEM.textCache[0] = '\0'; CUTSCENE_SYSTEM.onComplete = NULL; + CUTSCENE_SYSTEM.loadedFile[0] = '\0'; cutsceneLoadedSetDoc(NULL); } @@ -58,6 +59,7 @@ void cutsceneSystemPrepare( CUTSCENE_SYSTEM.textCache[0] = '\0'; CUTSCENE_SYSTEM.currentItem = 0xFF;// Set to 0xFF so Next wraps to 0. CUTSCENE_SYSTEM.onComplete = NULL; + CUTSCENE_SYSTEM.loadedFile[0] = '\0'; } void cutsceneSystemStartCutscene(cutscene_t *cutscene) { @@ -69,6 +71,12 @@ void cutsceneSystemStartCutsceneWith( entity_t *interact, entity_t *interacted ) { + assertNotNull(cutscene, "Cutscene cannot be NULL"); + assertTrue( + cutscene->itemCount <= cutscene->itemsMax, + "Cutscene itemCount exceeds itemsMax" + ); + cutsceneSystemPrepare(cutscene, interact, interacted); cutsceneSystemNext(); } @@ -139,6 +147,7 @@ void cutsceneSystemLoad(const char_t *file) { cutsceneLoadedSetDoc(doc); cutsceneSystemStartCutscene(&CUTSCENE_SYSTEM.loadedScene); + stringCopy(CUTSCENE_SYSTEM.loadedFile, file, ASSET_FILE_NAME_MAX - 1); } void cutsceneLoadedSetDoc(yyjson_doc *doc) { @@ -153,14 +162,30 @@ void cutsceneRestart(void) { // A restart is the same logical run trying again (e.g. retrying a failed // save-device check), not a fresh unrelated start, so it should not - // silently drop a completion callback the caller already armed. + // silently drop a completion callback the caller already armed, or the + // entities that triggered it - both cutsceneSystemStartCutsceneWith and + // cutsceneSystemLoad (via cutsceneSystemPrepare) forget them. cutscenecallback_t onComplete = CUTSCENE_SYSTEM.onComplete; - cutsceneSystemStartCutsceneWith( - CUTSCENE_SYSTEM.scene, - CUTSCENE_SYSTEM.entityInteract, - CUTSCENE_SYSTEM.entityInteracted - ); + entity_t *entityInteract = CUTSCENE_SYSTEM.entityInteract; + entity_t *entityInteracted = CUTSCENE_SYSTEM.entityInteracted; + + if(CUTSCENE_SYSTEM.loadedFile[0] != '\0') { + // Came from a cutscene asset - re-read+re-parse it from scratch + // rather than just rerunning whatever's still resident in + // loadedScene/loadedItems, so a restart always reflects the file's + // current contents. + char_t file[ASSET_FILE_NAME_MAX]; + stringCopy(file, CUTSCENE_SYSTEM.loadedFile, ASSET_FILE_NAME_MAX - 1); + cutsceneSystemLoad(file); + } else { + cutsceneSystemStartCutsceneWith( + CUTSCENE_SYSTEM.scene, entityInteract, entityInteracted + ); + } + CUTSCENE_SYSTEM.onComplete = onComplete; + CUTSCENE_SYSTEM.entityInteract = entityInteract; + CUTSCENE_SYSTEM.entityInteracted = entityInteracted; } void cutsceneSystemSetOnComplete(cutscenecallback_t onComplete) { diff --git a/src/dusk/rpg/cutscene/cutscenesystem.h b/src/dusk/rpg/cutscene/cutscenesystem.h index 33f5d1a4..edec0f2e 100644 --- a/src/dusk/rpg/cutscene/cutscenesystem.h +++ b/src/dusk/rpg/cutscene/cutscenesystem.h @@ -52,6 +52,16 @@ typedef struct { cutsceneitem_t loadedItems[CUTSCENE_LOADED_ITEMS_MAX]; cutscene_t loadedScene; + + // Filename last passed to cutsceneSystemLoad, e.g. "main_menu.jsonc" - + // set right after it starts loadedScene running. Empty ("") for a + // cutscene started directly via cutsceneSystemStartCutscene* instead + // (a C-authored one, or loadedScene reused without going through + // cutsceneSystemLoad again), and cleared by cutsceneSystemPrepare on + // every fresh start so it never lingers from a previous file load. See + // cutsceneRestart, which re-loads (rather than just rerunning) whatever + // this names. + char_t loadedFile[ASSET_FILE_NAME_MAX]; } cutscenesystem_t; extern cutscenesystem_t CUTSCENE_SYSTEM; @@ -153,7 +163,8 @@ void cutsceneSystemInsertCutscene(const cutscene_t *cutscene); * CUTSCENE_LOADED_ITEMS_MAX's doc comment for why), so it's always * re-read+re-parsed fresh, never assumed still resident from a previous * call. Opens the fatal error overlay (see uiFatalErrorOpen) instead of - * starting anything if the asset fails to load. + * starting anything if the asset fails to load. Records file into + * CUTSCENE_SYSTEM.loadedFile once it starts running. * * @param file Cutscene file name (with .jsonc extension), relative to * assets/cutscenes/. @@ -174,8 +185,14 @@ void cutsceneLoadedSetDoc(yyjson_doc *doc); /** * Restarts the currently running cutscene from its first item, - * preserving whatever interact/interacted entities triggered it. - * Asserts if no cutscene is running. + * preserving whatever interact/interacted entities triggered it and + * whatever completion callback was armed. If CUTSCENE_SYSTEM.loadedFile + * is set (i.e. the running cutscene came from cutsceneSystemLoad), this + * re-reads and re-parses that file via cutsceneSystemLoad rather than + * just rerunning whatever's still resident in loadedScene/loadedItems, so + * a restart always reflects the file's current contents - otherwise it's + * just cutsceneSystemStartCutsceneWith on the same cutscene_t. Asserts if + * no cutscene is running. */ void cutsceneRestart(void);