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,143 @@
|
||||
/**
|
||||
* 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/overworld/maparea.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
static void resetMapAreas(void) {
|
||||
memoryZero(MAP_AREAS, sizeof(MAP_AREAS));
|
||||
}
|
||||
|
||||
static void test_cutsceneMapAreaAddCreatesAreaAndStoresLastCreated(
|
||||
void **state
|
||||
) {
|
||||
|
||||
resetMapAreas();
|
||||
cutsceneitem_t item = CUTSCENE_MAP_AREA_ADD(
|
||||
0, 0, 0, 5, 5, 0, mapAreaNoopCallback, MAP_AREA_NOTIFY_ALL, MAP_TRIGGER_ALL
|
||||
);
|
||||
cutsceneitemdata_t data;
|
||||
|
||||
cutsceneMapAreaAddStart(&item, &data);
|
||||
assert_true(cutsceneMapAreaAddUpdate(&item, &data));
|
||||
|
||||
uint8_t id = CUTSCENE_SYSTEM.areaLastCreated;
|
||||
assert_ptr_equal(MAP_AREAS[id].callback, mapAreaNoopCallback);
|
||||
assert_int_equal(MAP_AREAS[id].max.x, 5);
|
||||
}
|
||||
|
||||
static void test_cutsceneMapAreaRemoveClearsSlot(void **state) {
|
||||
|
||||
resetMapAreas();
|
||||
uint8_t id = mapAreaAdd(
|
||||
(worldpos_t){ 0, 0, 0 }, (worldpos_t){ 5, 5, 0 },
|
||||
mapAreaNoopCallback, MAP_AREA_NOTIFY_ALL, MAP_TRIGGER_ALL
|
||||
);
|
||||
|
||||
cutsceneitem_t item = CUTSCENE_MAP_AREA_REMOVE(id);
|
||||
cutsceneitemdata_t data;
|
||||
|
||||
cutsceneMapAreaRemoveStart(&item, &data);
|
||||
assert_true(cutsceneMapAreaRemoveUpdate(&item, &data));
|
||||
assert_null(MAP_AREAS[id].callback);
|
||||
}
|
||||
|
||||
static void test_cutsceneMapAreaRemoveResolvesLastCreatedSentinel(
|
||||
void **state
|
||||
) {
|
||||
|
||||
resetMapAreas();
|
||||
cutsceneitem_t addItem = CUTSCENE_MAP_AREA_ADD(
|
||||
0, 0, 0, 5, 5, 0, mapAreaNoopCallback, MAP_AREA_NOTIFY_ALL, MAP_TRIGGER_ALL
|
||||
);
|
||||
cutsceneitemdata_t data;
|
||||
cutsceneMapAreaAddStart(&addItem, &data);
|
||||
uint8_t id = CUTSCENE_SYSTEM.areaLastCreated;
|
||||
|
||||
cutsceneitem_t removeItem = CUTSCENE_MAP_AREA_REMOVE(CUTSCENE_AREA_LAST_CREATED);
|
||||
cutsceneMapAreaRemoveStart(&removeItem, &data);
|
||||
assert_null(MAP_AREAS[id].callback);
|
||||
}
|
||||
|
||||
static void test_cutsceneMapAreaWaitCompletesWhenTriggerCountChanges(
|
||||
void **state
|
||||
) {
|
||||
|
||||
resetMapAreas();
|
||||
uint8_t id = mapAreaAdd(
|
||||
(worldpos_t){ 0, 0, 0 }, (worldpos_t){ 5, 5, 0 },
|
||||
mapAreaNoopCallback, MAP_AREA_NOTIFY_ALL, MAP_TRIGGER_ALL
|
||||
);
|
||||
|
||||
cutsceneitem_t item = CUTSCENE_MAP_AREA_WAIT(id);
|
||||
cutsceneitemdata_t data;
|
||||
|
||||
cutsceneMapAreaWaitStart(&item, &data);
|
||||
assert_false(cutsceneMapAreaWaitUpdate(&item, &data));
|
||||
|
||||
MAP_AREAS[id].triggerCount++;// simulates the area's callback firing
|
||||
assert_true(cutsceneMapAreaWaitUpdate(&item, &data));
|
||||
}
|
||||
|
||||
static void test_cutsceneMapAreaWaitCompletesWhenAnyWatchedAreaChanges(
|
||||
void **state
|
||||
) {
|
||||
|
||||
resetMapAreas();
|
||||
uint8_t idA = mapAreaAdd(
|
||||
(worldpos_t){ 0, 0, 0 }, (worldpos_t){ 5, 5, 0 },
|
||||
mapAreaNoopCallback, MAP_AREA_NOTIFY_ALL, MAP_TRIGGER_ALL
|
||||
);
|
||||
uint8_t idB = mapAreaAdd(
|
||||
(worldpos_t){ 10, 10, 0 }, (worldpos_t){ 15, 15, 0 },
|
||||
mapAreaNoopCallback, MAP_AREA_NOTIFY_ALL, MAP_TRIGGER_ALL
|
||||
);
|
||||
|
||||
cutsceneitem_t item = CUTSCENE_MAP_AREA_WAIT(idA, idB);
|
||||
cutsceneitemdata_t data;
|
||||
|
||||
cutsceneMapAreaWaitStart(&item, &data);
|
||||
assert_false(cutsceneMapAreaWaitUpdate(&item, &data));
|
||||
|
||||
MAP_AREAS[idB].triggerCount++;// only the second watched area fires
|
||||
assert_true(cutsceneMapAreaWaitUpdate(&item, &data));
|
||||
}
|
||||
|
||||
static void test_cutsceneMapAreaWaitResolvesLastCreatedSentinel(
|
||||
void **state
|
||||
) {
|
||||
|
||||
resetMapAreas();
|
||||
cutsceneitem_t addItem = CUTSCENE_MAP_AREA_ADD(
|
||||
0, 0, 0, 5, 5, 0, mapAreaNoopCallback, MAP_AREA_NOTIFY_ALL, MAP_TRIGGER_ALL
|
||||
);
|
||||
cutsceneitemdata_t data;
|
||||
cutsceneMapAreaAddStart(&addItem, &data);
|
||||
uint8_t id = CUTSCENE_SYSTEM.areaLastCreated;
|
||||
|
||||
cutsceneitem_t waitItem = CUTSCENE_MAP_AREA_WAIT(CUTSCENE_AREA_LAST_CREATED);
|
||||
cutsceneMapAreaWaitStart(&waitItem, &data);
|
||||
assert_false(cutsceneMapAreaWaitUpdate(&waitItem, &data));
|
||||
|
||||
MAP_AREAS[id].triggerCount++;
|
||||
assert_true(cutsceneMapAreaWaitUpdate(&waitItem, &data));
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test(test_cutsceneMapAreaAddCreatesAreaAndStoresLastCreated),
|
||||
cmocka_unit_test(test_cutsceneMapAreaRemoveClearsSlot),
|
||||
cmocka_unit_test(test_cutsceneMapAreaRemoveResolvesLastCreatedSentinel),
|
||||
cmocka_unit_test(test_cutsceneMapAreaWaitCompletesWhenTriggerCountChanges),
|
||||
cmocka_unit_test(test_cutsceneMapAreaWaitCompletesWhenAnyWatchedAreaChanges),
|
||||
cmocka_unit_test(test_cutsceneMapAreaWaitResolvesLastCreatedSentinel),
|
||||
};
|
||||
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
||||
Reference in New Issue
Block a user