Changeset - r25527:ad30d3893783
[Not reviewed]
master
0 5 0
rubidium42 - 3 years ago 2021-05-23 07:51:33
rubidium@openttd.org
Codechange: let SettingDesc extend SettingDescBase
5 files changed with 62 insertions and 63 deletions:
0 comments (0 inline, 0 general)
src/saveload/linkgraph_sl.cpp
Show inline comments
 
@@ -66,25 +66,25 @@ const SaveLoad *GetLinkGraphJobDesc()
 
	/* We store the offset of each member of the #LinkGraphSettings in the
 
	 * extra data of the saveload struct. Use it together with the address
 
	 * of the settings struct inside the job to find the final memory address. */
 
	static SaveLoadAddrProc * const proc = [](void *b, size_t extra) -> void * { return const_cast<void *>(static_cast<const void *>(reinterpret_cast<const char *>(std::addressof(static_cast<LinkGraphJob *>(b)->settings)) + extra)); };
 

	
 
	/* Build the SaveLoad array on first call and don't touch it later on */
 
	if (saveloads.size() == 0) {
 
		size_t prefixlen = strlen(prefix);
 

	
 
		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) {
 
			if (desc->name != nullptr && strncmp(desc->name, prefix, prefixlen) == 0) {
 
				SaveLoad sl = desc->save;
 
				sl.address_proc = proc;
 
				saveloads.push_back(sl);
 
			}
 
			desc = GetSettingDescription(++setting);
 
		}
 

	
 
		int i = 0;
 
		do {
 
			saveloads.push_back(job_desc[i++]);
 
		} while (saveloads[saveloads.size() - 1].cmd != SL_END);
 
	}
src/script/api/script_gamesettings.cpp
Show inline comments
 
@@ -9,47 +9,47 @@
 

	
 
#include "../../stdafx.h"
 
#include "script_gamesettings.hpp"
 
#include "../../settings_internal.h"
 
#include "../../settings_type.h"
 
#include "../../command_type.h"
 

	
 
#include "../../safeguards.h"
 

	
 
/* 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)
 
{
 
	if (!IsValid(setting)) return -1;
 

	
 
	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);
 
}
 

	
 
/* static */ bool ScriptGameSettings::SetValue(const char *setting, int value)
 
{
 
	if (!IsValid(setting)) return false;
 

	
 
	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);
 
}
 

	
 
/* static */ bool ScriptGameSettings::IsDisabledVehicleType(ScriptVehicle::VehicleType vehicle_type)
 
