M2 complete: disk saving works via MSXgl's tool/disk_save module

Replaces the hand-rolled PHYDIO/DSKIO sector writer, which never worked,
with engine/src/tool/disk_save.h — added in MSXgl v1.3.0 for exactly this
("save to disk from a ROM application"). Saves are now a real FAT file,
KISSAT00.SAV, on the disk in drive A.

Four non-obvious requirements, all documented in CLAUDE.md:
- LibModules needs both "tool/disk_save" and "dos"
- ROMDelayBoot = true, or the Disk ROM's INIT never runs
- boot then takes 40-90s of emulated time (use `set throttle off`)
- DiskSave_Check() returns SAVEDATA_UNSIGNED for good files: with APPSIGN
  it wants the first 4 bytes to be g_AppSignature, but DiskSave_Save()
  writes the payload raw and never adds it

Also fixes a save-timing bug: the write now happens in AdvanceDay() after
the day increments, so the file describes the morning the player wakes to.
Saving during the evening made a reload replay that day and double-count
its cups.

Verified: play a full day, cold boot, resume at day 2 with served intact.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-27 22:17:49 +02:00
co-authored by Claude Opus 5
parent 45749775fa
commit cbde457da5
5 changed files with 105 additions and 228 deletions
+7 -7
View File
@@ -76,10 +76,9 @@ rains" patterns.
**Produces:** `SaveState` struct, phase state machine, save/load module.
**Status:** day counter, three phases, journal line and `SaveState` are done
and playable. **Persistence is blocked** — sector I/O from a cartridge ROM
reports success without transferring data; full findings in the disk section
of `../CLAUDE.md`.
**Status: ✅ complete.** Day counter, three phases, journal line, `SaveState`
and disk persistence all working. Verified by playing a day, cold-booting, and
resuming at day 2 with the served count intact.
**Pacing dial, revisited at the end.** `CUSTOMERS_PER_DAY` in `kissaten.c` is
the only number that sets day length. Worth reconsidering at M10 as a
@@ -482,7 +481,7 @@ milestone that consumes them.
| # | Needed for | Decision | My recommendation |
|---|---|---|---|
| 1 | M2 | ~~Save medium~~**save disk (.dsk), asset supplied** | ⚠ decided, but **not working yet** — see the disk section in `../CLAUDE.md`. Sector I/O reports success without transferring. **The RTC CMOS fallback I previously suggested is not viable**: block 3 is 13 nibbles, and MSXgl's `RTC_SaveData()` stores **6 bytes**, against a ~40-byte `SaveState`. Real fallbacks are cartridge SRAM, the FM-PAC SRAM, or shrinking the save to a 6-byte fingerprint |
| 1 | M2 | ~~Save medium~~**save disk (.dsk)** | ✅ working, via MSXgl's `tool/disk_save` module. Saves `KISSAT00.SAV` to drive A. Four non-obvious requirements — see the disk section in `../CLAUDE.md` |
| 2 | M2 | ~~Day length~~**5 min / 5 customers** | ✅ done. One constant, `CUSTOMERS_PER_DAY` in `kissaten.c` |
| 3 | M2 | ~~Clock model~~**event-driven** | ✅ done. Customers are the clock |
| 4 | M3 | ~~Who writes the dialogue~~**drafted by me, you edit** | ✅ resolved |
@@ -510,8 +509,9 @@ project, and both want answering now.
`../CLAUDE.md` for everything established so far.
2.**Aki's beats as prose** — done, along with the other three arcs, in
`SCRIPT.md`. Awaiting your edit pass.
3.**Unblock saving.** Either keep digging at the disk path, or switch
medium. Note the RTC CMOS fallback is off the table (§8 item 1).
3.**M3 vertical slice** — Aki's first six beats, hardcoded, with a scratch
portrait. The next real milestone, and the one that decides whether the
game works (§2, M3).
4.**Start the portrait question** (§5) — still the only item with external
lead time, and now the longest pole by some distance.