Make party and save-slot init/new-game operate on SAVE.slot directly

party.c's functions no longer take a party_t* - they always operate on
SAVE.slot.party, since gameplay only ever has one active party. That
forced the same change on saveSlotInit/saveSlotNewGame (they called
partyInit/partyAddMember internally), so those are now parameterless
too, always resetting/seeding SAVE.slot. Callers building a save at a
specific index (new-game creation, slot deletion) now set
SAVE.slotCurrent first instead of building an independent local struct -
safe since the select-save screen is only ever reached before any
gameplay starts.

saveSlotWriteJSON/saveSlotReadJSON deliberately keep their explicit
saveslot_t* parameter - they're genuine serialization primitives used
by the save-device layer and tests against arbitrary structs, unrelated
to the single-current-party assumption. saveSlotReadJSON's internal
reset is now a plain memset instead of delegating to the now-global-only
saveSlotInit().

Updates test_save/test_savedevice/test_savedevicelinux/test_saveslot for
the new signatures. Note: test_savedevice/test_savedevicelinux/test_save
have pre-existing failures in this sandbox unrelated to this change -
savetestfixture.c swaps $HOME, but saveDeviceLinuxGetDirectory actually
derives the save path from ASSET.baseDirectory (the executable's own
location), so the fixture's sandboxing never actually applies. test_
saveslot.c (which doesn't depend on that fixture) passes 15/15.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
2026-09-12 21:30:08 -05:00
co-authored by Claude Sonnet 5
parent c2bd761383
commit b8cbd8ff6a
14 changed files with 180 additions and 158 deletions
+10 -7
View File
@@ -10,6 +10,7 @@
#include "save/savedevice.h"
#include "save/slot/saveslot.h"
#include "save/settings/savesettings.h"
#include "save/save.h"
#include "util/memory.h"
#include "util/string.h"
@@ -155,8 +156,9 @@ static void test_saveDeviceCheckAvailability_resolvesSynchronouslyOnLinux(
static void test_saveDeviceSlotWrite_nullAsserts(void **state) {
savedevice_t device;
// Content is never touched - both calls assert on a NULL argument
// before either device or slot would actually be read.
saveslot_t slot;
saveSlotInit(&slot);
expect_assert_failure(saveDeviceSlotWrite(NULL, &slot, 0));
expect_assert_failure(saveDeviceSlotWrite(&device, NULL, 0));
@@ -165,7 +167,6 @@ static void test_saveDeviceSlotWrite_nullAsserts(void **state) {
static void test_saveDeviceSlotRead_nullAsserts(void **state) {
savedevice_t device;
saveslot_t slot;
saveSlotInit(&slot);
expect_assert_failure(saveDeviceSlotRead(NULL, &slot, 0));
expect_assert_failure(saveDeviceSlotRead(&device, NULL, 0));
@@ -198,15 +199,17 @@ static void test_saveDeviceSlot_dispatchesToPlatform(void **state) {
saveDeviceCheckAvailability(&device, updateCallback, NULL);
saveDeviceUpdate(&device);
saveslot_t written;
saveSlotInit(&written);
written.cachedData.playerLevel = 21;
// saveSlotInit() only ever operates on SAVE.slot now, so that's the
// write source here.
saveSlotInit();
SAVE.slot.cachedData.playerLevel = 21;
errorret_t writeRet = saveDeviceSlotWrite(&device, &written, 0);
errorret_t writeRet = saveDeviceSlotWrite(&device, &SAVE.slot, 0);
assert_true(errorIsOk(writeRet));
// No pre-init needed - saveSlotReadJSON() (via saveDeviceSlotRead) fully
// resets/overwrites its destination struct regardless of prior content.
saveslot_t read;
saveSlotInit(&read);
errorret_t readRet = saveDeviceSlotRead(&device, &read, 0);
assert_true(errorIsOk(readRet));