{
 
	switch (vehicle_type) {
 
		case ScriptVehicle::VT_RAIL:  return _settings_game.ai.ai_disable_veh_train;
 
		case ScriptVehicle::VT_ROAD:  return _settings_game.ai.ai_disable_veh_roadveh;
 
		case ScriptVehicle::VT_WATER: return _settings_game.ai.ai_disable_veh_ship;
 
		case ScriptVehicle::VT_AIR:   return _settings_game.ai.ai_disable_veh_aircraft;
 
		default:                       return true;
src/settings.cpp
Show inline comments
 
@@ -425,25 +425,25 @@ static const void *StringToVal(const Set
 

	
 
/**
 
 * Set the value of a setting and if needed clamp the value to
 
 * the preset minimum and maximum.
 
 * @param ptr the variable itself
 
 * @param sd pointer to the 'information'-database of the variable
 
 * @param val signed long version of the new value
 
 * @pre SettingDesc is of type SDT_BOOLX, SDT_NUMX,
 
 * SDT_ONEOFMANY or SDT_MANYOFMANY. Other types are not supported as of now
 
 */
 
static void Write_ValidateSetting(void *ptr, const SettingDesc *sd, int32 val)
 
{
 
	const SettingDescBase *sdb = &sd->desc;
 
	const SettingDescBase *sdb = sd;
 

	
 
	if (sdb->cmd != SDT_BOOLX &&
 
			sdb->cmd != SDT_NUMX &&
 
			sdb->cmd != SDT_ONEOFMANY &&
 
			sdb->cmd != SDT_MANYOFMANY) {
 
		return;
 
	}
 

	
 
	/* We cannot know the maximum value of a bitset variable, so just have faith */
 
	if (sdb->cmd != SDT_MANYOFMANY) {
 
		/* We need to take special care of the uint32 type as we receive from the function
 
		 * a signed integer. While here also bail out on 64-bit settings as those are not
 
@@ -499,29 +499,29 @@ static void Write_ValidateSetting(void *
 
 * @param ptr Pointer to the std::string.
 
 * @param sd  Pointer to the information for the conversions and limitations to apply.
 
 * @param p   The string to save.
 
 */
 
static void Write_ValidateStdString(void *ptr, const SettingDesc *sd, const char *p)
 
{
 
	std::string *dst = reinterpret_cast<std::string *>(ptr);
 

	
 
	switch (GetVarMemType(sd->save.conv)) {
 
		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);
 
				}
 
			} else {
 
				dst->clear();
 
			}
 
			break;
 

	
 
		default: NOT_REACHED();
 
	}
 
}
 
@@ -532,29 +532,29 @@ static void Write_ValidateStdString(void
 
 * @param sd pointer to SettingDesc structure 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)
 
{
 
	IniGroup *group;
 
	IniGroup *group_def = ini->GetGroup(grpname);
 

	
 
	for (; sd->save.cmd != SL_END; sd++) {
 
		const SettingDescBase *sdb = &sd->desc;
 
		const SettingDescBase *sdb = sd;
 
		const SaveLoad        *sld = &sd->save;
 

	
 
		if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to)) continue;
 
		if (sd->desc.startup != only_startup) continue;
 
		if (sd->startup != only_startup) continue;
 

	
 
		/* For settings.xx.yy load the settings from [xx] yy = ? */
 
		std::string s{ sdb->name };
 
		auto sc = s.find('.');
 
		if (sc != std::string::npos) {
 
			group = ini->GetGroup(s.substr(0, sc));
 
			s = s.substr(sc + 1);
 
		} else {
 
			group = group_def;
 
		}
 

	
 
		IniItem *item = group->GetItem(s, false);
 
@@ -584,26 +584,26 @@ static void IniLoadSettings(IniFile *ini
 
			case SDT_STDSTRING:
 
				Write_ValidateStdString(ptr, sd, (const char *)p);
 
				break;
 

	
 
			case SDT_INTLIST: {
 
				if (!LoadIntList((const char*)p, ptr, sld->length, GetVarMemType(sld->conv))) {
 
					ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY);
 
					msg.SetDParamStr(0, sdb->name);
 
					_settings_error_list.push_back(msg);
 

	
 
					/* 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;
 
			}
 
			default: NOT_REACHED();
 
		}
 
	}
 
}
 

	
 
/**
 
 * Save the values of settings to the inifile.
 
 * @param ini pointer to IniFile structure
 
 * @param sd read-only SettingDesc structure which contains the unmodified,
 
@@ -614,25 +614,25 @@ static void IniLoadSettings(IniFile *ini
 
 * have a look if the value has changed since we started the game (the original
 
 * 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)
 
{
 
	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 SettingDescBase *sdb = sd;
 
		const SaveLoad        *sld = &sd->save;
 

	
 
		/* 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 (sld->conv & SLF_NOT_IN_CONFIG) continue;
 

	
 
		/* XXX - wtf is this?? (group override?) */
 
		std::string s{ sdb->name };
 
		auto sc = s.find('.');
 
		if (sc != std::string::npos) {
 
			group = ini->GetGroup(s.substr(0, sc));
 
@@ -793,41 +793,41 @@ void IniLoadWindowSettings(IniFile *ini,
 
void IniSaveWindowSettings(IniFile *ini, const char *grpname, void *desc)
 
{
 
	IniSaveSettings(ini, _window_settings, grpname, desc, false);
 
}
 

	
 
/**
 
 * Check whether the setting is editable in the current gamemode.
 
 * @param do_command true if this is about checking a command from the server.
 
 * @return true if editable.
 
 */
 
bool SettingDesc::IsEditable(bool do_command) const
 
{
 
	if (!do_command && !(this->save.conv & SLF_NO_NETWORK_SYNC) && _networking && !_network_server && !(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 && !(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;
 
}
 

	
 
/**
 
 * Return the type of the setting.
 
 * @return type of setting
 
 */
 
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;
 
}
 

	
 
/* Begin - Callback Functions for the various settings. */
 

	
 
/** Reposition the main toolbar as the setting changed. */
 
static bool v_PositionMainToolbar(int32 p1)
 
{
 
	if (_game_mode != GM_MENU) PositionMainToolbar(nullptr);
 
	return true;
 
}
 

	
 
@@ -1883,32 +1883,32 @@ CommandCost CmdChangeSetting(TileIndex t
 

	
 
	if (flags & DC_EXEC) {
 
		void *var = GetVariableAddress(&GetGameSettings(), &sd->save);
 

	
 
		int32 oldval = (int32)ReadValue(var, sd->save.conv);
 
		int32 newval = (int32)p2;
 

	
 
		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();
 
		}
 

	
 
		SetWindowClassesDirty(WC_GAME_OPTIONS);
 

	
 
		if (_save_config) SaveToConfig();
 
	}
 

	
 
	return CommandCost();
 
}
 

	
 
/**
 
@@ -1928,79 +1928,79 @@ CommandCost CmdChangeCompanySetting(Tile
 

	
 
	if (flags & DC_EXEC) {
 
		void *var = GetVariableAddress(&Company::Get(_current_company)->settings, &sd->save);
 

	
 
		int32 oldval = (int32)ReadValue(var, sd->save.conv);
 
		int32 newval = (int32)p2;
 

	
 
		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();
 
		}
 

	
 
		SetWindowClassesDirty(WC_GAME_OPTIONS);
 
	}
 

	
 
	return CommandCost();
 
}
 

	
 
/**
 
 * Get the index of the 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_SETTING.
 
 */
 
uint GetSettingIndex(const SettingDesc *sd)
 
{
 
	assert((sd->desc.flags & SGF_PER_COMPANY) == 0);
 
	assert((sd->flags & SGF_PER_COMPANY) == 0);
 
	return sd - _settings;
 
}
 

	
 
/**
 
 * Top function to save the new value of an element of the Settings struct
 
 * @param index offset in the SettingDesc array of the Settings struct which
 
 * identifies the setting member we want to change
 
 * @param value new value of the setting
 
 * @param force_newgame force the newgame settings
 
 */
 
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);
 
		}
 

	
 
		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;
 
	}
 

	
 
	/* If an item is company-based, we do not send it over the network
 
	 * (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 */
 
	if (sd->save.conv & SLF_NO_NETWORK_SYNC) {
 
		void *var = GetVariableAddress(&GetGameSettings(), &sd->save);
 
		Write_ValidateSetting(var, sd, value);
 

	
 
		if (_game_mode != GM_MENU) {
 
			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);
 

	
 
		if (_save_config) SaveToConfig();
 
		return true;
 
	}
 

	
 
	if (force_newgame) {
 
		void *var2 = GetVariableAddress(&_settings_newgame, &sd->save);
 
		Write_ValidateSetting(var2, sd, value);
 

	
 
		if (_save_config) SaveToConfig();
 
@@ -2014,25 +2014,25 @@ bool SetSettingValue(const SettingDesc *
 
	return false;
 
}
 

	
 
/**
 
 * Set the company settings for a new company to their default values.
 
 */
 
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);
 
		Write_ValidateSetting(var, sd, (int32)(size_t)sd->def);
 
	}
 
}
 

	
 
/**
 
 * Sync all company settings in a multiplayer game.
 
 */
 
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);
 
@@ -2042,99 +2042,99 @@ void SyncCompanySettings()
 
		if (old_value != new_value) NetworkSendCommand(0, i, new_value, CMD_CHANGE_COMPANY_SETTING, nullptr, nullptr, _local_company);
 
	}
 
}
 

	
 
