First pass cleaning cutscene system.
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
cutscene.c
|
||||
cutscenerefs.c
|
||||
cutscenesystem.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);
|
||||
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
);
|
||||
@@ -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
|
||||
@@ -163,12 +150,7 @@ void cutsceneSystemLoad(const char_t *file) {
|
||||
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);
|
||||
}
|
||||
@@ -178,9 +160,13 @@ void cutsceneRestart(void) {
|
||||
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"
|
||||
);
|
||||
assertTrue(
|
||||
CUTSCENE_SYSTEM.scene == &CUTSCENE_SYSTEM.loadedScene,
|
||||
"cutsceneSystemGoTo requires the running cutscene file reference (1)"
|
||||
);
|
||||
// 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"
|
||||
"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];
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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[] = {
|
||||
{
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -23,7 +23,7 @@ void cutsceneTextMiniStart(
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
CUTSCENE_SYSTEM.textMiniLastCreated = index;
|
||||
CUTSCENE_SYSTEM.refs.textMiniLastCreated = index;
|
||||
}
|
||||
|
||||
bool_t cutsceneTextMiniUpdate(
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user