diff --git a/src/saveload/linkgraph_sl.cpp b/src/saveload/linkgraph_sl.cpp index 207a6e3670..cd6376c9ad 100644 --- a/src/saveload/linkgraph_sl.cpp +++ b/src/saveload/linkgraph_sl.cpp @@ -69,8 +69,8 @@ const SaveLoad *GetLinkGraphJobDesc() int setting = 0; const SettingDesc *desc = GetSettingDescription(setting); - while (desc->save.cmd != SL_END) { - if (desc->desc.name != nullptr && strncmp(desc->desc.name, prefix, prefixlen) == 0) { + while (desc != nullptr) { + if (desc->name != nullptr && strncmp(desc->name, prefix, prefixlen) == 0) { SaveLoad sl = desc->save; char *&address = reinterpret_cast(sl.address); address -= offset_gamesettings; @@ -90,7 +90,7 @@ const SaveLoad *GetLinkGraphJobDesc() int i = 0; do { saveloads.push_back(job_desc[i++]); - } while (saveloads[saveloads.size() - 1].cmd != SL_END); + } while (saveloads.back().cmd != SL_END); } return &saveloads[0]; diff --git a/src/script/api/script_gamesettings.cpp b/src/script/api/script_gamesettings.cpp index 12435d253f..f96048e153 100644 --- a/src/script/api/script_gamesettings.cpp +++ b/src/script/api/script_gamesettings.cpp @@ -18,7 +18,7 @@ /* static */ bool ScriptGameSettings::IsValid(const char *setting) { const SettingDesc *sd = GetSettingFromName(setting); - return sd != nullptr && sd->desc.cmd != SDT_STDSTRING; + return sd != nullptr && sd->cmd != SDT_STDSTRING; } /* static */ int32 ScriptGameSettings::GetValue(const char *setting) @@ -28,7 +28,7 @@ const SettingDesc *sd = GetSettingFromName(setting); void *ptr = GetVariableAddress(&_settings_game, &sd->save); - if (sd->desc.cmd == SDT_BOOLX) return *(bool*)ptr; + if (sd->cmd == SDT_BOOLX) return *(bool*)ptr; return (int32)ReadValue(ptr, sd->save.conv); } @@ -40,7 +40,7 @@ const SettingDesc *sd = GetSettingFromName(setting); if ((sd->save.conv & SLF_NO_NETWORK_SYNC) != 0) return false; - if (sd->desc.cmd != SDT_BOOLX && sd->desc.cmd != SDT_NUMX) return false; + if (sd->cmd != SDT_BOOLX && sd->cmd != SDT_NUMX) return false; return ScriptObject::DoCommand(0, GetSettingIndex(sd), value, CMD_CHANGE_SETTING); } diff --git a/src/settings.cpp b/src/settings.cpp index 1876bceab7..c744a7d7a5 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -103,11 +103,33 @@ typedef std::list ErrorList; static ErrorList _settings_error_list; ///< Errors while loading minimal settings. -typedef void SettingDescProc(IniFile *ini, const SettingDesc *desc, const char *grpname, void *object, bool only_startup); +typedef void SettingDescProc(IniFile *ini, const SettingTable &desc, const char *grpname, void *object, bool only_startup); typedef void SettingDescProcList(IniFile *ini, const char *grpname, StringList &list); static bool IsSignedVarMemType(VarType vt); +/** + * Get the setting at the given index into the settings table. + * @param index The index to look for. + * @return The setting at the given index, or nullptr when the index is invalid. + */ +const SettingDesc *GetSettingDescription(uint index) +{ + if (index >= _settings.size()) return nullptr; + return &_settings.begin()[index]; +} + +/** + * Get the setting at the given index into the company settings table. + * @param index The index to look for. + * @return The setting at the given index, or nullptr when the index is invalid. + */ +static const SettingDesc *GetCompanySettingDescription(uint index) +{ + if (index >= _company_settings.size()) return nullptr; + return &_company_settings.begin()[index]; +} + /** * Groups in openttd.cfg that are actually lists. */ @@ -373,7 +395,7 @@ static void MakeManyOfMany(char *buf, const char *last, const char *many, uint32 * @param orig_str input string that will be parsed based on the type of desc * @return return the parsed value of the setting */ -static const void *StringToVal(const SettingDescBase *desc, const char *orig_str) +static const void *StringToVal(const SettingDesc *desc, const char *orig_str) { const char *str = orig_str == nullptr ? "" : orig_str; @@ -460,7 +482,7 @@ static bool ValidateEnumSetting(const SettingDescBase *sdb, int32 val) */ static void Write_ValidateSetting(void *ptr, const SettingDesc *sd, int32 val) { - const SettingDescBase *sdb = &sd->desc; + const SettingDesc *sdb = sd; if (sdb->cmd != SDT_BOOLX && sdb->cmd != SDT_NUMX && @@ -538,11 +560,11 @@ static void Write_ValidateStdString(void *ptr, const SettingDesc *sd, const char case SLE_VAR_STR: case SLE_VAR_STRQ: if (p != nullptr) { - if (sd->desc.max != 0 && strlen(p) >= sd->desc.max) { + if (sd->max != 0 && strlen(p) >= sd->max) { /* In case a maximum length is imposed by the setting, the length * includes the '\0' termination for network transfer purposes. * Also ensure the string is valid after chopping of some bytes. */ - std::string str(p, sd->desc.max - 1); + std::string str(p, sd->max - 1); dst->assign(str_validate(str, SVS_NONE)); } else { dst->assign(p); @@ -559,23 +581,23 @@ static void Write_ValidateStdString(void *ptr, const SettingDesc *sd, const char /** * Load values from a group of an IniFile structure into the internal representation * @param ini pointer to IniFile structure that holds administrative information - * @param sd pointer to SettingDesc structure whose internally pointed variables will + * @param settings_table table with SettingDesc structures whose internally pointed variables will * be given values * @param grpname the group of the IniFile to search in for the new values * @param object pointer to the object been loaded * @param only_startup load only the startup settings set */ -static void IniLoadSettings(IniFile *ini, const SettingDesc *sd, const char *grpname, void *object, bool only_startup) +static void IniLoadSettings(IniFile *ini, const SettingTable &settings_table, const char *grpname, void *object, bool only_startup) { IniGroup *group; IniGroup *group_def = ini->GetGroup(grpname); - for (; sd->save.cmd != SL_END; sd++) { - const SettingDescBase *sdb = &sd->desc; - const SaveLoad *sld = &sd->save; + for (auto &sd : settings_table) { + const SettingDesc *sdb = &sd; + const SaveLoad *sld = &sd.save; if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to, sld->ext_feature_test)) continue; - if (sd->desc.startup != only_startup) continue; + if (sd.startup != only_startup) continue; IniItem *item; if (sdb->flags & SGF_NO_NEWGAME) { item = nullptr; @@ -612,11 +634,11 @@ static void IniLoadSettings(IniFile *ini, const SettingDesc *sd, const char *grp case SDT_NUMX: case SDT_ONEOFMANY: case SDT_MANYOFMANY: - Write_ValidateSetting(ptr, sd, (int32)(size_t)p); + Write_ValidateSetting(ptr, &sd, (int32)(size_t)p); break; case SDT_STDSTRING: - Write_ValidateStdString(ptr, sd, (const char *)p); + Write_ValidateStdString(ptr, &sd, (const char *)p); break; case SDT_INTLIST: { @@ -627,8 +649,8 @@ static void IniLoadSettings(IniFile *ini, const SettingDesc *sd, const char *grp /* Use default */ LoadIntList((const char*)sdb->def, ptr, sld->length, GetVarMemType(sld->conv)); - } else if (sd->desc.proc_cnvt != nullptr) { - sd->desc.proc_cnvt((const char*)p); + } else if (sd.proc_cnvt != nullptr) { + sd.proc_cnvt((const char*)p); } break; } @@ -649,16 +671,16 @@ static void IniLoadSettings(IniFile *ini, const SettingDesc *sd, const char *grp * values are reloaded when saving). If settings indeed have changed, we get * these and save them. */ -static void IniSaveSettings(IniFile *ini, const SettingDesc *sd, const char *grpname, void *object, bool) +static void IniSaveSettings(IniFile *ini, const SettingTable &settings_table, const char *grpname, void *object, bool) { IniGroup *group_def = nullptr, *group; IniItem *item; char buf[512]; void *ptr; - for (; sd->save.cmd != SL_END; sd++) { - const SettingDescBase *sdb = &sd->desc; - const SaveLoad *sld = &sd->save; + for (auto &sd : settings_table) { + const SettingDesc *sdb = &sd; + const SaveLoad *sld = &sd.save; /* If the setting is not saved to the configuration * file, just continue with the next setting */ @@ -837,13 +859,13 @@ void IniSaveWindowSettings(IniFile *ini, const char *grpname, void *desc) */ bool SettingDesc::IsEditable(bool do_command) const { - if (!do_command && !(this->save.conv & SLF_NO_NETWORK_SYNC) && _networking && !(_network_server || _network_settings_access) && !(this->desc.flags & SGF_PER_COMPANY)) return false; - if ((this->desc.flags & SGF_NETWORK_ONLY) && !_networking && _game_mode != GM_MENU) return false; - if ((this->desc.flags & SGF_NO_NETWORK) && _networking) return false; - if ((this->desc.flags & SGF_NEWGAME_ONLY) && + if (!do_command && !(this->save.conv & SLF_NO_NETWORK_SYNC) && _networking && !(_network_server || _network_settings_access) && !(this->flags & SGF_PER_COMPANY)) return false; + if ((this->flags & SGF_NETWORK_ONLY) && !_networking && _game_mode != GM_MENU) return false; + if ((this->flags & SGF_NO_NETWORK) && _networking) return false; + if ((this->flags & SGF_NEWGAME_ONLY) && (_game_mode == GM_NORMAL || - (_game_mode == GM_EDITOR && !(this->desc.flags & SGF_SCENEDIT_TOO)))) return false; - if ((this->desc.flags & SGF_SCENEDIT_ONLY) && _game_mode != GM_EDITOR) return false; + (_game_mode == GM_EDITOR && !(this->flags & SGF_SCENEDIT_TOO)))) return false; + if ((this->flags & SGF_SCENEDIT_ONLY) && _game_mode != GM_EDITOR) return false; return true; } @@ -853,7 +875,7 @@ bool SettingDesc::IsEditable(bool do_command) const */ SettingType SettingDesc::GetType() const { - if (this->desc.flags & SGF_PER_COMPANY) return ST_COMPANY; + if (this->flags & SGF_PER_COMPANY) return ST_COMPANY; return (this->save.conv & SLF_NOT_IN_SAVE) ? ST_CLIENT : ST_GAME; } @@ -1890,7 +1912,7 @@ static void HandleOldDiffCustom(bool savegame) } for (uint i = 0; i < options_to_load; i++) { - const SettingDesc *sd = &_settings[i]; + const SettingDesc *sd = GetSettingDescription(i); /* Skip deprecated options */ 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); @@ -2174,9 +2196,9 @@ static void GRFSaveConfig(IniFile *ini, const char *grpname, const GRFConfig *li /* Common handler for saving/loading variables to the configuration file */ static void HandleSettingDescs(IniFile *ini, SettingDescProc *proc, SettingDescProcList *proc_list, bool only_startup = false) { - proc(ini, (const SettingDesc*)_misc_settings, "misc", nullptr, only_startup); + proc(ini, _misc_settings, "misc", nullptr, only_startup); #if defined(_WIN32) && !defined(DEDICATED) - proc(ini, (const SettingDesc*)_win32_settings, "win32", nullptr, only_startup); + proc(ini, _win32_settings, "win32", nullptr, only_startup); #endif /* _WIN32 */ proc(ini, _settings, "patches", &_settings_newgame, only_startup); @@ -2324,12 +2346,6 @@ void DeleteGRFPresetFromConfig(const char *config_name) delete ini; } -const SettingDesc *GetSettingDescription(uint index) -{ - if (index >= lengthof(_settings)) return nullptr; - return &_settings[index]; -} - /** * Network-safe changing of settings (server-only). * @param tile unused @@ -2356,21 +2372,21 @@ CommandCost CmdChangeSetting(TileIndex tile, DoCommandFlag flags, uint32 p1, uin int32 oldval = (int32)ReadValue(var, sd->save.conv); int32 newval = (int32)p2; - SCOPE_INFO_FMT([=], "CmdChangeSetting: %s, %d -> %d", sd->desc.name, oldval, newval); + SCOPE_INFO_FMT([=], "CmdChangeSetting: %s, %d -> %d", sd->name, oldval, newval); Write_ValidateSetting(var, sd, newval); newval = (int32)ReadValue(var, sd->save.conv); if (oldval == newval) return CommandCost(); - if (sd->desc.proc != nullptr && !sd->desc.proc(newval)) { + if (sd->proc != nullptr && !sd->proc(newval)) { WriteValue(var, sd->save.conv, (int64)oldval); return CommandCost(); } - if (sd->desc.flags & SGF_NO_NETWORK) { + if (sd->flags & SGF_NO_NETWORK) { GamelogStartAction(GLAT_SETTING); - GamelogSetting(sd->desc.name, oldval, newval); + GamelogSetting(sd->name, oldval, newval); GamelogStopAction(); } @@ -2387,7 +2403,7 @@ const char *GetSettingNameByIndex(uint32 idx) const SettingDesc *sd = GetSettingDescription(idx); if (sd == nullptr) return nullptr; - return sd->desc.name; + return sd->name; } /** @@ -2402,8 +2418,8 @@ const char *GetSettingNameByIndex(uint32 idx) */ CommandCost CmdChangeCompanySetting(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { - if (p1 >= lengthof(_company_settings)) return CMD_ERROR; - const SettingDesc *sd = &_company_settings[p1]; + const SettingDesc *sd = GetCompanySettingDescription(p1); + if (sd == nullptr) return CMD_ERROR; if (flags & DC_EXEC) { void *var = GetVariableAddress(&Company::Get(_current_company)->settings, &sd->save); @@ -2411,14 +2427,14 @@ CommandCost CmdChangeCompanySetting(TileIndex tile, DoCommandFlag flags, uint32 int32 oldval = (int32)ReadValue(var, sd->save.conv); int32 newval = (int32)p2; - SCOPE_INFO_FMT([=], "CmdChangeCompanySetting: %s, %d -> %d", sd->desc.name, oldval, newval); + SCOPE_INFO_FMT([=], "CmdChangeCompanySetting: %s, %d -> %d", sd->name, oldval, newval); Write_ValidateSetting(var, sd, newval); newval = (int32)ReadValue(var, sd->save.conv); if (oldval == newval) return CommandCost(); - if (sd->desc.proc != nullptr && !sd->desc.proc(newval)) { + if (sd->proc != nullptr && !sd->proc(newval)) { WriteValue(var, sd->save.conv, (int64)oldval); return CommandCost(); } @@ -2431,9 +2447,9 @@ CommandCost CmdChangeCompanySetting(TileIndex tile, DoCommandFlag flags, uint32 const char *GetCompanySettingNameByIndex(uint32 idx) { - if (idx >= lengthof(_company_settings)) return nullptr; + if (idx >= _company_settings.size()) return nullptr; - return _company_settings[idx].desc.name; + return GetCompanySettingDescription(idx)->name; } /** @@ -2443,8 +2459,19 @@ const char *GetCompanySettingNameByIndex(uint32 idx) */ uint GetSettingIndex(const SettingDesc *sd) { - assert((sd->desc.flags & SGF_PER_COMPANY) == 0); - return sd - _settings; + assert(sd != nullptr && (sd->flags & SGF_PER_COMPANY) == 0); + return sd - _settings.begin(); +} + +/** + * Get the index of the company setting with this description. + * @param sd the setting to get the index for. + * @return the index of the setting to be used for CMD_CHANGE_COMPANY_SETTING. + */ +static uint GetCompanySettingIndex(const SettingDesc *sd) +{ + assert(sd != nullptr && (sd->flags & SGF_PER_COMPANY) != 0); + return sd - _company_settings.begin(); } /** @@ -2456,16 +2483,16 @@ uint GetSettingIndex(const SettingDesc *sd) */ bool SetSettingValue(const SettingDesc *sd, int32 value, bool force_newgame) { - if ((sd->desc.flags & SGF_PER_COMPANY) != 0) { + if ((sd->flags & SGF_PER_COMPANY) != 0) { if (Company::IsValidID(_local_company) && _game_mode != GM_MENU) { - return DoCommandP(0, sd - _company_settings, value, CMD_CHANGE_COMPANY_SETTING); - } else if (sd->desc.flags & SGF_NO_NEWGAME) { + return DoCommandP(0, GetCompanySettingIndex(sd), value, CMD_CHANGE_COMPANY_SETTING); + } else if (sd->flags & SGF_NO_NEWGAME) { return false; } void *var = GetVariableAddress(&_settings_client.company, &sd->save); Write_ValidateSetting(var, sd, value); - if (sd->desc.proc != nullptr) sd->desc.proc((int32)ReadValue(var, sd->save.conv)); + if (sd->proc != nullptr) sd->proc((int32)ReadValue(var, sd->save.conv)); return true; } @@ -2473,7 +2500,7 @@ bool SetSettingValue(const SettingDesc *sd, int32 value, bool force_newgame) * (if any) to change. Also *hack*hack* we update the _newgame version * of settings because changing a company-based setting in a game also * changes its defaults. At least that is the convention we have chosen */ - bool no_newgame = sd->desc.flags & SGF_NO_NEWGAME; + bool no_newgame = sd->flags & SGF_NO_NEWGAME; if (no_newgame && _game_mode == GM_MENU) return false; if (sd->save.conv & SLF_NO_NETWORK_SYNC) { void *var = GetVariableAddress(&GetGameSettings(), &sd->save); @@ -2483,7 +2510,7 @@ bool SetSettingValue(const SettingDesc *sd, int32 value, bool force_newgame) void *var2 = GetVariableAddress(&_settings_newgame, &sd->save); Write_ValidateSetting(var2, sd, value); } - if (sd->desc.proc != nullptr) sd->desc.proc((int32)ReadValue(var, sd->save.conv)); + if (sd->proc != nullptr) sd->proc((int32)ReadValue(var, sd->save.conv)); SetWindowClassesDirty(WC_GAME_OPTIONS); @@ -2512,10 +2539,9 @@ bool SetSettingValue(const SettingDesc *sd, int32 value, bool force_newgame) void SetDefaultCompanySettings(CompanyID cid) { Company *c = Company::Get(cid); - const SettingDesc *sd; - for (sd = _company_settings; sd->save.cmd != SL_END; sd++) { - void *var = GetVariableAddress(&c->settings, &sd->save); - Write_ValidateSetting(var, sd, (int32)(size_t)sd->desc.def); + for (auto &sd : _company_settings) { + void *var = GetVariableAddress(&c->settings, &sd.save); + Write_ValidateSetting(var, &sd, (int32)(size_t)sd.def); } } @@ -2524,13 +2550,12 @@ void SetDefaultCompanySettings(CompanyID cid) */ void SyncCompanySettings() { - const SettingDesc *sd; uint i = 0; - for (sd = _company_settings; sd->save.cmd != SL_END; sd++, i++) { - const void *old_var = GetVariableAddress(&Company::Get(_current_company)->settings, &sd->save); - const void *new_var = GetVariableAddress(&_settings_client.company, &sd->save); - uint32 old_value = (uint32)ReadValue(old_var, sd->save.conv); - uint32 new_value = (uint32)ReadValue(new_var, sd->save.conv); + for (auto &sd : _company_settings) { + const void *old_var = GetVariableAddress(&Company::Get(_current_company)->settings, &sd.save); + const void *new_var = GetVariableAddress(&_settings_client.company, &sd.save); + uint32 old_value = (uint32)ReadValue(old_var, sd.save.conv); + uint32 new_value = (uint32)ReadValue(new_var, sd.save.conv); if (old_value != new_value) NetworkSendCommand(0, i, new_value, 0, CMD_CHANGE_COMPANY_SETTING, nullptr, nullptr, _local_company, 0); } } @@ -2542,9 +2567,7 @@ void SyncCompanySettings() */ uint GetCompanySettingIndex(const char *name) { - const SettingDesc *sd = GetSettingFromName(name); - assert(sd != nullptr && (sd->desc.flags & SGF_PER_COMPANY) != 0); - return sd - _company_settings; + return GetCompanySettingIndex(GetSettingFromName(name)); } /** @@ -2564,7 +2587,7 @@ bool SetSettingValue(const SettingDesc *sd, const char *value, bool force_newgam void *ptr = GetVariableAddress((_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game, &sd->save); Write_ValidateStdString(ptr, sd, value); - if (sd->desc.proc != nullptr) sd->desc.proc(0); + if (sd->proc != nullptr) sd->proc(0); if (_save_config) SaveToConfig(); return true; @@ -2581,29 +2604,29 @@ bool SetSettingValue(const SettingDesc *sd, const char *value, bool force_newgam const SettingDesc *GetSettingFromName(const char *name, bool ignore_version) { /* First check all full names */ - for (const SettingDesc *sd = _settings; sd->save.cmd != SL_END; sd++) { - if (sd->desc.name == nullptr) continue; - if (!ignore_version && !SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to, sd->save.ext_feature_test)) continue; - if (strcmp(sd->desc.name, name) == 0) return sd; + for (auto &sd : _settings) { + if (sd.name == nullptr) continue; + if (!ignore_version && !SlIsObjectCurrentlyValid(sd.save.version_from, sd.save.version_to, sd.save.ext_feature_test)) continue; + if (strcmp(sd.name, name) == 0) return &sd; } /* Then check the shortcut variant of the name. */ - for (const SettingDesc *sd = _settings; sd->save.cmd != SL_END; sd++) { - if (sd->desc.name == nullptr) continue; - if (!ignore_version && !SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to, sd->save.ext_feature_test)) continue; - const char *short_name = strchr(sd->desc.name, '.'); + for (auto &sd : _settings) { + if (sd.name == nullptr) continue; + if (!ignore_version && !SlIsObjectCurrentlyValid(sd.save.version_from, sd.save.version_to, sd.save.ext_feature_test)) continue; + const char *short_name = strchr(sd.name, '.'); if (short_name != nullptr) { short_name++; - if (strcmp(short_name, name) == 0) return sd; + if (strcmp(short_name, name) == 0) return &sd; } } if (strncmp(name, "company.", 8) == 0) name += 8; /* And finally the company-based settings */ - for (const SettingDesc *sd = _company_settings; sd->save.cmd != SL_END; sd++) { - if (sd->desc.name == nullptr) continue; - if (!ignore_version && !SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to, sd->save.ext_feature_test)) continue; - if (strcmp(sd->desc.name, name) == 0) return sd; + for (auto &sd : _company_settings) { + if (sd.name == nullptr) continue; + if (!ignore_version && !SlIsObjectCurrentlyValid(sd.save.version_from, sd.save.version_to, sd.save.ext_feature_test)) continue; + if (strcmp(sd.name, name) == 0) return &sd; } return nullptr; @@ -2615,13 +2638,13 @@ void IConsoleSetSetting(const char *name, const char *value, bool force_newgame) { const SettingDesc *sd = GetSettingFromName(name); - if (sd == nullptr || ((sd->desc.flags & SGF_NO_NEWGAME) && (_game_mode == GM_MENU || force_newgame))) { + if (sd == nullptr || ((sd->flags & SGF_NO_NEWGAME) && (_game_mode == GM_MENU || force_newgame))) { IConsolePrintF(CC_WARNING, "'%s' is an unknown setting.", name); return; } bool success; - if (sd->desc.cmd == SDT_STDSTRING) { + if (sd->cmd == SDT_STDSTRING) { success = SetSettingValue(sd, value, force_newgame); } else { uint32 val; @@ -2662,24 +2685,24 @@ void IConsoleGetSetting(const char *name, bool force_newgame) const SettingDesc *sd = GetSettingFromName(name); const void *ptr; - if (sd == nullptr || ((sd->desc.flags & SGF_NO_NEWGAME) && (_game_mode == GM_MENU || force_newgame))) { + if (sd == nullptr || ((sd->flags & SGF_NO_NEWGAME) && (_game_mode == GM_MENU || force_newgame))) { IConsolePrintF(CC_WARNING, "'%s' is an unknown setting.", name); return; } ptr = GetVariableAddress((_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game, &sd->save); - if (sd->desc.cmd == SDT_STDSTRING) { + if (sd->cmd == SDT_STDSTRING) { IConsolePrintF(CC_WARNING, "Current value for '%s' is: '%s'", name, reinterpret_cast(ptr)->c_str()); } else { bool show_min_max = true; - int64 min_value = sd->desc.min; - int64 max_value = sd->desc.max; - if (sd->desc.flags & SGF_ENUM) { + int64 min_value = sd->min; + int64 max_value = sd->max; + if (sd->flags & SGF_ENUM) { min_value = INT64_MAX; max_value = INT64_MIN; int count = 0; - for (const SettingDescEnumEntry *enumlist = sd->desc.enumlist; enumlist != nullptr && enumlist->str != STR_NULL; enumlist++) { + for (const SettingDescEnumEntry *enumlist = sd->enumlist; enumlist != nullptr && enumlist->str != STR_NULL; enumlist++) { if (enumlist->val < min_value) min_value = enumlist->val; if (enumlist->val > max_value) max_value = enumlist->val; count++; @@ -2689,15 +2712,15 @@ void IConsoleGetSetting(const char *name, bool force_newgame) show_min_max = false; } } - if (sd->desc.cmd == SDT_BOOLX) { + if (sd->cmd == SDT_BOOLX) { seprintf(value, lastof(value), (*(const bool*)ptr != 0) ? "on" : "off"); } else { - seprintf(value, lastof(value), sd->desc.min < 0 ? "%d" : "%u", (int32)ReadValue(ptr, sd->save.conv)); + seprintf(value, lastof(value), sd->min < 0 ? "%d" : "%u", (int32)ReadValue(ptr, sd->save.conv)); } if (show_min_max) { IConsolePrintF(CC_WARNING, "Current value for '%s' is: '%s' (min: %s" OTTD_PRINTF64 ", max: " OTTD_PRINTF64 ")", - name, value, (sd->desc.flags & SGF_0ISDISABLED) ? "(0) " : "", min_value, max_value); + name, value, (sd->flags & SGF_0ISDISABLED) ? "(0) " : "", min_value, max_value); } else { IConsolePrintF(CC_WARNING, "Current value for '%s' is: '%s'", name, value); @@ -2714,21 +2737,21 @@ 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, sd->save.ext_feature_test)) continue; - if (prefilter != nullptr && strstr(sd->desc.name, prefilter) == nullptr) continue; - if ((sd->desc.flags & SGF_NO_NEWGAME) && _game_mode == GM_MENU) continue; + for (auto &sd : _settings) { + if (!SlIsObjectCurrentlyValid(sd.save.version_from, sd.save.version_to, sd.save.ext_feature_test)) continue; + if (prefilter != nullptr && strstr(sd.name, prefilter) == nullptr) continue; + if ((sd.flags & SGF_NO_NEWGAME) && _game_mode == GM_MENU) continue; char value[80]; - const void *ptr = GetVariableAddress(&GetGameSettings(), &sd->save); + const void *ptr = GetVariableAddress(&GetGameSettings(), &sd.save); - if (sd->desc.cmd == SDT_BOOLX) { + if (sd.cmd == SDT_BOOLX) { seprintf(value, lastof(value), (*(const bool *)ptr != 0) ? "on" : "off"); - } else if (sd->desc.cmd == SDT_STDSTRING) { + } else if (sd.cmd == SDT_STDSTRING) { seprintf(value, lastof(value), "%s", reinterpret_cast(ptr)->c_str()); } else { - seprintf(value, lastof(value), sd->desc.min < 0 ? "%d" : "%u", (int32)ReadValue(ptr, sd->save.conv)); + seprintf(value, lastof(value), sd.min < 0 ? "%d" : "%u", (int32)ReadValue(ptr, sd.save.conv)); } - IConsolePrintF(CC_DEFAULT, "%s = %s", sd->desc.name, value); + IConsolePrintF(CC_DEFAULT, "%s = %s", sd.name, value); } IConsolePrintF(CC_WARNING, "Use 'setting' command to change a value"); @@ -2760,51 +2783,50 @@ static void LoadSettingsXref(const SettingDesc *osd, void *object) { /** * Save and load handler for settings, except for those which go in the PATX chunk - * @param osd SettingDesc struct containing all information + * @param settings SettingDesc struct containing all information * @param object can be either nullptr in which case we load global variables or * a pointer to a struct which is getting saved */ -static void LoadSettings(const SettingDesc *osd, void *object) +static void LoadSettings(const SettingTable &settings, void *object) { extern SaveLoadVersion _sl_version; - for (; osd->save.cmd != SL_END; osd++) { - if (osd->patx_name != nullptr) continue; - const SaveLoad *sld = &osd->save; - if (osd->xref.target != nullptr) { - if (sld->ext_feature_test.IsFeaturePresent(_sl_version, sld->version_from, sld->version_to)) LoadSettingsXref(osd, object); + for (auto &osd : settings) { + if (osd.patx_name != nullptr) continue; + const SaveLoad *sld = &osd.save; + if (osd.xref.target != nullptr) { + if (sld->ext_feature_test.IsFeaturePresent(_sl_version, sld->version_from, sld->version_to)) LoadSettingsXref(&osd, object); continue; } void *ptr = GetVariableAddress(object, sld); if (!SlObjectMember(ptr, sld)) continue; - if (IsNumericType(sld->conv)) Write_ValidateSetting(ptr, osd, ReadValue(ptr, sld->conv)); + if (IsNumericType(sld->conv)) Write_ValidateSetting(ptr, &osd, ReadValue(ptr, sld->conv)); } } /** * Save and load handler for settings, except for those which go in the PATX chunk - * @param sd SettingDesc struct containing all information + * @param settings SettingDesc struct containing all information * @param object can be either nullptr in which case we load global variables or * a pointer to a struct which is getting saved */ -static void SaveSettings(const SettingDesc *sd, void *object) +static void SaveSettings(const SettingTable &settings, void *object) { /* We need to write the CH_RIFF header, but unfortunately can't call * SlCalcLength() because we have a different format. So do this manually */ - const SettingDesc *i; size_t length = 0; - for (i = sd; i->save.cmd != SL_END; i++) { - if (i->patx_name != nullptr) continue; - if (i->xref.target != nullptr) continue; - length += SlCalcObjMemberLength(object, &i->save); + for (auto &sd : settings) { + if (sd.patx_name != nullptr) continue; + if (sd.xref.target != nullptr) continue; + length += SlCalcObjMemberLength(object, &sd.save); } SlSetLength(length); - for (i = sd; i->save.cmd != SL_END; i++) { - if (i->patx_name != nullptr) continue; - void *ptr = GetVariableAddress(object, &i->save); - SlObjectMember(ptr, &i->save); + for (auto &sd : settings) { + if (sd.patx_name != nullptr) continue; + void *ptr = GetVariableAddress(object, &sd.save); + SlObjectMember(ptr, &sd.save); } } @@ -2833,17 +2855,17 @@ static std::vector _sorted_patx_settings; * This is to enable efficient lookup of settings by name * This is stored in _sorted_patx_settings */ -static void MakeSettingsPatxList(const SettingDesc *sd) +static void MakeSettingsPatxList(const SettingTable &settings) { - static const SettingDesc *previous = nullptr; + static const SettingTable *previous = nullptr; - if (sd == previous) return; - previous = sd; + if (&settings == previous) return; + previous = &settings; _sorted_patx_settings.clear(); - for (const SettingDesc *desc = sd; desc->save.cmd != SL_END; desc++) { - if (desc->patx_name == nullptr) continue; - _sorted_patx_settings.push_back(desc); + for (auto &sd : settings) { + if (sd.patx_name == nullptr) continue; + _sorted_patx_settings.push_back(&sd); } std::sort(_sorted_patx_settings.begin(), _sorted_patx_settings.end(), [](const SettingDesc *a, const SettingDesc *b) { @@ -2889,9 +2911,9 @@ static const SaveLoad _settings_ext_save_desc[] = { * @param object can be either nullptr in which case we load global variables or * a pointer to a struct which is getting saved */ -static void LoadSettingsPatx(const SettingDesc *sd, void *object) +static void LoadSettingsPatx(const SettingTable &settings, void *object) { - MakeSettingsPatxList(sd); + MakeSettingsPatxList(settings); SettingsExtLoad current_setting; @@ -2938,7 +2960,7 @@ static void LoadSettingsPatx(const SettingDesc *sd, void *object) * @param object can be either nullptr in which case we load global variables or * a pointer to a struct which is getting saved */ -static void SaveSettingsPatx(const SettingDesc *sd, void *object) +static void SaveSettingsPatx(const SettingTable &settings, void *object) { SettingsExtSave current_setting; @@ -2949,12 +2971,12 @@ static void SaveSettingsPatx(const SettingDesc *sd, void *object) std::vector settings_to_add; size_t length = 8; - for (const SettingDesc *desc = sd; desc->save.cmd != SL_END; desc++) { - if (desc->patx_name == nullptr) continue; - uint32 setting_length = (uint32)SlCalcObjMemberLength(object, &desc->save); + for (auto &sd : settings) { + if (sd.patx_name == nullptr) continue; + uint32 setting_length = (uint32)SlCalcObjMemberLength(object, &sd.save); if (!setting_length) continue; - current_setting.name = desc->patx_name; + current_setting.name = sd.patx_name; // add length of setting header length += SlCalcObjLength(¤t_setting, _settings_ext_save_desc); @@ -2963,7 +2985,7 @@ static void SaveSettingsPatx(const SettingDesc *sd, void *object) length += setting_length; // duplicate copy made for compiler backwards compatibility - SettingToAdd new_setting = { desc, setting_length }; + SettingToAdd new_setting = { &sd, setting_length }; settings_to_add.push_back(new_setting); } SlSetLength(length); @@ -3046,9 +3068,9 @@ void LoadSettingsPlyx(bool skip) const SettingDesc *setting = nullptr; // not many company settings, so perform a linear scan - for (const SettingDesc *desc = _company_settings; desc->save.cmd != SL_END; desc++) { - if (desc->patx_name != nullptr && strcmp(desc->patx_name, current_setting.name) == 0) { - setting = desc; + for (auto &sd : _company_settings) { + if (sd.patx_name != nullptr && strcmp(sd.patx_name, current_setting.name) == 0) { + setting = &sd; break; } } @@ -3094,12 +3116,12 @@ void SaveSettingsPlyx() length += 12; companies_count++; uint32 setting_count = 0; - for (const SettingDesc *desc = _company_settings; desc->save.cmd != SL_END; desc++) { - if (desc->patx_name == nullptr) continue; - uint32 setting_length = (uint32)SlCalcObjMemberLength(&(c->settings), &desc->save); + for (auto &sd : _company_settings) { + if (sd.patx_name == nullptr) continue; + uint32 setting_length = (uint32)SlCalcObjMemberLength(&(c->settings), &sd.save); if (!setting_length) continue; - current_setting.name = desc->patx_name; + current_setting.name = sd.patx_name; // add length of setting header length += SlCalcObjLength(¤t_setting, _settings_ext_save_desc); @@ -3125,17 +3147,17 @@ void SaveSettingsPlyx() SlWriteUint32(company_setting_counts[index]); // setting count index++; - for (const SettingDesc *desc = _company_settings; desc->save.cmd != SL_END; desc++) { - if (desc->patx_name == nullptr) continue; - uint32 setting_length = (uint32)SlCalcObjMemberLength(&(c->settings), &desc->save); + for (auto &sd : _company_settings) { + if (sd.patx_name == nullptr) continue; + uint32 setting_length = (uint32)SlCalcObjMemberLength(&(c->settings), &sd.save); if (!setting_length) continue; current_setting.flags = 0; - current_setting.name = desc->patx_name; + current_setting.name = sd.patx_name; current_setting.setting_length = setting_length; SlObject(¤t_setting, _settings_plyx_desc); - void *ptr = GetVariableAddress(&(c->settings), &desc->save); - SlObjectMember(ptr, &desc->save); + void *ptr = GetVariableAddress(&(c->settings), &sd.save); + SlObjectMember(ptr, &sd.save); } } } diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index d13c77b8de..ef0fa162f7 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -865,12 +865,12 @@ private: */ StringID SettingEntry::GetHelpText() const { - StringID str = this->setting->desc.str_help; - if (this->setting->desc.guiproc != nullptr) { + StringID str = this->setting->str_help; + if (this->setting->guiproc != nullptr) { SettingOnGuiCtrlData data; data.type = SOGCT_DESCRIPTION_TEXT; data.text = str; - if (this->setting->desc.guiproc(data)) { + if (this->setting->guiproc(data)) { str = data.text; } } @@ -1087,7 +1087,7 @@ void SettingEntry::Init(byte level) /* Sets the given setting entry to its default value */ void SettingEntry::ResetAll() { - int32 default_value = ReadValue(&this->setting->desc.def, this->setting->save.conv); + int32 default_value = ReadValue(&this->setting->def, this->setting->save.conv); SetSettingValue(this->setting, default_value); } @@ -1131,8 +1131,8 @@ bool SettingEntry::IsVisibleByRestrictionMode(RestrictionMode mode) const GameSettings *settings_ptr = &GetGameSettings(); const SettingDesc *sd = this->setting; - if (mode == RM_BASIC) return (this->setting->desc.cat & SC_BASIC_LIST) != 0; - if (mode == RM_ADVANCED) return (this->setting->desc.cat & SC_ADVANCED_LIST) != 0; + if (mode == RM_BASIC) return (this->setting->cat & SC_BASIC_LIST) != 0; + if (mode == RM_ADVANCED) return (this->setting->cat & SC_ADVANCED_LIST) != 0; /* Read the current value. */ const void *var = ResolveVariableAddress(settings_ptr, sd); @@ -1144,7 +1144,7 @@ bool SettingEntry::IsVisibleByRestrictionMode(RestrictionMode mode) const /* This entry shall only be visible, if the value deviates from its default value. */ /* Read the default value. */ - filter_value = ReadValue(&sd->desc.def, sd->save.conv); + filter_value = ReadValue(&sd->def, sd->save.conv); } else { assert(mode == RM_CHANGED_AGAINST_NEW); /* This entry shall only be visible, if the value deviates from @@ -1169,7 +1169,7 @@ bool SettingEntry::IsVisibleByRestrictionMode(RestrictionMode mode) const */ bool SettingEntry::UpdateFilterState(SettingFilter &filter, bool force_visible) { - if (this->setting->desc.flags & SGF_NO_NEWGAME && _game_mode == GM_MENU) { + if (this->setting->flags & SGF_NO_NEWGAME && _game_mode == GM_MENU) { SETBITS(this->flags, SEF_FILTERED); return false; } @@ -1182,10 +1182,8 @@ bool SettingEntry::UpdateFilterState(SettingFilter &filter, bool force_visible) /* Process the search text filter for this item. */ filter.string.ResetState(); - const SettingDescBase *sdb = &sd->desc; - SetDParam(0, STR_EMPTY); - filter.string.AddLine(sdb->str); + filter.string.AddLine(sd->str); filter.string.AddLine(this->GetHelpText()); visible = filter.string.GetState(); @@ -1208,7 +1206,7 @@ bool SettingEntry::UpdateFilterState(SettingFilter &filter, bool force_visible) static const void *ResolveVariableAddress(const GameSettings *settings_ptr, const SettingDesc *sd) { - if ((sd->desc.flags & SGF_PER_COMPANY) != 0) { + if ((sd->flags & SGF_PER_COMPANY) != 0) { if (Company::IsValidID(_local_company) && _game_mode != GM_MENU) { return GetVariableAddress(&Company::Get(_local_company)->settings, &sd->save); } else { @@ -1226,36 +1224,35 @@ static const void *ResolveVariableAddress(const GameSettings *settings_ptr, cons */ void SettingEntry::SetValueDParams(uint first_param, int32 value, std::unique_ptr &tempdata) const { - const SettingDescBase *sdb = &this->setting->desc; - if (sdb->cmd == SDT_BOOLX) { + if (this->setting->cmd == SDT_BOOLX) { SetDParam(first_param++, value != 0 ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF); - } else if (sdb->flags & SGF_DEC1SCALE) { + } else if (this->setting->flags & SGF_DEC1SCALE) { tempdata.reset(new SettingEntry::SetValueDParamsTempData()); double scale = std::exp2(((double)value) / 10); int log = -std::min(0, (int)std::floor(std::log10(scale)) - 2); int64 args_array[] = { value, (int64)(scale * std::pow(10.f, (float)log)), log }; StringParameters tmp_params(args_array); - GetStringWithArgs(tempdata->buffer, sdb->str_val, &tmp_params, lastof(tempdata->buffer)); + GetStringWithArgs(tempdata->buffer, this->setting->str_val, &tmp_params, lastof(tempdata->buffer)); SetDParam(first_param++, STR_JUST_RAW_STRING); SetDParamStr(first_param++, tempdata->buffer); } else { - if ((sdb->flags & SGF_ENUM) != 0) { + if ((this->setting->flags & SGF_ENUM) != 0) { StringID str = STR_UNDEFINED; - for (const SettingDescEnumEntry *enumlist = sdb->enumlist; enumlist != nullptr && enumlist->str != STR_NULL; enumlist++) { + for (const SettingDescEnumEntry *enumlist = this->setting->enumlist; enumlist != nullptr && enumlist->str != STR_NULL; enumlist++) { if (enumlist->val == value) { str = enumlist->str; break; } } SetDParam(first_param++, str); - } else if ((sdb->flags & SGF_MULTISTRING) != 0) { - SetDParam(first_param++, sdb->str_val - sdb->min + value); - } else if ((sdb->flags & SGF_DISPLAY_ABS) != 0) { - SetDParam(first_param++, sdb->str_val + ((value >= 0) ? 1 : 0)); + } else if ((this->setting->flags & SGF_MULTISTRING) != 0) { + SetDParam(first_param++, this->setting->str_val - this->setting->min + value); + } else if ((this->setting->flags & SGF_DISPLAY_ABS) != 0) { + SetDParam(first_param++, this->setting->str_val + ((value >= 0) ? 1 : 0)); value = abs(value); } else { - SetDParam(first_param++, sdb->str_val + ((value == 0 && (sdb->flags & SGF_0ISDISABLED) != 0) ? 1 : 0)); + SetDParam(first_param++, this->setting->str_val + ((value == 0 && (this->setting->flags & SGF_0ISDISABLED) != 0) ? 1 : 0)); } SetDParam(first_param++, value); } @@ -1272,7 +1269,6 @@ void SettingEntry::SetValueDParams(uint first_param, int32 value, std::unique_pt void SettingEntry::DrawSetting(GameSettings *settings_ptr, int left, int right, int y, bool highlight) const { const SettingDesc *sd = this->setting; - const SettingDescBase *sdb = &sd->desc; const void *var = ResolveVariableAddress(settings_ptr, sd); int state = this->flags & SEF_BUTTONS_MASK; @@ -1287,16 +1283,16 @@ void SettingEntry::DrawSetting(GameSettings *settings_ptr, int left, int right, SetDParam(0, highlight ? STR_ORANGE_STRING1_WHITE : STR_ORANGE_STRING1_LTBLUE); int32 value = (int32)ReadValue(var, sd->save.conv); - if (sdb->cmd == SDT_BOOLX) { + if (sd->cmd == SDT_BOOLX) { /* Draw checkbox for boolean-value either on/off */ DrawBoolButton(buttons_left, button_y, value != 0, editable); - } else if ((sdb->flags & (SGF_MULTISTRING | SGF_ENUM)) != 0) { + } else if ((sd->flags & (SGF_MULTISTRING | SGF_ENUM)) != 0) { /* Draw [v] button for settings of an enum-type */ DrawDropDownButton(buttons_left, button_y, COLOUR_YELLOW, state != 0, editable); } else { /* Draw [<][>] boxes for settings of an integer-type */ DrawArrowButtons(buttons_left, button_y, COLOUR_YELLOW, state, - editable && value != (sdb->flags & SGF_0ISDISABLED ? 0 : sdb->min), editable && (uint32)value != sdb->max); + editable && value != (sd->flags & SGF_0ISDISABLED ? 0 : sd->min), editable && (uint32)value != sd->max); } this->DrawSettingString(text_left, text_right, y + (SETTING_HEIGHT - FONT_HEIGHT_NORMAL) / 2, highlight, value); } @@ -1304,10 +1300,9 @@ void SettingEntry::DrawSetting(GameSettings *settings_ptr, int left, int right, void SettingEntry::DrawSettingString(uint left, uint right, int y, bool highlight, int32 value) const { const SettingDesc *sd = this->setting; - const SettingDescBase *sdb = &sd->desc; std::unique_ptr tempdata; this->SetValueDParams(1, value, tempdata); - DrawString(left, right, y, sdb->str, highlight ? TC_WHITE : TC_LIGHT_BLUE); + DrawString(left, right, y, sd->str, highlight ? TC_WHITE : TC_LIGHT_BLUE); } /* == CargoDestPerCargoSettingEntry methods == */ @@ -1323,8 +1318,7 @@ void CargoDestPerCargoSettingEntry::Init(byte level) void CargoDestPerCargoSettingEntry::DrawSettingString(uint left, uint right, int y, bool highlight, int32 value) const { const SettingDesc *sd = this->setting; - const SettingDescBase *sdb = &sd->desc; - assert(sdb->str == STR_CONFIG_SETTING_DISTRIBUTION_PER_CARGO); + assert(sd->str == STR_CONFIG_SETTING_DISTRIBUTION_PER_CARGO); SetDParam(0, CargoSpec::Get(this->cargo)->name); SetDParam(1, highlight ? STR_ORANGE_STRING1_WHITE : STR_ORANGE_STRING1_LTBLUE); std::unique_ptr tempdata; @@ -2439,7 +2433,7 @@ struct GameSettingsWindow : Window { DrawString(r.left, r.right, y, STR_CONFIG_SETTING_TYPE); y += FONT_HEIGHT_NORMAL; - int32 default_value = ReadValue(&sd->desc.def, sd->save.conv); + int32 default_value = ReadValue(&sd->def, sd->save.conv); std::unique_ptr tempdata; this->last_clicked->SetValueDParams(0, default_value, tempdata); DrawString(r.left, r.right, y, STR_CONFIG_SETTING_DEFAULT_VALUE); @@ -2544,8 +2538,7 @@ struct GameSettingsWindow : Window { int32 value = (int32)ReadValue(var, sd->save.conv); /* clicked on the icon on the left side. Either scroller, bool on/off or dropdown */ - if (x < SETTING_BUTTON_WIDTH && (sd->desc.flags & (SGF_MULTISTRING | SGF_ENUM))) { - const SettingDescBase *sdb = &sd->desc; + if (x < SETTING_BUTTON_WIDTH && (sd->flags & (SGF_MULTISTRING | SGF_ENUM))) { this->SetDisplayedHelpText(pe); if (this->valuedropdown_entry == pe) { @@ -2573,22 +2566,22 @@ struct GameSettingsWindow : Window { this->valuedropdown_entry->SetButtons(SEF_LEFT_DEPRESSED); DropDownList list; - if (sd->desc.flags & SGF_MULTISTRING) { - for (int i = sdb->min; i <= (int)sdb->max; i++) { + if (sd->flags & SGF_MULTISTRING) { + for (int i = sd->min; i <= (int)sd->max; i++) { int val = i; - if (sd->desc.guiproc != nullptr) { + if (sd->guiproc != nullptr) { SettingOnGuiCtrlData data; data.type = SOGCT_MULTISTRING_ORDER; - data.val = i - sdb->min; - if (sd->desc.guiproc(data)) { + data.val = i - sd->min; + if (sd->guiproc(data)) { val = data.val; } } - assert_msg(val >= sdb->min && val <= (int)sdb->max, "min: %d, max: %d, val: %d", sdb->min, sdb->max, val); - list.emplace_back(new DropDownListStringItem(sdb->str_val + val - sdb->min, val, false)); + assert_msg(val >= sd->min && val <= (int)sd->max, "min: %d, max: %d, val: %d", sd->min, sd->max, val); + list.emplace_back(new DropDownListStringItem(sd->str_val + val - sd->min, val, false)); } - } else if ((sd->desc.flags & SGF_ENUM)) { - for (const SettingDescEnumEntry *enumlist = sd->desc.enumlist; enumlist != nullptr && enumlist->str != STR_NULL; enumlist++) { + } else if ((sd->flags & SGF_ENUM)) { + for (const SettingDescEnumEntry *enumlist = sd->enumlist; enumlist != nullptr && enumlist->str != STR_NULL; enumlist++) { list.emplace_back(new DropDownListStringItem(enumlist->str, enumlist->val, false)); } } @@ -2599,10 +2592,9 @@ struct GameSettingsWindow : Window { this->SetDirty(); } else if (x < SETTING_BUTTON_WIDTH) { this->SetDisplayedHelpText(pe); - const SettingDescBase *sdb = &sd->desc; int32 oldvalue = value; - switch (sdb->cmd) { + switch (sd->cmd) { case SDT_BOOLX: value ^= 1; break; case SDT_ONEOFMANY: case SDT_NUMX: { @@ -2610,7 +2602,7 @@ struct GameSettingsWindow : Window { * 50-steps you should be able to get from min to max, * unless specified otherwise in the 'interval' variable * of the current setting. */ - uint32 step = (sdb->interval == 0) ? ((sdb->max - sdb->min) / 50) : sdb->interval; + uint32 step = (sd->interval == 0) ? ((sd->max - sd->min) / 50) : sd->interval; if (step == 0) step = 1; /* don't allow too fast scrolling */ @@ -2622,16 +2614,16 @@ struct GameSettingsWindow : Window { /* Increase or decrease the value and clamp it to extremes */ if (x >= SETTING_BUTTON_WIDTH / 2) { value += step; - if (sdb->min < 0) { - assert((int32)sdb->max >= 0); - if (value > (int32)sdb->max) value = (int32)sdb->max; + if (sd->min < 0) { + assert((int32)sd->max >= 0); + if (value > (int32)sd->max) value = (int32)sd->max; } else { - if ((uint32)value > sdb->max) value = (int32)sdb->max; + if ((uint32)value > sd->max) value = (int32)sd->max; } - if (value < sdb->min) value = sdb->min; // skip between "disabled" and minimum + if (value < sd->min) value = sd->min; // skip between "disabled" and minimum } else { value -= step; - if (value < sdb->min) value = (sdb->flags & SGF_0ISDISABLED) ? 0 : sdb->min; + if (value < sd->min) value = (sd->flags & SGF_0ISDISABLED) ? 0 : sd->min; } /* Set up scroller timeout for numeric values */ @@ -2656,13 +2648,13 @@ struct GameSettingsWindow : Window { } } else { /* Only open editbox if clicked for the second time, and only for types where it is sensible for. */ - if (this->last_clicked == pe && sd->desc.cmd != SDT_BOOLX && !(sd->desc.flags & (SGF_MULTISTRING | SGF_ENUM))) { + if (this->last_clicked == pe && sd->cmd != SDT_BOOLX && !(sd->flags & (SGF_MULTISTRING | SGF_ENUM))) { int64 value64 = value; /* Show the correct currency-translated value */ - if (sd->desc.flags & SGF_CURRENCY) value64 *= _currency->rate; + if (sd->flags & SGF_CURRENCY) value64 *= _currency->rate; this->valuewindow_entry = pe; - if (sd->desc.flags & SGF_DECIMAL1) { + if (sd->flags & SGF_DECIMAL1) { SetDParam(0, value64); ShowQueryString(STR_JUST_DECIMAL1, STR_CONFIG_SETTING_QUERY_CAPTION, 10, this, CS_NUMERAL_DECIMAL, QSF_ENABLE_DEFAULT); } else { @@ -2695,18 +2687,18 @@ struct GameSettingsWindow : Window { int32 value; if (!StrEmpty(str)) { long long llvalue; - if (sd->desc.flags & SGF_DECIMAL1) { + if (sd->flags & SGF_DECIMAL1) { llvalue = atof(str) * 10; } else { llvalue = atoll(str); } /* Save the correct currency-translated value */ - if (sd->desc.flags & SGF_CURRENCY) llvalue /= _currency->rate; + if (sd->flags & SGF_CURRENCY) llvalue /= _currency->rate; value = (int32)ClampToI32(llvalue); } else { - value = (int32)(size_t)sd->desc.def; + value = (int32)(size_t)sd->def; } SetSettingValue(this->valuewindow_entry->setting, value); @@ -2743,7 +2735,7 @@ struct GameSettingsWindow : Window { /* Deal with drop down boxes on the panel. */ assert(this->valuedropdown_entry != nullptr); const SettingDesc *sd = this->valuedropdown_entry->setting; - assert(sd->desc.flags & (SGF_MULTISTRING | SGF_ENUM)); + assert(sd->flags & (SGF_MULTISTRING | SGF_ENUM)); SetSettingValue(sd, index); this->SetDirty(); diff --git a/src/settings_internal.h b/src/settings_internal.h index 8735366fdc..543616ed1e 100644 --- a/src/settings_internal.h +++ b/src/settings_internal.h @@ -133,8 +133,7 @@ struct SettingsXref { SettingsXref(const char *target_, OnXrefValueConvert *conv_) : target(target_), conv(conv_) {} }; -struct SettingDesc { - SettingDescBase desc; ///< Settings structure (going to configuration file) +struct SettingDesc : SettingDescBase { SaveLoad save; ///< Internal structure (going to savegame, parts to config) const char *patx_name; ///< Name to save/load setting from in PATX chunk, if nullptr save/load from PATS chunk as normal SettingsXref xref; ///< Details of SettingDesc to use instead of the contents of this one, useful for loading legacy savegames, if target field nullptr save/load as normal @@ -143,6 +142,8 @@ struct SettingDesc { SettingType GetType() const; }; +typedef std::initializer_list SettingTable; + const SettingDesc *GetSettingFromName(const char *name, bool ignore_version = false); bool SetSettingValue(const SettingDesc *sd, int32 value, bool force_newgame = false); bool SetSettingValue(const SettingDesc *sd, const char *value, bool force_newgame = false); diff --git a/src/table/company_settings.ini b/src/table/company_settings.ini index 62503309c5..60052d834d 100644 --- a/src/table/company_settings.ini +++ b/src/table/company_settings.ini @@ -12,14 +12,13 @@ static bool UpdateIntervalRoadVeh(int32 p1); static bool UpdateIntervalShips(int32 p1); static bool UpdateIntervalAircraft(int32 p1); -static const SettingDesc _company_settings[] = { +static const SettingTable _company_settings{ [post-amble] }; [templates] SDT_BOOL = SDT_BOOL($base, $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname), SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname), SDT_NULL = SDT_NULL($length, $from, $to, $extver), -SDT_END = SDT_END() [validation] SDT_VAR = static_assert($max <= MAX_$type, "Maximum value for $base.$var exceeds storage size"); @@ -272,8 +271,3 @@ strhelp = STR_CONFIG_SETTING_SIMULATE_SIGNALS_HELPTEXT strval = STR_CONFIG_SETTING_SIMULATE_SIGNALS_VALUE cat = SC_ADVANCED patxname = ""simulated_wormhole_signals"" - -[SDT_END] - - -}; diff --git a/src/table/currency_settings.ini b/src/table/currency_settings.ini index 26d019e805..c446d808a3 100644 --- a/src/table/currency_settings.ini +++ b/src/table/currency_settings.ini @@ -5,13 +5,12 @@ ; [pre-amble] -static const SettingDesc _currency_settings[] = { +static const SettingTable _currency_settings{ [post-amble] }; [templates] SDT_VAR = SDT_VAR ($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), SDT_SSTR = SDT_SSTR($base, $var, $type, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), -SDT_END = SDT_END() [validation] SDT_VAR = static_assert($max <= MAX_$type, "Maximum value for $base.$var exceeds storage size"); @@ -68,6 +67,3 @@ base = CurrencySpec var = suffix type = SLE_STRQ def = "" credits"" - -[SDT_END] - diff --git a/src/table/gameopt_settings.ini b/src/table/gameopt_settings.ini index 3093ecc69c..d4bf8286a9 100644 --- a/src/table/gameopt_settings.ini +++ b/src/table/gameopt_settings.ini @@ -24,7 +24,7 @@ static const char *_osk_activation = "disabled|double|single|immediately"; static const char *_settings_profiles = "easy|medium|hard"; static const char *_news_display = "off|summarized|full"; -static const SettingDesc _gameopt_settings[] = { +static const SettingTable _gameopt_settings{ /* In version 4 a new difficulty setting has been added to the difficulty settings, * town attitude towards demolishing. Needs special handling because some dimwit thought * it funny to have the GameDifficulty struct be an array while it is a struct of @@ -44,7 +44,6 @@ SDTC_OMANY = SDTC_OMANY( $var, $type, $flags, $guiflags, $def, $ma SDTG_OMANY = SDTG_OMANY($name, $type, $flags, $guiflags, $var, $def, $max, $full, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), SDT_OMANY = SDT_OMANY($base, $var, $type, $flags, $guiflags, $def, $max, $full, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $load, $cat, $startup, $extver, nullptr), SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), -SDT_END = SDT_END() [validation] SDTG_VAR = static_assert($max <= MAX_$type, "Maximum value for $var exceeds storage size"); @@ -193,6 +192,3 @@ def = 1 max = 1 full = _roadsides cat = SC_BASIC - -[SDT_END] - diff --git a/src/table/misc_settings.ini b/src/table/misc_settings.ini index 59fa4abd57..4d74d05253 100644 --- a/src/table/misc_settings.ini +++ b/src/table/misc_settings.ini @@ -16,7 +16,7 @@ extern bool _allow_hidpi_window; #define WITHOUT_COCOA #endif -static const SettingDesc _misc_settings[] = { +static const SettingTable _misc_settings{ [post-amble] }; [templates] @@ -26,7 +26,6 @@ SDTG_OMANY = SDTG_OMANY($name, $type, $flags, $guiflags, $var, $def, SDTG_SSTR = SDTG_SSTR($name, $type, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), SDTG_BOOL = SDTG_BOOL($name, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), -SDTG_END = SDTG_END() [validation] SDTG_VAR = static_assert($max <= MAX_$type, "Maximum value for $var exceeds storage size"); @@ -387,6 +386,3 @@ var = _cargo_payment_x_mode def = 0 min = 0 max = 1 - -[SDTG_END] - diff --git a/src/table/settings.h.preamble b/src/table/settings.h.preamble index 13510a711d..bf066f0249 100644 --- a/src/table/settings.h.preamble +++ b/src/table/settings.h.preamble @@ -92,8 +92,6 @@ static size_t ConvertLandscape(const char *value); #define SDTG_NULL(length, from, to, extver)\ {{"", nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, nullptr, SC_NONE, false, nullptr}, SLEG_NULL_X(length, from, to, extver), nullptr, SettingsXref()} -#define SDTG_END() {{nullptr, nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, nullptr, SC_NONE, false, nullptr}, SLEG_END(), nullptr, SettingsXref()} - /* Macros for various objects to go in the configuration file. * This section is for structures where their various members are saved */ #define SDT_GENERAL2(name, sdt_cmd, sle_cmd, type, flags, guiflags, base, var, length, def, min, max, interval, full, str, strhelp, strval, proc, guiproc, load, from, to, cat, startup, extver, patxname, enumlist)\ @@ -154,5 +152,3 @@ static size_t ConvertLandscape(const char *value); #define SDT_XREF(from, to, extver, xref, xrefcvt)\ {{"", nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, nullptr, SC_NONE, false, nullptr}, SLE_CONDNULL_X(0, from, to, extver), nullptr, SettingsXref(xref, xrefcvt)} -#define SDT_END() {{nullptr, nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, nullptr, SC_NONE, false, nullptr}, SLE_END(), nullptr, SettingsXref()} - diff --git a/src/table/settings.ini b/src/table/settings.ini index 41ab17824c..5b2060530a 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -139,7 +139,7 @@ static const SettingDescEnumEntry _train_braking_model[] = { * assigns its own value. If the setting was company-based, that would mean that * vehicles could decide on different moments that they are heading back to a * service depot, causing desyncs on a massive scale. */ -const SettingDesc _settings[] = { +const SettingTable _settings{ [post-amble] }; [templates] @@ -159,7 +159,6 @@ SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, SDT_ENUM = SDT_ENUM($base, $var, $type, $flags, $guiflags, $def, $str, $strhelp, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname, $enumlist), SDT_NULL = SDT_NULL($length, $from, $to, $extver), SDT_XREF = SDT_XREF( $from, $to, $extver, $xref, $xrefcvt), -SDT_END = SDT_END() SDT_LINKGRAPH_PER_CARGO = SDT_ENUM(GameSettings, linkgraph.distribution_per_cargo[$linkgraph_cargo], SLE_UINT8, $flags | SLF_NOT_IN_CONFIG, $guiflags | SGF_NO_NEWGAME, DT_PER_CARGO_DEFAULT, STR_CONFIG_SETTING_DISTRIBUTION_PER_CARGO, STR_CONFIG_SETTING_DISTRIBUTION_PER_CARGO_HELPTEXT, $proc, LinkGraphDistributionSettingGUI, $from, $to, SC_EXPERT, false, SlXvFeatureTest(XSLFTO_AND, XSLFI_LINKGRAPH_MODES), nullptr, _linkgraph_mode_per_cargo), @@ -6440,6 +6439,3 @@ min = 0 max = 0xFFFFFFFF cat = SC_EXPERT patxname = ""debug.chicken_bits"" - -[SDT_END] - diff --git a/src/table/win32_settings.ini b/src/table/win32_settings.ini index 3f726b05b0..6afae025ba 100644 --- a/src/table/win32_settings.ini +++ b/src/table/win32_settings.ini @@ -9,14 +9,13 @@ #if defined(_WIN32) && !defined(DEDICATED) extern bool _window_maximize; -static const SettingDesc _win32_settings[] = { +static const SettingTable _win32_settings{ [post-amble] }; #endif /* _WIN32 */ [templates] SDTG_BOOL = SDTG_BOOL($name, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), -SDTG_END = SDTG_END() [validation] SDTG_VAR = static_assert($max <= MAX_$type, "Maximum value for $var exceeds storage size"); @@ -43,6 +42,3 @@ name = ""window_maximize"" var = _window_maximize def = false cat = SC_BASIC - -[SDTG_END] - diff --git a/src/table/window_settings.ini b/src/table/window_settings.ini index 573986aeb3..17d5130828 100644 --- a/src/table/window_settings.ini +++ b/src/table/window_settings.ini @@ -6,13 +6,12 @@ [pre-amble] -static const SettingDesc _window_settings[] = { +static const SettingTable _window_settings{ [post-amble] }; [templates] SDT_BOOL = SDT_BOOL($base, $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), -SDT_END = SDT_END() [validation] SDT_VAR = static_assert($max <= MAX_$type, "Maximum value for $base.$var exceeds storage size"); @@ -53,7 +52,3 @@ type = SLE_INT16 def = 0 min = 0 max = 32000 - -[SDT_END] - -};