/**
 
 * Get the index in the _company_settings array of a setting
 
 * @param name The name of the setting
 
 * @return The index in the _company_settings array
 
 */
 
uint GetCompanySettingIndex(const char *name)
 
{
 
	const SettingDesc *sd = GetSettingFromName(name);
 
	assert(sd != nullptr && (sd->desc.flags & SGF_PER_COMPANY) != 0);
 
	assert(sd != nullptr && (sd->flags & SGF_PER_COMPANY) != 0);
 
	return sd - _company_settings;
 
}
 

	
 
/**
 
 * Set a setting value with a string.
 
 * @param sd the setting to change.
 
 * @param value the value to write
 
 * @param force_newgame force the newgame settings
 
 * @note Strings WILL NOT be synced over the network
 
 */
 
bool SetSettingValue(const SettingDesc *sd, const char *value, bool force_newgame)
 
{
 
	assert(sd->save.conv & SLF_NO_NETWORK_SYNC);
 

	
 
	if (GetVarMemType(sd->save.conv) == SLE_VAR_STRQ && strcmp(value, "(null)") == 0) {
 
		value = nullptr;
 
	}
 

	
 
	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;
 
}
 

	
 
/**
 
 * Given a name of setting, return a setting description of it.
 
 * @param name  Name of the setting to return a setting description of
 
 * @param i     Pointer to an integer that will contain the index of the setting after the call, if it is successful.
 
 * @return Pointer to the setting description of setting \a name if it can be found,
 
 *         \c nullptr indicates failure to obtain the description
 
 */
 
