- party.jsonc's "members" is now a key/value object (e.g. "hero",
"companion") instead of an array - partyInit seeds party_t.keys
alongside members, and partyGetMemberIndexByKey/partyGetMemberKey do the
lookups. Cutscene items (PARTY_ADD_MEMBER/PARTY_REMOVE_MEMBER/
PARTY_HEAL_MEMBER) now take a "key" JSON field, resolved to a roster
index at load time, instead of a raw index.
- Battle UI shows who's acting: uibattlemenu.c draws the current fighter's
party key above the action menu, and uibattlehud.c draws each ally
fighter's key as an extra line above their HP/MP.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
- Battle selection menu can now go back a fighter to re-decide their move,
and battle win/loss no longer leaks the round's remaining queued move
cutscenes into the ending state (cutsceneSystemDiscardQueued).
- Party roster is now driven by party.jsonc: every defined member always
exists (partyInit), while party->order alone determines who's currently
active - partyAddMember/partyRemoveMember (and their cutscene items) now
activate/deactivate an existing roster member by index instead of
creating/destroying one, with removal compacting order to stay packed.
- New PARTY_ADD_MEMBER/PARTY_REMOVE_MEMBER/PARTY_HEAL_MEMBER/PARTY_HEAL_ALL
cutscene items.
- saveSlotInit/partyInit now return errorret_t and take their target
struct directly (saveslot_t*/party_t*) instead of implicitly operating
on SAVE.slot; saveSlotReadJSON resets through saveSlotInit rather than
duplicating the reset logic.
- Test coverage: stub the JSON asset loader in save test fixtures so
partyInit's real party.jsonc load runs against an in-memory doc instead
of hanging with no asset system initialized.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Pure whitespace/line-break reformatting (braces, newlines, and line
continuations matching this codebase's existing wrap conventions) - no
logic, string content, or identifiers changed anywhere. Confirmed via
diff against the pre-change tree and by rebuilding + re-running the
affected test suites, which produce identical pass/fail results.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Covers save.c (device discovery/orchestration), savedevice.c (the
generic device state machine and platform dispatch), and the Linux
platform backend (path building, availability checks, JSON read/write,
corrupt/missing-file handling), plus saveslot.c/savesettings.c JSON
round-trips. 88 tests across 5 files, all run against the real Linux
filesystem backend sandboxed to a temp $HOME (there's no mockable
platform layer - the hooks are compile-time macros, not function
pointers).
Deliberately locks in two existing behaviors rather than working around
them: saveSaveSettings() is a permanent no-op because nothing anywhere
ever sets SAVE.settingsDirty = true, and saveUpdate() unconditionally
rewrites settings back out the moment a device is found regardless of
that same dirty flag. Both are pre-existing, not introduced here.
Does not cover the SAVE_DEVICE_DATA_RAW blob codec (PSP/GameCube/Wii
only) or GameCube's 2-device fallback chain - neither compiles into the
Linux host test build.
Co-Authored-By: Claude Sonnet 5 <[email protected]>