Files
dusk/test/rpg/entity/test_entityinteract.c
T
YourWishesandClaude Sonnet 5 2ee97ad4ce Sunset the dedicated cutscene asset loader and the item pool
Cutscenes now load through the generic ASSET_LOADER_TYPE_JSON loader
and parse straight into fixed static buffers via new cutsceneParseDoc/
cutsceneParseItem/cutsceneCountItems helpers (cutscene.c), removing the
bespoke ASSET_LOADER_TYPE_CUTSCENE pipeline entirely. Only one cutscene
(plus one INSERT target) is ever resident, so each resolve locks,
steals the parsed doc, unlocks, and force-reaps immediately - fixing a
stale-cache-reuse bug where revisiting a cutscene name after a
different one could return data from the shared buffer's previous
occupant.

ENTITY_WALK_TO and MAP_AREA_WAIT now store their waypoints/area ids in
fixed-size arrays inline on their own item struct instead of a shared
bump-allocated pool, so pool/poolOffset are gone from every item type's
Load callback. cutscene_t.dataSize (and the CUTSCENE(...) macro's SIZE
parameter) is removed along with it - it sized entries out of that same
now-deleted pool and had no other reader.

NPC #4's battletest cutscene and the main menu's cutscene now resolve
their target by name on interact instead of eagerly at init, so a
resolved-once pointer is never held past the point its backing buffer
can be reused for something else.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-09-13 15:18:57 -05:00

135 lines
3.8 KiB
C

/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "dusktest.h"
#include "entitytestfixture.h"
#include "ui/rpg/textbox/uitextboxmain.h"
#include "ui/focus/uifocus.h"
#include "rpg/cutscene/cutscenesystem.h"
static const cutsceneitem_t CUTSCENE_TEST_INTERACT_ITEMS[] = {
CUTSCENE_WAIT(1.0f)
};
static const cutscene_t CUTSCENE_TEST_INTERACT = {
.items = CUTSCENE_TEST_INTERACT_ITEMS,
.itemCount = 1,
.pause = CUTSCENE_PAUSE_NONE
};
static entity_t *player;
static entity_t *target;
static void resetInteractFixture(void) {
entityTestFixtureReset();
uiFocusInit();
uiTextboxMainInit();
uiTextboxMainFocusClosed(NULL);// force-clear stale focus from a prior test
cutsceneSystemInit();
entityInit(&ENTITIES[0], ENTITY_TYPE_PLAYER);
entityInit(&ENTITIES[1], ENTITY_TYPE_NPC);
player = &ENTITIES[0];
target = &ENTITIES[1];
player->direction = ENTITY_DIR_NORTH;
}
static void test_entityInteractWithNull(void **state) {
resetInteractFixture();
target->interact.type = ENTITY_INTERACT_NULL;
entityInteractWith(player, target);// should not crash or change anything
assert_int_equal(target->interact.type, ENTITY_INTERACT_NULL);
}
static void test_entityInteractWithPrintTurnsNpcToFacePlayer(void **state) {
resetInteractFixture();
target->interact.type = ENTITY_INTERACT_PRINT;
target->interact.data.message = "Hello!";
entityInteractWith(player, target);
assert_true(uiTextboxMainIsActive());
assert_int_equal(
target->data.npc.interactState, NPC_INTERACT_STATE_CONVERSING
);
// NPC turns to face the opposite of the player's facing direction.
assert_int_equal(target->direction, entityDirGetOpposite(player->direction));
}
static entity_t *callbackPlayerArg;
static entity_t *callbackTargetArg;
static uint8_t callbackCount;
static void recordInteractCallback(entity_t *p, entity_t *t) {
callbackPlayerArg = p;
callbackTargetArg = t;
callbackCount++;
}
static void test_entityInteractWithCallback(void **state) {
resetInteractFixture();
callbackCount = 0;
target->interact.type = ENTITY_INTERACT_CALLBACK;
target->interact.data.callback = recordInteractCallback;
entityInteractWith(player, target);
assert_int_equal(callbackCount, 1);
assert_ptr_equal(callbackPlayerArg, player);
assert_ptr_equal(callbackTargetArg, target);
}
static void test_entityInteractWithCallbackRequiresNonNull(void **state) {
resetInteractFixture();
target->interact.type = ENTITY_INTERACT_CALLBACK;
target->interact.data.callback = NULL;
expect_assert_failure(entityInteractWith(player, target));
}
static void test_entityInteractWithCutsceneStartsIt(void **state) {
resetInteractFixture();
target->interact.type = ENTITY_INTERACT_CUTSCENE;
target->interact.data.cutscene = &CUTSCENE_TEST_INTERACT;
entityInteractWith(player, target);
assert_ptr_equal(CUTSCENE_SYSTEM.scene, &CUTSCENE_TEST_INTERACT);
assert_ptr_equal(CUTSCENE_SYSTEM.entityInteract, player);
assert_ptr_equal(CUTSCENE_SYSTEM.entityInteracted, target);
}
static void test_entityInteractWithRequiresNonNullEntities(void **state) {
resetInteractFixture();
expect_assert_failure(entityInteractWith(NULL, target));
expect_assert_failure(entityInteractWith(player, NULL));
}
int main(int argc, char** argv) {
const struct CMUnitTest tests[] = {
cmocka_unit_test(test_entityInteractWithNull),
cmocka_unit_test(test_entityInteractWithPrintTurnsNpcToFacePlayer),
cmocka_unit_test(test_entityInteractWithCallback),
cmocka_unit_test(test_entityInteractWithCallbackRequiresNonNull),
cmocka_unit_test(test_entityInteractWithCutsceneStartsIt),
cmocka_unit_test(test_entityInteractWithRequiresNonNullEntities),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}