const SettingDesc *GetSettingFromName(const char *name)
 
{
 
	/* First check all full names */
 
	for (const SettingDesc *sd = _settings; sd->save.cmd != SL_END; sd++) {
 
		if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
 
		if (strcmp(sd->desc.name, name) == 0) return sd;
 
		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 (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
 
		const char *short_name = strchr(sd->desc.name, '.');
 
		const char *short_name = strchr(sd->name, '.');
 
		if (short_name != nullptr) {
 
			short_name++;
 
			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 (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
 
		if (strcmp(sd->desc.name, name) == 0) return sd;
 
		if (strcmp(sd->name, name) == 0) return sd;
 
	}
 

	
 
	return nullptr;
 
}
 

	
 
/* Those 2 functions need to be here, else we have to make some stuff non-static
 
 * and besides, it is also better to keep stuff like this at the same place */
 
void IConsoleSetSetting(const char *name, const char *value, bool force_newgame)
 
{
 
	const SettingDesc *sd = GetSettingFromName(name);
 

	
 
	if (sd == nullptr) {
 
		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;
 
		extern bool GetArgumentInteger(uint32 *value, const char *arg);
 
		success = GetArgumentInteger(&val, value);
 
		if (!success) {
 
			IConsolePrintF(CC_ERROR, "'%s' is not an integer.", value);
 
			return;
 
		}
 

	
 
		success = SetSettingValue(sd, val, force_newgame);
 
	}
 
@@ -2164,61 +2164,61 @@ void IConsoleGetSetting(const char *name
 
{
 
	char value[20];
 
	const SettingDesc *sd = GetSettingFromName(name);
 
	const void *ptr;
 

	
 
	if (sd == nullptr) {
 
		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<const std::string *>(ptr)->c_str());
 
	} else {
 
		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));
 
		}
 

	
 
		IConsolePrintF(CC_WARNING, "Current value for '%s' is: '%s' (min: %s%d, max: %u)",
 
			name, value, (sd->desc.flags & SGF_0ISDISABLED) ? "(0) " : "", sd->desc.min, sd->desc.max);
 
			name, value, (sd->flags & SGF_0ISDISABLED) ? "(0) " : "", sd->min, sd->max);
 
	}
 
}
 

	
 
