Clamp keyframe interpolation to last value, add main menu scene/UI, battle HUD, and expanded test coverage
- keyframeGetValue now returns the last keyframe's value for times at or beyond it, fixes a missing util/math.h include, and asserts keyframes are sorted by time; adds test/animation/test_keyframe.c - Adds mainmenu scene/UI and a battle HUD UI frame - Adds save autosave-related fields and battle scene tweaks - Adds headless test coverage for cutscenes, entities, and map areas
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* 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,
|
||||
.dataSize = 0
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user