From 4d9541523288cdc9583daf631b729499801df539 Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Tue, 4 Aug 2026 11:10:44 -0500 Subject: [PATCH] Move global item collected-state, deadzone, and story flags into save file Adds three new pieces of save-file state, all following the same shape: the save file is the single source of truth, not a separate live runtime copy that gets synced in/out. - globalitemstore.h/.c: per-global-entity-ID "collected" flags (savefile_t.globalItemCollected), so a global item entity's init callback can check whether it was already picked up in a prior session without needing to keep the entity itself alive to remember that. - Gamepad deadzone: removed input_t.deadzone entirely. The setting UI and every platform's actual deadzone-applying code (inputGetDeadzoneDolphin/ SDL2, previously hardcoded per-platform literals that the settings menu didn't actually affect) now read savefile_t.deadzone directly via saveGet(SAVE_ACTIVE_SLOT). Default lives in savefile.h (SAVE_DEADZONE_DEFAULT), stamped onto every slot in saveInit(). - Story flags: STORY_FLAG_VALUES (a live, codegen-initialized array) is replaced by savefile_t.storyFlags, read/written via the existing storyFlagGet()/storyFlagSet() call sites (now macros/functions over the active save file instead of a separate array). tools/story.py now generates STORY_FLAG_DEFAULTS (const) instead; storyFlagInitDefaults() stamps those onto a save the first time it's used (file->exists false), called from rpgInit(). Added SAVE_ACTIVE_SLOT (0) to savefile.h as the one shared "which slot is actually being played" constant, replacing three different local/implicit 0s (uigamemenu.c, rpg.c, and now the settings/input call sites). Verified round-trip on Linux (all three together in one save/load cycle); both Linux and PSP build clean. --- src/dusk/input/input.c | 1 - src/dusk/input/input.h | 4 -- src/dusk/rpg/entity/global/CMakeLists.txt | 1 + src/dusk/rpg/entity/global/globalitemstore.c | 25 ++++++++++ src/dusk/rpg/entity/global/globalitemstore.h | 40 ++++++++++++++++ src/dusk/rpg/rpg.c | 10 +++- src/dusk/rpg/story/storyflag.c | 18 +++++-- src/dusk/rpg/story/storyflag.h | 29 +++++++++--- src/dusk/save/save.c | 7 +++ src/dusk/save/savefile.h | 49 ++++++++++++++++++++ src/dusk/save/savestream.c | 14 ++++++ src/dusk/ui/frame/game/uigamemenu.c | 12 ++--- src/dusk/ui/frame/settings/uisettingsinput.c | 10 ++-- src/duskdolphin/input/inputdolphin.c | 3 +- src/dusklinux/input/inputlinux.c | 3 +- src/duskpsp/input/inputpsp.c | 3 +- src/duskvita/input/inputvita.c | 3 +- tools/story.py | 6 ++- 18 files changed, 203 insertions(+), 35 deletions(-) create mode 100644 src/dusk/rpg/entity/global/globalitemstore.c create mode 100644 src/dusk/rpg/entity/global/globalitemstore.h diff --git a/src/dusk/input/input.c b/src/dusk/input/input.c index 80a5d83d..060b9962 100644 --- a/src/dusk/input/input.c +++ b/src/dusk/input/input.c @@ -17,7 +17,6 @@ input_t INPUT; errorret_t inputInit(void) { memoryZero(&INPUT, sizeof(input_t)); - INPUT.deadzone = INPUT_DEADZONE_DEFAULT; for(uint8_t i = 0; i < INPUT_ACTION_COUNT; i++) { INPUT.actions[i].action = (inputaction_t)i; diff --git a/src/dusk/input/input.h b/src/dusk/input/input.h index 06093eef..b1545979 100644 --- a/src/dusk/input/input.h +++ b/src/dusk/input/input.h @@ -12,15 +12,11 @@ #define INPUT_LISTENER_PRESSED_MAX 16 #define INPUT_LISTENER_RELEASED_MAX INPUT_LISTENER_PRESSED_MAX -#define INPUT_DEADZONE_DEFAULT 0.1f typedef struct { inputactiondata_t actions[INPUT_ACTION_COUNT]; inputplatform_t platform; - - /** User-configured gamepad axis deadzone (0.0f to 1.0f). */ - float_t deadzone; } input_t; extern input_t INPUT; diff --git a/src/dusk/rpg/entity/global/CMakeLists.txt b/src/dusk/rpg/entity/global/CMakeLists.txt index 9b35b01d..b5f1a268 100644 --- a/src/dusk/rpg/entity/global/CMakeLists.txt +++ b/src/dusk/rpg/entity/global/CMakeLists.txt @@ -6,4 +6,5 @@ # Sources target_sources(${DUSK_LIBRARY_TARGET_NAME} PUBLIC + globalitemstore.c ) \ No newline at end of file diff --git a/src/dusk/rpg/entity/global/globalitemstore.c b/src/dusk/rpg/entity/global/globalitemstore.c new file mode 100644 index 00000000..000b14a3 --- /dev/null +++ b/src/dusk/rpg/entity/global/globalitemstore.c @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "globalitemstore.h" +#include "assert/assert.h" + +bool_t globalItemStoreIsCollected( + const savefile_t *file, const entityglobalid_t id +) { + assertNotNull(file, "Save file cannot be NULL"); + assertTrue(id < SAVE_GLOBAL_ITEM_COUNT_MAX, "Global item ID out of range"); + return file->globalItemCollected[id]; +} + +void globalItemStoreSetCollected( + savefile_t *file, const entityglobalid_t id, const bool_t collected +) { + assertNotNull(file, "Save file cannot be NULL"); + assertTrue(id < SAVE_GLOBAL_ITEM_COUNT_MAX, "Global item ID out of range"); + file->globalItemCollected[id] = collected; +} diff --git a/src/dusk/rpg/entity/global/globalitemstore.h b/src/dusk/rpg/entity/global/globalitemstore.h new file mode 100644 index 00000000..ecfd0e83 --- /dev/null +++ b/src/dusk/rpg/entity/global/globalitemstore.h @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "error/error.h" +#include "save/savefile.h" +#include "rpg/entity/entity.h" + +/** + * Checks whether the global entity with the given ID has already been + * marked collected in the given save file's data - e.g. so a global item + * entity's init callback (see rpg/entity/global/entitygloballist.h) can + * skip spawning itself if the player already picked it up in a prior + * session, without needing to keep the entity itself alive to remember + * that (which would need render/collision special-casing - this doesn't). + * + * @param file The save file to check. + * @param id The global entity ID to check. + * @return True if already marked collected. + */ +bool_t globalItemStoreIsCollected( + const savefile_t *file, const entityglobalid_t id +); + +/** + * Marks the global entity with the given ID as collected (or not) in the + * given save file's data. Does not itself write the save to disk - call + * saveWrite() separately once ready to persist it. + * + * @param file The save file to write into. + * @param id The global entity ID to mark. + * @param collected The new collected state. + */ +void globalItemStoreSetCollected( + savefile_t *file, const entityglobalid_t id, const bool_t collected +); diff --git a/src/dusk/rpg/rpg.c b/src/dusk/rpg/rpg.c index 94e7496a..f806b529 100644 --- a/src/dusk/rpg/rpg.c +++ b/src/dusk/rpg/rpg.c @@ -22,6 +22,7 @@ #include "error/error.h" #include "ui/rpg/uiemoji.h" +#include "rpg/story/storyflag.h" static void rpgTestSaveComplete(errorret_t result, void *user) { if(errorIsNotOk(result)) errorCatch(errorPrint(result)); @@ -31,6 +32,11 @@ errorret_t rpgInit(void) { memoryZero(ENTITIES, sizeof(ENTITIES)); memoryZero(MAP_AREAS, sizeof(MAP_AREAS)); + // Must run before any code reads a story flag - stamps CSV-defined + // defaults onto the active save slot if it's never actually been + // loaded from disk yet. + storyFlagInitDefaults(saveGet(SAVE_ACTIVE_SLOT)); + backpackInit(); partyInit(); cutsceneSystemInit(); @@ -61,9 +67,9 @@ errorret_t rpgInit(void) { // header/version. Remove once there's an actual name-entry flow. On PSP // this shows the real native save dialog every boot - expected while // testing that path, not something to ship as-is. - savefile_t *saveFile = saveGet(0); + savefile_t *saveFile = saveGet(SAVE_ACTIVE_SLOT); stringCopy(saveFile->playerName, "Dusk", SAVE_PLAYER_NAME_MAX); - saveWrite(0, rpgTestSaveComplete, NULL); + saveWrite(SAVE_ACTIVE_SLOT, rpgTestSaveComplete, NULL); // All Good! errorOk(); diff --git a/src/dusk/rpg/story/storyflag.c b/src/dusk/rpg/story/storyflag.c index e83ba3a8..95a28436 100644 --- a/src/dusk/rpg/story/storyflag.c +++ b/src/dusk/rpg/story/storyflag.c @@ -1,6 +1,6 @@ /** * Copyright (c) 2026 Dominic Masters - * + * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ @@ -10,5 +10,17 @@ void storyFlagSet(const storyflag_t flag, const storyflagvalue_t value) { assertTrue(flag > STORY_FLAG_NULL && flag < STORY_FLAG_COUNT, "Bad Flag"); - STORY_FLAG_VALUES[flag] = value; -} \ No newline at end of file + saveGet(SAVE_ACTIVE_SLOT)->storyFlags[flag] = value; +} + +void storyFlagInitDefaults(savefile_t *file) { + assertNotNull(file, "Save file cannot be NULL"); + if(file->exists) return; + assertTrue( + STORY_FLAG_COUNT <= SAVE_STORY_FLAG_COUNT_MAX, + "Too many story flags for the save format - bump SAVE_STORY_FLAG_COUNT_MAX" + ); + for(storyflag_t i = 0; i < STORY_FLAG_COUNT; i++) { + file->storyFlags[i] = STORY_FLAG_DEFAULTS[i]; + } +} diff --git a/src/dusk/rpg/story/storyflag.h b/src/dusk/rpg/story/storyflag.h index 00fb88e0..509ec881 100644 --- a/src/dusk/rpg/story/storyflag.h +++ b/src/dusk/rpg/story/storyflag.h @@ -1,25 +1,40 @@ /** * Copyright (c) 2026 Dominic Masters - * + * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #pragma once #include "rpg/story/storyflagvalue.h" +#include "save/save.h" /** - * Gets the value of a story flag. - * + * Gets the value of a story flag. Reads directly from the active save + * file (see SAVE_ACTIVE_SLOT) - flag values have no separate live copy. + * * @param flag The story flag to get. * @return The value of the story flag. */ -#define storyFlagGet(flag) (STORY_FLAG_VALUES[(flag)]) +#define storyFlagGet(flag) (saveGet(SAVE_ACTIVE_SLOT)->storyFlags[(flag)]) /** - * Sets the value of a story flag. - * + * Sets the value of a story flag, directly in the active save file (see + * SAVE_ACTIVE_SLOT). Does not itself write the save to disk - call + * saveWrite() separately once ready to persist it. + * * @param flag The story flag to set. * @param value The value to set the story flag to. */ -void storyFlagSet(const storyflag_t flag, const storyflagvalue_t value); \ No newline at end of file +void storyFlagSet(const storyflag_t flag, const storyflagvalue_t value); + +/** + * Stamps each story flag's CSV-defined default (STORY_FLAG_DEFAULTS) onto + * the given save file, but only if it hasn't actually been loaded from + * disk yet (file->exists is false) - otherwise leaves already-played + * progress alone. Call once, e.g. during rpgInit(), before any gameplay + * code reads a story flag. + * + * @param file The save file to stamp defaults onto. + */ +void storyFlagInitDefaults(savefile_t *file); diff --git a/src/dusk/save/save.c b/src/dusk/save/save.c index 2365b6c3..34873373 100644 --- a/src/dusk/save/save.c +++ b/src/dusk/save/save.c @@ -16,6 +16,13 @@ save_t SAVE; errorret_t saveInit(void) { memoryZero(&SAVE, sizeof(save_t)); + // Establishes the default for a slot that hasn't actually been loaded + // from disk yet - saveLoad() overwrites this the moment a real file is + // found, so this only matters for a brand new save. + for(uint8_t i = 0; i < SAVE_FILE_COUNT_MAX; i++) { + SAVE.files[i].deadzone = SAVE_DEADZONE_DEFAULT; + } + #ifdef saveInitPlatform // A missing/unreachable save medium is expected, recoverable state, // not a reason to fail booting the whole game - log it and carry on diff --git a/src/dusk/save/savefile.h b/src/dusk/save/savefile.h index 6e118ce6..024bed92 100644 --- a/src/dusk/save/savefile.h +++ b/src/dusk/save/savefile.h @@ -20,9 +20,44 @@ /** Maximum number of independent save slots supported. */ #define SAVE_FILE_COUNT_MAX 3 +/** + * The save slot actually used for gameplay right now - there's no slot + * select/multi-save UX yet (SAVE_FILE_COUNT_MAX > 1 exists for later), so + * every part of the game that needs "the" save file (settings, the game + * menu's Save button, etc.) reads/writes this one slot. + */ +#define SAVE_ACTIVE_SLOT 0 + /** Maximum length of a saved player name, including the null terminator. */ #define SAVE_PLAYER_NAME_MAX 32 +/** + * Maximum number of global entities whose "collected" state can be + * tracked - see rpg/entity/global/globalitemstore.h. Bounded/fixed here + * rather than tied to ENTITY_GLOBAL_LIST_COUNT, since savefile.h is a + * leaf header with no dependency on the entity system (and no reason to + * take one just for a size constant). + */ +#define SAVE_GLOBAL_ITEM_COUNT_MAX 64 + +/** + * Default gamepad deadzone for a save slot that's never actually been + * loaded from disk yet (see saveInit(), which stamps this onto every + * slot up front) - defined here, rather than by the input system, since + * the save file is now the single source of truth for this value (see + * savefile_t.deadzone) - nothing else stores or defaults it. + */ +#define SAVE_DEADZONE_DEFAULT 0.1f + +/** + * Maximum number of story flags the save format can hold - see + * rpg/story/storyflag.h. Bounded/fixed here (with real headroom over the + * current flag count) rather than tied to STORY_FLAG_COUNT, since + * savefile.h is a leaf header with no dependency on generated story + * content, matching SAVE_GLOBAL_ITEM_COUNT_MAX's reasoning. + */ +#define SAVE_STORY_FLAG_COUNT_MAX 128 + typedef struct { /** Magic header bytes read from the file; must equal SAVE_FILE_HEADER. */ char_t header[SAVE_FILE_HEADER_SIZE]; @@ -32,6 +67,20 @@ typedef struct { bool_t exists; /** The player's saved name. */ char_t playerName[SAVE_PLAYER_NAME_MAX]; + /** Per-global-ID "already collected" flags - see globalitemstore.h. */ + bool_t globalItemCollected[SAVE_GLOBAL_ITEM_COUNT_MAX]; + /** + * User-configured gamepad deadzone (0.0f-1.0f) - the save file is the + * only place this lives; read it directly via saveGet(SAVE_ACTIVE_SLOT) + * ->deadzone rather than caching it anywhere else. + */ + float_t deadzone; + /** + * Story flag values, indexed by storyflag_t - the save file is the only + * place these live; read/write via storyFlagGet()/storyFlagSet() (see + * rpg/story/storyflag.h), not directly. + */ + uint8_t storyFlags[SAVE_STORY_FLAG_COUNT_MAX]; } savefile_t; /** diff --git a/src/dusk/save/savestream.c b/src/dusk/save/savestream.c index d39bd9ee..ca1e19d4 100644 --- a/src/dusk/save/savestream.c +++ b/src/dusk/save/savestream.c @@ -331,6 +331,13 @@ errorret_t saveFileLoad(savestream_t *stream, savefile_t *file) { saveFileReadHeader(stream, file->header); saveFileReadVersion(stream, &file->version); saveFileReadString(stream, file->playerName, SAVE_PLAYER_NAME_MAX); + for(size_t i = 0; i < SAVE_GLOBAL_ITEM_COUNT_MAX; i++) { + saveFileReadBool(stream, &file->globalItemCollected[i]); + } + saveFileReadFloat(stream, &file->deadzone); + for(size_t i = 0; i < SAVE_STORY_FLAG_COUNT_MAX; i++) { + saveFileReadUInt8(stream, &file->storyFlags[i]); + } errorOk(); } @@ -338,5 +345,12 @@ errorret_t saveFileWrite(savestream_t *stream, savefile_t *file) { saveFileWriteHeader(stream, file->header); saveFileWriteVersion(stream, &file->version); saveFileWriteString(stream, file->playerName, SAVE_PLAYER_NAME_MAX); + for(size_t i = 0; i < SAVE_GLOBAL_ITEM_COUNT_MAX; i++) { + saveFileWriteBool(stream, &file->globalItemCollected[i]); + } + saveFileWriteFloat(stream, &file->deadzone); + for(size_t i = 0; i < SAVE_STORY_FLAG_COUNT_MAX; i++) { + saveFileWriteUInt8(stream, &file->storyFlags[i]); + } errorOk(); } diff --git a/src/dusk/ui/frame/game/uigamemenu.c b/src/dusk/ui/frame/game/uigamemenu.c index 2e4d0111..d3fbd6fb 100644 --- a/src/dusk/ui/frame/game/uigamemenu.c +++ b/src/dusk/ui/frame/game/uigamemenu.c @@ -26,10 +26,6 @@ #define UI_GAME_MENU_INDEX_SETTINGS 2 #define UI_GAME_MENU_INDEX_SAVE 3 -// Only one save slot is exposed through this menu for now - there is no -// slot-select UI yet, and SAVE_FILE_COUNT_MAX > 1 exists for later. -#define UI_GAME_MENU_SAVE_SLOT 0 - static void uiGameMenuSaveWriteComplete(errorret_t result, void *user) { if(errorIsNotOk(result)) { // Generously sized - stringFormat asserts (crashes) rather than @@ -53,7 +49,7 @@ static void uiGameMenuSaveCreateConfirmed(const bool_t confirmed, void *user) { return; } - saveWrite(UI_GAME_MENU_SAVE_SLOT, uiGameMenuSaveWriteComplete, NULL); + saveWrite(SAVE_ACTIVE_SLOT, uiGameMenuSaveWriteComplete, NULL); } // Determines whether there's actually save data to overwrite (not just @@ -72,8 +68,8 @@ static void uiGameMenuSaveCheckComplete(errorret_t result, void *user) { return; } - if(saveExists(UI_GAME_MENU_SAVE_SLOT)) { - saveWrite(UI_GAME_MENU_SAVE_SLOT, uiGameMenuSaveWriteComplete, NULL); + if(saveExists(SAVE_ACTIVE_SLOT)) { + saveWrite(SAVE_ACTIVE_SLOT, uiGameMenuSaveWriteComplete, NULL); return; } @@ -91,7 +87,7 @@ static void uiGameMenuSave(void) { } if(saveIsBusy()) return;// A save/load dialog (e.g. on PSP) is already up. - saveLoad(UI_GAME_MENU_SAVE_SLOT, uiGameMenuSaveCheckComplete, NULL); + saveLoad(SAVE_ACTIVE_SLOT, uiGameMenuSaveCheckComplete, NULL); } uigamemenu_t UI_GAME_MENU; diff --git a/src/dusk/ui/frame/settings/uisettingsinput.c b/src/dusk/ui/frame/settings/uisettingsinput.c index 287329cd..fbf05b3e 100644 --- a/src/dusk/ui/frame/settings/uisettingsinput.c +++ b/src/dusk/ui/frame/settings/uisettingsinput.c @@ -11,7 +11,7 @@ #include "util/memory.h" #include "locale/localemanager.h" #include "asset/loader/locale/assetlocaleloader.h" -#include "input/input.h" +#include "save/save.h" void uiSettingsInputSelected( const uimenu_t *menu, @@ -39,7 +39,7 @@ errorret_t uiSettingsInputInit(uisettingsdata_t *data) { UI_SETTINGS_INPUT_LABEL_MAX )); MENU_SLIDER_FLOAT( - input->deadzoneLabel, INPUT_DEADZONE_DEFAULT, 0.0f, 1.0f, 0.05f + input->deadzoneLabel, SAVE_DEADZONE_DEFAULT, 0.0f, 1.0f, 0.05f ); #else MENU_LABEL("No input settings yet"); @@ -55,14 +55,14 @@ void uiSettingsInputLoad(void) { #ifdef DUSK_INPUT_GAMEPAD uiSliderSetFloat( &UI_SETTINGS.data.input.items[UI_SETTINGS_INPUT_INDEX_DEADZONE].slider, - INPUT.deadzone + saveGet(SAVE_ACTIVE_SLOT)->deadzone ); #endif } void uiSettingsInputApply(void) { #ifdef DUSK_INPUT_GAMEPAD - INPUT.deadzone = uiSliderGetFloat( + saveGet(SAVE_ACTIVE_SLOT)->deadzone = uiSliderGetFloat( &UI_SETTINGS.data.input.items[UI_SETTINGS_INPUT_INDEX_DEADZONE].slider ); #endif @@ -73,7 +73,7 @@ bool_t uiSettingsInputHasChanges(void) { #ifdef DUSK_INPUT_GAMEPAD if(uiSliderGetFloat( &UI_SETTINGS.data.input.items[UI_SETTINGS_INPUT_INDEX_DEADZONE].slider - ) != INPUT.deadzone) return true; + ) != saveGet(SAVE_ACTIVE_SLOT)->deadzone) return true; #endif return false; diff --git a/src/duskdolphin/input/inputdolphin.c b/src/duskdolphin/input/inputdolphin.c index c9fb4869..1e2f623b 100644 --- a/src/duskdolphin/input/inputdolphin.c +++ b/src/duskdolphin/input/inputdolphin.c @@ -9,6 +9,7 @@ #include "assert/assert.h" #include "log/log.h" #include "util/string.h" +#include "save/save.h" inputbuttondata_t INPUT_BUTTON_DATA[] = { #ifdef DUSK_INPUT_GAMEPAD @@ -187,5 +188,5 @@ float_t inputButtonGetValueDolphin(const inputbutton_t button) { } float_t inputGetDeadzoneDolphin(const inputbutton_t button) { - return 0.2f; + return saveGet(SAVE_ACTIVE_SLOT)->deadzone; } \ No newline at end of file diff --git a/src/dusklinux/input/inputlinux.c b/src/dusklinux/input/inputlinux.c index fb952efa..f9cf744e 100644 --- a/src/dusklinux/input/inputlinux.c +++ b/src/dusklinux/input/inputlinux.c @@ -6,6 +6,7 @@ */ #include "input/input.h" +#include "save/save.h" inputbuttondata_t INPUT_BUTTON_DATA[] = { #ifdef DUSK_INPUT_GAMEPAD @@ -547,5 +548,5 @@ errorret_t inputInitLinux(void) { } float_t inputGetDeadzoneSDL2(const inputbutton_t button) { - return 0.17f; + return saveGet(SAVE_ACTIVE_SLOT)->deadzone; } \ No newline at end of file diff --git a/src/duskpsp/input/inputpsp.c b/src/duskpsp/input/inputpsp.c index 6bc7ef62..0b61cf24 100644 --- a/src/duskpsp/input/inputpsp.c +++ b/src/duskpsp/input/inputpsp.c @@ -6,6 +6,7 @@ */ #include "input/input.h" +#include "save/save.h" // #define INPUT_PSP_GAMEPAD_BUTTON_ACCEPT INPUT_SDL2_GAMEPAD_BUTTON_CUSTOM // #define INPUT_PSP_GAMEPAD_BUTTON_CANCEL INPUT_SDL2_GAMEPAD_BUTTON_CUSTOM @@ -94,5 +95,5 @@ errorret_t inputInitPSP(void) { } float_t inputGetDeadzoneSDL2(const inputbutton_t button) { - return 0.2f; + return saveGet(SAVE_ACTIVE_SLOT)->deadzone; } \ No newline at end of file diff --git a/src/duskvita/input/inputvita.c b/src/duskvita/input/inputvita.c index 339839ab..550985e2 100644 --- a/src/duskvita/input/inputvita.c +++ b/src/duskvita/input/inputvita.c @@ -6,6 +6,7 @@ */ #include "input/input.h" +#include "save/save.h" inputbuttondata_t INPUT_BUTTON_DATA[] = { { .name = "triangle", { @@ -83,5 +84,5 @@ inputbuttondata_t INPUT_BUTTON_DATA[] = { }; float_t inputGetDeadzoneSDL2(const inputbutton_t button) { - return 0.17f; + return saveGet(SAVE_ACTIVE_SLOT)->deadzone; } diff --git a/tools/story.py b/tools/story.py index c1f9bcfc..fd7fac31 100644 --- a/tools/story.py +++ b/tools/story.py @@ -38,7 +38,11 @@ out += [ " STORY_FLAG_COUNT", "} storyflag_t;", "", - "static storyflagvalue_t STORY_FLAG_VALUES[STORY_FLAG_COUNT] = {", + "// Stamped onto a save file's storyFlags the first time it's used (see", + "// storyFlagInitDefaults()) - not a live value array. Live flag state", + "// lives entirely in the save file (savefile_t.storyFlags), read/written", + "// via storyFlagGet()/storyFlagSet() - see storyflag.h.", + "static const storyflagvalue_t STORY_FLAG_DEFAULTS[STORY_FLAG_COUNT] = {", ] for flag in flags: out.append(f" [{flag_enum(flag['id'])}] = {flag['initial']},")