Wire story flags into the save slot and add cutscene controls

Implements storyInit/storyGetFlagByName/storyGetFlagValue/etc, moves flag
storage into saveslot_t (persisted keyed by name so save files survive
flag reordering), and adds STORY_SET_FLAG/STORY_WAIT_FLAG cutscene items.
Also removes the now-superseded storyflag.c/h stub.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
2026-09-19 20:39:53 -05:00
co-authored by Claude Sonnet 5
parent 6f1bbe4f2f
commit 4b29bf7a30
24 changed files with 396 additions and 65 deletions
+6 -1
View File
@@ -1,5 +1,10 @@
{ {
"flags": { "flags": {
"test": { "description": "Test flag for debugging purposes", "initial": true } "test": {
"initial": true
},
"test2": {
"initial": 1
}
} }
} }
@@ -20,3 +20,4 @@ add_subdirectory(battle)
add_subdirectory(save) add_subdirectory(save)
add_subdirectory(audio) add_subdirectory(audio)
add_subdirectory(json) add_subdirectory(json)
add_subdirectory(story)
+13
View File
@@ -339,6 +339,19 @@ cutsceneitemcallbacks_t CUTSCENE_ITEM_CALLBACKS[CUTSCENE_ITEM_TYPE_COUNT] = {
.update = cutsceneInsertUpdate, .update = cutsceneInsertUpdate,
.jsonName = "INSERT", .jsonName = "INSERT",
.load = cutsceneInsertLoad .load = cutsceneInsertLoad
},
[CUTSCENE_ITEM_TYPE_STORY_SET_FLAG] = {
.init = cutsceneStorySetFlagStart,
.update = cutsceneStorySetFlagUpdate,
.jsonName = "STORY_SET_FLAG",
.load = cutsceneStorySetFlagLoad
},
[CUTSCENE_ITEM_TYPE_STORY_WAIT_FLAG] = {
.update = cutsceneStoryWaitFlagUpdate,
.jsonName = "STORY_WAIT_FLAG",
.load = cutsceneStoryWaitFlagLoad
} }
}; };
@@ -55,6 +55,8 @@
#include "audio/cutsceneaudiosetpan.h" #include "audio/cutsceneaudiosetpan.h"
#include "audio/cutsceneaudiosetloop.h" #include "audio/cutsceneaudiosetloop.h"
#include "audio/cutsceneaudioset.h" #include "audio/cutsceneaudioset.h"
#include "story/cutscenestorysetflag.h"
#include "story/cutscenestorywaitflag.h"
typedef struct cutscene_s cutscene_t; typedef struct cutscene_s cutscene_t;
@@ -138,6 +140,8 @@ struct cutsceneitem_s {
cutsceneaudiosetloop_t audioSetLoop; cutsceneaudiosetloop_t audioSetLoop;
cutsceneaudioset_t audioSet; cutsceneaudioset_t audioSet;
cutsceneuishow_t uiShow; cutsceneuishow_t uiShow;
cutscenestorysetflag_t storySetFlag;
cutscenestorywaitflag_t storyWaitFlag;
}; };
}; };
@@ -64,6 +64,8 @@ typedef enum {
CUTSCENE_ITEM_TYPE_UI_SHOW, CUTSCENE_ITEM_TYPE_UI_SHOW,
CUTSCENE_ITEM_TYPE_REGULAR_BATTLE, CUTSCENE_ITEM_TYPE_REGULAR_BATTLE,
CUTSCENE_ITEM_TYPE_INSERT, CUTSCENE_ITEM_TYPE_INSERT,
CUTSCENE_ITEM_TYPE_STORY_SET_FLAG,
CUTSCENE_ITEM_TYPE_STORY_WAIT_FLAG,
CUTSCENE_ITEM_TYPE_COUNT CUTSCENE_ITEM_TYPE_COUNT
} cutsceneitemtype_t; } cutsceneitemtype_t;
@@ -20,4 +20,5 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME}
cutscenejsonscenetype.c cutscenejsonscenetype.c
cutscenejsonuiscreentype.c cutscenejsonuiscreentype.c
cutscenejsonaudiochannel.c cutscenejsonaudiochannel.c
cutscenejsonstoryflag.c
) )
@@ -0,0 +1,18 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "cutscenejsonstoryflag.h"
bool_t cutsceneJsonGetStoryFlag(yyjson_val *val, storyflag_t *outFlag) {
if(!yyjson_is_str(val)) return false;
storyflag_t flag = storyGetFlagByName(yyjson_get_str(val));
if(flag >= STORY_FLAG_COUNT) return false;
*outFlag = flag;
return true;
}
@@ -0,0 +1,21 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
#include "yyjson.h"
#include "rpg/story/story.h"
/**
* Resolves a JSON string value naming a story flag (via storyGetFlagByName)
* into a storyflag_t.
*
* @param val JSON value to resolve (a string).
* @param outFlag Set to the resolved story flag id on success.
* @return true if val resolved to a known story flag, false otherwise.
*/
bool_t cutsceneJsonGetStoryFlag(yyjson_val *val, storyflag_t *outFlag);
@@ -0,0 +1,10 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
cutscenestorysetflag.c
cutscenestorywaitflag.c
)
@@ -0,0 +1,39 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "rpg/cutscene/item/cutsceneitem.h"
#include "rpg/cutscene/item/json/cutscenejsonstoryflag.h"
#include "rpg/cutscene/item/json/cutscenejsonfield.h"
void cutsceneStorySetFlagStart(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
) {
storySetFlagValue(item->storySetFlag.flag, item->storySetFlag.value);
}
bool_t cutsceneStorySetFlagUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
) {
return true;
}
errorret_t cutsceneStorySetFlagLoad(
yyjson_val *itemObj,
cutsceneitem_t *item
) {
yyjson_val *flagVal = yyjson_obj_get(itemObj, "flag");
if(!cutsceneJsonGetStoryFlag(flagVal, &item->storySetFlag.flag)) {
errorThrow("Cutscene item (STORY_SET_FLAG): invalid or missing 'flag'");
}
item->storySetFlag.value =
(storyflagval_t)cutsceneJsonGetInt(itemObj, "value", 1);
errorOk();
}
@@ -0,0 +1,51 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "rpg/cutscene/item/cutsceneitembase.h"
#include "rpg/story/story.h"
typedef struct {
storyflag_t flag;
storyflagval_t value;
} cutscenestorysetflag_t;
/**
* Starts a story set-flag step, immediately writing the given value to the
* given story flag.
*
* @param item The cutscene item.
* @param data Runtime data storage.
*/
void cutsceneStorySetFlagStart(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
/**
* Updates a story set-flag step (always completes immediately).
*
* @param item The cutscene item.
* @param data Runtime data storage.
* @returns true always.
*/
bool_t cutsceneStorySetFlagUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
/**
* Parses a STORY_SET_FLAG cutscene item's JSON fields into item.
*
* @param itemObj The item's JSON object.
* @param item Destination item, already zeroed by the caller.
* @return Error code indicating success or failure of the parse.
*/
errorret_t cutsceneStorySetFlagLoad(
yyjson_val *itemObj,
cutsceneitem_t *item
);
@@ -0,0 +1,32 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "rpg/cutscene/item/cutsceneitem.h"
#include "rpg/cutscene/item/json/cutscenejsonstoryflag.h"
#include "rpg/cutscene/item/json/cutscenejsonfield.h"
bool_t cutsceneStoryWaitFlagUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
) {
return storyGetFlagValue(item->storyWaitFlag.flag) == item->storyWaitFlag.value;
}
errorret_t cutsceneStoryWaitFlagLoad(
yyjson_val *itemObj,
cutsceneitem_t *item
) {
yyjson_val *flagVal = yyjson_obj_get(itemObj, "flag");
if(!cutsceneJsonGetStoryFlag(flagVal, &item->storyWaitFlag.flag)) {
errorThrow("Cutscene item (STORY_WAIT_FLAG): invalid or missing 'flag'");
}
item->storyWaitFlag.value =
(storyflagval_t)cutsceneJsonGetInt(itemObj, "value", 1);
errorOk();
}
@@ -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 "rpg/cutscene/item/cutsceneitembase.h"
#include "rpg/story/story.h"
typedef struct {
storyflag_t flag;
storyflagval_t value;
} cutscenestorywaitflag_t;
/**
* Updates a story wait-flag step, completing once the given story flag's
* current value matches the given value.
*
* @param item The cutscene item.
* @param data Runtime data storage.
* @returns true once the flag's current value matches, false otherwise.
*/
bool_t cutsceneStoryWaitFlagUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
/**
* Parses a STORY_WAIT_FLAG cutscene item's JSON fields into item.
*
* @param itemObj The item's JSON object.
* @param item Destination item, already zeroed by the caller.
* @return Error code indicating success or failure of the parse.
*/
errorret_t cutsceneStoryWaitFlagLoad(
yyjson_val *itemObj,
cutsceneitem_t *item
);
-1
View File
@@ -22,7 +22,6 @@
#include "error/error.h" #include "error/error.h"
#include "scene/scene.h" #include "scene/scene.h"
#include "ui/rpg/uiemoji.h" #include "ui/rpg/uiemoji.h"
#include "rpg/story/storyflag.h"
#include "rpg/story/story.h" #include "rpg/story/story.h"
errorret_t rpgInit(void) { errorret_t rpgInit(void) {
-1
View File
@@ -7,5 +7,4 @@
target_sources(${DUSK_LIBRARY_TARGET_NAME} target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC PUBLIC
story.c story.c
storyflag.c
) )
+62 -2
View File
@@ -8,8 +8,19 @@
#include "story.h" #include "story.h"
#include "asset/asset.h" #include "asset/asset.h"
#include "asset/loader/assetloader.h" #include "asset/loader/assetloader.h"
#include "assert/assert.h"
#include "save/save.h"
#include "util/memory.h"
#include "util/string.h"
#include "yyjson.h"
storyflagmap_t STORY_FLAG_MAP[STORY_FLAG_COUNT_MAX];
storyflag_t STORY_FLAG_COUNT;
errorret_t storyInit(void) { errorret_t storyInit(void) {
memoryZero(STORY_FLAG_MAP, sizeof(STORY_FLAG_MAP));
STORY_FLAG_COUNT = 0;
assetentry_t *entry = assetLock( assetentry_t *entry = assetLock(
"story/storyflag.jsonc", ASSET_LOADER_TYPE_JSON, NULL "story/storyflag.jsonc", ASSET_LOADER_TYPE_JSON, NULL
); );
@@ -19,9 +30,58 @@ errorret_t storyInit(void) {
errorChain(ret); errorChain(ret);
} }
// TODO: Parse entry->data.json into a storyflagid_t registry, the same yyjson_val *root = yyjson_doc_get_root(entry->data.json);
// way item.c's itemInit() builds ITEM.defs from items/items.jsonc. yyjson_val *flags = yyjson_obj_get(root, "flags");
yyjson_obj_iter iter = yyjson_obj_iter_with(flags);
yyjson_val *key;
while((key = yyjson_obj_iter_next(&iter))) {
assertTrue(
STORY_FLAG_COUNT < STORY_FLAG_COUNT_MAX, "Too many story flags defined."
);
yyjson_val *val = yyjson_obj_iter_get_val(key);
yyjson_val *initial = yyjson_obj_get(val, "initial");
storyflag_t flag = STORY_FLAG_COUNT++;
stringCopy(STORY_FLAG_MAP[flag].name, yyjson_get_str(key), STORY_FLAG_NAME_MAX);
STORY_FLAG_MAP[flag].initial = yyjson_is_bool(initial) ?
(storyflagval_t)yyjson_get_bool(initial) :
(storyflagval_t)yyjson_get_int(initial);
}
assetUnlockEntry(entry); assetUnlockEntry(entry);
errorOk(); errorOk();
} }
storyflag_t storyGetFlagByName(const char_t *name) {
assertNotNull(name, "name must not be NULL");
for(storyflag_t flag = 0; flag < STORY_FLAG_COUNT; flag++) {
if(stringEquals(STORY_FLAG_MAP[flag].name, name)) return flag;
}
return STORY_FLAG_COUNT_MAX;
}
const char_t * storyGetNameByFlag(storyflag_t flag) {
if(flag >= STORY_FLAG_COUNT) return NULL;
return STORY_FLAG_MAP[flag].name;
}
storyflagval_t storyGetFlagValue(storyflag_t flag) {
if(flag >= STORY_FLAG_COUNT) return 0;
return SAVE.slot.storyFlags[flag];
}
void storySetFlagValue(storyflag_t flag, storyflagval_t value) {
assertTrue(flag < STORY_FLAG_COUNT, "Bad story flag");
SAVE.slot.storyFlags[flag] = value;
SAVE.slotDirty = true;
}
void storySetFlagValueByName(const char_t *name, storyflagval_t value) {
storyflag_t flag = storyGetFlagByName(name);
assertTrue(flag < STORY_FLAG_COUNT, "Unknown story flag");
storySetFlagValue(flag, value);
}
+59
View File
@@ -8,6 +8,20 @@
#pragma once #pragma once
#include "error/error.h" #include "error/error.h"
#define STORY_FLAG_COUNT_MAX 256
#define STORY_FLAG_NAME_MAX 16
typedef uint16_t storyflag_t;
typedef uint8_t storyflagval_t;
typedef struct {
char_t name[STORY_FLAG_NAME_MAX];
storyflagval_t initial;
} storyflagmap_t;
extern storyflagmap_t STORY_FLAG_MAP[STORY_FLAG_COUNT_MAX];
extern storyflag_t STORY_FLAG_COUNT;
/** /**
* Initializes the story subsystem, loading assets/story/storyflag.jsonc. * Initializes the story subsystem, loading assets/story/storyflag.jsonc.
@@ -15,3 +29,48 @@
* @return Any error that occurs. * @return Any error that occurs.
*/ */
errorret_t storyInit(void); errorret_t storyInit(void);
/**
* Gets the ID of a story flag by name.
*
* @param name The name of the story flag to get.
* @return The ID of the story flag, or STORY_FLAG_COUNT_MAX if not found.
*/
storyflag_t storyGetFlagByName(const char_t *name);
/**
* Gets the name of a story flag by ID.
*
* @param flag The ID of the story flag to get.
* @return The name of the story flag, or NULL if not found.
*/
const char_t * storyGetNameByFlag(storyflag_t flag);
/**
* Gets the value of a story flag. Reads directly from the active save
* slot (SAVE.slot.storyFlags) - flag values have no separate live copy.
*
* @param flag The ID of the story flag to get.
* @return The value of the story flag, or 0 if not found.
*/
storyflagval_t storyGetFlagValue(storyflag_t flag);
/**
* Sets the value of a story flag. Writes directly to the active save
* slot (SAVE.slot.storyFlags) - flag values have no separate live copy.
* Marks the save slot dirty.
*
* @param flag The ID of the story flag to set.
* @param value The value to set the story flag to.
*/
void storySetFlagValue(storyflag_t flag, storyflagval_t value);
/**
* Sets the value of a story flag by name. Writes directly to the active save
* slot (SAVE.slot.storyFlags) - flag values have no separate live copy.
* Marks the save slot dirty.
*
* @param name The name of the story flag to set.
* @param value The value to set the story flag to.
*/
void storySetFlagValueByName(const char_t *name, storyflagval_t value);
-23
View File
@@ -1,23 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "storyflag.h"
#include "assert/assert.h"
#include "console/console.h"
bool_t storyFlagGet(const storyflag_t flag) {
assertTrue(flag < STORY_FLAG_COUNT_MAX, "Bad Flag");
consolePrint("Story flag get without save implementation");
return false;
}
void storyFlagSet(const storyflag_t flag, const bool_t value) {
assertTrue(flag < STORY_FLAG_COUNT_MAX, "Bad Flag");
// TODO: Dirty savefile
consolePrint("Story flag set without save implementation");
}
-37
View File
@@ -1,37 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
#define STORY_FLAG_BASE_TYPE uint32_t
#define STORY_FLAG_BASE_BITS (sizeof(STORY_FLAG_BASE_TYPE) * 8)
#define STORY_FLAG_COUNT_MAX 1024
#define STORY_FLAG_BASE_COUNT \
((STORY_FLAG_COUNT_MAX + STORY_FLAG_BASE_BITS - 1) / STORY_FLAG_BASE_BITS)
typedef STORY_FLAG_BASE_TYPE storyflag_t;
typedef STORY_FLAG_BASE_TYPE storyflaglist_t[STORY_FLAG_BASE_COUNT];
typedef uint16_t storyflagid_t;
/**
* Gets the value of a story flag. Reads directly from the active save
* slot (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.
*/
bool_t storyFlagGet(const storyflag_t flag);
/**
* Sets the value of a story flag. Will dirty the savefile.
*
* @param flag The story flag to set.
* @param value The value to set the story flag to.
*/
void storyFlagSet(const storyflag_t flag, const bool_t value);
+4
View File
@@ -17,6 +17,10 @@ void saveSlotInit(void) {
SAVE.slot.version = 1; SAVE.slot.version = 1;
for(storyflag_t flag = 0; flag < STORY_FLAG_COUNT; flag++) {
SAVE.slot.storyFlags[flag] = STORY_FLAG_MAP[flag].initial;
}
partyInit(); partyInit();
} }
+2
View File
@@ -9,6 +9,7 @@
#include "save/savedevice.h" #include "save/savedevice.h"
#include "rpg/overworld/map.h" #include "rpg/overworld/map.h"
#include "rpg/battle/party.h" #include "rpg/battle/party.h"
#include "rpg/story/story.h"
#include "time/timeepoch.h" #include "time/timeepoch.h"
#include "yyjson.h" #include "yyjson.h"
@@ -32,6 +33,7 @@ typedef struct saveslot_s {
uint8_t dataType; uint8_t dataType;
saveslotcache_t cachedData; saveslotcache_t cachedData;
party_t party; party_t party;
storyflagval_t storyFlags[STORY_FLAG_COUNT_MAX];
} saveslot_t; } saveslot_t;
/** /**
+4
View File
@@ -35,6 +35,8 @@ errorret_t saveSlotCurrentWriteJSON(
); );
memoryCopy(ver1.partyOrder, slot->party.order, sizeof(ver1.partyOrder)); memoryCopy(ver1.partyOrder, slot->party.order, sizeof(ver1.partyOrder));
memoryCopy(ver1.storyFlags, slot->storyFlags, sizeof(ver1.storyFlags));
errorChain(saveSlotVer1WriteJSON(&ver1, doc, object)); errorChain(saveSlotVer1WriteJSON(&ver1, doc, object));
errorOk(); errorOk();
} }
@@ -62,5 +64,7 @@ errorret_t saveSlotCurrentReadJSON(saveslot_t *slot, yyjson_val *object) {
); );
memoryCopy(slot->party.order, ver1.partyOrder, sizeof(slot->party.order)); memoryCopy(slot->party.order, ver1.partyOrder, sizeof(slot->party.order));
memoryCopy(slot->storyFlags, ver1.storyFlags, sizeof(slot->storyFlags));
errorOk(); errorOk();
} }
+20
View File
@@ -46,6 +46,13 @@ errorret_t saveSlotVer1WriteJSON(
writeUInt8Array("partyOrder", slot->partyOrder, PARTY_ACTIVE_SIZE_MAX); writeUInt8Array("partyOrder", slot->partyOrder, PARTY_ACTIVE_SIZE_MAX);
yyjson_mut_val *storyFlagsObj = yyjson_mut_obj_add_obj(doc, object, "storyFlags");
for(storyflag_t flag = 0; flag < STORY_FLAG_COUNT; flag++) {
yyjson_mut_obj_add_uint(
doc, storyFlagsObj, storyGetNameByFlag(flag), slot->storyFlags[flag]
);
}
errorOk(); errorOk();
} }
@@ -102,5 +109,18 @@ errorret_t saveSlotVer1ReadJSON(saveslotver1_t *slot, yyjson_val *object) {
PARTY_ORDER_EMPTY PARTY_ORDER_EMPTY
); );
yyjson_val *storyFlagsObj = yyjson_obj_get(object, "storyFlags");
if(storyFlagsObj != NULL) {
yyjson_obj_iter iter = yyjson_obj_iter_with(storyFlagsObj);
yyjson_val *flagKey;
while((flagKey = yyjson_obj_iter_next(&iter))) {
storyflag_t flag = storyGetFlagByName(yyjson_get_str(flagKey));
if(flag >= STORY_FLAG_COUNT) continue;// Flag no longer exists, ignore
slot->storyFlags[flag] =
(storyflagval_t)yyjson_get_uint(yyjson_obj_iter_get_val(flagKey));
}
}
errorOk(); errorOk();
} }
+7
View File
@@ -10,6 +10,7 @@
#include "time/timeepoch.h" #include "time/timeepoch.h"
#include "save/slot/saveslotver.h" #include "save/slot/saveslotver.h"
#include "rpg/battle/party.h" #include "rpg/battle/party.h"
#include "rpg/story/story.h"
#include "yyjson.h" #include "yyjson.h"
// This schema's own frozen copies of save/slot/saveslot.h's field sizes - // This schema's own frozen copies of save/slot/saveslot.h's field sizes -
@@ -19,6 +20,10 @@
// party arrays below are the exception - saveSlotVer1ReadJSON() checks their // party arrays below are the exception - saveSlotVer1ReadJSON() checks their
// JSON array lengths explicitly, so PARTY_MEMBER_COUNT_MAX/ // JSON array lengths explicitly, so PARTY_MEMBER_COUNT_MAX/
// PARTY_ACTIVE_SIZE_MAX (rpg/battle/party.h) can be referenced directly. // PARTY_ACTIVE_SIZE_MAX (rpg/battle/party.h) can be referenced directly.
// storyFlags is a further exception, for a different reason - it's written
// keyed by flag name (not position), so its on-disk shape is decoupled from
// STORY_FLAG_COUNT_MAX entirely; a save simply loses whatever flags no
// longer resolve by name (see storyGetFlagByName) if that cap ever shrinks.
#define SAVE_SLOT_VER1_NAME_LENGTH 8 #define SAVE_SLOT_VER1_NAME_LENGTH 8
#define SAVE_SLOT_VER1_MAP_NAME_MAX 10 #define SAVE_SLOT_VER1_MAP_NAME_MAX 10
@@ -35,6 +40,8 @@ typedef struct saveslotver1_s {
battlefighter_t partyMembers[PARTY_MEMBER_COUNT_MAX]; battlefighter_t partyMembers[PARTY_MEMBER_COUNT_MAX];
uint8_t partyOrder[PARTY_ACTIVE_SIZE_MAX]; uint8_t partyOrder[PARTY_ACTIVE_SIZE_MAX];
storyflagval_t storyFlags[STORY_FLAG_COUNT_MAX];
} saveslotver1_t; } saveslotver1_t;
/** /**