Save Screen
The save-slot selection and write flow used whenever the game persists progress to the PSX memory card. Lives inside the menu overlay (same 129-function binary as shop, inn, and status screens — not a separate overlay). Outer dispatcher: FUN_801DC6B4 (856 bytes). Sources: overlay_save_ui_select.bin and overlay_save_ui_saving.bin mednafen captures (mc1/mc2), both confirmed as the menu overlay by function-address identity.
How it works
FUN_801DC6B4 drives a 9-case state machine on _DAT_8007B43C. It returns true when the save flow terminates (state ≥ 6). The entry-context pointer _DAT_8007B450 is decoded on state 0 to select which sub-screen opens:
_DAT_8007B450 | Sub-screen ID | Meaning |
|---|---|---|
(char*)1 sentinel | 0x2 | Save from menu entry |
*ptr == '\x01' | 0x19 | Load from slot |
*ptr == '\x07' | 0x20 | Auto-save path |
*ptr == '\r' | 0x4 | Post-save return |
*ptr == '\x00' | 0x1a | Cancel / back |
State 2 dispatches via the sub-screen function pointer table at 0x801E4F40: (*(DAT_801E46A4 * 4 + 0x801E4F40))(_DAT_8007B874). Input is suppressed while _DAT_8007B440 > 0x79 (mid-fade). States 3–5 handle the fade-out sequence before the terminal return.
Key functions
FUN_801DAEF4 — save-slot selector (sub-screens 0x1 / 0x2)
Runs an actor VM with bytecode at &DAT_801E4E30 (slot-select menu), waits on _DAT_8007BB80 != 0 (menu-active flag), calls FUN_801DD35C(1, 1) to confirm selection, and clears DAT_801E46A4 on return. Each step calls FUN_80031D00 (text-actor tick / MES advance).
FUN_801DAFD4 — slot confirm + saving in progress
Runs the 3-item slot scrolling list via FUN_801D688C(&DAT_801E46BC, 3, 1). On slot 1 confirmed: validates against the save-block existence table at &DAT_80084140 + slot * 2 + 0x1818 (byte 0 = slot present, byte 1 = slot valid), then advances DAT_801E46A4 to 0x1E (the write sub-screen). On slot 2: cancel SFX. Slot 0 routes to the card-full/error sub-screen (0x1B).
Sub-screen pointer table at 0x801E4F40
| ID | Address | Function |
|---|---|---|
0x1 | 0x801E4F44 | FUN_801DAEF4 — slot selector |
0x2 | 0x801E4F48 | Save entry (from menu) |
0x4 | 0x801E4F50 | Post-save return path |
0x19 | — | Load-from-slot path |
0x1B | — | Card-full / error screen |
0x1E | 0x801E4FB8 | Actual write sub-screen (story_flags + inventory write path — not yet dumped) |
Engine port
legaia_save::SaveFile (with SaveExt) is the clean-room counterpart. It stores party + story flags + money + inventory in the LGSF v1 format and round-trips via engine-core's save_full / load_full calls. The legaia-engine save / load subcommands exercise this path end-to-end.
The exact on-disc offsets for story_flags and inventory within the retail save block require a dump of the ID 0x1E sub-screen function (the actual write path at 0x801E4FB8); until then the LGSF format uses its own offset scheme. See docs/subsystems/save-screen.md for the pending trace.
Full reference
Complete state-machine and sub-screen tables with Ghidra provenance live at docs/subsystems/save-screen.md in the repo. Function dumps: ghidra/scripts/funcs/overlay_menu_801dc6b4.txt, overlay_menu_801daef4.txt, overlay_menu_801dafd4.txt.