diff --git a/settings.c b/settings.c --- a/settings.c +++ b/settings.c @@ -11,6 +11,8 @@ #include "variables.h" #include "network.h" #include "settings.h" +#include "command.h" +#include "console.h" #include "saveload.h" typedef struct IniFile IniFile; @@ -1261,6 +1263,29 @@ const SettingDesc *GetSettingDescription return &_patch_settings[index]; } +/** Network-safe changing of patch-settings (server-only). + * @param p1 the index of the patch in the SettingDesc array which identifies it + * @param p2 the new value for the patch + * The new value is properly clamped to its minimum/maximum when setting + * @see _patch_settings + */ +int32 CmdChangePatchSetting(int x, int y, uint32 flags, uint32 p1, uint32 p2) +{ + const SettingDesc *sd = GetSettingDescription(p1); + + if (sd == NULL) return CMD_ERROR; + + if (flags & DC_EXEC) { + Patches *patches_ptr = &_patches; + void *var = ini_get_variable(&sd->save, patches_ptr); + Write_ValidateSetting(var, sd, (int32)p2); + + InvalidateWindow(WC_GAME_OPTIONS, 0); + } + + return 0; +} + /* Top function to save the new value of an element of the Patches struct * @param index offset in the SettingDesc array of the Patches struct which * identifies the patch member we want to change @@ -1283,6 +1308,72 @@ void SetPatchValue(uint index, const Pat } } +static const SettingDesc *GetPatchFromName(const char *name, uint *i) +{ + const SettingDesc *sd; + + for (*i = 0, sd = _patch_settings; sd->save.cmd != SL_END; sd++, *i++) { + if (strncmp(sd->desc.name, name, sizeof(sd->desc.name)) == 0) return sd; + } + + return NULL; +} + +/* 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 IConsoleSetPatchSetting(const char *name, const char *value) +{ + char newval[20]; + int val; + uint index; + const SettingDesc *sd = GetPatchFromName(name, &index); + const Patches *patches_ptr; + void *ptr; + + if (sd == NULL) { + IConsolePrintF(_icolour_warn, "'%s' is an unknown patch setting.", name); + return; + } + + sscanf(value, "%d", &val); + patches_ptr = &_patches; + ptr = ini_get_variable(&sd->save, patches_ptr); + + SetPatchValue(index, patches_ptr, val); + + if (sd->desc.cmd == SDT_BOOLX) { + snprintf(newval, sizeof(newval), (*(bool*)ptr == 1) ? "on" : "off"); + } else { + snprintf(newval, sizeof(newval), "%d", (int32)ReadValue(ptr, sd->save.conv)); + } + + IConsolePrintF(_icolour_warn, "'%s' changed to: %s", name, newval); +} + +void IConsoleGetPatchSetting(const char *name) +{ + char value[20]; + uint index; + const SettingDesc *sd = GetPatchFromName(name, &index); + const void *ptr; + + if (sd == NULL) { + IConsolePrintF(_icolour_warn, "'%s' is an unknown patch setting.", name); + return; + } + + ptr = ini_get_variable(&sd->save, &_patches); + + if (sd->desc.cmd == SDT_BOOLX) { + snprintf(value, sizeof(value), (*(bool*)ptr == 1) ? "on" : "off"); + } else { + snprintf(value, sizeof(value), "%d", (int32)ReadValue(ptr, sd->save.conv)); + } + + IConsolePrintF(_icolour_warn, "Current value for '%s' is: '%s' (min: %s%d, max: %d)", + name, value, (sd->desc.flags & SGF_0ISDISABLED) ? "(0) " : "", sd->desc.min, sd->desc.max); +} + /** Save and load handler for patches/settings * @param osd SettingDesc struct containing all information * @param object can be either NULL in which case we load global variables or diff --git a/settings_gui.c b/settings_gui.c --- a/settings_gui.c +++ b/settings_gui.c @@ -16,7 +16,6 @@ #include "screenshot.h" #include "newgrf.h" #include "network.h" -#include "console.h" #include "town.h" #include "variables.h" #include "settings.h" @@ -869,108 +868,6 @@ static void PatchesSelectionWndProc(Wind } } -/** Network-safe changing of patch-settings. - * @param p1 various bitstuffed elements - * - p1 = (bit 0- 7) - the patches type (page) that is being changed (construction, network, ai) - * - p2 = (bit 8-15) - the actual patch (entry) being set inside the category - * @param p2 the new value for the patch - * @todo check that the new value is a valid one. Awful lot of work, but since only - * the server is allowed to do this, we trust it on this one :) - */ -int32 CmdChangePatchSetting(int x, int y, uint32 flags, uint32 p1, uint32 p2) -{ - byte pcat = GB(p1, 0, 8); - byte pel = GB(p1, 8, 8); - - if (pcat >= lengthof(_patches_page)) return CMD_ERROR; - if (pel >= _patches_page[pcat].num) return CMD_ERROR; - - if (flags & DC_EXEC) { - const PatchEntry *pe = &_patches_page[pcat].entries[pel]; - WritePE(pe, (int32)p2); - - InvalidateWindow(WC_GAME_OPTIONS, 0); - } - - return 0; -} - -static const PatchEntry *IConsoleGetPatch(const char *name, uint *page, uint *entry) -{ - const PatchPage *pp; - const PatchEntry *pe; - - for (*page = 0; *page < lengthof(_patches_page); (*page)++) { - pp = &_patches_page[*page]; - for (*entry = 0; *entry < pp->num; (*entry)++) { - pe = &pp->entries[*entry]; - if (strncmp(pe->console_name, name, sizeof(pe->console_name)) == 0) - return pe; - } - } - - return NULL; -} - -/* 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 IConsoleSetPatchSetting(const char *name, const char *value) -{ - const PatchEntry *pe; - uint page, entry; - int val; - - pe = IConsoleGetPatch(name, &page, &entry); - - if (pe == NULL) { - IConsolePrintF(_icolour_warn, "'%s' is an unknown patch setting.", name); - return; - } - - sscanf(value, "%d", &val); - - if (pe->type == PE_CURRENCY) // currency can be different on each client - val /= _currency->rate; - - // If an item is playerbased, we do not send it over the network (if any) - if (pe->flags & PF_PLAYERBASED) { - WritePE(pe, val); - } else // Else we do - DoCommandP(0, page + (entry << 8), val, NULL, CMD_CHANGE_PATCH_SETTING); - - { - char tval[20]; - const char *tval2 = value; - if (pe->type == PE_BOOL) { - snprintf(tval, sizeof(tval), (val == 1) ? "on" : "off"); - tval2 = tval; - } - - IConsolePrintF(_icolour_warn, "'%s' changed to: %s", name, tval2); - } -} - -void IConsoleGetPatchSetting(const char *name) -{ - char value[20]; - uint page, entry; - const PatchEntry *pe = IConsoleGetPatch(name, &page, &entry); - - /* We did not find the patch setting */ - if (pe == NULL) { - IConsolePrintF(_icolour_warn, "'%s' is an unknown patch setting.", name); - return; - } - - if (pe->type == PE_BOOL) { - snprintf(value, sizeof(value), (ReadPE(pe) == 1) ? "on" : "off"); - } else { - snprintf(value, sizeof(value), "%d", ReadPE(pe)); - } - - IConsolePrintF(_icolour_warn, "Current value for '%s' is: '%s'", name, value); -} - static const Widget _patches_selection_widgets[] = { { WWT_CLOSEBOX, RESIZE_NONE, 10, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, { WWT_CAPTION, RESIZE_NONE, 10, 11, 369, 0, 13, STR_CONFIG_PATCHES_CAPTION, STR_018C_WINDOW_TITLE_DRAG_THIS},