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_8007B450Sub-screen IDMeaning
(char*)1 sentinel0x2Save from menu entry
*ptr == '\x01'0x19Load from slot
*ptr == '\x07'0x20Auto-save path
*ptr == '\r'0x4Post-save return
*ptr == '\x00'0x1aCancel / 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

IDAddressFunction
0x10x801E4F44FUN_801DAEF4 — slot selector
0x20x801E4F48Save entry (from menu)
0x40x801E4F50Post-save return path
0x19Load-from-slot path
0x1BCard-full / error screen
0x1E0x801E4FB8Actual 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.