summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--misc.c60
-rw-r--r--saveload.c148
-rw-r--r--saveload.h146
3 files changed, 197 insertions, 157 deletions
diff --git a/misc.c b/misc.c
index cd8f85f87..25a6f5193 100644
--- a/misc.c
+++ b/misc.c
@@ -661,7 +661,7 @@ static void Load_NAME(void)
static const SaveLoad _game_opt_desc[] = {
// added a new difficulty option (town attitude) in version 4
SLE_CONDARR(GameOptions,diff, SLE_FILE_I16 | SLE_VAR_I32, 17, 0, 3),
- SLE_CONDARR(GameOptions,diff, SLE_FILE_I16 | SLE_VAR_I32, 18, 4, 255),
+ SLE_CONDARR(GameOptions,diff, SLE_FILE_I16 | SLE_VAR_I32, 18, 4, SL_MAX_VERSION),
SLE_VAR(GameOptions,diff_level, SLE_UINT8),
SLE_VAR(GameOptions,currency, SLE_UINT8),
SLE_VAR(GameOptions,kilometers, SLE_UINT8),
@@ -681,26 +681,26 @@ static void SaveLoad_OPTS(void)
static const SaveLoadGlobVarList _date_desc[] = {
- {&_date, SLE_UINT16, 0, 255},
- {&_date_fract, SLE_UINT16, 0, 255},
- {&_tick_counter, SLE_UINT16, 0, 255},
- {&_vehicle_id_ctr_day, SLE_UINT16, 0, 255},
- {&_age_cargo_skip_counter, SLE_UINT8, 0, 255},
- {&_avail_aircraft, SLE_UINT8, 0, 255},
- {&_cur_tileloop_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5},
- {&_cur_tileloop_tile, SLE_UINT32, 6, 255},
- {&_disaster_delay, SLE_UINT16, 0, 255},
- {&_station_tick_ctr, SLE_UINT16, 0, 255},
- {&_random_seeds[0][0], SLE_UINT32, 0, 255},
- {&_random_seeds[0][1], SLE_UINT32, 0, 255},
- {&_cur_town_ctr, SLE_FILE_U8 | SLE_VAR_U32, 0, 9},
- {&_cur_town_ctr, SLE_UINT32, 10, 255},
- {&_cur_player_tick_index, SLE_FILE_U8 | SLE_VAR_UINT, 0, 255},
- {&_next_competitor_start, SLE_FILE_U16 | SLE_VAR_UINT, 0, 255},
- {&_trees_tick_ctr, SLE_UINT8, 0, 255},
- {&_pause, SLE_UINT8, 4, 255},
- {&_cur_town_iter, SLE_UINT32, 11, 255},
- {NULL, 0, 0, 0}
+ SLEG_VAR(_date, SLE_UINT16),
+ SLEG_VAR(_date_fract, SLE_UINT16),
+ SLEG_VAR(_tick_counter, SLE_UINT16),
+ SLEG_VAR(_vehicle_id_ctr_day, SLE_UINT16),
+ SLEG_VAR(_age_cargo_skip_counter,SLE_UINT8),
+ SLEG_VAR(_avail_aircraft, SLE_UINT8),
+ SLEG_CONDVAR(_cur_tileloop_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
+ SLEG_CONDVAR(_cur_tileloop_tile, SLE_UINT32, 6, SL_MAX_VERSION),
+ SLEG_VAR(_disaster_delay, SLE_UINT16),
+ SLEG_VAR(_station_tick_ctr, SLE_UINT16),
+ SLEG_VAR(_random_seeds[0][0], SLE_UINT32),
+ SLEG_VAR(_random_seeds[0][1], SLE_UINT32),
+ SLEG_CONDVAR(_cur_town_ctr, SLE_FILE_U8 | SLE_VAR_U32, 0, 9),
+ SLEG_CONDVAR(_cur_town_ctr, SLE_UINT32, 10, SL_MAX_VERSION),
+ SLEG_VAR(_cur_player_tick_index, SLE_FILE_U8 | SLE_VAR_U32),
+ SLEG_VAR(_next_competitor_start, SLE_FILE_U16 | SLE_VAR_U32),
+ SLEG_VAR(_trees_tick_ctr, SLE_UINT8),
+ SLEG_CONDVAR(_pause, SLE_UINT8, 4, SL_MAX_VERSION),
+ SLEG_CONDVAR(_cur_town_iter, SLE_UINT32, 11, SL_MAX_VERSION),
+ SLEG_END()
};
// Save load date related variables as well as persistent tick counters
@@ -712,12 +712,12 @@ static void SaveLoad_DATE(void)
static const SaveLoadGlobVarList _view_desc[] = {
- {&_saved_scrollpos_x, SLE_FILE_I16 | SLE_VAR_INT, 0, 5},
- {&_saved_scrollpos_x, SLE_INT32, 6, 255},
- {&_saved_scrollpos_y, SLE_FILE_I16 | SLE_VAR_INT, 0, 5},
- {&_saved_scrollpos_y, SLE_INT32, 6, 255},
- {&_saved_scrollpos_zoom, SLE_UINT8, 0, 255},
- {NULL, 0, 0, 0}
+ SLEG_CONDVAR(_saved_scrollpos_x, SLE_FILE_I16 | SLE_VAR_I32, 0, 5),
+ SLEG_CONDVAR(_saved_scrollpos_x, SLE_INT32, 6, SL_MAX_VERSION),
+ SLEG_CONDVAR(_saved_scrollpos_y, SLE_FILE_I16 | SLE_VAR_I32, 0, 5),
+ SLEG_CONDVAR(_saved_scrollpos_y, SLE_INT32, 6, SL_MAX_VERSION),
+ SLEG_VAR(_saved_scrollpos_zoom,SLE_UINT8),
+ SLEG_END()
};
static void SaveLoad_VIEW(void)
@@ -729,9 +729,9 @@ static uint32 _map_dim_x;
static uint32 _map_dim_y;
static const SaveLoadGlobVarList _map_dimensions[] = {
- {&_map_dim_x, SLE_UINT32, 6, 255},
- {&_map_dim_y, SLE_UINT32, 6, 255},
- {NULL, 0, 0, 0}
+ SLEG_CONDVAR(_map_dim_x, SLE_UINT32, 6, SL_MAX_VERSION),
+ SLEG_CONDVAR(_map_dim_y, SLE_UINT32, 6, SL_MAX_VERSION),
+ SLEG_END()
};
static void Save_MAPS(void)
diff --git a/saveload.c b/saveload.c
index dff7fb681..5401e0ace 100644
--- a/saveload.c
+++ b/saveload.c
@@ -536,24 +536,82 @@ static size_t SlCalcObjLength(const SaveLoad *sld)
// Need to determine the length and write a length tag.
for (; sld->cmd != SL_END; sld++) {
- if (sld->cmd < SL_WRITEBYTE) {
+ length += SlCalcObjMemberLength(sld);
+ }
+ return length;
+}
+
+size_t SlCalcObjMemberLength(const SaveLoad *sld)
+{
+ assert(_sl.save);
+
+ switch (sld->cmd) {
+ case SL_VAR:
+ case SL_REF:
+ case SL_ARR:
/* CONDITIONAL saveload types depend on the savegame version */
- if (!SlIsObjectValidInSavegame(sld)) continue;
+ if (!SlIsObjectValidInSavegame(sld)) break;
switch (sld->cmd) {
- case SL_VAR: length += SlCalcConvFileLen(sld->type); break;
- case SL_REF: length += SlCalcRefLen(); break;
- case SL_ARR: length += SlCalcArrayLen(sld->length, sld->type); break;
+ case SL_VAR: return SlCalcConvFileLen(sld->conv);
+ case SL_REF: return SlCalcRefLen();
+ case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
default: NOT_REACHED();
}
- } else if (sld->cmd == SL_WRITEBYTE) {
- length++; // a byte is logically of size 1
- } else if (sld->cmd == SL_INCLUDE) {
- length += SlCalcObjLength(_sl.includes[sld->version_from]);
- } else
- assert(sld->cmd == SL_END);
+ break;
+ case SL_WRITEBYTE: return 1; // a byte is logically of size 1
+ case SL_INCLUDE: return SlCalcObjLength(_sl.includes[sld->version_from]);
+ default: NOT_REACHED();
}
- return length;
+ return 0;
+}
+
+bool SlObjectMember(void *ptr, const SaveLoad *sld)
+{
+ VarType conv = GB(sld->conv, 0, 8);
+ switch (sld->cmd) {
+ case SL_VAR:
+ case SL_REF:
+ case SL_ARR:
+ /* CONDITIONAL saveload types depend on the savegame version */
+ if (!SlIsObjectValidInSavegame(sld)) return false;
+
+ switch (sld->cmd) {
+ case SL_VAR: SlSaveLoadConv(ptr, conv); break;
+ case SL_REF: /* Reference variable, translate */
+ /// @todo XXX - another artificial limitof 65K elements of pointers?
+ if (_sl.save) { // XXX - read/write pointer as uint16? What is with higher indeces?
+ SlWriteUint16(_sl.ref_to_int_proc(*(void**)ptr, conv));
+ } else
+ *(void**)ptr = _sl.int_to_ref_proc(SlReadUint16(), conv);
+ break;
+ case SL_ARR: SlArray(ptr, sld->length, conv); break;
+ default: NOT_REACHED();
+ }
+ break;
+
+ /* SL_WRITEBYTE translates a value of a variable to another one upon
+ * saving or loading.
+ * XXX - variable renaming abuse
+ * game_value: the value of the variable ingame is abused by sld->version_from
+ * file_value: the value of the variable in the savegame is abused by sld->version_to */
+ case SL_WRITEBYTE:
+ if (_sl.save) {
+ SlWriteByte(sld->version_to);
+ } else {
+ *(byte*)ptr = sld->version_from;
+ }
+ break;
+
+ /* SL_INCLUDE loads common code for a type
+ * XXX - variable renaming abuse
+ * include_index: common code to include from _desc_includes[], abused by sld->version_from */
+ case SL_INCLUDE:
+ SlObject(ptr, _sl.includes[sld->version_from]);
+ break;
+ default: NOT_REACHED();
+ }
+ return true;
}
/**
@@ -570,76 +628,24 @@ void SlObject(void *object, const SaveLoad *sld)
}
for (; sld->cmd != SL_END; sld++) {
- void *ptr = (byte*)object + sld->offset;
-
- if (sld->cmd < SL_WRITEBYTE) {
- /* CONDITIONAL saveload types depend on the savegame version */
- if (!SlIsObjectValidInSavegame(sld)) continue;
-
- switch (sld->cmd) {
- case SL_VAR: SlSaveLoadConv(ptr, sld->type); break;
- case SL_REF: /* Reference variable, translate */
- /// @todo XXX - another artificial limitof 65K elements of pointers?
- if (_sl.save) { // XXX - read/write pointer as uint16? What is with higher indeces?
- SlWriteUint16(_sl.ref_to_int_proc(*(void**)ptr, sld->type));
- } else
- *(void**)ptr = _sl.int_to_ref_proc(SlReadUint16(), sld->type);
- break;
- case SL_ARR: SlArray(ptr, sld->length, sld->type); break;
- default: NOT_REACHED();
- }
-
- /* SL_WRITEBYTE translates a value of a variable to another one upon
- * saving or loading.
- * XXX - variable renaming abuse
- * g_value: the value of the variable ingame is abused by sld->version_from
- * f_value: the value of the variable in the savegame is abused by sld->version_to */
- } else if (sld->cmd == SL_WRITEBYTE) {
- if (_sl.save) {
- SlWriteByte(sld->version_to);
- } else
- *(byte*)ptr = sld->version_from;
- /* SL_INCLUDE loads common code for a type
- * XXX - variable renaming abuse
- * include_index: common code to include from _desc_includes[], abused by sld->version_from */
- } else if (sld->cmd == SL_INCLUDE) {
- SlObject(ptr, _sl.includes[sld->version_from]);
- } else
- assert(sld->cmd == SL_END);
+ void *ptr = (byte*)object + sld->s.offset;
+ SlObjectMember(ptr, sld);
}
}
-/** Calculate the length of global variables
- * @param desc The global variable that we want to know the size of
- * @return Returns the length of the sought global object
- */
-static size_t SlCalcGlobListLength(const SaveLoadGlobVarList *desc)
-{
- size_t length = 0;
-
- for (; desc->address != NULL; desc++) {
- // Of course the global variable must exist in the sought savegame version
- if (_sl_version >= desc->from_version && _sl_version <= desc->to_version)
- length += SlCalcConvFileLen(desc->conv);
- }
- return length;
-}
-
/**
* Save or Load (a list of) global variables
* @param desc The global variable that is being loaded or saved
*/
-void SlGlobList(const SaveLoadGlobVarList *desc)
+void SlGlobList(const SaveLoadGlobVarList *sldg)
{
if (_sl.need_length != NL_NONE) {
- SlSetLength(SlCalcGlobListLength(desc));
- if (_sl.need_length == NL_CALCLENGTH)
- return;
+ SlSetLength(SlCalcObjLength((const SaveLoad*)sldg));
+ if (_sl.need_length == NL_CALCLENGTH) return;
}
- for (; desc->address != NULL; desc++) {
- if (_sl_version >= desc->from_version && _sl_version <= desc->to_version)
- SlSaveLoadConv(desc->address, desc->conv);
+ for (; sldg->cmd != SL_END; sldg++) {
+ SlObjectMember(sldg->s.address, (const SaveLoad*)sldg);
}
}
diff --git a/saveload.h b/saveload.h
index bcd6c6ad7..f2f04248d 100644
--- a/saveload.h
+++ b/saveload.h
@@ -23,13 +23,6 @@ void WaitTillSaved(void);
typedef void ChunkSaveLoadProc(void);
typedef void AutolengthProc(void *arg);
-typedef struct SaveLoadGlobVarList {
- void *address;
- byte conv;
- uint16 from_version;
- uint16 to_version;
-} SaveLoadGlobVarList;
-
typedef struct {
uint32 id;
ChunkSaveLoadProc *save_proc;
@@ -73,45 +66,53 @@ enum {
CH_NUM_PRI_LEVELS = 4,
};
-typedef enum VarTypes {
- SLE_FILE_I8 = 0,
- SLE_FILE_U8 = 1,
- SLE_FILE_I16 = 2,
- SLE_FILE_U16 = 3,
- SLE_FILE_I32 = 4,
- SLE_FILE_U32 = 5,
- SLE_FILE_I64 = 6,
- SLE_FILE_U64 = 7,
-
- SLE_FILE_STRINGID = 8,
-// SLE_FILE_IVAR = 8,
-// SLE_FILE_UVAR = 9,
-
- SLE_VAR_I8 = 0 << 4,
- SLE_VAR_U8 = 1 << 4,
- SLE_VAR_I16 = 2 << 4,
- SLE_VAR_U16 = 3 << 4,
- SLE_VAR_I32 = 4 << 4,
- SLE_VAR_U32 = 5 << 4,
- SLE_VAR_I64 = 6 << 4,
- SLE_VAR_U64 = 7 << 4,
-
- SLE_VAR_NULL = 8 << 4, // useful to write zeros in savegame.
-
- SLE_VAR_INT = SLE_VAR_I32,
- SLE_VAR_UINT = SLE_VAR_U32,
-
- SLE_INT8 = SLE_FILE_I8 | SLE_VAR_I8,
- SLE_UINT8 = SLE_FILE_U8 | SLE_VAR_U8,
- SLE_INT16 = SLE_FILE_I16 | SLE_VAR_I16,
- SLE_UINT16 = SLE_FILE_U16 | SLE_VAR_U16,
- SLE_INT32 = SLE_FILE_I32 | SLE_VAR_I32,
- SLE_UINT32 = SLE_FILE_U32 | SLE_VAR_U32,
- SLE_INT64 = SLE_FILE_I64 | SLE_VAR_I64,
- SLE_UINT64 = SLE_FILE_U64 | SLE_VAR_U64,
-
- SLE_STRINGID = SLE_FILE_STRINGID | SLE_VAR_U16,
-} VarType;
+enum VarTypes {
+ /* 4 bytes allocated a maximum of 16 types for NumberType */
+ SLE_FILE_I8 = 0,
+ SLE_FILE_U8 = 1,
+ SLE_FILE_I16 = 2,
+ SLE_FILE_U16 = 3,
+ SLE_FILE_I32 = 4,
+ SLE_FILE_U32 = 5,
+ SLE_FILE_I64 = 6,
+ SLE_FILE_U64 = 7,
+ SLE_FILE_STRINGID = 8, /// StringID offset into strings-array
+ /* 7 more possible primitives */
+
+ /* 4 bytes allocated a maximum of 16 types for NumberType */
+ SLE_VAR_I8 = 0 << 4,
+ SLE_VAR_U8 = 1 << 4,
+ SLE_VAR_I16 = 2 << 4,
+ SLE_VAR_U16 = 3 << 4,
+ SLE_VAR_I32 = 4 << 4,
+ SLE_VAR_U32 = 5 << 4,
+ SLE_VAR_I64 = 6 << 4,
+ SLE_VAR_U64 = 7 << 4,
+ SLE_VAR_NULL = 8 << 4, /// useful to write zeros in savegame.
+ /* 7 more possible primitives */
+
+ /* Shortcut values */
+ SLE_VAR_CHAR = SLE_VAR_I8,
+
+ /* Default combinations of variables. As savegames change, so can variables
+ * and thus it is possible that the saved value and internal size do not
+ * match and you need to specify custom combo. The defaults are listed here */
+ SLE_INT8 = SLE_FILE_I8 | SLE_VAR_I8,
+ SLE_UINT8 = SLE_FILE_U8 | SLE_VAR_U8,
+ SLE_INT16 = SLE_FILE_I16 | SLE_VAR_I16,
+ SLE_UINT16 = SLE_FILE_U16 | SLE_VAR_U16,
+ SLE_INT32 = SLE_FILE_I32 | SLE_VAR_I32,
+ SLE_UINT32 = SLE_FILE_U32 | SLE_VAR_U32,
+ SLE_INT64 = SLE_FILE_I64 | SLE_VAR_I64,
+ SLE_UINT64 = SLE_FILE_U64 | SLE_VAR_U64,
+ SLE_STRINGID = SLE_FILE_STRINGID | SLE_VAR_U16,
+
+ /* Shortcut values */
+ SLE_UINT = SLE_UINT32,
+ SLE_INT = SLE_INT32,
+};
+
+typedef uint32 VarType;
enum SaveLoadTypes {
SL_VAR = 0,
@@ -123,18 +124,31 @@ enum SaveLoadTypes {
SL_END = 15
};
+typedef byte SaveLoadType;
+typedef uint16 OffSetType;
+
/** SaveLoad type struct. Do NOT use this directly but use the SLE_ macros defined just below! */
typedef struct SaveLoad {
- byte cmd; /// the action to take with the saved/loaded type, All types need different action
- VarType type; /// type of the variable to be saved, int
- uint16 offset; /// offset of this variable in the struct (max offset is 65536)
+ SaveLoadType cmd; /// the action to take with the saved/loaded type, All types need different action
+ VarType conv; /// type of the variable to be saved, int
uint16 length; /// (conditional) length of the variable (eg. arrays) (max array size is 65536 elements)
uint16 version_from; /// save/load the variable starting from this savegame version
uint16 version_to; /// save/load the variable until this savegame version
+ /* NOTE: This element either denotes the address of the variable for a global
+ * variable, or the offset within a struct which is then bound to a variable
+ * during runtime. Decision on which one to use is controlled by the function
+ * that is called to save it. address: SlGlobList, offset: SlObject */
+ union {
+ void *address; /// address of variable
+ OffSetType offset; /// offset of variable in the struct (max offset is 65536)
+ } s;
} SaveLoad;
+/* Same as SaveLoad but global variables are used (for better readability); */
+typedef SaveLoad SaveLoadGlobVarList;
+
/* Simple variables, references (pointers) and arrays */
-#define SLE_GENERAL(cmd, base, variable, type, length, from, to) {cmd, type, offsetof(base, variable), length, from, to}
+#define SLE_GENERAL(cmd, base, variable, type, length, from, to) {cmd, type, length, from, to, (void*)offsetof(base, variable)}
#define SLE_CONDVAR(base, variable, type, from, to) SLE_GENERAL(SL_VAR, base, variable, type, 0, from, to)
#define SLE_CONDREF(base, variable, type, from, to) SLE_GENERAL(SL_REF, base, variable, type, 0, from, to)
#define SLE_CONDARR(base, variable, type, length, from, to) SLE_GENERAL(SL_ARR, base, variable, type, length, from, to)
@@ -151,7 +165,7 @@ typedef struct SaveLoad {
#define SLE_INCLUDE(base, variable, include_index) SLE_GENERAL(SL_INCLUDE, base, variable, 0, 0, include_index, 0)
/* The same as the ones at the top, only the offset is given directly; used for unions */
-#define SLE_GENERALX(cmd, offset, type, param1, param2) {cmd, type, (offset), 0, param1, param2}
+#define SLE_GENERALX(cmd, offset, type, param1, param2) {cmd, type, 0, param1, param2, (void*)(offset)}
#define SLE_CONDVARX(offset, type, from, to) SLE_GENERALX(SL_VAR, offset, type, from, to)
#define SLE_CONDREFX(offset, type, from, to) SLE_GENERALX(SL_REF, offset, type, from, to)
@@ -162,7 +176,22 @@ typedef struct SaveLoad {
#define SLE_INCLUDEX(offset, type) SLE_GENERALX(SL_INCLUDE, offset, type, 0, SL_MAX_VERSION)
/* End marker */
-#define SLE_END() {SL_END, 0, 0, 0, 0, 0}
+#define SLE_END() {SL_END, 0, 0, 0, 0, (void*)0}
+
+/* Simple variables, references (pointers) and arrays, but for global variables */
+#define SLEG_GENERAL(cmd, variable, type, length, from, to) {cmd, type, length, from, to, &variable}
+
+#define SLEG_CONDVAR(variable, type, from, to) SLEG_GENERAL(SL_VAR, variable, type, 0, from, to)
+#define SLEG_CONDREF(variable, type, from, to) SLEG_GENERAL(SL_REF, variable, type, 0, from, to)
+#define SLEG_CONDARR(variable, type, length, from, to) SLEG_GENERAL(SL_ARR, variable, type, length, from, to)
+#define SLEG_CONDSTR(variable, type, length, from, to) SLEG_GENERAL(SL_STR, variable, type, length, from, to)
+
+#define SLEG_VAR(variable, type) SLEG_CONDVAR(variable, type, 0, SL_MAX_VERSION)
+#define SLEG_REF(variable, type) SLEG_CONDREF(variable, type, 0, SL_MAX_VERSION)
+#define SLEG_ARR(variable, type) SLEG_CONDARR(variable, type, lengthof(variable), SL_MAX_VERSION)
+#define SLEG_STR(variable, type) SLEG_CONDSTR(variable, type, lengthof(variable), SL_MAX_VERSION)
+
+#define SLEG_END() {SL_END, 0, 0, 0, 0, NULL}
/** Checks if the savegame is below major.minor.
*/
@@ -183,14 +212,19 @@ static inline bool CheckSavegameVersion(uint16 version)
void SlSetArrayIndex(uint index);
int SlIterateArray(void);
-void SlArray(void *array, uint length, VarType conv);
-void SlObject(void *object, const SaveLoad *desc);
+
void SlAutolength(AutolengthProc *proc, void *arg);
uint SlGetFieldLength(void);
-byte SlReadByte(void);
void SlSetLength(size_t length);
+size_t SlCalcObjMemberLength(const SaveLoad *sld);
+
+byte SlReadByte(void);
void SlWriteByte(byte b);
-void SlGlobList(const SaveLoadGlobVarList *desc);
+
+void SlGlobList(const SaveLoadGlobVarList *sldg);
+void SlArray(void *array, uint length, VarType conv);
+void SlObject(void *object, const SaveLoad *sld);
+bool SlObjectMember(void *object, const SaveLoad *sld);
void SaveFileStart(void);
void SaveFileDone(void);