/**
 
 * List all settings and their value to the console
 
 *
 
 * @param prefilter  If not \c nullptr, only list settings with names that begin with \a prefilter prefix
 
 */
 
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 (prefilter != nullptr && strstr(sd->desc.name, prefilter) == nullptr) continue;
 
		if (prefilter != nullptr && strstr(sd->name, prefilter) == nullptr) continue;
 
		char value[80];
 
		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<const std::string *>(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");
 
}
 

	
 
/**
 
 * Save and load handler for settings
 
 * @param osd 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)
src/settings_gui.cpp
Show inline comments
 
@@ -834,25 +834,25 @@ struct SettingEntry : BaseSettingEntry {
 
	virtual uint Length() const;
 
	virtual uint GetMaxHelpHeight(int maxw);
 
	virtual bool UpdateFilterState(SettingFilter &filter, bool force_visible);
 

	
 
	void SetButtons(byte new_val);
 

	
 
	/**
 
	 * Get the help text of a single setting.
 
	 * @return The requested help text.
 
	 */
 
	inline StringID GetHelpText() const
 
	{
 
		return this->setting->desc.str_help;
 
		return this->setting->str_help;
 
	}
 

	
 
	void SetValueDParams(uint first_param, int32 value) const;
 

	
 
protected:
 
	virtual void DrawSetting(GameSettings *settings_ptr, int left, int right, int y, bool highlight) const;
 

	
 
private:
 
	bool IsVisibleByRestrictionMode(RestrictionMode mode) const;
 
};
 

	
 
/** Containers for BaseSettingEntry */
 
