# Save & Locale --- ## Save system (`src/dusk/save/`) Slot-based persistent storage. Currently disabled in engine init (commented out in `engine.c`) — the system is fully implemented but not yet wired up. ### Slots Up to `SAVE_FILE_COUNT_MAX` (3) save slots. The global `SAVE` holds all slots: ```c saveInit(); saveExists(slot); // bool_t — check before load saveLoad(slot); // read from platform storage → SAVE.files[slot] saveWrite(slot); // write SAVE.files[slot] → platform storage saveDelete(slot); savefile_t *f = saveGet(slot); saveDispose(); ``` ### Save file format `savefile_t` is the serialized struct stored per slot. Currently minimal: ```c typedef struct { char_t header[3]; // "DSK" uint32_t version; // SAVE_FILE_VERSION = 1 bool_t exists; } savefile_t; ``` Extend this struct to add game-specific save data (player position, story flags, etc.). ### Stream serialization (`save/savestream.h`) `savestream_t` is a cursor used to read/write a save slot's bytes. It CRC32-checksums all data written through it and verifies the checksum on read. Write a save: ```c savestream_t stream; // (platform opens stream for slot) saveFileWriteHeader(&stream, SAVE_FILE_HEADER); saveFileWriteVersion(&stream, SAVE_FILE_VERSION); saveFileWriteBool(&stream, myFlag); saveFileWriteInt32(&stream, myInt); saveFileWriteString(&stream, myString, sizeof(myString)); saveStreamFinalizeWriteImpl(&stream); // writes CRC ``` Read a save: ```c saveFileReadHeader(&stream, headerBuf); saveFileReadVersion(&stream, &version); saveFileReadBool(&stream, &myFlag); saveFileReadInt32(&stream, &myInt); saveFileReadString(&stream, myString, sizeof(myString)); saveStreamVerifyChecksumImpl(&stream, slot); // returns error if CRC mismatch ``` All multi-byte values are stored in little-endian byte order. The `saveFile*` macros are thin wrappers over the `*Impl` functions that integrate `errorChain` — always use the macros. ### Platform backends Each `src/dusk{platform}/save/` provides `saveplatform_t` (e.g. a file path on Linux, a memory-card handle on GameCube). The stream implementations (`savestream{platform}.c`) do the actual I/O. --- ## Locale / i18n (`src/dusk/locale/`) Translations are stored as GNU `.po` files in `assets/locale/`. Only `en_US.po` currently exists. ### Loading `localemanager_t LOCALE` tracks the active locale and its in-progress asset entry: ```c localeManagerInit(); // loads en_US by default localeManagerSetLocale(&LOCALE_EN_US); // switch locale (async load) localeManagerDispose(); ``` `LOCALE_EN_US` is a predefined `localeinfo_t` constant (`name = "en-US"`, `file = "locale/en_US.po"`). ### Looking up strings ```c char_t buf[128]; localeManagerGetText("my.key", buf, sizeof(buf), 1, /* format args */ ); ``` The macro handles plural forms and `printf`-style format arguments. Pass plural `1` for singular, any other value for plural. `assetlocaleloader.c` parses the `.po` format (msgid / msgstr pairs) into a key→string table during the async asset load phase.