diff --git a/src/dusk/rpg/cutscene/item/battle/cutsceneregularbattle.c b/src/dusk/rpg/cutscene/item/battle/cutsceneregularbattle.c index a753d0e5..24cad590 100644 --- a/src/dusk/rpg/cutscene/item/battle/cutsceneregularbattle.c +++ b/src/dusk/rpg/cutscene/item/battle/cutsceneregularbattle.c @@ -11,5 +11,5 @@ bool_t cutsceneRegularBattleUpdate( const cutsceneitem_t *item, cutsceneitemdata_t *data ) { - return false; + return true; } diff --git a/src/dusk/rpg/cutscene/item/battle/cutsceneregularbattle.h b/src/dusk/rpg/cutscene/item/battle/cutsceneregularbattle.h index 05d432ae..d8f631bd 100644 --- a/src/dusk/rpg/cutscene/item/battle/cutsceneregularbattle.h +++ b/src/dusk/rpg/cutscene/item/battle/cutsceneregularbattle.h @@ -9,12 +9,15 @@ #include "rpg/cutscene/item/cutsceneitembase.h" /** - * Updates a regular-battle step. Currently a placeholder - behaves exactly - * like IDLE (see cutsceneidle.h) and never completes on its own. + * Updates a regular-battle step. By the time this item runs, the preceding + * START_BATTLE item has already waited out the whole encounter, synced + * party HP/MP, and returned to the overworld scene - so this is currently + * just a completes-immediately hook point for whatever regular-battle- + * specific follow-up (loot, post-battle dialogue, etc.) gets added later. * * @param item The cutscene item. * @param data Runtime data storage. - * @returns false always. + * @returns true always. */ bool_t cutsceneRegularBattleUpdate( const cutsceneitem_t *item, diff --git a/test/save/test_saveslot.c b/test/save/test_saveslot.c index 9e1f4adc..bcdb10e9 100644 --- a/test/save/test_saveslot.c +++ b/test/save/test_saveslot.c @@ -143,6 +143,12 @@ static void test_saveSlotReadJSON_roundTrip(void **state) { written.version = 7;// deliberately non-default, not part of the JSON schema stringCopy(written.cachedData.name, "Hero", sizeof(written.cachedData.name)); written.cachedData.playerLevel = 42; + // An in-use slot (non-empty name) requires a non-empty map name too - + // see saveSlotNewGame/requireStrMin("mapName", 1) in saveSlotVer1ReadJSON. + stringCopy( + written.cachedData.mapName, "overworld", + sizeof(written.cachedData.mapName) + ); char_t *json; size_t len; @@ -157,6 +163,7 @@ static void test_saveSlotReadJSON_roundTrip(void **state) { assert_true(stringEquals(read.cachedData.name, "Hero")); assert_int_equal(read.cachedData.playerLevel, 42); + assert_true(stringEquals(read.cachedData.mapName, "overworld")); assert_true(read.cachedData.time.time == written.cachedData.time.time); // version/dataType are struct-only bookkeeping, never serialized - the @@ -167,21 +174,40 @@ static void test_saveSlotReadJSON_roundTrip(void **state) { free(json); } -static void test_saveSlotReadJSON_missingFieldsUseDefaults(void **state) { +static void test_saveSlotReadJSON_blankSlot_shortCircuits(void **state) { saveslot_t slot; saveSlotInit(&slot); stringCopy(slot.cachedData.name, "sentinel", sizeof(slot.cachedData.name)); slot.cachedData.playerLevel = 999; - errorret_t ret = slotFromJSON( - &slot, - "{\"version\":1," - "\"time\":{\"time\":1.0,\"timeZone\":0.0,\"offsetTime\":0.0}}" - ); + // No "name" key (or an empty one) means a blank/never-used slot (see + // saveSlotInUse) - the reader returns right after reading that, without + // needing or validating time/mapName/partyMembers/partyOrder at all, so + // this succeeds despite omitting fields that would otherwise be required. + errorret_t ret = slotFromJSON(&slot, "{\"version\":1}"); assert_true(errorIsOk(ret)); assert_int_equal(slot.cachedData.name[0], '\0'); - assert_int_equal(slot.cachedData.playerLevel, 1); + assert_int_equal(slot.cachedData.mapName[0], '\0'); + // Not readInt32's own default of 1 - the early return happens before + // playerLevel is ever read, leaving the zero-init saveSlotCurrentReadJSON + // seeds ver1 with (see the memoryZero in saveSlotCurrentReadJSON). + assert_int_equal(slot.cachedData.playerLevel, 0); +} + +static void test_saveSlotReadJSON_inUseMissingMapName_errors(void **state) { + saveslot_t slot; + saveSlotInit(&slot); + + // "name" is present (in use) but "mapName" is missing - a real save + // (via saveSlotNewGame) always has both, so this is corrupt. + errorret_t ret = slotFromJSON( + &slot, + "{\"version\":1,\"name\":\"Hero\"," + "\"time\":{\"time\":1.0,\"timeZone\":0.0,\"offsetTime\":0.0}}" + ); + assert_true(errorIsNotOk(ret)); + errorCatch(ret); } static void test_saveSlotReadJSON_missingTimeKey_errors(void **state) { @@ -265,7 +291,8 @@ int main(void) { cmocka_unit_test(test_saveSlotReadJSON_nullAsserts), cmocka_unit_test(test_saveSlotReadJSON_roundTrip), - cmocka_unit_test(test_saveSlotReadJSON_missingFieldsUseDefaults), + cmocka_unit_test(test_saveSlotReadJSON_blankSlot_shortCircuits), + cmocka_unit_test(test_saveSlotReadJSON_inUseMissingMapName_errors), cmocka_unit_test(test_saveSlotReadJSON_missingTimeKey_errors), cmocka_unit_test(test_saveSlotReadJSON_nameTooLong_errors), cmocka_unit_test(test_saveSlotReadJSON_nonObjectRoot_errors),