@@ -1027,25 +1027,25 @@ SettingEntry::SettingEntry(const char *n
 
 * @param level      Page nesting level of this entry
 
 */
 
void SettingEntry::Init(byte level)
 
{
 
	BaseSettingEntry::Init(level);
 
	this->setting = GetSettingFromName(this->name);
 
	assert(this->setting != nullptr);
 
}
 

	
 
/* 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);
 
}
 

	
 
/**
 
 * Set the button-depressed flags (#SEF_LEFT_DEPRESSED and #SEF_RIGHT_DEPRESSED) to a specified value
 
 * @param new_val New value for the button flags
 
 * @see SettingEntryFlags
 
 */
 
void SettingEntry::SetButtons(byte new_val)
 
{
 
	assert((new_val & ~SEF_BUTTONS_MASK) == 0); // Should not touch any flags outside the buttons
 
	this->flags = (this->flags & ~SEF_BUTTONS_MASK) | new_val;
 
@@ -1071,38 +1071,38 @@ uint SettingEntry::GetMaxHelpHeight(int 
 
 * Checks whether an entry shall be made visible based on the restriction mode.
 
 * @param mode The current status of the restriction drop down box.
 
 * @return true if the entry shall be visible.
 
 */
 
bool SettingEntry::IsVisibleByRestrictionMode(RestrictionMode mode) const
 
{
 
	/* There shall not be any restriction, i.e. all settings shall be visible. */
 
	if (mode == RM_ALL) return true;
 

	
 
	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);
 
	int64 current_value = ReadValue(var, sd->save.conv);
 

	
 
	int64 filter_value;
 

	
 
	if (mode == RM_CHANGED_AGAINST_DEFAULT) {
 
		/* 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
 
		 * its value is used when starting a new game. */
 

	
 
		/* Make sure we're not comparing the new game settings against itself. */
 
		assert(settings_ptr != &_settings_newgame);
 

	
 
		/* Read the new game's value. */
 
		var = ResolveVariableAddress(&_settings_newgame, sd);
 
		filter_value = ReadValue(var, sd->save.conv);
 
	}
 
@@ -1118,25 +1118,25 @@ bool SettingEntry::IsVisibleByRestrictio
 
 */
 
bool SettingEntry::UpdateFilterState(SettingFilter &filter, bool force_visible)
 
{
 
	CLRBITS(this->flags, SEF_FILTERED);
 

	
 
	bool visible = true;
 

	
 
	const SettingDesc *sd = this->setting;
 
	if (!force_visible && !filter.string.IsEmpty()) {
 
		/* Process the search text filter for this item. */
 
		filter.string.ResetState();
 

	
 
		const SettingDescBase *sdb = &sd->desc;
 
		const SettingDescBase *sdb = sd;
 

	
 
		SetDParam(0, STR_EMPTY);
 
		filter.string.AddLine(sdb->str);
 
		filter.string.AddLine(this->GetHelpText());
 

	
 
		visible = filter.string.GetState();
 
	}
 

	
 
	if (visible) {
 
		if (filter.type != ST_ALL && sd->GetType() != filter.type) {
 
			filter.type_hides = true;
 
			visible = false;
 
@@ -1144,43 +1144,43 @@ bool SettingEntry::UpdateFilterState(Set
 
		if (!this->IsVisibleByRestrictionMode(filter.mode)) {
 
			while (filter.min_cat < RM_ALL && (filter.min_cat == filter.mode || !this->IsVisibleByRestrictionMode(filter.min_cat))) filter.min_cat++;
 
			visible = false;
 
		}
 
	}
 

	
 
	if (!visible) SETBITS(this->flags, SEF_FILTERED);
 
	return 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 {
 
			return GetVariableAddress(&_settings_client.company, &sd->save);
 
		}
 
	} else {
 
		return GetVariableAddress(settings_ptr, &sd->save);
 
	}
 
}
 

	
 
/**
 
 * Set the DParams for drawing the value of a setting.
 
 * @param first_param First DParam to use
 
 * @param value Setting value to set params for.
 
 */
 
void SettingEntry::SetValueDParams(uint first_param, int32 value) const
 
{
 
	const SettingDescBase *sdb = &this->setting->desc;
 
	const SettingDescBase *sdb = this->setting;
 
	if (sdb->cmd == SDT_BOOLX) {
 
		SetDParam(first_param++, value != 0 ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF);
 
	} 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));
 
			value = abs(value);
 
		} else {
 
			SetDParam(first_param++, sdb->str_val + ((value == 0 && (sdb->flags & SGF_0ISDISABLED) != 0) ? 1 : 0));
 
		}
 
		SetDParam(first_param++, value);
 
@@ -1189,25 +1189,25 @@ void SettingEntry::SetValueDParams(uint 
 

	
 
/**
 
 * Function to draw setting value (button + text + current value)
 
 * @param settings_ptr Pointer to current values of all settings
 
 * @param left         Left-most position in window/panel to start drawing
 
 * @param right        Right-most position in window/panel to draw
 
 * @param y            Upper-most position in window/panel to start drawing
 
 * @param highlight    Highlight entry.
 
 */
 
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 SettingDescBase *sdb = sd;
 
	const void *var = ResolveVariableAddress(settings_ptr, sd);
 
	int state = this->flags & SEF_BUTTONS_MASK;
 

	
 
	bool rtl = _current_text_dir == TD_RTL;
 
	uint buttons_left = rtl ? right + 1 - SETTING_BUTTON_WIDTH : left;
 
	uint text_left  = left + (rtl ? 0 : SETTING_BUTTON_WIDTH + 5);
 
	uint text_right = right - (rtl ? SETTING_BUTTON_WIDTH + 5 : 0);
 
	uint button_y = y + (SETTING_HEIGHT - SETTING_BUTTON_HEIGHT) / 2;
 

	
 
	/* We do not allow changes of some items when we are a client in a networkgame */
 
	bool editable = sd->IsEditable();
 

	
 
@@ -2082,25 +2082,25 @@ struct GameSettingsWindow : Window {
 
					const SettingDesc *sd = this->last_clicked->setting;
 

	
 
					int y = r.top;
 
					switch (sd->GetType()) {
 
						case ST_COMPANY: SetDParam(0, _game_mode == GM_MENU ? STR_CONFIG_SETTING_TYPE_COMPANY_MENU : STR_CONFIG_SETTING_TYPE_COMPANY_INGAME); break;
 
						case ST_CLIENT:  SetDParam(0, STR_CONFIG_SETTING_TYPE_CLIENT); break;
 
						case ST_GAME:    SetDParam(0, _game_mode == GM_MENU ? STR_CONFIG_SETTING_TYPE_GAME_MENU : STR_CONFIG_SETTING_TYPE_GAME_INGAME); break;
 
						default: NOT_REACHED();
 
					}
 
					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);
 
					this->last_clicked->SetValueDParams(0, default_value);
 
					DrawString(r.left, r.right, y, STR_CONFIG_SETTING_DEFAULT_VALUE);
 
					y += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL;
 

	
 
					DrawStringMultiLine(r.left, r.right, y, r.bottom, this->last_clicked->GetHelpText(), TC_WHITE);
 
				}
 
				break;
 

	
 
			default:
 
				break;
 
		}
 
	}
 
