Track the loaded cutscene filename and re-load it on restart

Adds CUTSCENE_SYSTEM.loadedFile, set by cutsceneSystemLoad and cleared
by cutsceneSystemPrepare. cutsceneRestart now re-reads and re-parses
that file via cutsceneSystemLoad instead of just rerunning whatever's
still resident in loadedScene/loadedItems, so restarting a file-loaded
cutscene always reflects its current on-disk contents - restart of a
C-authored cutscene is unchanged.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
2026-09-18 09:28:15 -05:00
co-authored by Claude Sonnet 5
parent abf6863044
commit 70ae41bd29
2 changed files with 51 additions and 9 deletions
+31 -6
View File
@@ -36,6 +36,7 @@ void cutsceneSystemDispose() {
CUTSCENE_SYSTEM.textMiniLastCreated = CUTSCENE_TEXT_MINI_LAST_CREATED; CUTSCENE_SYSTEM.textMiniLastCreated = CUTSCENE_TEXT_MINI_LAST_CREATED;
CUTSCENE_SYSTEM.textCache[0] = '\0'; CUTSCENE_SYSTEM.textCache[0] = '\0';
CUTSCENE_SYSTEM.onComplete = NULL; CUTSCENE_SYSTEM.onComplete = NULL;
CUTSCENE_SYSTEM.loadedFile[0] = '\0';
cutsceneLoadedSetDoc(NULL); cutsceneLoadedSetDoc(NULL);
} }
@@ -58,6 +59,7 @@ void cutsceneSystemPrepare(
CUTSCENE_SYSTEM.textCache[0] = '\0'; CUTSCENE_SYSTEM.textCache[0] = '\0';
CUTSCENE_SYSTEM.currentItem = 0xFF;// Set to 0xFF so Next wraps to 0. CUTSCENE_SYSTEM.currentItem = 0xFF;// Set to 0xFF so Next wraps to 0.
CUTSCENE_SYSTEM.onComplete = NULL; CUTSCENE_SYSTEM.onComplete = NULL;
CUTSCENE_SYSTEM.loadedFile[0] = '\0';
} }
void cutsceneSystemStartCutscene(cutscene_t *cutscene) { void cutsceneSystemStartCutscene(cutscene_t *cutscene) {
@@ -69,6 +71,12 @@ void cutsceneSystemStartCutsceneWith(
entity_t *interact, entity_t *interact,
entity_t *interacted entity_t *interacted
) { ) {
assertNotNull(cutscene, "Cutscene cannot be NULL");
assertTrue(
cutscene->itemCount <= cutscene->itemsMax,
"Cutscene itemCount exceeds itemsMax"
);
cutsceneSystemPrepare(cutscene, interact, interacted); cutsceneSystemPrepare(cutscene, interact, interacted);
cutsceneSystemNext(); cutsceneSystemNext();
} }
@@ -139,6 +147,7 @@ void cutsceneSystemLoad(const char_t *file) {
cutsceneLoadedSetDoc(doc); cutsceneLoadedSetDoc(doc);
cutsceneSystemStartCutscene(&CUTSCENE_SYSTEM.loadedScene); cutsceneSystemStartCutscene(&CUTSCENE_SYSTEM.loadedScene);
stringCopy(CUTSCENE_SYSTEM.loadedFile, file, ASSET_FILE_NAME_MAX - 1);
} }
void cutsceneLoadedSetDoc(yyjson_doc *doc) { 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 // 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 // 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; cutscenecallback_t onComplete = CUTSCENE_SYSTEM.onComplete;
cutsceneSystemStartCutsceneWith( entity_t *entityInteract = CUTSCENE_SYSTEM.entityInteract;
CUTSCENE_SYSTEM.scene, entity_t *entityInteracted = CUTSCENE_SYSTEM.entityInteracted;
CUTSCENE_SYSTEM.entityInteract,
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.onComplete = onComplete;
CUTSCENE_SYSTEM.entityInteract = entityInteract;
CUTSCENE_SYSTEM.entityInteracted = entityInteracted;
} }
void cutsceneSystemSetOnComplete(cutscenecallback_t onComplete) { void cutsceneSystemSetOnComplete(cutscenecallback_t onComplete) {
+20 -3
View File
@@ -52,6 +52,16 @@ typedef struct {
cutsceneitem_t loadedItems[CUTSCENE_LOADED_ITEMS_MAX]; cutsceneitem_t loadedItems[CUTSCENE_LOADED_ITEMS_MAX];
cutscene_t loadedScene; 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; } cutscenesystem_t;
extern cutscenesystem_t CUTSCENE_SYSTEM; 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 * 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 * re-read+re-parsed fresh, never assumed still resident from a previous
* call. Opens the fatal error overlay (see uiFatalErrorOpen) instead of * 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 * @param file Cutscene file name (with .jsonc extension), relative to
* assets/cutscenes/. * assets/cutscenes/.
@@ -174,8 +185,14 @@ void cutsceneLoadedSetDoc(yyjson_doc *doc);
/** /**
* Restarts the currently running cutscene from its first item, * Restarts the currently running cutscene from its first item,
* preserving whatever interact/interacted entities triggered it. * preserving whatever interact/interacted entities triggered it and
* Asserts if no cutscene is running. * 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); void cutsceneRestart(void);