Files
dusk/test/rpg/cutscene/test_cutscenesystem.c
T
YourWishesandClaude Sonnet 5 1646e964b5 Remove the C-authoring shorthand for declaring cutscenes
CUTSCENE(...)/CUTSCENE_REFERENCE/CUTSCENE_CUTSCENE/CUTSCENE_INSERT
existed to build a cutscene_t and its item array directly in C; real
cutscenes are now authored exclusively as .jsonc files parsed via
cutsceneParseDoc, so these are dead weight in production. Deletes the
demo scene that still used them (testcutscene.h, wired to NPC #3) along
with its now-dead include in npc.c. test_cutscenesystem.c - the only
other user, building cutscenes in-memory for tests - now writes the
equivalent struct literals directly, matching the convention already
used by test_battle.c/test_entityinteract.c.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-09-14 09:52:42 -05:00

535 lines
19 KiB
C

/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "dusktest.h"
#include "rpg/cutscene/cutscenesystem.h"
#include "rpg/entity/entity.h"
#include "time/time.h"
static uint8_t callbackFired;
static void recordCallback(void *userData) {
callbackFired++;
}
// INNER is jumped into by OUTER's second item, never returning -- this is
// the "nested cutscene is a one-way jump" behavior: cutsceneCutsceneStart
// replaces CUTSCENE_SYSTEM.scene outright, and the callback item's effect
// fires in Start, not Update, so it fires the same frame the jump happens.
static const cutsceneitem_t CUTSCENE_TEST_INNER_ITEMS[] = {
CUTSCENE_CALLBACK(recordCallback)
};
static const cutscene_t CUTSCENE_TEST_INNER = {
.items = CUTSCENE_TEST_INNER_ITEMS,
.itemCount = sizeof(CUTSCENE_TEST_INNER_ITEMS) / sizeof(cutsceneitem_t),
.pause = CUTSCENE_PAUSE_NONE
};
static const cutsceneitem_t CUTSCENE_TEST_OUTER_ITEMS[] = {
CUTSCENE_WAIT(0.5f),
{
.type = CUTSCENE_ITEM_TYPE_CUTSCENE,
.cutsceneRef = { .cutscene = &CUTSCENE_TEST_INNER, .name = NULL }
}
};
static const cutscene_t CUTSCENE_TEST_OUTER = {
.items = CUTSCENE_TEST_OUTER_ITEMS,
.itemCount = sizeof(CUTSCENE_TEST_OUTER_ITEMS) / sizeof(cutsceneitem_t),
.pause = CUTSCENE_PAUSE_DEFAULT
};
static void test_cutsceneSystemStartSetsUpInitialItem(void **state) {
cutsceneSystemInit();
cutsceneSystemStartCutscene(&CUTSCENE_TEST_OUTER);
assert_ptr_equal(CUTSCENE_SYSTEM.scene, &CUTSCENE_TEST_OUTER);
assert_int_equal(CUTSCENE_SYSTEM.currentItem, 0);
assert_int_equal(CUTSCENE_SYSTEM.pause, CUTSCENE_PAUSE_DEFAULT);
}
static void test_cutsceneSystemNestedCutsceneIsOneWayJump(void **state) {
cutsceneSystemInit();
callbackFired = 0;
cutsceneSystemStartCutscene(&CUTSCENE_TEST_OUTER);
TIME.delta = 0.1f;
cutsceneSystemUpdate();// wait not elapsed yet
assert_ptr_equal(CUTSCENE_SYSTEM.scene, &CUTSCENE_TEST_OUTER);
assert_int_equal(callbackFired, 0);
// The wait elapses, advancing to the nested-cutscene item, which jumps
// straight into INNER and starts its first item (the callback) -- all
// within this single update call.
TIME.delta = 1.0f;
cutsceneSystemUpdate();
assert_ptr_equal(CUTSCENE_SYSTEM.scene, &CUTSCENE_TEST_INNER);
assert_int_equal(CUTSCENE_SYSTEM.currentItem, 0);
assert_int_equal(callbackFired, 1);
// INNER's only item (the callback) always reports complete -- one more
// update ends the whole cutscene.
cutsceneSystemUpdate();
assert_null(CUTSCENE_SYSTEM.scene);
assert_int_equal(CUTSCENE_SYSTEM.currentItem, 0xFF);
assert_int_equal(CUTSCENE_SYSTEM.pause, CUTSCENE_PAUSE_NONE);
}
static void test_cutsceneSystemUpdateIsNoopWithNoActiveCutscene(void **state) {
cutsceneSystemInit();
cutsceneSystemUpdate();// should not crash
assert_null(CUTSCENE_SYSTEM.scene);
}
static const cutsceneitem_t CUTSCENE_TEST_SINGLE_WAIT_ITEMS[] = {
CUTSCENE_WAIT(1.0f)
};
static const cutscene_t CUTSCENE_TEST_SINGLE_WAIT = {
.items = CUTSCENE_TEST_SINGLE_WAIT_ITEMS,
.itemCount = sizeof(CUTSCENE_TEST_SINGLE_WAIT_ITEMS) / sizeof(cutsceneitem_t),
.pause = CUTSCENE_PAUSE_NONE
};
static void test_cutsceneSystemStartWithSetsInteractEntities(void **state) {
cutsceneSystemInit();
entityInit(&ENTITIES[0], ENTITY_TYPE_PLAYER);
entityInit(&ENTITIES[1], ENTITY_TYPE_NPC);
cutsceneSystemStartCutsceneWith(
&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(
cutsceneSystemGetEntity(CUTSCENE_ENTITY_INTERACT), &ENTITIES[0]
);
assert_ptr_equal(
cutsceneSystemGetEntity(CUTSCENE_ENTITY_INTERACTED), &ENTITIES[1]
);
TIME.delta = 2.0f;
cutsceneSystemUpdate();// ends the cutscene
assert_null(CUTSCENE_SYSTEM.entityInteract);// reset on end
assert_null(CUTSCENE_SYSTEM.entityInteracted);
}
static void test_cutsceneSystemGetEntitySentinelsRequireBeingSet(
void **state
) {
cutsceneSystemInit();
expect_assert_failure(cutsceneSystemGetEntity(CUTSCENE_ENTITY_INTERACT));
expect_assert_failure(cutsceneSystemGetEntity(CUTSCENE_ENTITY_INTERACTED));
expect_assert_failure(cutsceneSystemGetEntity(CUTSCENE_ENTITY_LAST_CREATED));
expect_assert_failure(cutsceneSystemGetEntity(CUTSCENE_ENTITY_LAST_REF));
}
static void test_cutsceneSystemGetEntityDirectIndexUpdatesLastRef(
void **state
) {
cutsceneSystemInit();
entityInit(&ENTITIES[2], ENTITY_TYPE_NPC);
entity_t *resolved = cutsceneSystemGetEntity(2);
assert_ptr_equal(resolved, &ENTITIES[2]);
// Resolving by direct index also updates LAST_REF.
assert_ptr_equal(
cutsceneSystemGetEntity(CUTSCENE_ENTITY_LAST_REF), &ENTITIES[2]
);
}
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;
expect_assert_failure(cutsceneSystemGetAreaId(CUTSCENE_AREA_LAST_CREATED));
assert_int_equal(cutsceneSystemGetAreaId(5), 5);// direct IDs pass through
CUTSCENE_SYSTEM.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;
expect_assert_failure(
cutsceneSystemGetTextMiniId(CUTSCENE_TEXT_MINI_LAST_CREATED)
);
assert_int_equal(cutsceneSystemGetTextMiniId(4), 4);
CUTSCENE_SYSTEM.textMiniLastCreated = 1;
assert_int_equal(
cutsceneSystemGetTextMiniId(CUTSCENE_TEXT_MINI_LAST_CREATED), 1
);
}
static void test_cutsceneSystemDisposeResetsState(void **state) {
cutsceneSystemInit();
entityInit(&ENTITIES[0], ENTITY_TYPE_PLAYER);
cutsceneSystemStartCutsceneWith(
&CUTSCENE_TEST_SINGLE_WAIT, &ENTITIES[0], &ENTITIES[0]
);
cutsceneSystemDispose();
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);
}
// --- CUTSCENE_INSERT ---------------------------------------------------
static uint8_t insertOrderLog[8];
static uint8_t insertOrderLogCount;
static void recordOrder0(void *userData) { insertOrderLog[insertOrderLogCount++] = 0; }
static void recordOrder1(void *userData) { insertOrderLog[insertOrderLogCount++] = 1; }
static void recordOrder2(void *userData) { insertOrderLog[insertOrderLogCount++] = 2; }
static void recordOrderA(void *userData) { insertOrderLog[insertOrderLogCount++] = 3; }
static void recordOrderB(void *userData) { insertOrderLog[insertOrderLogCount++] = 4; }
static const cutsceneitem_t CUTSCENE_TEST_INSERT_SNIPPET_ITEMS[] = {
CUTSCENE_CALLBACK(recordOrderA),
CUTSCENE_WAIT(2.0f),
CUTSCENE_CALLBACK(recordOrderB)
};
static const cutscene_t CUTSCENE_TEST_INSERT_SNIPPET = {
.items = CUTSCENE_TEST_INSERT_SNIPPET_ITEMS,
.itemCount =
sizeof(CUTSCENE_TEST_INSERT_SNIPPET_ITEMS) / sizeof(cutsceneitem_t),
.pause = CUTSCENE_PAUSE_NONE
};
static const cutsceneitem_t CUTSCENE_TEST_INSERT_OUTER_ITEMS[] = {
CUTSCENE_CALLBACK(recordOrder0),
CUTSCENE_WAIT(1.0f),
CUTSCENE_CALLBACK(recordOrder1),
{
.type = CUTSCENE_ITEM_TYPE_INSERT,
.insert = { .cutscene = &CUTSCENE_TEST_INSERT_SNIPPET, .name = NULL }
},
CUTSCENE_CALLBACK(recordOrder2)
};
static const cutscene_t CUTSCENE_TEST_INSERT_OUTER = {
.items = CUTSCENE_TEST_INSERT_OUTER_ITEMS,
.itemCount =
sizeof(CUTSCENE_TEST_INSERT_OUTER_ITEMS) / sizeof(cutsceneitem_t),
.pause = CUTSCENE_PAUSE_NONE
};
static void test_cutsceneInsertSplicesItemsInPlaceThenResumes(void **state) {
insertOrderLogCount = 0;
cutsceneSystemInit();
cutsceneSystemStartCutscene(&CUTSCENE_TEST_INSERT_OUTER);
TIME.delta = 1.5f;// elapses the outer WAIT(1.0)
cutsceneSystemUpdate();// order0 done -> starts the outer WAIT
cutsceneSystemUpdate();// the WAIT elapses -> starts order1
cutsceneSystemUpdate();// order1 done -> starts the INSERT, cascading into orderA
assert_ptr_equal(CUTSCENE_SYSTEM.scene, &CUTSCENE_TEST_INSERT_SNIPPET);
TIME.delta = 2.5f;// elapses the snippet's WAIT(2.0)
cutsceneSystemUpdate();// orderA done -> starts snippet's WAIT
cutsceneSystemUpdate();// snippet's WAIT elapses -> starts orderB
cutsceneSystemUpdate();// orderB done -> pops back, starts order2
assert_ptr_equal(CUTSCENE_SYSTEM.scene, &CUTSCENE_TEST_INSERT_OUTER);
cutsceneSystemUpdate();// order2 done -> cutscene ends naturally
assert_null(CUTSCENE_SYSTEM.scene);
const uint8_t expected[] = { 0, 1, 3, 4, 2 };
assert_int_equal(insertOrderLogCount, sizeof(expected));
assert_memory_equal(insertOrderLog, expected, sizeof(expected));
}
static const cutsceneitem_t CUTSCENE_TEST_INSERT_AS_LAST_ITEM_SNIPPET_ITEMS[] = {
CUTSCENE_CALLBACK(recordOrderA)
};
static const cutscene_t CUTSCENE_TEST_INSERT_AS_LAST_ITEM_SNIPPET = {
.items = CUTSCENE_TEST_INSERT_AS_LAST_ITEM_SNIPPET_ITEMS,
.itemCount = sizeof(CUTSCENE_TEST_INSERT_AS_LAST_ITEM_SNIPPET_ITEMS) /
sizeof(cutsceneitem_t),
.pause = CUTSCENE_PAUSE_NONE
};
static const cutsceneitem_t CUTSCENE_TEST_INSERT_AS_LAST_ITEM_OUTER_ITEMS[] = {
CUTSCENE_CALLBACK(recordOrder0),
{
.type = CUTSCENE_ITEM_TYPE_INSERT,
.insert = {
.cutscene = &CUTSCENE_TEST_INSERT_AS_LAST_ITEM_SNIPPET, .name = NULL
}
}
};
static const cutscene_t CUTSCENE_TEST_INSERT_AS_LAST_ITEM_OUTER = {
.items = CUTSCENE_TEST_INSERT_AS_LAST_ITEM_OUTER_ITEMS,
.itemCount = sizeof(CUTSCENE_TEST_INSERT_AS_LAST_ITEM_OUTER_ITEMS) /
sizeof(cutsceneitem_t),
.pause = CUTSCENE_PAUSE_NONE
};
static void test_cutsceneInsertAsLastItemEndsCutsceneNaturally(
void **state
) {
insertOrderLogCount = 0;
cutsceneSystemInit();
cutsceneSystemStartCutscene(&CUTSCENE_TEST_INSERT_AS_LAST_ITEM_OUTER);
cutsceneSystemUpdate();// order0 done -> starts INSERT, cascades to orderA
assert_ptr_equal(
CUTSCENE_SYSTEM.scene, &CUTSCENE_TEST_INSERT_AS_LAST_ITEM_SNIPPET
);
// orderA is the snippet's only item, and the snippet is the outer's last
// item -- finishing it should pop straight through to the natural end
// of the whole cutscene, not get stuck.
cutsceneSystemUpdate();
assert_null(CUTSCENE_SYSTEM.scene);
const uint8_t expected[] = { 0, 3 };
assert_int_equal(insertOrderLogCount, sizeof(expected));
assert_memory_equal(insertOrderLog, expected, sizeof(expected));
}
static const cutsceneitem_t CUTSCENE_TEST_INSERT_NESTED_INNER_ITEMS[] = {
CUTSCENE_CALLBACK(recordOrderA)
};
static const cutscene_t CUTSCENE_TEST_INSERT_NESTED_INNER = {
.items = CUTSCENE_TEST_INSERT_NESTED_INNER_ITEMS,
.itemCount =
sizeof(CUTSCENE_TEST_INSERT_NESTED_INNER_ITEMS) / sizeof(cutsceneitem_t),
.pause = CUTSCENE_PAUSE_NONE
};
// INSERT is MID's first item, so entering MID (from OUTER) cascades
// straight through into INNER within the same Start chain, one level
// deeper than a single insert.
static const cutsceneitem_t CUTSCENE_TEST_INSERT_NESTED_MID_ITEMS[] = {
{
.type = CUTSCENE_ITEM_TYPE_INSERT,
.insert = { .cutscene = &CUTSCENE_TEST_INSERT_NESTED_INNER, .name = NULL }
},
CUTSCENE_CALLBACK(recordOrderB)
};
static const cutscene_t CUTSCENE_TEST_INSERT_NESTED_MID = {
.items = CUTSCENE_TEST_INSERT_NESTED_MID_ITEMS,
.itemCount =
sizeof(CUTSCENE_TEST_INSERT_NESTED_MID_ITEMS) / sizeof(cutsceneitem_t),
.pause = CUTSCENE_PAUSE_NONE
};
static const cutsceneitem_t CUTSCENE_TEST_INSERT_NESTED_OUTER_ITEMS[] = {
CUTSCENE_CALLBACK(recordOrder0),
{
.type = CUTSCENE_ITEM_TYPE_INSERT,
.insert = { .cutscene = &CUTSCENE_TEST_INSERT_NESTED_MID, .name = NULL }
},
CUTSCENE_CALLBACK(recordOrder2)
};
static const cutscene_t CUTSCENE_TEST_INSERT_NESTED_OUTER = {
.items = CUTSCENE_TEST_INSERT_NESTED_OUTER_ITEMS,
.itemCount =
sizeof(CUTSCENE_TEST_INSERT_NESTED_OUTER_ITEMS) / sizeof(cutsceneitem_t),
.pause = CUTSCENE_PAUSE_NONE
};
static void test_cutsceneInsertNestsThroughMultipleLevels(void **state) {
insertOrderLogCount = 0;
cutsceneSystemInit();
cutsceneSystemStartCutscene(&CUTSCENE_TEST_INSERT_NESTED_OUTER);
// order0 done -> starts INSERT(MID), cascading through INSERT(INNER) ->
// orderA, all within this one Update call's Start chain.
cutsceneSystemUpdate();
assert_ptr_equal(CUTSCENE_SYSTEM.scene, &CUTSCENE_TEST_INSERT_NESTED_INNER);
cutsceneSystemUpdate();// orderA done -> pops to MID, starts orderB
assert_ptr_equal(CUTSCENE_SYSTEM.scene, &CUTSCENE_TEST_INSERT_NESTED_MID);
cutsceneSystemUpdate();// orderB done -> pops to OUTER, starts order2
assert_ptr_equal(CUTSCENE_SYSTEM.scene, &CUTSCENE_TEST_INSERT_NESTED_OUTER);
cutsceneSystemUpdate();// order2 done -> ends naturally
assert_null(CUTSCENE_SYSTEM.scene);
const uint8_t expected[] = { 0, 3, 4, 2 };
assert_int_equal(insertOrderLogCount, sizeof(expected));
assert_memory_equal(insertOrderLog, expected, sizeof(expected));
}
static const cutsceneitem_t CUTSCENE_TEST_INSERT_OVERFLOW_LEVEL5_ITEMS[] = {
CUTSCENE_CALLBACK(recordOrderA)
};
static const cutscene_t CUTSCENE_TEST_INSERT_OVERFLOW_LEVEL5 = {
.items = CUTSCENE_TEST_INSERT_OVERFLOW_LEVEL5_ITEMS,
.itemCount = sizeof(CUTSCENE_TEST_INSERT_OVERFLOW_LEVEL5_ITEMS) /
sizeof(cutsceneitem_t),
.pause = CUTSCENE_PAUSE_NONE
};
static const cutsceneitem_t CUTSCENE_TEST_INSERT_OVERFLOW_LEVEL4_ITEMS[] = {
{
.type = CUTSCENE_ITEM_TYPE_INSERT,
.insert = { .cutscene = &CUTSCENE_TEST_INSERT_OVERFLOW_LEVEL5, .name = NULL }
}
};
static const cutscene_t CUTSCENE_TEST_INSERT_OVERFLOW_LEVEL4 = {
.items = CUTSCENE_TEST_INSERT_OVERFLOW_LEVEL4_ITEMS,
.itemCount = sizeof(CUTSCENE_TEST_INSERT_OVERFLOW_LEVEL4_ITEMS) /
sizeof(cutsceneitem_t),
.pause = CUTSCENE_PAUSE_NONE
};
static const cutsceneitem_t CUTSCENE_TEST_INSERT_OVERFLOW_LEVEL3_ITEMS[] = {
{
.type = CUTSCENE_ITEM_TYPE_INSERT,
.insert = { .cutscene = &CUTSCENE_TEST_INSERT_OVERFLOW_LEVEL4, .name = NULL }
}
};
static const cutscene_t CUTSCENE_TEST_INSERT_OVERFLOW_LEVEL3 = {
.items = CUTSCENE_TEST_INSERT_OVERFLOW_LEVEL3_ITEMS,
.itemCount = sizeof(CUTSCENE_TEST_INSERT_OVERFLOW_LEVEL3_ITEMS) /
sizeof(cutsceneitem_t),
.pause = CUTSCENE_PAUSE_NONE
};
static const cutsceneitem_t CUTSCENE_TEST_INSERT_OVERFLOW_LEVEL2_ITEMS[] = {
{
.type = CUTSCENE_ITEM_TYPE_INSERT,
.insert = { .cutscene = &CUTSCENE_TEST_INSERT_OVERFLOW_LEVEL3, .name = NULL }
}
};
static const cutscene_t CUTSCENE_TEST_INSERT_OVERFLOW_LEVEL2 = {
.items = CUTSCENE_TEST_INSERT_OVERFLOW_LEVEL2_ITEMS,
.itemCount = sizeof(CUTSCENE_TEST_INSERT_OVERFLOW_LEVEL2_ITEMS) /
sizeof(cutsceneitem_t),
.pause = CUTSCENE_PAUSE_NONE
};
static const cutsceneitem_t CUTSCENE_TEST_INSERT_OVERFLOW_LEVEL1_ITEMS[] = {
{
.type = CUTSCENE_ITEM_TYPE_INSERT,
.insert = { .cutscene = &CUTSCENE_TEST_INSERT_OVERFLOW_LEVEL2, .name = NULL }
}
};
static const cutscene_t CUTSCENE_TEST_INSERT_OVERFLOW_LEVEL1 = {
.items = CUTSCENE_TEST_INSERT_OVERFLOW_LEVEL1_ITEMS,
.itemCount = sizeof(CUTSCENE_TEST_INSERT_OVERFLOW_LEVEL1_ITEMS) /
sizeof(cutsceneitem_t),
.pause = CUTSCENE_PAUSE_NONE
};
static const cutsceneitem_t CUTSCENE_TEST_INSERT_OVERFLOW_LEVEL0_ITEMS[] = {
{
.type = CUTSCENE_ITEM_TYPE_INSERT,
.insert = { .cutscene = &CUTSCENE_TEST_INSERT_OVERFLOW_LEVEL1, .name = NULL }
}
};
static const cutscene_t CUTSCENE_TEST_INSERT_OVERFLOW_LEVEL0 = {
.items = CUTSCENE_TEST_INSERT_OVERFLOW_LEVEL0_ITEMS,
.itemCount = sizeof(CUTSCENE_TEST_INSERT_OVERFLOW_LEVEL0_ITEMS) /
sizeof(cutsceneitem_t),
.pause = CUTSCENE_PAUSE_NONE
};
static void test_cutsceneInsertAssertsWhenNestingExceedsStackMax(
void **state
) {
cutsceneSystemInit();
// 5 levels of INSERT deep, one past CUTSCENE_INSERT_STACK_MAX (4) --
// all cascade synchronously within this one call, since each level's
// only item is the INSERT starting immediately.
expect_assert_failure(
cutsceneSystemStartCutscene(&CUTSCENE_TEST_INSERT_OVERFLOW_LEVEL0)
);
}
static void noopInsertCallback(void *userData) {}
static const cutsceneitem_t CUTSCENE_TEST_INSERT_PERSIST_SNIPPET_ITEMS[] = {
CUTSCENE_CALLBACK(noopInsertCallback)
};
static const cutscene_t CUTSCENE_TEST_INSERT_PERSIST_SNIPPET = {
.items = CUTSCENE_TEST_INSERT_PERSIST_SNIPPET_ITEMS,
.itemCount = sizeof(CUTSCENE_TEST_INSERT_PERSIST_SNIPPET_ITEMS) /
sizeof(cutsceneitem_t),
.pause = CUTSCENE_PAUSE_ALL
};
static const cutsceneitem_t CUTSCENE_TEST_INSERT_PERSIST_OUTER_ITEMS[] = {
{
.type = CUTSCENE_ITEM_TYPE_INSERT,
.insert = { .cutscene = &CUTSCENE_TEST_INSERT_PERSIST_SNIPPET, .name = NULL }
}
};
static const cutscene_t CUTSCENE_TEST_INSERT_PERSIST_OUTER = {
.items = CUTSCENE_TEST_INSERT_PERSIST_OUTER_ITEMS,
.itemCount = sizeof(CUTSCENE_TEST_INSERT_PERSIST_OUTER_ITEMS) /
sizeof(cutsceneitem_t),
.pause = CUTSCENE_PAUSE_NPC
};
static void test_cutsceneInsertDoesNotResetPauseOrInteractEntities(
void **state
) {
cutsceneSystemInit();
entityInit(&ENTITIES[3], ENTITY_TYPE_PLAYER);
entityInit(&ENTITIES[4], ENTITY_TYPE_NPC);
cutsceneSystemStartCutsceneWith(
&CUTSCENE_TEST_INSERT_PERSIST_OUTER, &ENTITIES[3], &ENTITIES[4]
);
// The INSERT item's Start already cascaded into the snippet by now.
assert_ptr_equal(
CUTSCENE_SYSTEM.scene, &CUTSCENE_TEST_INSERT_PERSIST_SNIPPET
);
assert_ptr_equal(CUTSCENE_SYSTEM.entityInteract, &ENTITIES[3]);
assert_ptr_equal(CUTSCENE_SYSTEM.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);
}
int main(int argc, char** argv) {
const struct CMUnitTest tests[] = {
cmocka_unit_test(test_cutsceneSystemStartSetsUpInitialItem),
cmocka_unit_test(test_cutsceneSystemNestedCutsceneIsOneWayJump),
cmocka_unit_test(test_cutsceneSystemUpdateIsNoopWithNoActiveCutscene),
cmocka_unit_test(test_cutsceneSystemStartWithSetsInteractEntities),
cmocka_unit_test(test_cutsceneSystemGetEntitySentinelsRequireBeingSet),
cmocka_unit_test(test_cutsceneSystemGetEntityDirectIndexUpdatesLastRef),
cmocka_unit_test(test_cutsceneSystemGetAreaId),
cmocka_unit_test(test_cutsceneSystemGetTextMiniId),
cmocka_unit_test(test_cutsceneSystemDisposeResetsState),
cmocka_unit_test(test_cutsceneInsertSplicesItemsInPlaceThenResumes),
cmocka_unit_test(test_cutsceneInsertAsLastItemEndsCutsceneNaturally),
cmocka_unit_test(test_cutsceneInsertNestsThroughMultipleLevels),
cmocka_unit_test(test_cutsceneInsertAssertsWhenNestingExceedsStackMax),
cmocka_unit_test(test_cutsceneInsertDoesNotResetPauseOrInteractEntities),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}