@@ -2186,26 +2186,26 @@ struct GameSettingsWindow : Window {
 
		const SettingDesc *sd = pe->setting;
 

	
 
		/* return if action is only active in network, or only settable by server */
 
		if (!sd->IsEditable()) {
 
			this->SetDisplayedHelpText(pe);
 
			return;
 
		}
 

	
 
		const void *var = ResolveVariableAddress(settings_ptr, sd);
 
		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)) {
 
			const SettingDescBase *sdb = &sd->desc;
 
		if (x < SETTING_BUTTON_WIDTH && (sd->flags & SGF_MULTISTRING)) {
 
			const SettingDescBase *sdb = sd;
 
			this->SetDisplayedHelpText(pe);
 

	
 
			if (this->valuedropdown_entry == pe) {
 
				/* unclick the dropdown */
 
				HideDropDownMenu(this);
 
				this->closing_dropdown = false;
 
				this->valuedropdown_entry->SetButtons(0);
 
				this->valuedropdown_entry = nullptr;
 
			} else {
 
				if (this->valuedropdown_entry != nullptr) this->valuedropdown_entry->SetButtons(0);
 
				this->closing_dropdown = false;
 

	
 
@@ -2225,25 +2225,25 @@ struct GameSettingsWindow : Window {
 

	
 
					DropDownList list;
 
					for (int i = sdb->min; i <= (int)sdb->max; i++) {
 
						list.emplace_back(new DropDownListStringItem(sdb->str_val + i - sdb->min, i, false));
 
					}
 

	
 
					ShowDropDownListAt(this, std::move(list), value, -1, wi_rect, COLOUR_ORANGE, true);
 
				}
 
			}
 
			this->SetDirty();
 
		} else if (x < SETTING_BUTTON_WIDTH) {
 
			this->SetDisplayedHelpText(pe);
 
			const SettingDescBase *sdb = &sd->desc;
 
			const SettingDescBase *sdb = sd;
 
			int32 oldvalue = value;
 

	
 
			switch (sdb->cmd) {
 
				case SDT_BOOLX: value ^= 1; break;
 
				case SDT_ONEOFMANY:
 
				case SDT_NUMX: {
 
					/* Add a dynamic step-size to the scroller. In a maximum of
 
					 * 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;
 
					if (step == 0) step = 1;
 
@@ -2282,28 +2282,28 @@ struct GameSettingsWindow : Window {
 
					break;
 
				}
 

	
 
				default: NOT_REACHED();
 
			}
 

	
 
			if (value != oldvalue) {
 
				SetSettingValue(sd, value);
 
				this->SetDirty();
 
			}
 
		} 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)) {
 
			if (this->last_clicked == pe && sd->cmd != SDT_BOOLX && !(sd->flags & SGF_MULTISTRING)) {
 
				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;
 
				SetDParam(0, value64);
 
				/* Limit string length to 14 so that MAX_INT32 * max currency rate doesn't exceed MAX_INT64. */
 
				ShowQueryString(STR_JUST_INT, STR_CONFIG_SETTING_QUERY_CAPTION, 15, this, CS_NUMERAL, QSF_ENABLE_DEFAULT);
 
			}
 
			this->SetDisplayedHelpText(pe);
 
		}
 
	}
 

	
 
	void OnTimeout() override
 
	{
 
@@ -2318,29 +2318,29 @@ struct GameSettingsWindow : Window {
 
	{
 
		/* The user pressed cancel */
 
		if (str == nullptr) return;
 

	
 
		assert(this->valuewindow_entry != nullptr);
 
		const SettingDesc *sd = this->valuewindow_entry->setting;
 

	
 
		int32 value;
 
		if (!StrEmpty(str)) {
 
			long long 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);
 
		this->SetDirty();
 
	}
 

	
 
	void OnDropdownSelect(int widget, int index) override
 
	{
 
		switch (widget) {
 
			case WID_GS_RESTRICT_DROPDOWN:
 
				this->filter.mode = (RestrictionMode)index;
 
				if (this->filter.mode == RM_CHANGED_AGAINST_DEFAULT ||
 
@@ -2359,25 +2359,25 @@ struct GameSettingsWindow : Window {
 
				break;
 

	
 
			case WID_GS_TYPE_DROPDOWN:
 
				this->filter.type = (SettingType)index;
 
				this->InvalidateData();
 
				break;
 

	
 
			default:
 
				if (widget < 0) {
 
					/* 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);
 
					assert(sd->flags & SGF_MULTISTRING);
 

	
 
					SetSettingValue(sd, index);
 
					this->SetDirty();
 
				}
 
				break;
 
		}
 
	}
 

	
 
	void OnDropdownClose(Point pt, int widget, int index, bool instant_close) override
 
	{
 
		if (widget >= 0) {
 
			/* Normally the default implementation of OnDropdownClose() takes care of
src/settings_internal.h
Show inline comments
 
@@ -91,26 +91,25 @@ struct SettingDescBase {
 
	uint32 max;             ///< maximum values
 
	int32 interval;         ///< the interval to use between settings in the 'settings' window. If interval is '0' the interval is dynamically determined
 
	const char *many;       ///< ONE/MANY_OF_MANY: string of possible values for this type
 
	StringID str;           ///< (translated) string with descriptive text; gui and console
 
	StringID str_help;      ///< (Translated) string with help text; gui only.
 
	StringID str_val;       ///< (Translated) first string describing the value.
 
	OnChange *proc;         ///< callback procedure for when the value is changed
 
	OnConvert *proc_cnvt;   ///< callback procedure when loading value mechanism fails
 
	SettingCategory cat;    ///< assigned categories of the setting
 
	bool startup;           ///< setting has to be loaded directly at startup?
 
};
 

	
 
struct SettingDesc {
 
	SettingDescBase desc;   ///< Settings structure (going to configuration file)
 
struct SettingDesc : SettingDescBase {
 
	SaveLoad save;          ///< Internal structure (going to savegame, parts to config)
 

	
 
	bool IsEditable(bool do_command = false) const;
 
	SettingType GetType() const;
 
};
 

	
 
const SettingDesc *GetSettingFromName(const char *name);
 
bool SetSettingValue(const SettingDesc *sd, int32 value, bool force_newgame = false);
 
bool SetSettingValue(const SettingDesc *sd, const char *value, bool force_newgame = false);
 
uint GetSettingIndex(const SettingDesc *sd);
 

	
 
#endif /* SETTINGS_INTERNAL_H */
0 comments (0 inline, 0 general)