diff --git a/source.list b/source.list
index df35cdd26e..62b1dd3f43 100644
--- a/source.list
+++ b/source.list
@@ -633,6 +633,8 @@ saveload/subsidy_sl.cpp
saveload/town_sl.cpp
saveload/vehicle_sl.cpp
saveload/waypoint_sl.cpp
+saveload/extended_ver_sl.h
+saveload/extended_ver_sl.cpp
# Tables
table/airport_defaults.h
diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp
new file mode 100644
index 0000000000..143167d6ed
--- /dev/null
+++ b/src/saveload/extended_ver_sl.cpp
@@ -0,0 +1,105 @@
+/* $Id$ */
+
+/*
+ * This file is part of OpenTTD.
+ * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
+ * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see .
+ */
+
+/** @file extended_ver_sl.cpp Functions related to handling save/load extended version info. */
+
+#include "../stdafx.h"
+#include "../debug.h"
+#include "extended_ver_sl.h"
+
+#include "../safeguards.h"
+
+uint16 _sl_xv_feature_versions[XSLFI_SIZE]; ///< array of all known feature types and their current versions
+std::vector _sl_xv_discardable_chunk_ids; ///< list of chunks IDs which we can discard if no chunk loader exists
+
+/**
+ * Extended save/load feature test
+ *
+ * First performs a tradional check on the provided @p savegame_version against @p savegame_version_from and @p savegame_version_to.
+ * Then, if the feature set in the constructor is not XSLFI_NULL, also check than the feature version is inclusively bounded by @p min_version and @p max_version,
+ * and return the combination of the two tests using the operator defined in the constructor.
+ * Otherwise just returns the result of the savegame version test
+ */
+bool ExtendedSaveLoadFeatureTest::IsFeaturePresent(uint16 savegame_version, uint16 savegame_version_from, uint16 savegame_version_to) const
+{
+ bool savegame_version_ok = savegame_version >= savegame_version_from && savegame_version <= savegame_version_to;
+
+ ExtendedSaveLoadFeatureIndex feature = static_cast(GB(this->value, 0, 16));
+ if (feature == XSLFI_NULL) return savegame_version_ok;
+
+ uint16 min_version = GB(this->value, 16, 16);
+ uint16 max_version = GB(this->value, 32, 16);
+ ExtendedSaveLoadFeatureTestOperator op = static_cast(GB(this->value, 48, 16));
+ bool feature_ok = SlXvIsFeaturePresent(feature, min_version, max_version);
+
+ switch (op) {
+ case XSLFTO_OR:
+ return savegame_version_ok || feature_ok;
+
+ case XSLFTO_AND:
+ return savegame_version_ok && feature_ok;
+
+ default:
+ NOT_REACHED();
+ return false;
+ }
+}
+
+/**
+ * Returns true if @p feature is present and has a version inclusively bounded by @p min_version and @p max_version
+ */
+bool SlXvIsFeaturePresent(ExtendedSaveLoadFeatureIndex feature, uint16 min_version, uint16 max_version)
+{
+ assert(feature < XSLFI_SIZE);
+ return _sl_xv_feature_versions[feature] >= min_version && _sl_xv_feature_versions[feature] <= max_version;
+}
+
+/**
+ * Resets all extended feature versions to 0
+ */
+void SlXvResetState()
+{
+ memset(_sl_xv_feature_versions, 0, sizeof(_sl_xv_feature_versions));
+}
+
+/**
+ * Resets all extended feature versions to their currently enabled versions, i.e. versions suitable for saving
+ */
+void SlXvSetCurrentState()
+{
+ extern bool _sl_is_ext_version;
+
+ SlXvResetState();
+ _sl_is_ext_version = true;
+
+ // TODO: set versions for currently enabled features here
+}
+
+/**
+ * Check for "special" savegame versions (i.e. known patchpacks) and set correct savegame version, settings, etc.
+ */
+void SlXvCheckSpecialSavegameVersions()
+{
+ extern uint16 _sl_version;
+
+ // TODO: check for savegame versions
+}
+
+/**
+ * Return true if this chunk has been marked as discardable
+ */
+bool SlXvIsChunkDiscardable(uint32 id)
+{
+ for(size_t i = 0; i < _sl_xv_discardable_chunk_ids.size(); i++) {
+ if (_sl_xv_discardable_chunk_ids[i] == id) {
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/src/saveload/extended_ver_sl.h b/src/saveload/extended_ver_sl.h
new file mode 100644
index 0000000000..96b0feddec
--- /dev/null
+++ b/src/saveload/extended_ver_sl.h
@@ -0,0 +1,79 @@
+/* $Id$ */
+
+/*
+ * This file is part of OpenTTD.
+ * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
+ * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see .
+ */
+
+/** @file extended_ver_sl.h Functions/types related to handling save/load extended version info. */
+
+#ifndef EXTENDED_VER_SL_H
+#define EXTENDED_VER_SL_H
+
+#include "../core/bitmath_func.hpp"
+
+#include
+
+/**
+ * List of extended features, each feature has its own (16 bit) version
+ */
+enum ExtendedSaveLoadFeatureIndex {
+ XSLFI_NULL = 0, ///< Unused value, to indicate that no extended feature test is in use
+
+ XSLFI_SIZE, ///< Total count of features, including null feature
+};
+
+extern uint16 _sl_xv_feature_versions[XSLFI_SIZE];
+
+/**
+ * Operator to use when combining traditional savegame number test with an extended feature version test
+ */
+enum ExtendedSaveLoadFeatureTestOperator {
+ XSLFTO_OR = 0, ///< Test if traditional savegame version is in bounds OR extended feature is in version bounds
+ XSLFTO_AND ///< Test if traditional savegame version is in bounds AND extended feature is in version bounds
+};
+
+/**
+ * Structure to describe an extended feature version test, and how it combines with a traditional savegame version test
+ */
+struct ExtendedSaveLoadFeatureTest {
+ private:
+ uint64 value;
+
+ public:
+ ExtendedSaveLoadFeatureTest()
+ : value(0) { }
+
+ ExtendedSaveLoadFeatureTest(ExtendedSaveLoadFeatureTestOperator op, ExtendedSaveLoadFeatureIndex feature, uint16 min_version = 1, uint16 max_version = 0xFFFF)
+ {
+ this->value = 0;
+ SB(this->value, 0, 16, feature);
+ SB(this->value, 16, 16, min_version);
+ SB(this->value, 32, 16, max_version);
+ SB(this->value, 48, 16, op);
+ }
+
+ bool IsFeaturePresent(uint16 savegame_version, uint16 savegame_version_from, uint16 savegame_version_to) const;
+};
+
+bool SlXvIsFeaturePresent(ExtendedSaveLoadFeatureIndex feature, uint16 min_version = 1, uint16 max_version = 0xFFFF);
+
+/**
+ * Returns true if @p feature is missing (i.e. has a version of 0)
+ */
+inline bool SlXvIsFeatureMissing(ExtendedSaveLoadFeatureIndex feature)
+{
+ return !SlXvIsFeaturePresent(feature);
+}
+
+void SlXvResetState();
+
+void SlXvSetCurrentState();
+
+void SlXvCheckSpecialSavegameVersions();
+
+bool SlXvIsChunkDiscardable(uint32 id);
+
+#endif /* EXTENDED_VER_SL_H */
diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp
index bd3c83d139..06836855da 100644
--- a/src/saveload/saveload.cpp
+++ b/src/saveload/saveload.cpp
@@ -48,9 +48,12 @@
#include "saveload_internal.h"
#include "saveload_filter.h"
+#include "extended_ver_sl.h"
#include "../safeguards.h"
+#include
+
/*
* Previous savegame versions, the trunk revision where they were
* introduced and the released version that had that particular
@@ -264,12 +267,14 @@
* 194 26881 1.5.x
*/
extern const uint16 SAVEGAME_VERSION = 194; ///< Current savegame version of OpenTTD.
+const uint16 SAVEGAME_VERSION_EXT = 0x8000; ///< Savegame extension indicator mask
SavegameType _savegame_type; ///< type of savegame we are loading
uint32 _ttdp_version; ///< version of TTDP savegame (if applicable)
uint16 _sl_version; ///< the major savegame version identifier
byte _sl_minor_version; ///< the minor savegame version, DO NOT USE!
+bool _sl_is_ext_version; ///< is this an extended savegame version, with more info in the SLXI chunk?
char _savegame_format[8]; ///< how to compress savegames
bool _do_autosave; ///< are we doing an autosave at the moment?
@@ -414,6 +419,7 @@ struct SaveLoadParams {
static SaveLoadParams _sl; ///< Parameters used for/at saveload.
/* these define the chunks */
+//extern const ChunkHandler _version_ext_chunk_handlers[];
extern const ChunkHandler _gamelog_chunk_handlers[];
extern const ChunkHandler _map_chunk_handlers[];
extern const ChunkHandler _misc_chunk_handlers[];
@@ -450,6 +456,7 @@ extern const ChunkHandler _persistent_storage_chunk_handlers[];
/** Array of all chunks in a savegame, \c NULL terminated. */
static const ChunkHandler * const _chunk_handlers[] = {
+// _version_ext_chunk_handlers, // this should be first, such that it is saved first, as when loading it affects the loading of subsequent chunks
_gamelog_chunk_handlers,
_map_chunk_handlers,
_misc_chunk_handlers,
@@ -503,6 +510,7 @@ static void SlNullPointers()
* during NULLing; especially those that try to get
* pointers from other pools. */
_sl_version = SAVEGAME_VERSION;
+ SlXvSetCurrentState();
DEBUG(sl, 1, "Nulling pointers");
@@ -1414,7 +1422,7 @@ static void SlList(void *list, SLRefType conv)
/** Are we going to save this object or not? */
static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld)
{
- if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false;
+ if (!sld->ext_feature_test.IsFeaturePresent(_sl_version, sld->version_from, sld->version_to)) return false;
if (sld->conv & SLF_NOT_IN_SAVE) return false;
return true;
@@ -1692,7 +1700,7 @@ static void SlLoadChunk(const ChunkHandler *ch)
/**
* Load a chunk of data for checking savegames.
* If the chunkhandler is NULL, the chunk is skipped.
- * @param ch The chunkhandler that will be used for the operation
+ * @param ch The chunkhandler that will be used for the operation, this may be NULL
*/
static void SlLoadCheckChunk(const ChunkHandler *ch)
{
@@ -1706,14 +1714,14 @@ static void SlLoadCheckChunk(const ChunkHandler *ch)
switch (m) {
case CH_ARRAY:
_sl.array_index = 0;
- if (ch->load_check_proc) {
+ if (ch && ch->load_check_proc) {
ch->load_check_proc();
} else {
SlSkipArray();
}
break;
case CH_SPARSE_ARRAY:
- if (ch->load_check_proc) {
+ if (ch && ch->load_check_proc) {
ch->load_check_proc();
} else {
SlSkipArray();
@@ -1726,7 +1734,7 @@ static void SlLoadCheckChunk(const ChunkHandler *ch)
len += SlReadUint16();
_sl.obj_len = len;
endoffs = _sl.reader->GetSize() + len;
- if (ch->load_check_proc) {
+ if (ch && ch->load_check_proc) {
ch->load_check_proc();
} else {
SlSkipBytes(len);
@@ -1840,8 +1848,16 @@ static void SlLoadChunks()
DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
ch = SlFindChunkHandler(id);
- if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
- SlLoadChunk(ch);
+ if (ch == NULL) {
+ if (SlXvIsChunkDiscardable(id)) {
+ DEBUG(sl, 1, "Discarding chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
+ SlLoadCheckChunk(NULL);
+ } else {
+ SlErrorCorrupt("Unknown chunk type");
+ }
+ } else {
+ SlLoadChunk(ch);
+ }
}
}
@@ -1855,7 +1871,7 @@ static void SlLoadCheckChunks()
DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
ch = SlFindChunkHandler(id);
- if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
+ if (ch == NULL && !SlXvIsChunkDiscardable(id)) SlErrorCorrupt("Unknown chunk type");
SlLoadCheckChunk(ch);
}
}
@@ -2511,7 +2527,7 @@ static SaveOrLoadResult SaveFileToDisk(bool threaded)
const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format, &compression);
/* We have written our stuff to memory, now write it to file! */
- uint32 hdr[2] = { fmt->tag, TO_BE32(SAVEGAME_VERSION << 16) };
+ uint32 hdr[2] = { fmt->tag, TO_BE32((SAVEGAME_VERSION | SAVEGAME_VERSION_EXT) << 16) };
_sl.sf->Write((byte*)hdr, sizeof(hdr));
_sl.sf = fmt->init_write(_sl.sf, compression);
@@ -2578,6 +2594,7 @@ static SaveOrLoadResult DoSave(SaveFilter *writer, bool threaded)
_sl.sf = writer;
_sl_version = SAVEGAME_VERSION;
+ SlXvSetCurrentState();
SaveViewportBeforeSaveGame();
SlSaveChunks();
@@ -2629,6 +2646,8 @@ static SaveOrLoadResult DoLoad(LoadFilter *reader, bool load_check)
_load_check_data.checkable = true;
}
+ SlXvResetState();
+
uint32 hdr[2];
if (_sl.lf->Read((byte*)hdr, sizeof(hdr)) != sizeof(hdr)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
@@ -2641,6 +2660,8 @@ static SaveOrLoadResult DoLoad(LoadFilter *reader, bool load_check)
_sl.lf->Reset();
_sl_version = 0;
_sl_minor_version = 0;
+ _sl_is_ext_version = false;
+ SlXvResetState();
/* Try to find the LZO savegame format; it uses 'OTTD' as tag. */
fmt = _saveload_formats;
@@ -2663,7 +2684,14 @@ static SaveOrLoadResult DoLoad(LoadFilter *reader, bool load_check)
* Therefore it is loaded, but never saved (or, it saves a 0 in any scenario). */
_sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
- DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
+ if (_sl_version & SAVEGAME_VERSION_EXT) {
+ _sl_version &= ~SAVEGAME_VERSION_EXT;
+ _sl_is_ext_version = true;
+ } else {
+ SlXvCheckSpecialSavegameVersions();
+ }
+
+ DEBUG(sl, 1, "Loading savegame version %d%s", _sl_version, _sl_is_ext_version ? " (extended)" : "");
/* Is the version higher than the current? */
if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
@@ -2800,6 +2828,8 @@ SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, boo
if (!LoadOldSaveGame(filename)) return SL_REINIT;
_sl_version = 0;
_sl_minor_version = 0;
+ _sl_is_ext_version = false;
+ SlXvResetState();
GamelogStartAction(GLAT_LOAD);
if (!AfterLoadGame()) {
GamelogStopAction();
diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h
index 72c51fa69d..230203b4e7 100644
--- a/src/saveload/saveload.h
+++ b/src/saveload/saveload.h
@@ -14,6 +14,7 @@
#include "../fileio_type.h"
#include "../strings_type.h"
+#include "extended_ver_sl.h"
/** Save or load result codes. */
enum SaveOrLoadResult {
@@ -213,6 +214,7 @@ struct SaveLoad {
* that is called to save it. address: global=true, offset: global=false */
void *address; ///< address of variable OR offset of variable in the struct (max offset is 65536)
size_t size; ///< the sizeof size.
+ ExtendedSaveLoadFeatureTest ext_feature_test; ///< extended feature test
};
/** Same as #SaveLoad but global variables are used (for better readability); */
@@ -226,9 +228,11 @@ typedef SaveLoad SaveLoadGlobVarList;
* @param type Storage of the data in memory and in the savegame.
* @param from First savegame version that has the field.
* @param to Last savegame version that has the field.
+ * @param extver ExtendedSaveLoadFeatureTest to test (along with from and to) which savegames have the field
* @note In general, it is better to use one of the SLE_* macros below.
*/
-#define SLE_GENERAL(cmd, base, variable, type, length, from, to) {false, cmd, type, length, from, to, (void*)cpp_offsetof(base, variable), cpp_sizeof(base, variable)}
+#define SLE_GENERAL_X(cmd, base, variable, type, length, from, to, extver) {false, cmd, type, length, from, to, (void*)cpp_offsetof(base, variable), cpp_sizeof(base, variable), extver}
+#define SLE_GENERAL(cmd, base, variable, type, length, from, to) SLE_GENERAL_X(cmd, base, variable, type, length, from, to, {})
/**
* Storage of a variable in some savegame versions.
@@ -237,8 +241,10 @@ typedef SaveLoad SaveLoadGlobVarList;
* @param type Storage of the data in memory and in the savegame.
* @param from First savegame version that has the field.
* @param to Last savegame version that has the field.
+ * @param extver ExtendedSaveLoadFeatureTest to test (along with from and to) which savegames have the field
*/
-#define SLE_CONDVAR(base, variable, type, from, to) SLE_GENERAL(SL_VAR, base, variable, type, 0, from, to)
+#define SLE_CONDVAR_X(base, variable, type, from, to, extver) SLE_GENERAL_X(SL_VAR, base, variable, type, 0, from, to, extver)
+#define SLE_CONDVAR(base, variable, type, from, to) SLE_CONDVAR_X(base, variable, type, from, to, {})
/**
* Storage of a reference in some savegame versions.
@@ -247,8 +253,10 @@ typedef SaveLoad SaveLoadGlobVarList;
* @param type Type of the reference, a value from #SLRefType.
* @param from First savegame version that has the field.
* @param to Last savegame version that has the field.
+ * @param extver ExtendedSaveLoadFeatureTest to test (along with from and to) which savegames have the field
*/
-#define SLE_CONDREF(base, variable, type, from, to) SLE_GENERAL(SL_REF, base, variable, type, 0, from, to)
+#define SLE_CONDREF_X(base, variable, type, from, to, extver) SLE_GENERAL_X(SL_REF, base, variable, type, 0, from, to, extver)
+#define SLE_CONDREF(base, variable, type, from, to) SLE_CONDREF_X(base, variable, type, from, to, {})
/**
* Storage of an array in some savegame versions.
@@ -258,8 +266,10 @@ typedef SaveLoad SaveLoadGlobVarList;
* @param length Number of elements in the array.
* @param from First savegame version that has the array.
* @param to Last savegame version that has the array.
+ * @param extver ExtendedSaveLoadFeatureTest to test (along with from and to) which savegames have the field
*/
-#define SLE_CONDARR(base, variable, type, length, from, to) SLE_GENERAL(SL_ARR, base, variable, type, length, from, to)
+#define SLE_CONDARR_X(base, variable, type, length, from, to, extver) SLE_GENERAL_X(SL_ARR, base, variable, type, length, from, to, extver)
+#define SLE_CONDARR(base, variable, type, length, from, to) SLE_CONDARR_X(base, variable, type, length, from, to, {})
/**
* Storage of a string in some savegame versions.
@@ -269,8 +279,10 @@ typedef SaveLoad SaveLoadGlobVarList;
* @param length Number of elements in the string (only used for fixed size buffers).
* @param from First savegame version that has the string.
* @param to Last savegame version that has the string.
+ * @param extver ExtendedSaveLoadFeatureTest to test (along with from and to) which savegames have the field
*/
-#define SLE_CONDSTR(base, variable, type, length, from, to) SLE_GENERAL(SL_STR, base, variable, type, length, from, to)
+#define SLE_CONDSTR_X(base, variable, type, length, from, to, extver) SLE_GENERAL_X(SL_STR, base, variable, type, length, from, to, extver)
+#define SLE_CONDSTR(base, variable, type, length, from, to) SLE_CONDSTR_X(base, variable, type, length, from, to, {})
/**
* Storage of a list in some savegame versions.
@@ -279,8 +291,10 @@ typedef SaveLoad SaveLoadGlobVarList;
* @param type Storage of the data in memory and in the savegame.
* @param from First savegame version that has the list.
* @param to Last savegame version that has the list.
+ * @param extver ExtendedSaveLoadFeatureTest to test (along with from and to) which savegames have the field
*/
-#define SLE_CONDLST(base, variable, type, from, to) SLE_GENERAL(SL_LST, base, variable, type, 0, from, to)
+#define SLE_CONDLST_X(base, variable, type, from, to, extver) SLE_GENERAL_X(SL_LST, base, variable, type, 0, from, to, extver)
+#define SLE_CONDLST(base, variable, type, from, to) SLE_CONDLST_X(base, variable, type, from, to, {})
/**
* Storage of a variable in every version of a savegame.
@@ -335,17 +349,19 @@ typedef SaveLoad SaveLoadGlobVarList;
* @param length Length of the empty space.
* @param from First savegame version that has the empty space.
* @param to Last savegame version that has the empty space.
+ * @param extver ExtendedSaveLoadFeatureTest to test (along with from and to) which savegames have empty space
*/
-#define SLE_CONDNULL(length, from, to) SLE_CONDARR(NullStruct, null, SLE_FILE_U8 | SLE_VAR_NULL | SLF_NOT_IN_CONFIG, length, from, to)
+#define SLE_CONDNULL_X(length, from, to, extver) SLE_CONDARR_X(NullStruct, null, SLE_FILE_U8 | SLE_VAR_NULL | SLF_NOT_IN_CONFIG, length, from, to, extver)
+#define SLE_CONDNULL(length, from, to) SLE_CONDNULL_X(length, from, to, {})
/** Translate values ingame to different values in the savegame and vv. */
#define SLE_WRITEBYTE(base, variable, value) SLE_GENERAL(SL_WRITEBYTE, base, variable, 0, 0, value, value)
-#define SLE_VEH_INCLUDE() {false, SL_VEH_INCLUDE, 0, 0, 0, SL_MAX_VERSION, NULL, 0}
-#define SLE_ST_INCLUDE() {false, SL_ST_INCLUDE, 0, 0, 0, SL_MAX_VERSION, NULL, 0}
+#define SLE_VEH_INCLUDE() {false, SL_VEH_INCLUDE, 0, 0, 0, SL_MAX_VERSION, NULL, 0, {}}
+#define SLE_ST_INCLUDE() {false, SL_ST_INCLUDE, 0, 0, 0, SL_MAX_VERSION, NULL, 0, {}}
/** End marker of a struct/class save or load. */
-#define SLE_END() {false, SL_END, 0, 0, 0, 0, NULL, 0}
+#define SLE_END() {false, SL_END, 0, 0, 0, 0, NULL, 0, {}}
/**
* Storage of global simple variables, references (pointers), and arrays.
@@ -354,9 +370,11 @@ typedef SaveLoad SaveLoadGlobVarList;
* @param type Storage of the data in memory and in the savegame.
* @param from First savegame version that has the field.
* @param to Last savegame version that has the field.
+ * @param extver ExtendedSaveLoadFeatureTest to test (along with from and to) which savegames have the field
* @note In general, it is better to use one of the SLEG_* macros below.
*/
-#define SLEG_GENERAL(cmd, variable, type, length, from, to) {true, cmd, type, length, from, to, (void*)&variable, sizeof(variable)}
+#define SLEG_GENERAL_X(cmd, variable, type, length, from, to, extver) {true, cmd, type, length, from, to, (void*)&variable, sizeof(variable), extver}
+#define SLEG_GENERAL(cmd, variable, type, length, from, to) SLEG_GENERAL_X(cmd, variable, type, length, from, to, {})
/**
* Storage of a global variable in some savegame versions.
@@ -364,8 +382,10 @@ typedef SaveLoad SaveLoadGlobVarList;
* @param type Storage of the data in memory and in the savegame.
* @param from First savegame version that has the field.
* @param to Last savegame version that has the field.
+ * @param extver ExtendedSaveLoadFeatureTest to test (along with from and to) which savegames have the field
*/
-#define SLEG_CONDVAR(variable, type, from, to) SLEG_GENERAL(SL_VAR, variable, type, 0, from, to)
+#define SLEG_CONDVAR_X(variable, type, from, to, extver) SLEG_GENERAL_X(SL_VAR, variable, type, 0, from, to, extver)
+#define SLEG_CONDVAR(variable, type, from, to) SLEG_CONDVAR_X(variable, type, from, to, {})
/**
* Storage of a global reference in some savegame versions.
@@ -373,8 +393,10 @@ typedef SaveLoad SaveLoadGlobVarList;
* @param type Storage of the data in memory and in the savegame.
* @param from First savegame version that has the field.
* @param to Last savegame version that has the field.
+ * @param extver ExtendedSaveLoadFeatureTest to test (along with from and to) which savegames have the field
*/
-#define SLEG_CONDREF(variable, type, from, to) SLEG_GENERAL(SL_REF, variable, type, 0, from, to)
+#define SLEG_CONDREF_X(variable, type, from, to, extver) SLEG_GENERAL_X(SL_REF, variable, type, 0, from, to, extver)
+#define SLEG_CONDREF(variable, type, from, to) SLEG_CONDREF_X(variable, type, from, to, {})
/**
* Storage of a global array in some savegame versions.
@@ -383,8 +405,10 @@ typedef SaveLoad SaveLoadGlobVarList;
* @param length Number of elements in the array.
* @param from First savegame version that has the array.
* @param to Last savegame version that has the array.
+ * @param extver ExtendedSaveLoadFeatureTest to test (along with from and to) which savegames have the field
*/
-#define SLEG_CONDARR(variable, type, length, from, to) SLEG_GENERAL(SL_ARR, variable, type, length, from, to)
+#define SLEG_CONDARR_X(variable, type, length, from, to, extver) SLEG_GENERAL_X(SL_ARR, variable, type, length, from, to, extver)
+#define SLEG_CONDARR(variable, type, length, from, to) SLEG_CONDARR_X(variable, type, length, from, to, {})
/**
* Storage of a global string in some savegame versions.
@@ -393,8 +417,10 @@ typedef SaveLoad SaveLoadGlobVarList;
* @param length Number of elements in the string (only used for fixed size buffers).
* @param from First savegame version that has the string.
* @param to Last savegame version that has the string.
+ * @param extver ExtendedSaveLoadFeatureTest to test (along with from and to) which savegames have the field
*/
-#define SLEG_CONDSTR(variable, type, length, from, to) SLEG_GENERAL(SL_STR, variable, type, length, from, to)
+#define SLEG_CONDSTR_X(variable, type, length, from, to, extver) SLEG_GENERAL_X(SL_STR, variable, type, length, from, to, extver)
+#define SLEG_CONDSTR(variable, type, length, from, to) SLEG_CONDSTR_X(variable, type, length, from, to, {})
/**
* Storage of a global list in some savegame versions.
@@ -402,8 +428,10 @@ typedef SaveLoad SaveLoadGlobVarList;
* @param type Storage of the data in memory and in the savegame.
* @param from First savegame version that has the list.
* @param to Last savegame version that has the list.
+ * @param extver ExtendedSaveLoadFeatureTest to test (along with from and to) which savegames have the field
*/
-#define SLEG_CONDLST(variable, type, from, to) SLEG_GENERAL(SL_LST, variable, type, 0, from, to)
+#define SLEG_CONDLST_X(variable, type, from, to, extver) SLEG_GENERAL_X(SL_LST, variable, type, 0, from, to, extver)
+#define SLEG_CONDLST(variable, type, from, to) SLEG_CONDLST_X(variable, type, from, to, {})
/**
* Storage of a global variable in every savegame version.
@@ -445,11 +473,12 @@ typedef SaveLoad SaveLoadGlobVarList;
* @param length Length of the empty space.
* @param from First savegame version that has the empty space.
* @param to Last savegame version that has the empty space.
+ * @param extver ExtendedSaveLoadFeatureTest to test (along with from and to) which savegames have empty space
*/
-#define SLEG_CONDNULL(length, from, to) {true, SL_ARR, SLE_FILE_U8 | SLE_VAR_NULL | SLF_NOT_IN_CONFIG, length, from, to, (void*)NULL}
+#define SLEG_CONDNULL(length, from, to) {true, SL_ARR, SLE_FILE_U8 | SLE_VAR_NULL | SLF_NOT_IN_CONFIG, length, from, to, (void*)NULL, {}}
/** End marker of global variables save or load. */
-#define SLEG_END() {true, SL_END, 0, 0, 0, 0, NULL, 0}
+#define SLEG_END() {true, SL_END, 0, 0, 0, 0, NULL, 0, {}}
/**
* Checks whether the savegame is below \a major.\a minor.
@@ -471,10 +500,10 @@ static inline bool IsSavegameVersionBefore(uint16 major, byte minor = 0)
* @param version_to Highest version number that falls within the range.
* @return Active savegame version falls within the given range.
*/
-static inline bool SlIsObjectCurrentlyValid(uint16 version_from, uint16 version_to)
+static inline bool SlIsObjectCurrentlyValid(uint16 version_from, uint16 version_to, ExtendedSaveLoadFeatureTest ext_feature_test)
{
extern const uint16 SAVEGAME_VERSION;
- if (SAVEGAME_VERSION < version_from || SAVEGAME_VERSION > version_to) return false;
+ if (!ext_feature_test.IsFeaturePresent(SAVEGAME_VERSION, version_from, version_to)) return false;
return true;
}
diff --git a/src/settings.cpp b/src/settings.cpp
index e6754bb905..2ed2f6f26b 100644
--- a/src/settings.cpp
+++ b/src/settings.cpp
@@ -486,7 +486,7 @@ static void IniLoadSettings(IniFile *ini, const SettingDesc *sd, const char *grp
const SettingDescBase *sdb = &sd->desc;
const SaveLoad *sld = &sd->save;
- if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to)) continue;
+ if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to, sld->ext_feature_test)) continue;
/* For settings.xx.yy load the settings from [xx] yy = ? */
s = strchr(sdb->name, '.');
@@ -585,7 +585,7 @@ static void IniSaveSettings(IniFile *ini, const SettingDesc *sd, const char *grp
/* If the setting is not saved to the configuration
* file, just continue with the next setting */
- if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to)) continue;
+ if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to, sld->ext_feature_test)) continue;
if (sld->conv & SLF_NOT_IN_CONFIG) continue;
/* XXX - wtf is this?? (group override?) */
@@ -1381,7 +1381,7 @@ static void HandleOldDiffCustom(bool savegame)
for (uint i = 0; i < options_to_load; i++) {
const SettingDesc *sd = &_settings[i];
/* Skip deprecated options */
- if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
+ if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to, sd->save.ext_feature_test)) continue;
void *var = GetVariableAddress(savegame ? &_settings_game : &_settings_newgame, &sd->save);
Write_ValidateSetting(var, sd, (int32)((i == 4 ? 1000 : 1) * _old_diff_custom[i]));
}
@@ -1839,7 +1839,7 @@ CommandCost CmdChangeSetting(TileIndex tile, DoCommandFlag flags, uint32 p1, uin
const SettingDesc *sd = GetSettingDescription(p1);
if (sd == NULL) return CMD_ERROR;
- if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) return CMD_ERROR;
+ if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to, sd->save.ext_feature_test)) return CMD_ERROR;
if (!sd->IsEditable(true)) return CMD_ERROR;
@@ -2050,13 +2050,13 @@ const SettingDesc *GetSettingFromName(const char *name, uint *i)
/* First check all full names */
for (*i = 0, sd = _settings; sd->save.cmd != SL_END; sd++, (*i)++) {
- if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
+ if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to, sd->save.ext_feature_test)) continue;
if (strcmp(sd->desc.name, name) == 0) return sd;
}
/* Then check the shortcut variant of the name. */
for (*i = 0, sd = _settings; sd->save.cmd != SL_END; sd++, (*i)++) {
- if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
+ if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to, sd->save.ext_feature_test)) continue;
const char *short_name = strchr(sd->desc.name, '.');
if (short_name != NULL) {
short_name++;
@@ -2067,7 +2067,7 @@ const SettingDesc *GetSettingFromName(const char *name, uint *i)
if (strncmp(name, "company.", 8) == 0) name += 8;
/* And finally the company-based settings */
for (*i = 0, sd = _company_settings; sd->save.cmd != SL_END; sd++, (*i)++) {
- if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
+ if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to, sd->save.ext_feature_test)) continue;
if (strcmp(sd->desc.name, name) == 0) return sd;
}
@@ -2161,7 +2161,7 @@ void IConsoleListSettings(const char *prefilter)
IConsolePrintF(CC_WARNING, "All settings with their current value:");
for (const SettingDesc *sd = _settings; sd->save.cmd != SL_END; sd++) {
- if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
+ if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to, sd->save.ext_feature_test)) continue;
if (prefilter != NULL && strstr(sd->desc.name, prefilter) == NULL) continue;
char value[80];
const void *ptr = GetVariableAddress(&GetGameSettings(), &sd->save);
diff --git a/src/table/company_settings.ini b/src/table/company_settings.ini
index 71b95cc393..615e808cb3 100644
--- a/src/table/company_settings.ini
+++ b/src/table/company_settings.ini
@@ -18,8 +18,8 @@ static const SettingDesc _company_settings[] = {
[post-amble]
};
[templates]
-SDT_BOOL = SDT_BOOL($base, $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat),
-SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat),
+SDT_BOOL = SDT_BOOL($base, $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver),
+SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver),
SDT_END = SDT_END()
[defaults]
@@ -34,6 +34,7 @@ load = NULL
from = 0
to = SL_MAX_VERSION
cat = SC_ADVANCED
+extver = {}
diff --git a/src/table/currency_settings.ini b/src/table/currency_settings.ini
index dede8b0fb7..e38349f3df 100644
--- a/src/table/currency_settings.ini
+++ b/src/table/currency_settings.ini
@@ -11,9 +11,9 @@ static const SettingDesc _currency_settings[] = {
[post-amble]
};
[templates]
-SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat),
-SDT_CHR = SDT_CHR($base, $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat),
-SDT_STR = SDT_STR($base, $var, $type, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat),
+SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver),
+SDT_CHR = SDT_CHR($base, $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver),
+SDT_STR = SDT_STR($base, $var, $type, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver),
SDT_END = SDT_END()
[defaults]
@@ -28,6 +28,7 @@ load = NULL
from = 0
to = SL_MAX_VERSION
cat = SC_ADVANCED
+extver = {}
diff --git a/src/table/gameopt_settings.ini b/src/table/gameopt_settings.ini
index 3a47c09e33..593d849ab8 100644
--- a/src/table/gameopt_settings.ini
+++ b/src/table/gameopt_settings.ini
@@ -41,13 +41,13 @@ static const SettingDesc _gameopt_settings[] = {
[post-amble]
};
[templates]
-SDTG_GENERAL = SDTG_GENERAL($name, $sdt_cmd, $sle_cmd, $type, $flags, $guiflags, $var, $length, $def, $min, $max, $interval, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat),
-SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat),
-SDT_NULL = SDT_NULL($length, $from, $to),
-SDTC_OMANY = SDTC_OMANY( $var, $type, $flags, $guiflags, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat),
-SDTG_OMANY = SDTG_OMANY($name, $type, $flags, $guiflags, $var, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat),
-SDT_OMANY = SDT_OMANY($base, $var, $type, $flags, $guiflags, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $load, $cat),
-SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat),
+SDTG_GENERAL = SDTG_GENERAL($name, $sdt_cmd, $sle_cmd, $type, $flags, $guiflags, $var, $length, $def, $min, $max, $interval, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver),
+SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver),
+SDT_NULL = SDT_NULL($length, $from, $to, $extver),
+SDTC_OMANY = SDTC_OMANY( $var, $type, $flags, $guiflags, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver),
+SDTG_OMANY = SDTG_OMANY($name, $type, $flags, $guiflags, $var, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver),
+SDT_OMANY = SDT_OMANY($base, $var, $type, $flags, $guiflags, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $load, $cat, $extver),
+SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver),
SDT_END = SDT_END()
[defaults]
@@ -62,6 +62,7 @@ load = NULL
from = 0
to = SL_MAX_VERSION
cat = SC_ADVANCED
+extver = {}
diff --git a/src/table/misc_settings.ini b/src/table/misc_settings.ini
index 52ca2d16ef..26620318e6 100644
--- a/src/table/misc_settings.ini
+++ b/src/table/misc_settings.ini
@@ -15,12 +15,12 @@ static const SettingDescGlobVarList _misc_settings[] = {
[post-amble]
};
[templates]
-SDTG_LIST = SDTG_LIST($name, $type, $length, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat),
-SDTG_MMANY = SDTG_MMANY($name, $type, $flags, $guiflags, $var, $def, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat),
-SDTG_OMANY = SDTG_OMANY($name, $type, $flags, $guiflags, $var, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat),
-SDTG_STR = SDTG_STR($name, $type, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat),
-SDTG_BOOL = SDTG_BOOL($name, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat),
-SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat),
+SDTG_LIST = SDTG_LIST($name, $type, $length, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver),
+SDTG_MMANY = SDTG_MMANY($name, $type, $flags, $guiflags, $var, $def, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver),
+SDTG_OMANY = SDTG_OMANY($name, $type, $flags, $guiflags, $var, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver),
+SDTG_STR = SDTG_STR($name, $type, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver),
+SDTG_BOOL = SDTG_BOOL($name, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver),
+SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver),
SDTG_END = SDTG_END()
[defaults]
@@ -35,6 +35,7 @@ load = NULL
from = 0
to = SL_MAX_VERSION
cat = SC_ADVANCED
+extver = {}
diff --git a/src/table/settings.h.preamble b/src/table/settings.h.preamble
index 33345bb713..7c0ca8a972 100644
--- a/src/table/settings.h.preamble
+++ b/src/table/settings.h.preamble
@@ -61,76 +61,76 @@ static size_t ConvertLandscape(const char *value);
/* Macros for various objects to go in the configuration file.
* This section is for global variables */
-#define SDTG_GENERAL(name, sdt_cmd, sle_cmd, type, flags, guiflags, var, length, def, min, max, interval, full, str, strhelp, strval, proc, from, to, cat)\
- {NSD_GENERAL(name, def, sdt_cmd, guiflags, min, max, interval, full, str, strhelp, strval, proc, NULL, cat), SLEG_GENERAL(sle_cmd, var, type | flags, length, from, to)}
+#define SDTG_GENERAL(name, sdt_cmd, sle_cmd, type, flags, guiflags, var, length, def, min, max, interval, full, str, strhelp, strval, proc, from, to, cat, extver)\
+ {NSD_GENERAL(name, def, sdt_cmd, guiflags, min, max, interval, full, str, strhelp, strval, proc, NULL, cat), SLEG_GENERAL_X(sle_cmd, var, type | flags, length, from, to, extver)}
-#define SDTG_VAR(name, type, flags, guiflags, var, def, min, max, interval, str, strhelp, strval, proc, from, to, cat)\
- SDTG_GENERAL(name, SDT_NUMX, SL_VAR, type, flags, guiflags, var, 0, def, min, max, interval, NULL, str, strhelp, strval, proc, from, to, cat)
+#define SDTG_VAR(name, type, flags, guiflags, var, def, min, max, interval, str, strhelp, strval, proc, from, to, cat, extver)\
+ SDTG_GENERAL(name, SDT_NUMX, SL_VAR, type, flags, guiflags, var, 0, def, min, max, interval, NULL, str, strhelp, strval, proc, from, to, cat, extver)
-#define SDTG_BOOL(name, flags, guiflags, var, def, str, strhelp, strval, proc, from, to, cat)\
- SDTG_GENERAL(name, SDT_BOOLX, SL_VAR, SLE_BOOL, flags, guiflags, var, 0, def, 0, 1, 0, NULL, str, strhelp, strval, proc, from, to, cat)
+#define SDTG_BOOL(name, flags, guiflags, var, def, str, strhelp, strval, proc, from, to, cat, extver)\
+ SDTG_GENERAL(name, SDT_BOOLX, SL_VAR, SLE_BOOL, flags, guiflags, var, 0, def, 0, 1, 0, NULL, str, strhelp, strval, proc, from, to, cat, extver)
-#define SDTG_LIST(name, type, length, flags, guiflags, var, def, str, strhelp, strval, proc, from, to, cat)\
- SDTG_GENERAL(name, SDT_INTLIST, SL_ARR, type, flags, guiflags, var, length, def, 0, 0, 0, NULL, str, strhelp, strval, proc, from, to, cat)
+#define SDTG_LIST(name, type, length, flags, guiflags, var, def, str, strhelp, strval, proc, from, to, cat, extver)\
+ SDTG_GENERAL(name, SDT_INTLIST, SL_ARR, type, flags, guiflags, var, length, def, 0, 0, 0, NULL, str, strhelp, strval, proc, from, to, cat, extver)
-#define SDTG_STR(name, type, flags, guiflags, var, def, str, strhelp, strval, proc, from, to, cat)\
- SDTG_GENERAL(name, SDT_STRING, SL_STR, type, flags, guiflags, var, lengthof(var), def, 0, 0, 0, NULL, str, strhelp, strval, proc, from, to, cat)
+#define SDTG_STR(name, type, flags, guiflags, var, def, str, strhelp, strval, proc, from, to, cat, extver)\
+ SDTG_GENERAL(name, SDT_STRING, SL_STR, type, flags, guiflags, var, lengthof(var), def, 0, 0, 0, NULL, str, strhelp, strval, proc, from, to, cat, extver)
-#define SDTG_OMANY(name, type, flags, guiflags, var, def, max, full, str, strhelp, strval, proc, from, to, cat)\
- SDTG_GENERAL(name, SDT_ONEOFMANY, SL_VAR, type, flags, guiflags, var, 0, def, 0, max, 0, full, str, strhelp, strval, proc, from, to, cat)
+#define SDTG_OMANY(name, type, flags, guiflags, var, def, max, full, str, strhelp, strval, proc, from, to, cat, extver)\
+ SDTG_GENERAL(name, SDT_ONEOFMANY, SL_VAR, type, flags, guiflags, var, 0, def, 0, max, 0, full, str, strhelp, strval, proc, from, to, cat, extver)
-#define SDTG_MMANY(name, type, flags, guiflags, var, def, full, str, strhelp, strval, proc, from, to, cat)\
- SDTG_GENERAL(name, SDT_MANYOFMANY, SL_VAR, type, flags, guiflags, var, 0, def, 0, 0, 0, full, str, strhelp, strval, proc, from, to, cat)
+#define SDTG_MMANY(name, type, flags, guiflags, var, def, full, str, strhelp, strval, proc, from, to, cat, extver)\
+ SDTG_GENERAL(name, SDT_MANYOFMANY, SL_VAR, type, flags, guiflags, var, 0, def, 0, 0, 0, full, str, strhelp, strval, proc, from, to, cat, extver)
-#define SDTG_NULL(length, from, to)\
- {{"", NULL, {0}, {0}, 0, 0, 0, NULL, STR_NULL, STR_NULL, STR_NULL, NULL, NULL, SC_NONE}, SLEG_NULL(length, from, to)}
+#define SDTG_NULL(length, from, to, extver)\
+ {{"", NULL, {0}, {0}, 0, 0, 0, NULL, STR_NULL, STR_NULL, STR_NULL, NULL, NULL, SC_NONE}, SLEG_NULL_X(length, from, to, extver)}
#define SDTG_END() {{NULL, NULL, {0}, {0}, 0, 0, 0, NULL, STR_NULL, STR_NULL, STR_NULL, NULL, NULL, SC_NONE}, SLEG_END()}
/* Macros for various objects to go in the configuration file.
* This section is for structures where their various members are saved */
-#define SDT_GENERAL(name, sdt_cmd, sle_cmd, type, flags, guiflags, base, var, length, def, min, max, interval, full, str, strhelp, strval, proc, load, from, to, cat)\
- {NSD_GENERAL(name, def, sdt_cmd, guiflags, min, max, interval, full, str, strhelp, strval, proc, load, cat), SLE_GENERAL(sle_cmd, base, var, type | flags, length, from, to)}
+#define SDT_GENERAL(name, sdt_cmd, sle_cmd, type, flags, guiflags, base, var, length, def, min, max, interval, full, str, strhelp, strval, proc, load, from, to, cat, extver)\
+ {NSD_GENERAL(name, def, sdt_cmd, guiflags, min, max, interval, full, str, strhelp, strval, proc, load, cat), SLE_GENERAL_X(sle_cmd, base, var, type | flags, length, from, to, extver)}
-#define SDT_VAR(base, var, type, flags, guiflags, def, min, max, interval, str, strhelp, strval, proc, from, to, cat)\
- SDT_GENERAL(#var, SDT_NUMX, SL_VAR, type, flags, guiflags, base, var, 1, def, min, max, interval, NULL, str, strhelp, strval, proc, NULL, from, to, cat)
+#define SDT_VAR(base, var, type, flags, guiflags, def, min, max, interval, str, strhelp, strval, proc, from, to, cat, extver)\
+ SDT_GENERAL(#var, SDT_NUMX, SL_VAR, type, flags, guiflags, base, var, 1, def, min, max, interval, NULL, str, strhelp, strval, proc, NULL, from, to, cat, extver)
-#define SDT_BOOL(base, var, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat)\
- SDT_GENERAL(#var, SDT_BOOLX, SL_VAR, SLE_BOOL, flags, guiflags, base, var, 1, def, 0, 1, 0, NULL, str, strhelp, strval, proc, NULL, from, to, cat)
+#define SDT_BOOL(base, var, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat, extver)\
+ SDT_GENERAL(#var, SDT_BOOLX, SL_VAR, SLE_BOOL, flags, guiflags, base, var, 1, def, 0, 1, 0, NULL, str, strhelp, strval, proc, NULL, from, to, cat, extver)
-#define SDT_LIST(base, var, type, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat)\
- SDT_GENERAL(#var, SDT_INTLIST, SL_ARR, type, flags, guiflags, base, var, lengthof(((base*)8)->var), def, 0, 0, 0, NULL, str, strhelp, strval, proc, NULL, from, to, cat)
+#define SDT_LIST(base, var, type, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat, extver)\
+ SDT_GENERAL(#var, SDT_INTLIST, SL_ARR, type, flags, guiflags, base, var, lengthof(((base*)8)->var), def, 0, 0, 0, NULL, str, strhelp, strval, proc, NULL, from, to, cat, extver)
-#define SDT_STR(base, var, type, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat)\
- SDT_GENERAL(#var, SDT_STRING, SL_STR, type, flags, guiflags, base, var, lengthof(((base*)8)->var), def, 0, 0, 0, NULL, str, strhelp, strval, proc, NULL, from, to, cat)
+#define SDT_STR(base, var, type, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat, extver)\
+ SDT_GENERAL(#var, SDT_STRING, SL_STR, type, flags, guiflags, base, var, lengthof(((base*)8)->var), def, 0, 0, 0, NULL, str, strhelp, strval, proc, NULL, from, to, cat, extver)
-#define SDT_CHR(base, var, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat)\
- SDT_GENERAL(#var, SDT_STRING, SL_VAR, SLE_CHAR, flags, guiflags, base, var, 1, def, 0, 0, 0, NULL, str, strhelp, strval, proc, NULL, from, to, cat)
+#define SDT_CHR(base, var, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat, extver)\
+ SDT_GENERAL(#var, SDT_STRING, SL_VAR, SLE_CHAR, flags, guiflags, base, var, 1, def, 0, 0, 0, NULL, str, strhelp, strval, proc, NULL, from, to, cat, extver)
-#define SDT_OMANY(base, var, type, flags, guiflags, def, max, full, str, strhelp, strval, proc, from, to, load, cat)\
- SDT_GENERAL(#var, SDT_ONEOFMANY, SL_VAR, type, flags, guiflags, base, var, 1, def, 0, max, 0, full, str, strhelp, strval, proc, load, from, to, cat)
+#define SDT_OMANY(base, var, type, flags, guiflags, def, max, full, str, strhelp, strval, proc, from, to, load, cat, extver)\
+ SDT_GENERAL(#var, SDT_ONEOFMANY, SL_VAR, type, flags, guiflags, base, var, 1, def, 0, max, 0, full, str, strhelp, strval, proc, load, from, to, cat, extver)
-#define SDT_MMANY(base, var, type, flags, guiflags, def, full, str, proc, strhelp, strval, from, to, cat)\
- SDT_GENERAL(#var, SDT_MANYOFMANY, SL_VAR, type, flags, guiflags, base, var, 1, def, 0, 0, 0, full, str, strhelp, strval, proc, NULL, from, to, cat)
+#define SDT_MMANY(base, var, type, flags, guiflags, def, full, str, proc, strhelp, strval, from, to, cat, extver)\
+ SDT_GENERAL(#var, SDT_MANYOFMANY, SL_VAR, type, flags, guiflags, base, var, 1, def, 0, 0, 0, full, str, strhelp, strval, proc, NULL, from, to, cat, extver)
-#define SDT_NULL(length, from, to)\
- {{"", NULL, {0}, {0}, 0, 0, 0, NULL, STR_NULL, STR_NULL, STR_NULL, NULL, NULL, SC_NONE}, SLE_CONDNULL(length, from, to)}
+#define SDT_NULL(length, from, to, extver)\
+ {{"", NULL, {0}, {0}, 0, 0, 0, NULL, STR_NULL, STR_NULL, STR_NULL, NULL, NULL, SC_NONE}, SLE_CONDNULL_X(length, from, to, extver)}
-#define SDTC_VAR(var, type, flags, guiflags, def, min, max, interval, str, strhelp, strval, proc, from, to, cat)\
- SDTG_GENERAL(#var, SDT_NUMX, SL_VAR, type, flags, guiflags, _settings_client.var, 1, def, min, max, interval, NULL, str, strhelp, strval, proc, from, to, cat)
+#define SDTC_VAR(var, type, flags, guiflags, def, min, max, interval, str, strhelp, strval, proc, from, to, cat, extver)\
+ SDTG_GENERAL(#var, SDT_NUMX, SL_VAR, type, flags, guiflags, _settings_client.var, 1, def, min, max, interval, NULL, str, strhelp, strval, proc, from, to, cat, extver)
-#define SDTC_BOOL(var, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat)\
- SDTG_GENERAL(#var, SDT_BOOLX, SL_VAR, SLE_BOOL, flags, guiflags, _settings_client.var, 1, def, 0, 1, 0, NULL, str, strhelp, strval, proc, from, to, cat)
+#define SDTC_BOOL(var, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat, extver)\
+ SDTG_GENERAL(#var, SDT_BOOLX, SL_VAR, SLE_BOOL, flags, guiflags, _settings_client.var, 1, def, 0, 1, 0, NULL, str, strhelp, strval, proc, from, to, cat, extver)
-#define SDTC_LIST(var, type, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat)\
- SDTG_GENERAL(#var, SDT_INTLIST, SL_ARR, type, flags, guiflags, _settings_client.var, lengthof(_settings_client.var), def, 0, 0, 0, NULL, str, strhelp, strval, proc, from, to, cat)
+#define SDTC_LIST(var, type, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat, extver)\
+ SDTG_GENERAL(#var, SDT_INTLIST, SL_ARR, type, flags, guiflags, _settings_client.var, lengthof(_settings_client.var), def, 0, 0, 0, NULL, str, strhelp, strval, proc, from, to, cat, extver)
-#define SDTC_STR(var, type, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat)\
- SDTG_GENERAL(#var, SDT_STRING, SL_STR, type, flags, guiflags, _settings_client.var, lengthof(_settings_client.var), def, 0, 0, 0, NULL, str, strhelp, strval, proc, from, to, cat)
+#define SDTC_STR(var, type, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat, extver)\
+ SDTG_GENERAL(#var, SDT_STRING, SL_STR, type, flags, guiflags, _settings_client.var, lengthof(_settings_client.var), def, 0, 0, 0, NULL, str, strhelp, strval, proc, from, to, cat, extver)
-#define SDTC_OMANY(var, type, flags, guiflags, def, max, full, str, strhelp, strval, proc, from, to, cat)\
- SDTG_GENERAL(#var, SDT_ONEOFMANY, SL_VAR, type, flags, guiflags, _settings_client.var, 1, def, 0, max, 0, full, str, strhelp, strval, proc, from, to, cat)
+#define SDTC_OMANY(var, type, flags, guiflags, def, max, full, str, strhelp, strval, proc, from, to, cat, extver)\
+ SDTG_GENERAL(#var, SDT_ONEOFMANY, SL_VAR, type, flags, guiflags, _settings_client.var, 1, def, 0, max, 0, full, str, strhelp, strval, proc, from, to, cat, extver)
#define SDT_END() {{NULL, NULL, {0}, {0}, 0, 0, 0, NULL, STR_NULL, STR_NULL, STR_NULL, NULL, NULL, SC_NONE}, SLE_END()}
diff --git a/src/table/settings.ini b/src/table/settings.ini
index f314f21e92..3256e20dab 100644
--- a/src/table/settings.ini
+++ b/src/table/settings.ini
@@ -64,19 +64,19 @@ const SettingDesc _settings[] = {
[post-amble]
};
[templates]
-SDTG_BOOL = SDTG_BOOL($name, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat),
-SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat),
-SDTG_OMANY = SDTG_OMANY($name, $type, $flags, $guiflags, $var, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat),
-SDTC_BOOL = SDTC_BOOL( $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat),
-SDTC_LIST = SDTC_LIST( $var, $type, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat),
-SDTC_OMANY = SDTC_OMANY( $var, $type, $flags, $guiflags, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat),
-SDTC_STR = SDTC_STR( $var, $type, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat),
-SDTC_VAR = SDTC_VAR( $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat),
-SDT_BOOL = SDT_BOOL($base, $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat),
-SDT_OMANY = SDT_OMANY($base, $var, $type, $flags, $guiflags, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $load, $cat),
-SDT_STR = SDT_STR($base, $var, $type, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat),
-SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat),
-SDT_NULL = SDT_NULL($length, $from, $to),
+SDTG_BOOL = SDTG_BOOL($name, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver),
+SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver),
+SDTG_OMANY = SDTG_OMANY($name, $type, $flags, $guiflags, $var, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver),
+SDTC_BOOL = SDTC_BOOL( $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver),
+SDTC_LIST = SDTC_LIST( $var, $type, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver),
+SDTC_OMANY = SDTC_OMANY( $var, $type, $flags, $guiflags, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver),
+SDTC_STR = SDTC_STR( $var, $type, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver),
+SDTC_VAR = SDTC_VAR( $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver),
+SDT_BOOL = SDT_BOOL($base, $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver),
+SDT_OMANY = SDT_OMANY($base, $var, $type, $flags, $guiflags, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $load, $cat, $extver),
+SDT_STR = SDT_STR($base, $var, $type, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver),
+SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver),
+SDT_NULL = SDT_NULL($length, $from, $to, $extver),
SDT_END = SDT_END()
[defaults]
@@ -91,6 +91,7 @@ load = NULL
from = 0
to = SL_MAX_VERSION
cat = SC_ADVANCED
+extver = {}
diff --git a/src/table/win32_settings.ini b/src/table/win32_settings.ini
index 1e0c9ad023..71b8499d2b 100644
--- a/src/table/win32_settings.ini
+++ b/src/table/win32_settings.ini
@@ -17,8 +17,8 @@ static const SettingDescGlobVarList _win32_settings[] = {
};
#endif /* WIN32 */
[templates]
-SDTG_BOOL = SDTG_BOOL($name, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat),
-SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat),
+SDTG_BOOL = SDTG_BOOL($name, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver),
+SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver),
SDTG_END = SDTG_END()
[defaults]
@@ -33,6 +33,7 @@ load = NULL
from = 0
to = SL_MAX_VERSION
cat = SC_ADVANCED
+extver = {}
diff --git a/src/table/window_settings.ini b/src/table/window_settings.ini
index ad77423d9d..cfa2f76d5a 100644
--- a/src/table/window_settings.ini
+++ b/src/table/window_settings.ini
@@ -12,8 +12,8 @@ static const SettingDesc _window_settings[] = {
[post-amble]
};
[templates]
-SDT_BOOL = SDT_BOOL($base, $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat),
-SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat),
+SDT_BOOL = SDT_BOOL($base, $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver),
+SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver),
SDT_END = SDT_END()
[defaults]
@@ -29,6 +29,7 @@ load = NULL
from = 0
to = SL_MAX_VERSION
cat = SC_ADVANCED
+extver = {}