diff --git a/src/command.cpp b/src/command.cpp index 2f9cc7d9fc..fffb39f69c 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -152,7 +152,6 @@ DEF_COMMAND(CmdDoTownAction); DEF_COMMAND(CmdSetRoadDriveSide); -DEF_COMMAND(CmdChangeDifficultyLevel); DEF_COMMAND(CmdChangePatchSetting); DEF_COMMAND(CmdStartStopShip); @@ -304,7 +303,6 @@ static const Command _command_proc_table[] = { {CmdDoTownAction, 0}, /* CMD_DO_TOWN_ACTION */ {CmdSetRoadDriveSide, CMD_SERVER}, /* CMD_SET_ROAD_DRIVE_SIDE */ - {CmdChangeDifficultyLevel, CMD_SERVER}, /* CMD_CHANGE_DIFFICULTY_LEVEL */ {CmdStartStopShip, 0}, /* CMD_START_STOP_SHIP */ {CmdSellShip, 0}, /* CMD_SELL_SHIP */ diff --git a/src/command_type.h b/src/command_type.h index da310fe4ea..742bdd9bae 100644 --- a/src/command_type.h +++ b/src/command_type.h @@ -233,8 +233,6 @@ enum { CMD_SET_ROAD_DRIVE_SIDE, ///< set the side where the road vehicles drive - CMD_CHANGE_DIFFICULTY_LEVEL, ///< change the difficult of a game (each setting for it own) - CMD_START_STOP_SHIP, ///< start/stop a ship CMD_SELL_SHIP, ///< sell a ship CMD_BUILD_SHIP, ///< build a new ship diff --git a/src/economy.cpp b/src/economy.cpp index c11125e947..d21f15efb3 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -832,7 +832,7 @@ void StartupEconomy() _economy.interest_rate = _settings.difficulty.initial_interest; _economy.infl_amount = _settings.difficulty.initial_interest; _economy.infl_amount_pr = max(0, _settings.difficulty.initial_interest - 1); - _economy.max_loan_unround = _economy.max_loan = _settings.difficulty.max_loan * 1000; + _economy.max_loan_unround = _economy.max_loan = _settings.difficulty.max_loan; _economy.fluct = GB(Random(), 0, 8) + 168; } diff --git a/src/genworld_gui.cpp b/src/genworld_gui.cpp index 63ba75b837..ef040e4da4 100644 --- a/src/genworld_gui.cpp +++ b/src/genworld_gui.cpp @@ -48,7 +48,7 @@ extern void SwitchMode(int new_mode); static inline void SetNewLandscapeType(byte landscape) { - _settings.game_creation.landscape = landscape; + _settings_newgame.game_creation.landscape = landscape; InvalidateWindowClasses(WC_SELECT_GAME); InvalidateWindowClasses(WC_GENERATE_LANDSCAPE); } @@ -253,7 +253,7 @@ struct GenerateLandscapeWindow : public QueryStringBaseWindow { GenerateLandscapeWindow(const WindowDesc *desc, WindowNumber number = 0) : QueryStringBaseWindow(desc, number) { - this->LowerWidget(_settings.game_creation.landscape + GLAND_TEMPERATE); + this->LowerWidget(_settings_newgame.game_creation.landscape + GLAND_TEMPERATE); snprintf(this->edit_str_buf, sizeof(this->edit_str_buf), "%u", _settings_newgame.game_creation.generation_seed); InitializeTextBuffer(&this->text, this->edit_str_buf, lengthof(this->edit_str_buf), 120); @@ -272,7 +272,7 @@ struct GenerateLandscapeWindow : public QueryStringBaseWindow { this->SetWidgetDisabledState(GLAND_SMOOTHNESS_PULLDOWN, _settings_newgame.game_creation.land_generator == 0); } /* Disable snowline if not hilly */ - this->SetWidgetDisabledState(GLAND_SNOW_LEVEL_TEXT, _settings.game_creation.landscape != LT_ARCTIC); + this->SetWidgetDisabledState(GLAND_SNOW_LEVEL_TEXT, _settings_newgame.game_creation.landscape != LT_ARCTIC); /* Disable town, industry and trees in SE */ this->SetWidgetDisabledState(GLAND_TOWN_PULLDOWN, _game_mode == GM_EDITOR); this->SetWidgetDisabledState(GLAND_INDUSTRY_PULLDOWN, _game_mode == GM_EDITOR); @@ -280,13 +280,13 @@ struct GenerateLandscapeWindow : public QueryStringBaseWindow { this->SetWidgetDisabledState(GLAND_START_DATE_DOWN, _settings_newgame.game_creation.starting_year <= MIN_YEAR); this->SetWidgetDisabledState(GLAND_START_DATE_UP, _settings_newgame.game_creation.starting_year >= MAX_YEAR); - this->SetWidgetDisabledState(GLAND_SNOW_LEVEL_DOWN, _settings_newgame.game_creation.snow_line_height <= 2 || _settings.game_creation.landscape != LT_ARCTIC); - this->SetWidgetDisabledState(GLAND_SNOW_LEVEL_UP, _settings_newgame.game_creation.snow_line_height >= MAX_SNOWLINE_HEIGHT || _settings.game_creation.landscape != LT_ARCTIC); + this->SetWidgetDisabledState(GLAND_SNOW_LEVEL_DOWN, _settings_newgame.game_creation.snow_line_height <= 2 || _settings_newgame.game_creation.landscape != LT_ARCTIC); + this->SetWidgetDisabledState(GLAND_SNOW_LEVEL_UP, _settings_newgame.game_creation.snow_line_height >= MAX_SNOWLINE_HEIGHT || _settings_newgame.game_creation.landscape != LT_ARCTIC); - this->SetWidgetLoweredState(GLAND_TEMPERATE, _settings.game_creation.landscape == LT_TEMPERATE); - this->SetWidgetLoweredState(GLAND_ARCTIC, _settings.game_creation.landscape == LT_ARCTIC); - this->SetWidgetLoweredState(GLAND_TROPICAL, _settings.game_creation.landscape == LT_TROPIC); - this->SetWidgetLoweredState(GLAND_TOYLAND, _settings.game_creation.landscape == LT_TOYLAND); + this->SetWidgetLoweredState(GLAND_TEMPERATE, _settings_newgame.game_creation.landscape == LT_TEMPERATE); + this->SetWidgetLoweredState(GLAND_ARCTIC, _settings_newgame.game_creation.landscape == LT_ARCTIC); + this->SetWidgetLoweredState(GLAND_TROPICAL, _settings_newgame.game_creation.landscape == LT_TROPIC); + this->SetWidgetLoweredState(GLAND_TOYLAND, _settings_newgame.game_creation.landscape == LT_TOYLAND); if (_game_mode == GM_EDITOR) { this->widget[GLAND_TOWN_PULLDOWN].data = STR_6836_OFF; @@ -345,7 +345,7 @@ struct GenerateLandscapeWindow : public QueryStringBaseWindow { case GLAND_ARCTIC: case GLAND_TROPICAL: case GLAND_TOYLAND: - this->RaiseWidget(_settings.game_creation.landscape + GLAND_TEMPERATE); + this->RaiseWidget(_settings_newgame.game_creation.landscape + GLAND_TEMPERATE); SetNewLandscapeType(widget - GLAND_TEMPERATE); break; @@ -492,13 +492,13 @@ struct GenerateLandscapeWindow : public QueryStringBaseWindow { case GLAND_TOWN_PULLDOWN: _settings_newgame.difficulty.number_towns = index; if (_settings_newgame.difficulty.diff_level != 3) ShowErrorMessage(INVALID_STRING_ID, STR_DIFFICULTY_TO_CUSTOM, 0, 0); - DoCommandP(0, 2, _settings_newgame.difficulty.number_towns, NULL, CMD_CHANGE_DIFFICULTY_LEVEL); + IConsoleSetPatchSetting("difficulty.number_towns", _settings_newgame.difficulty.number_towns); break; case GLAND_INDUSTRY_PULLDOWN: _settings_newgame.difficulty.number_industries = index; if (_settings_newgame.difficulty.diff_level != 3) ShowErrorMessage(INVALID_STRING_ID, STR_DIFFICULTY_TO_CUSTOM, 0, 0); - DoCommandP(0, 3, _settings_newgame.difficulty.number_industries, NULL, CMD_CHANGE_DIFFICULTY_LEVEL); + IConsoleSetPatchSetting("difficulty.number_industries", _settings_newgame.difficulty.number_industries); break; case GLAND_LANDSCAPE_PULLDOWN: @@ -513,13 +513,13 @@ struct GenerateLandscapeWindow : public QueryStringBaseWindow { case GLAND_TERRAIN_PULLDOWN: _settings_newgame.difficulty.terrain_type = index; if (_settings_newgame.difficulty.diff_level != 3) ShowErrorMessage(INVALID_STRING_ID, STR_DIFFICULTY_TO_CUSTOM, 0, 0); - DoCommandP(0, 12, _settings_newgame.difficulty.terrain_type, NULL, CMD_CHANGE_DIFFICULTY_LEVEL); + IConsoleSetPatchSetting("difficulty.terrain_type", _settings_newgame.difficulty.terrain_type); break; case GLAND_WATER_PULLDOWN: _settings_newgame.difficulty.quantity_sea_lakes = index; if (_settings_newgame.difficulty.diff_level != 3) ShowErrorMessage(INVALID_STRING_ID, STR_DIFFICULTY_TO_CUSTOM, 0, 0); - DoCommandP(0, 13, _settings_newgame.difficulty.quantity_sea_lakes, NULL, CMD_CHANGE_DIFFICULTY_LEVEL); + IConsoleSetPatchSetting("difficulty.quantity_sea_lakes", _settings_newgame.difficulty.quantity_sea_lakes); break; } this->SetDirty(); @@ -642,7 +642,7 @@ struct CreateScenarioWindow : public Window CreateScenarioWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number) { - this->LowerWidget(_settings.game_creation.landscape + CSCEN_TEMPERATE); + this->LowerWidget(_settings_newgame.game_creation.landscape + CSCEN_TEMPERATE); this->FindWindowPlacementAndResize(desc); } @@ -653,10 +653,10 @@ struct CreateScenarioWindow : public Window this->SetWidgetDisabledState(CSCEN_FLAT_LAND_HEIGHT_DOWN, _settings_newgame.game_creation.se_flat_world_height <= 0); this->SetWidgetDisabledState(CSCEN_FLAT_LAND_HEIGHT_UP, _settings_newgame.game_creation.se_flat_world_height >= MAX_TILE_HEIGHT); - this->SetWidgetLoweredState(CSCEN_TEMPERATE, _settings.game_creation.landscape == LT_TEMPERATE); - this->SetWidgetLoweredState(CSCEN_ARCTIC, _settings.game_creation.landscape == LT_ARCTIC); - this->SetWidgetLoweredState(CSCEN_TROPICAL, _settings.game_creation.landscape == LT_TROPIC); - this->SetWidgetLoweredState(CSCEN_TOYLAND, _settings.game_creation.landscape == LT_TOYLAND); + this->SetWidgetLoweredState(CSCEN_TEMPERATE, _settings_newgame.game_creation.landscape == LT_TEMPERATE); + this->SetWidgetLoweredState(CSCEN_ARCTIC, _settings_newgame.game_creation.landscape == LT_ARCTIC); + this->SetWidgetLoweredState(CSCEN_TROPICAL, _settings_newgame.game_creation.landscape == LT_TROPIC); + this->SetWidgetLoweredState(CSCEN_TOYLAND, _settings_newgame.game_creation.landscape == LT_TOYLAND); /* Set parameters for widget text that requires them */ SetDParam(0, ConvertYMDToDate(_settings_newgame.game_creation.starting_year, 0, 1)); // CSCEN_START_DATE_TEXT @@ -674,7 +674,7 @@ struct CreateScenarioWindow : public Window case CSCEN_ARCTIC: case CSCEN_TROPICAL: case CSCEN_TOYLAND: - this->RaiseWidget(_settings.game_creation.landscape + CSCEN_TEMPERATE); + this->RaiseWidget(_settings_newgame.game_creation.landscape + CSCEN_TEMPERATE); SetNewLandscapeType(widget - CSCEN_TEMPERATE); break; diff --git a/src/misc.cpp b/src/misc.cpp index 6d0f453926..e53e2f1403 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -67,6 +67,7 @@ void InitializeGame(int mode, uint size_x, uint size_y) _realtime_tick = 0; _date_fract = 0; _cur_tileloop_tile = 0; + _settings = _settings_newgame; if ((mode & IG_DATE_RESET) == IG_DATE_RESET) { SetDate(ConvertYMDToDate(_settings.game_creation.starting_year, 0, 1)); diff --git a/src/misc_cmd.cpp b/src/misc_cmd.cpp index 49e3eafdbc..6da4895fbf 100644 --- a/src/misc_cmd.cpp +++ b/src/misc_cmd.cpp @@ -22,7 +22,6 @@ #include "player_base.h" #include "player_gui.h" #include "settings_type.h" -#include "station_func.h" #include "table/strings.h" @@ -380,46 +379,3 @@ CommandCost CmdGiveMoney(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) /* Subtract money from local-player */ return amount; } - -/** Change difficulty level/settings (server-only). - * We cannot really check for valid values of p2 (too much work mostly); stored - * in file 'settings_gui.c' _game_setting_info[]; we'll just trust the server it knows - * what to do and does this correctly - * @param tile unused - * @param flags operation to perform - * @param p1 the difficulty setting being changed. If it is -1, the difficulty level - * itself is changed. The new value is inside p2 - * @param p2 new value for a difficulty setting or difficulty level - */ -CommandCost CmdChangeDifficultyLevel(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) -{ - if (p1 != (uint32)-1L && ((int32)p1 >= GAME_DIFFICULTY_NUM || (int32)p1 < 0)) return CMD_ERROR; - - DifficultySettings *opt_ptr = (_game_mode == GM_MENU) ? &_settings_newgame.difficulty : &_settings.difficulty; - - if (flags & DC_EXEC) { - if (p1 != (uint32)-1L) { - ((GDType*)opt_ptr)[p1] = p2; - opt_ptr->diff_level = 3; // custom difficulty level - } else { - opt_ptr->diff_level = p2; - } - - /* Since the tolerance of the town council has a direct impact on the noise generation/tolerance, - * launch a re-evaluation of the actual values only when setting has changed */ - if (p2 == GAME_DIFFICULTY_TOWNCOUNCIL_TOLERANCE && _game_mode == GM_NORMAL) { - UpdateAirportsNoise(); - if (_settings.economy.station_noise_level) { - InvalidateWindowClassesData(WC_TOWN_VIEW, 0); - } - } - - /* If we are a network-client, update the difficult setting (if it is open). - * Use this instead of just dirtying the window because we need to load in - * the new difficulty settings */ - if (_networking && !_network_server && FindWindowById(WC_GAME_OPTIONS, 0) != NULL) { - ShowGameDifficulty(); - } - } - return CommandCost(); -} diff --git a/src/oldloader.cpp b/src/oldloader.cpp index 8bc9c7be40..bf7543bc1c 100644 --- a/src/oldloader.cpp +++ b/src/oldloader.cpp @@ -1374,7 +1374,7 @@ static const OldChunks game_difficulty_chunk[] = { OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, competitor_start_time ), OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, number_towns ), OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, number_industries ), - OCL_SVAR( OC_FILE_U16 | OC_VAR_U16, DifficultySettings, max_loan ), + OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, DifficultySettings, max_loan ), OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, initial_interest ), OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, vehicle_costs ), OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, competitor_speed ), @@ -1392,7 +1392,9 @@ static const OldChunks game_difficulty_chunk[] = { static inline bool LoadOldGameDifficulty(LoadgameState *ls, int num) { - return LoadChunk(ls, &_settings.difficulty, game_difficulty_chunk); + bool ret = LoadChunk(ls, &_settings.difficulty, game_difficulty_chunk); + _settings.difficulty.max_loan *= 1000; + return ret; } diff --git a/src/saveload.cpp b/src/saveload.cpp index fc13f8b89d..d9fecbd973 100644 --- a/src/saveload.cpp +++ b/src/saveload.cpp @@ -35,7 +35,7 @@ #include "table/strings.h" -extern const uint16 SAVEGAME_VERSION = 96; +extern const uint16 SAVEGAME_VERSION = 97; SavegameType _savegame_type; ///< type of savegame we are loading diff --git a/src/settings.cpp b/src/settings.cpp index b03bff6023..b827175299 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -60,6 +60,7 @@ #include "sound/sound_driver.hpp" #include "music/music_driver.hpp" #include "blitter/factory.hpp" +#include "station_func.h" #include "table/strings.h" @@ -764,7 +765,7 @@ static void ini_load_settings(IniFile *ini, const SettingDesc *sd, const char *g } p = (item == NULL) ? sdb->def : string_to_val(sdb, item->value); - ptr = GetVariableAddress(object, sld); + ptr = GetVariableAddress(sld->global ? NULL : object, sld); switch (sdb->cmd) { case SDT_BOOLX: /* All four are various types of (integer) numbers */ @@ -1133,6 +1134,7 @@ static void ini_save_setting_list(IniFile *ini, const char *grpname, char **list #define NO SGF_NETWORK_ONLY #define CR SGF_CURRENCY #define NN SGF_NO_NETWORK +#define NG SGF_NEWGAME_ONLY /* Begin - Callback Functions for the various settings */ /* virtual PositionMainToolbar function, calls the right one.*/ @@ -1274,6 +1276,92 @@ static int32 DragSignalsDensityChanged(int32) return 0; } +/* + * A: competitors + * B: start time in months / 3 + * C: town count (3 = high, 0 = very low) + * D: industry count (4 = high, 0 = none) + * E: inital loan (in GBP) + * F: interest rate + * G: running costs (0 = low, 2 = high) + * H: construction speed of competitors (0 = very slow, 4 = very fast) + * I: intelligence (0-2) + * J: breakdowns (0 = off, 2 = normal) + * K: subsidy multiplier (0 = 1.5, 3 = 4.0) + * L: construction cost (0-2) + * M: terrain type (0 = very flat, 3 = mountainous) + * N: amount of water (0 = very low, 3 = high) + * O: economy (0 = steady, 1 = fluctuating) + * P: Train reversing (0 = end of line + stations, 1 = end of line) + * Q: disasters + * R: area restructuring (0 = permissive, 2 = hostile) + * S: the difficulty level + */ +static const DifficultySettings _default_game_diff[3] = { /* + A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S*/ + {2, 2, 2, 4, 300000, 2, 0, 2, 0, 1, 2, 0, 1, 0, 0, 0, 0, 0, 0}, ///< easy + {4, 1, 2, 3, 150000, 3, 1, 3, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1}, ///< medium + {7, 0, 3, 3, 100000, 4, 1, 3, 2, 2, 0, 2, 3, 2, 1, 1, 1, 2, 2}, ///< hard +}; + +void SetDifficultyLevel(int mode, DifficultySettings *gm_opt) +{ + assert(mode <= 3); + + if (mode != 3) { + *gm_opt = _default_game_diff[mode]; + } else { + gm_opt->diff_level = 3; + } +} + +/** + * Checks the difficulty levels read from the configuration and + * forces them to be correct when invalid. + */ +void CheckDifficultyLevels() +{ + if (_settings_newgame.difficulty.diff_level != 3) { + SetDifficultyLevel(_settings_newgame.difficulty.diff_level, &_settings_newgame.difficulty); + } +} + +static int32 DifficultyReset(int32 level) +{ + SetDifficultyLevel(level, (_game_mode == GM_MENU) ? &_settings_newgame.difficulty : &_settings.difficulty); + return 0; +} + +static int32 DifficultyChange(int32) +{ + if (_game_mode == GM_MENU) { + _settings_newgame.difficulty.diff_level = 3; + } else { + _settings.difficulty.diff_level = 3; + } + + /* If we are a network-client, update the difficult setting (if it is open). + * Use this instead of just dirtying the window because we need to load in + * the new difficulty settings */ + if (_networking && FindWindowById(WC_GAME_OPTIONS, 0) != NULL) { + ShowGameDifficulty(); + } + + return 0; +} + +static int32 DifficultyNoiseChange(int32 i) +{ + if (_game_mode == GM_NORMAL) { + UpdateAirportsNoise(); + if (_settings.economy.station_noise_level) { + InvalidateWindowClassesData(WC_TOWN_VIEW, 0); + } + } + + return DifficultyChange(i); +} + /** * Check for right TownLayout usage in editor mode. * The No Road mode is not desirable since towns have to be @@ -1417,6 +1505,9 @@ static const SettingDescGlobVarList _network_settings[] = { }; #endif /* ENABLE_NETWORK */ +static const uint GAME_DIFFICULTY_NUM = 18; +uint16 _old_diff_custom[GAME_DIFFICULTY_NUM]; + static const SettingDesc _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 @@ -1427,18 +1518,19 @@ static const SettingDesc _gameopt_settings[] = { * and why not byte for example? * 'SLE_FILE_I16 | SLE_VAR_U16' in "diff_custom" is needed to get around SlArray() hack * for savegames version 0 - though it is an array, it has to go through the byteswap process */ - SDT_GENERAL("diff_custom", SDT_INTLIST, SL_ARR, SLE_FILE_I16 | SLE_VAR_U16, 0, 0, Settings, difficulty, 17, 0, 0, 0, 0, NULL, STR_NULL, NULL, NULL, 0, 3), - SDT_GENERAL("diff_custom", SDT_INTLIST, SL_ARR, SLE_UINT16, 0, 0, Settings, difficulty, 18, 0, 0, 0, 0, NULL, STR_NULL, NULL, NULL, 4, SL_MAX_VERSION), - SDT_VAR(Settings, difficulty.diff_level, SLE_UINT8, 0, 0, 0, 0, 3, 0, STR_NULL, NULL), - SDT_OMANY(Settings, gui.currency, SLE_UINT8, N, 0, 0, CUSTOM_CURRENCY_ID, "GBP|USD|EUR|YEN|ATS|BEF|CHF|CZK|DEM|DKK|ESP|FIM|FRF|GRD|HUF|ISK|ITL|NLG|NOK|PLN|ROL|RUR|SIT|SEK|YTL|SKK|BRR|custom", STR_NULL, NULL, NULL), - SDT_OMANY(Settings, gui.units, SLE_UINT8, N, 0, 1, 2, "imperial|metric|si", STR_NULL, NULL, NULL), + SDTG_GENERAL("diff_custom", SDT_INTLIST, SL_ARR, SLE_FILE_I16 | SLE_VAR_U16, C, 0, _old_diff_custom, 17, 0, 0, 0, 0, NULL, STR_NULL, NULL, 0, 3), + SDTG_GENERAL("diff_custom", SDT_INTLIST, SL_ARR, SLE_UINT16, C, 0, _old_diff_custom, 18, 0, 0, 0, 0, NULL, STR_NULL, NULL, 4, 96), + + SDT_VAR(Settings, difficulty.diff_level, SLE_UINT8, 0, 0, 0, 0, 3, 0, STR_NULL, NULL), + SDT_OMANY(Settings, gui.currency, SLE_UINT8, N, 0, 0, CUSTOM_CURRENCY_ID, "GBP|USD|EUR|YEN|ATS|BEF|CHF|CZK|DEM|DKK|ESP|FIM|FRF|GRD|HUF|ISK|ITL|NLG|NOK|PLN|ROL|RUR|SIT|SEK|YTL|SKK|BRR|custom", STR_NULL, NULL, NULL), + SDT_OMANY(Settings, gui.units, SLE_UINT8, N, 0, 1, 2, "imperial|metric|si", STR_NULL, NULL, NULL), /* There are only 21 predefined town_name values (0-20), but you can have more with newgrf action F so allow these bigger values (21-255). Invalid values will fallback to english on use and (undefined string) in GUI. */ - SDT_OMANY(Settings, game_creation.town_name, SLE_UINT8, 0, 0, 0, 255, "english|french|german|american|latin|silly|swedish|dutch|finnish|polish|slovakish|norwegian|hungarian|austrian|romanian|czech|swiss|danish|turkish|italian|catalan", STR_NULL, NULL, NULL), - SDT_OMANY(Settings, game_creation.landscape, SLE_UINT8, 0, 0, 0, 3, "temperate|arctic|tropic|toyland", STR_NULL, NULL, ConvertLandscape), - SDT_VAR(Settings, game_creation.snow_line, SLE_UINT8, 0, 0, 7 * TILE_HEIGHT, 2 * TILE_HEIGHT, 13 * TILE_HEIGHT, 0, STR_NULL, NULL), - SDT_CONDOMANY(Settings,gui.autosave, SLE_UINT8, 0, 22, N, 0, 0, 0, "", STR_NULL, NULL, NULL), - SDT_CONDOMANY(Settings,gui.autosave, SLE_UINT8,23, SL_MAX_VERSION, S, 0, 1, 4, "off|monthly|quarterly|half year|yearly", STR_NULL, NULL, NULL), - SDT_OMANY(Settings, vehicle.road_side, SLE_UINT8, 0, 0, 1, 1, "left|right", STR_NULL, NULL, NULL), + SDT_OMANY(Settings, game_creation.town_name, SLE_UINT8, 0, 0, 0, 255, "english|french|german|american|latin|silly|swedish|dutch|finnish|polish|slovakish|norwegian|hungarian|austrian|romanian|czech|swiss|danish|turkish|italian|catalan", STR_NULL, NULL, NULL), + SDT_OMANY(Settings, game_creation.landscape, SLE_UINT8, 0, 0, 0, 3, "temperate|arctic|tropic|toyland", STR_NULL, NULL, ConvertLandscape), + SDT_VAR(Settings, game_creation.snow_line, SLE_UINT8, 0, 0, 7 * TILE_HEIGHT, 2 * TILE_HEIGHT, 13 * TILE_HEIGHT, 0, STR_NULL, NULL), + SDT_CONDOMANY(Settings, gui.autosave, SLE_UINT8, 0, 22, N, 0, 0, 0, "", STR_NULL, NULL, NULL), + SDT_CONDOMANY(Settings, gui.autosave, SLE_UINT8, 23, SL_MAX_VERSION, S, 0, 1, 4, "off|monthly|quarterly|half year|yearly", STR_NULL, NULL, NULL), + SDT_OMANY(Settings, vehicle.road_side, SLE_UINT8, 0, 0, 1, 1, "left|right", STR_NULL, NULL, NULL), SDT_END() }; @@ -1454,6 +1546,32 @@ static const SettingDesc _gameopt_settings[] = { const SettingDesc _patch_settings[] = { /***************************************************************************/ /* Saved patch variables. */ + /* Do not ADD or REMOVE something in this "difficulty.XXX" table or before it. It breaks savegame compatability. */ + SDT_CONDVAR(Settings, difficulty.max_no_competitors, SLE_UINT8, 97, SL_MAX_VERSION, 0, 0, 2, 0, 7, 1, STR_NULL, DifficultyChange), + SDT_CONDVAR(Settings, difficulty.competitor_start_time, SLE_UINT8, 97, SL_MAX_VERSION, 0,NG, 2, 0, 3, 1, STR_6830_IMMEDIATE, DifficultyChange), + SDT_CONDVAR(Settings, difficulty.number_towns, SLE_UINT8, 97, SL_MAX_VERSION, 0,NG, 2, 0, 3, 1, STR_NUM_VERY_LOW, DifficultyChange), + SDT_CONDVAR(Settings, difficulty.number_industries, SLE_UINT8, 97, SL_MAX_VERSION, 0,NG, 4, 0, 4, 1, STR_NONE, DifficultyChange), + SDT_CONDVAR(Settings, difficulty.max_loan, SLE_UINT32, 97, SL_MAX_VERSION, 0,NG|CR,300000,100000,500000,50000,STR_NULL, DifficultyChange), + SDT_CONDVAR(Settings, difficulty.initial_interest, SLE_UINT8, 97, SL_MAX_VERSION, 0,NG, 2, 2, 4, 1, STR_NULL, DifficultyChange), + SDT_CONDVAR(Settings, difficulty.vehicle_costs, SLE_UINT8, 97, SL_MAX_VERSION, 0, 0, 0, 0, 2, 1, STR_6820_LOW, DifficultyChange), + SDT_CONDVAR(Settings, difficulty.competitor_speed, SLE_UINT8, 97, SL_MAX_VERSION, 0, 0, 2, 0, 4, 1, STR_681B_VERY_SLOW, DifficultyChange), + SDT_CONDVAR(Settings, difficulty.competitor_intelligence, SLE_UINT8, 97, SL_MAX_VERSION, 0, 0, 0, 0, 2, 1, STR_6820_LOW, DifficultyChange), + SDT_CONDVAR(Settings, difficulty.vehicle_breakdowns, SLE_UINT8, 97, SL_MAX_VERSION, 0, 0, 1, 0, 2, 1, STR_6823_NONE, DifficultyChange), + SDT_CONDVAR(Settings, difficulty.subsidy_multiplier, SLE_UINT8, 97, SL_MAX_VERSION, 0, 0, 2, 0, 3, 1, STR_6826_X1_5, DifficultyChange), + SDT_CONDVAR(Settings, difficulty.construction_cost, SLE_UINT8, 97, SL_MAX_VERSION, 0,NG, 0, 0, 2, 1, STR_6820_LOW, DifficultyChange), + SDT_CONDVAR(Settings, difficulty.terrain_type, SLE_UINT8, 97, SL_MAX_VERSION, 0,NG, 1, 0, 3, 1, STR_682A_VERY_FLAT, DifficultyChange), + SDT_CONDVAR(Settings, difficulty.quantity_sea_lakes, SLE_UINT8, 97, SL_MAX_VERSION, 0,NG, 0, 0, 3, 1, STR_VERY_LOW, DifficultyChange), + SDT_CONDVAR(Settings, difficulty.economy, SLE_UINT8, 97, SL_MAX_VERSION, 0, 0, 0, 0, 1, 1, STR_682E_STEADY, DifficultyChange), + SDT_CONDVAR(Settings, difficulty.line_reverse_mode, SLE_UINT8, 97, SL_MAX_VERSION, 0, 0, 0, 0, 1, 1, STR_6834_AT_END_OF_LINE_AND_AT_STATIONS, DifficultyChange), + SDT_CONDVAR(Settings, difficulty.disasters, SLE_UINT8, 97, SL_MAX_VERSION, 0, 0, 0, 0, 1, 1, STR_6836_OFF, DifficultyChange), + SDT_CONDVAR(Settings, difficulty.town_council_tolerance, SLE_UINT8, 97, SL_MAX_VERSION, 0, 0, 0, 0, 2, 1, STR_PERMISSIVE, DifficultyNoiseChange), + SDT_CONDVAR(Settings, difficulty.diff_level, SLE_UINT8, 97, SL_MAX_VERSION, 0,NG, 0, 0, 3, 0, STR_NULL, DifficultyReset), + + /* There are only 21 predefined town_name values (0-20), but you can have more with newgrf action F so allow these bigger values (21-255). Invalid values will fallback to english on use and (undefined string) in GUI. */ + SDT_CONDOMANY(Settings, game_creation.town_name, SLE_UINT8, 97, SL_MAX_VERSION, 0,NN, 0, 255, "english|french|german|american|latin|silly|swedish|dutch|finnish|polish|slovakish|norwegian|hungarian|austrian|romanian|czech|swiss|danish|turkish|italian|catalan", STR_NULL, NULL, NULL), + SDT_CONDOMANY(Settings, game_creation.landscape, SLE_UINT8, 97, SL_MAX_VERSION, 0,NN, 0, 3, "temperate|arctic|tropic|toyland", STR_NULL, NULL, ConvertLandscape), + SDT_CONDVAR(Settings, game_creation.snow_line, SLE_UINT8, 97, SL_MAX_VERSION, 0,NN, 7 * TILE_HEIGHT, 2 * TILE_HEIGHT, 13 * TILE_HEIGHT, 0, STR_NULL, NULL), + SDT_CONDOMANY(Settings, vehicle.road_side, SLE_UINT8, 97, SL_MAX_VERSION, 0,NN, 1, 1, "left|right", STR_NULL, NULL, NULL), SDT_BOOL(Settings, construction.build_on_slopes, 0,NN, true, STR_CONFIG_PATCHES_BUILDONSLOPES, NULL), SDT_CONDBOOL(Settings, construction.autoslope, 75, SL_MAX_VERSION, 0, 0, true, STR_CONFIG_PATCHES_AUTOSLOPE, NULL), @@ -1593,8 +1711,12 @@ const SettingDesc _patch_settings[] = { SDT_VAR(Settings, game_creation.heightmap_rotation, SLE_UINT8, S,MS, 0, 0, 1, 0, STR_CONFIG_PATCHES_HEIGHTMAP_ROTATION, NULL), SDT_VAR(Settings, game_creation.se_flat_world_height, SLE_UINT8, S, 0, 0, 0, 15, 0, STR_CONFIG_PATCHES_SE_FLAT_WORLD_HEIGHT, NULL), + SDT_CONDOMANY(Settings, gui.currency, SLE_UINT8, 97, SL_MAX_VERSION, N, 0, 0, CUSTOM_CURRENCY_ID, "GBP|USD|EUR|YEN|ATS|BEF|CHF|CZK|DEM|DKK|ESP|FIM|FRF|GRD|HUF|ISK|ITL|NLG|NOK|PLN|ROL|RUR|SIT|SEK|YTL|SKK|BRR|custom", STR_NULL, NULL, NULL), + SDT_CONDOMANY(Settings, gui.units, SLE_UINT8, 97, SL_MAX_VERSION, N, 0, 1, 2, "imperial|metric|si", STR_NULL, NULL, NULL), + /***************************************************************************/ /* Unsaved patch variables. */ + SDT_OMANY(Settings, gui.autosave, SLE_UINT8, S, 0, 1, 4, "off|monthly|quarterly|half year|yearly", STR_NULL, NULL, NULL), SDT_BOOL(Settings, gui.vehicle_speed, S, 0, true, STR_CONFIG_PATCHES_VEHICLESPEED, NULL), SDT_BOOL(Settings, gui.status_long_date, S, 0, true, STR_CONFIG_PATCHES_LONGDATE, NULL), SDT_BOOL(Settings, gui.show_finances, S, 0, true, STR_CONFIG_PATCHES_SHOWFINANCES, NULL), @@ -1671,6 +1793,31 @@ static const SettingDesc _currency_settings[] = { #undef NO #undef CR +static void PrepareOldDiffCustom() +{ + memset(_old_diff_custom, 0, sizeof(_old_diff_custom)); +} + +static void HandleOldDiffCustom() +{ + uint options_to_load = GAME_DIFFICULTY_NUM - (CheckSavegameVersion(4) ? 1 : 0); + + /* If we did read to old_diff_custom, then at least one value must be non 0. */ + bool old_diff_custom_used = false; + for (uint i = 0; i < options_to_load && !old_diff_custom_used; i++) { + old_diff_custom_used = (_old_diff_custom[i] != 0); + } + + if (!old_diff_custom_used) return; + + for (uint i = 0; i < options_to_load; i++) { + const SettingDesc *sd = &_patch_settings[i]; + void *var = GetVariableAddress((_game_mode == GM_MENU) ? &_settings_newgame : &_settings, &sd->save); + Write_ValidateSetting(var, sd, (int32)((i == 4 ? 1000 : 1) * _old_diff_custom[i])); + } +} + + static void NewsDisplayLoadConfig(IniFile *ini, const char *grpname) { IniGroup *group = ini_getgroup(ini, grpname); @@ -1836,7 +1983,10 @@ static void HandleSettingDescs(IniFile *ini, SettingDescProc *proc, SettingDescP proc(ini, (const SettingDesc*)_win32_settings, "win32", NULL); #endif /* WIN32 */ + PrepareOldDiffCustom(); proc(ini, _gameopt_settings, "gameopt", &_settings_newgame); + HandleOldDiffCustom(); + proc(ini, _patch_settings, "patches", &_settings_newgame); proc(ini, _currency_settings,"currency", &_custom_currency); @@ -1847,8 +1997,6 @@ static void HandleSettingDescs(IniFile *ini, SettingDescProc *proc, SettingDescP #endif /* ENABLE_NETWORK */ } -extern void CheckDifficultyLevels(); - /** Load the values from the configuration files */ void LoadFromConfig() { @@ -1870,6 +2018,7 @@ void SaveToConfig() /* Remove some obsolete groups. These have all been loaded into other groups. */ ini_removegroup(ini, "patches"); ini_removegroup(ini, "yapf"); + ini_removegroup(ini, "gameopt"); HandleSettingDescs(ini, ini_save_settings, ini_save_setting_list); GRFSaveConfig(ini, "newgrf", _grfconfig_newgame); @@ -1903,6 +2052,7 @@ CommandCost CmdChangePatchSetting(TileIndex tile, uint32 flags, uint32 p1, uint3 if ((sd->desc.flags & SGF_NETWORK_ONLY) && !_networking) return CMD_ERROR; if ((sd->desc.flags & SGF_NO_NETWORK) && _networking) return CMD_ERROR; + if ((sd->desc.flags & SGF_NEWGAME_ONLY) && _game_mode != GM_MENU) return CMD_ERROR; if (flags & DC_EXEC) { Settings *s = (_game_mode == GM_MENU) ? &_settings_newgame : &_settings; @@ -2034,7 +2184,7 @@ static void LoadSettings(const SettingDesc *osd, void *object) { for (; osd->save.cmd != SL_END; osd++) { const SaveLoad *sld = &osd->save; - void *ptr = GetVariableAddress(object, sld); + void *ptr = GetVariableAddress(sld->global ? NULL : object, sld); if (!SlObjectMember(ptr, sld)) continue; } @@ -2084,12 +2234,9 @@ static void Load_OPTS() /* Copy over default setting since some might not get loaded in * a networking environment. This ensures for example that the local * autosave-frequency stays when joining a network-server */ + PrepareOldDiffCustom(); LoadSettings(_gameopt_settings, &_settings); -} - -static void Save_OPTS() -{ - SaveSettings(_gameopt_settings, &_settings); + HandleOldDiffCustom(); } static void Load_PATS() @@ -2124,7 +2271,7 @@ void UpdatePatches() } extern const ChunkHandler _setting_chunk_handlers[] = { - { 'OPTS', Save_OPTS, Load_OPTS, CH_RIFF}, + { 'OPTS', NULL, Load_OPTS, CH_RIFF}, { 'PATS', Save_PATS, Load_PATS, CH_RIFF | CH_LAST}, }; diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 7b2fbdaef6..4b0f2a3d35 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -289,7 +289,7 @@ struct GameOptionsWindow : Window { break; case GAMEOPT_AUTOSAVE_BTN: // Autosave options - _settings.gui.autosave = _settings.gui.autosave = index; + _settings.gui.autosave = _settings_newgame.gui.autosave = index; this->SetDirty(); break; @@ -361,90 +361,6 @@ void ShowGameOptions() new GameOptionsWindow(&_game_options_desc); } -struct GameSettingData { - int16 min; - int16 max; - int16 step; - StringID str; -}; - -static const GameSettingData _game_setting_info[] = { - { 0, 7, 1, STR_NULL}, - { 0, 3, 1, STR_6830_IMMEDIATE}, - { 0, 3, 1, STR_NUM_VERY_LOW}, - { 0, 4, 1, STR_NONE}, - {100, 500, 50, STR_NULL}, - { 2, 4, 1, STR_NULL}, - { 0, 2, 1, STR_6820_LOW}, - { 0, 4, 1, STR_681B_VERY_SLOW}, - { 0, 2, 1, STR_6820_LOW}, - { 0, 2, 1, STR_6823_NONE}, - { 0, 3, 1, STR_6826_X1_5}, - { 0, 2, 1, STR_6820_LOW}, - { 0, 3, 1, STR_682A_VERY_FLAT}, - { 0, 3, 1, STR_VERY_LOW}, - { 0, 1, 1, STR_682E_STEADY}, - { 0, 1, 1, STR_6834_AT_END_OF_LINE_AND_AT_STATIONS}, - { 0, 1, 1, STR_6836_OFF}, - { 0, 2, 1, STR_PERMISSIVE}, -}; - -/* - * A: competitors - * B: start time in months / 3 - * C: town count (3 = high, 0 = very low) - * D: industry count (4 = high, 0 = none) - * E: inital loan / 1000 (in GBP) - * F: interest rate - * G: running costs (0 = low, 2 = high) - * H: construction speed of competitors (0 = very slow, 4 = very fast) - * I: intelligence (0-2) - * J: breakdowns (0 = off, 2 = normal) - * K: subsidy multiplier (0 = 1.5, 3 = 4.0) - * L: construction cost (0-2) - * M: terrain type (0 = very flat, 3 = mountainous) - * N: amount of water (0 = very low, 3 = high) - * O: economy (0 = steady, 1 = fluctuating) - * P: Train reversing (0 = end of line + stations, 1 = end of line) - * Q: disasters - * R: area restructuring (0 = permissive, 2 = hostile) - */ -static const GDType _default_game_diff[3][GAME_DIFFICULTY_NUM] = { /* - A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R*/ - {2, 2, 2, 4, 300, 2, 0, 2, 0, 1, 2, 0, 1, 0, 0, 0, 0, 0}, ///< easy - {4, 1, 2, 3, 150, 3, 1, 3, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1}, ///< medium - {7, 0, 3, 3, 100, 4, 1, 3, 2, 2, 0, 2, 3, 2, 1, 1, 1, 2}, ///< hard -}; - -void SetDifficultyLevel(int mode, DifficultySettings *gm_opt) -{ - int i; - assert(mode <= 3); - - gm_opt->diff_level = mode; - if (mode != 3) { // not custom - for (i = 0; i != GAME_DIFFICULTY_NUM; i++) - ((GDType*)gm_opt)[i] = _default_game_diff[mode][i]; - } -} - -/** - * Checks the difficulty levels read from the configuration and - * forces them to be correct when invalid. - */ -void CheckDifficultyLevels() -{ - if (_settings_newgame.difficulty.diff_level != 3) { - SetDifficultyLevel(_settings_newgame.difficulty.diff_level, &_settings_newgame.difficulty); - } else { - for (uint i = 0; i < GAME_DIFFICULTY_NUM; i++) { - GDType *diff = ((GDType*)&_settings_newgame.difficulty) + i; - *diff = Clamp(*diff, _game_setting_info[i].min, _game_setting_info[i].max); - *diff -= *diff % _game_setting_info[i].step; - } - } -} - extern void StartupEconomy(); /* Widget definition for the game difficulty settings window */ @@ -472,20 +388,21 @@ static const WindowDesc _game_difficulty_desc = { _game_difficulty_widgets, }; +void SetDifficultyLevel(int mode, DifficultySettings *gm_opt); + struct GameDifficultyWindow : public Window { private: + static const uint GAME_DIFFICULTY_NUM = 18; bool clicked_increase; uint8 clicked_button; uint8 timeout; /* Temporary holding place of values in the difficulty window until 'Save' is clicked */ - DifficultySettings opt_mod_temp; + Settings opt_mod_temp; enum { GAMEDIFF_WND_TOP_OFFSET = 45, GAMEDIFF_WND_ROWSIZE = 9, - // 0x383E = (1 << 13) | (1 << 12) | (1 << 11) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1) - DIFF_INGAME_DISABLED_BUTTONS = 0x383E, NO_SETTINGS_BUTTON = 0xFF, }; @@ -510,7 +427,7 @@ public: { /* Copy current settings (ingame or in intro) to temporary holding place * change that when setting stuff, copy back on clicking 'OK' */ - this->opt_mod_temp = (_game_mode == GM_MENU) ? _settings_newgame.difficulty : _settings.difficulty; + this->opt_mod_temp = (_game_mode == GM_MENU) ? _settings_newgame : _settings; this->clicked_increase = false; this->clicked_button = NO_SETTINGS_BUTTON; this->timeout = 0; @@ -527,7 +444,7 @@ public: WIDGET_LIST_END); this->SetWidgetDisabledState(GDW_HIGHSCORE, _game_mode == GM_EDITOR || _networking); // highscore chart in multiplayer this->SetWidgetDisabledState(GDW_ACCEPT, _networking && !_network_server); // Save-button in multiplayer (and if client) - this->LowerWidget(GDW_LVL_EASY + this->opt_mod_temp.diff_level); + this->LowerWidget(GDW_LVL_EASY + this->opt_mod_temp.difficulty.diff_level); this->FindWindowPlacementAndResize(&_game_difficulty_desc); } @@ -535,29 +452,20 @@ public: { this->DrawWidgets(); - /* XXX - Disabled buttons in normal gameplay or during muliplayer as non server. - * Bitshifted for each button to see if that bit is set. If it is set, the - * button is disabled */ - uint32 disabled = 0; - if (_networking && !_network_server) { - disabled = MAX_UVALUE(uint32); // Disable all - } else if (_game_mode == GM_NORMAL) { - disabled = DIFF_INGAME_DISABLED_BUTTONS; - } - - int value; + uint i; + const SettingDesc *sd = GetPatchFromName("difficulty.max_no_competitors", &i); int y = GAMEDIFF_WND_TOP_OFFSET; - for (uint i = 0; i != GAME_DIFFICULTY_NUM; i++) { - const GameSettingData *gsd = &_game_setting_info[i]; - value = ((GDType*)&this->opt_mod_temp)[i]; + for (i = 0; i < GAME_DIFFICULTY_NUM; i++, sd++) { + const SettingDescBase *sdb = &sd->desc; + int32 value = (int32)ReadValue(GetVariableAddress(&this->opt_mod_temp, &sd->save), sd->save.conv); + bool editable = (_game_mode == GM_MENU || (sdb->flags & SGF_NEWGAME_ONLY) == 0); DrawArrowButtons(5, y, 3, (this->clicked_button == i) ? 1 + !!this->clicked_increase : 0, - !(HasBit(disabled, i) || gsd->min == value), - !(HasBit(disabled, i) || gsd->max == value)); + editable && sdb->min != value, + editable && sdb->max != value); - value += _game_setting_info[i].str; - if (i == 4) value *= 1000; // XXX - handle currency option + value += sdb->str; SetDParam(0, value); DrawString(30, y, STR_6805_MAXIMUM_NO_COMPETITORS + i, TC_FROMSTRING); @@ -582,30 +490,33 @@ public: const uint8 btn = y / (GAMEDIFF_WND_ROWSIZE + 2); if (btn >= GAME_DIFFICULTY_NUM || y % (GAMEDIFF_WND_ROWSIZE + 2) >= 9) return; + uint i; + const SettingDesc *sd = GetPatchFromName("difficulty.max_no_competitors", &i) + btn; + const SettingDescBase *sdb = &sd->desc; + /* Clicked disabled button? */ - if (_game_mode == GM_NORMAL && HasBit((int)DIFF_INGAME_DISABLED_BUTTONS, btn)) return; + bool editable = (_game_mode == GM_MENU || (sdb->flags & SGF_NEWGAME_ONLY) == 0); + if (!editable) return; this->timeout = 5; + int32 val = (int32)ReadValue(GetVariableAddress(&this->opt_mod_temp, &sd->save), sd->save.conv); - int16 val = ((GDType*)&this->opt_mod_temp)[btn]; - - const GameSettingData *info = &_game_setting_info[btn]; // get information about the difficulty setting if (x >= 10) { /* Increase button clicked */ - val = min(val + info->step, info->max); + val = min(val + sdb->interval, sdb->max); this->clicked_increase = true; } else { /* Decrease button clicked */ - val -= info->step; - val = max(val, info->min); + val -= sdb->interval; + val = max(val, sdb->min); this->clicked_increase = false; } this->clicked_button = btn; /* save value in temporary variable */ - ((GDType*)&this->opt_mod_temp)[btn] = val; - this->RaiseWidget(GDW_LVL_EASY + this->opt_mod_temp.diff_level); - SetDifficultyLevel(3, &this->opt_mod_temp); // set difficulty level to custom + WriteValue(GetVariableAddress(&this->opt_mod_temp, &sd->save), sd->save.conv, val); + this->RaiseWidget(GDW_LVL_EASY + this->opt_mod_temp.difficulty.diff_level); + SetDifficultyLevel(3, &this->opt_mod_temp.difficulty); // set difficulty level to custom this->LowerWidget(GDW_LVL_CUSTOM); this->SetDirty(); } break; @@ -615,27 +526,32 @@ public: case GDW_LVL_HARD: case GDW_LVL_CUSTOM: /* temporarily change difficulty level */ - this->RaiseWidget(GDW_LVL_EASY + this->opt_mod_temp.diff_level); - SetDifficultyLevel(widget - GDW_LVL_EASY, &this->opt_mod_temp); - this->LowerWidget(GDW_LVL_EASY + this->opt_mod_temp.diff_level); + this->RaiseWidget(GDW_LVL_EASY + this->opt_mod_temp.difficulty.diff_level); + SetDifficultyLevel(widget - GDW_LVL_EASY, &this->opt_mod_temp.difficulty); + this->LowerWidget(GDW_LVL_EASY + this->opt_mod_temp.difficulty.diff_level); this->SetDirty(); break; case GDW_HIGHSCORE: // Highscore Table - ShowHighscoreTable(this->opt_mod_temp.diff_level, -1); + ShowHighscoreTable(this->opt_mod_temp.difficulty.diff_level, -1); break; case GDW_ACCEPT: { // Save button - save changes - GDType btn, val; Settings *opt_ptr = (_game_mode == GM_MENU) ? &_settings_newgame : &_settings; - for (btn = 0; btn != GAME_DIFFICULTY_NUM; btn++) { - val = ((GDType*)&this->opt_mod_temp)[btn]; + + uint i; + const SettingDesc *sd = GetPatchFromName("difficulty.max_no_competitors", &i); + for (uint btn = 0; btn != GAME_DIFFICULTY_NUM; btn++, sd++) { + int32 new_val = (int32)ReadValue(GetVariableAddress(&this->opt_mod_temp, &sd->save), sd->save.conv); + int32 cur_val = (int32)ReadValue(GetVariableAddress(opt_ptr, &sd->save), sd->save.conv); /* if setting has changed, change it */ - if (val != ((GDType*)&opt_ptr->difficulty)[btn]) { - DoCommandP(0, btn, val, NULL, CMD_CHANGE_DIFFICULTY_LEVEL); + if (new_val != cur_val) { + DoCommandP(0, i + btn, new_val, NULL, CMD_CHANGE_PATCH_SETTING); } } - DoCommandP(0, UINT_MAX, this->opt_mod_temp.diff_level, NULL, CMD_CHANGE_DIFFICULTY_LEVEL); + + GetPatchFromName("difficulty.diff_level", &i); + DoCommandP(0, i, this->opt_mod_temp.difficulty.diff_level, NULL, CMD_CHANGE_PATCH_SETTING); delete this; /* If we are in the editor, we should reload the economy. * This way when you load a game, the max loan and interest rate diff --git a/src/settings_internal.h b/src/settings_internal.h index 7ac0a4f6a4..2c2979e701 100644 --- a/src/settings_internal.h +++ b/src/settings_internal.h @@ -39,8 +39,8 @@ enum SettingGuiFlagLong { SGF_NETWORK_ONLY = 1 << 3, ///< this setting only applies to network games SGF_CURRENCY = 1 << 4, ///< the number represents money, so when reading value multiply by exchange rate SGF_NO_NETWORK = 1 << 5, ///< this setting does not apply to network games; it may not be changed during the game - SGF_END = 1 << 6, - /* 3 more possible flags */ + SGF_NEWGAME_ONLY = 1 << 6, ///< this setting cannot be changed in inside a game + SGF_END = 1 << 7, }; DECLARE_ENUM_AS_BIT_SET(SettingGuiFlagLong); diff --git a/src/settings_type.h b/src/settings_type.h index 6cd8d326f0..a8a78115dd 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -9,51 +9,27 @@ #include "town_type.h" #include "transport_type.h" -enum { - GAME_DIFFICULTY_AI_NUMBER, - GAME_DIFFICULTY_AI_STARTTIME, - GAME_DIFFICULTY_TOWN_NUMBER, - GAME_DIFFICULTY_INDUSTRIE_NUMBER, - GAME_DIFFICULTY_MAX_LOAN, - GAME_DIFFICULTY_INITIAL_INTEREST, - GAME_DIFFICULTY_VEHICLE_COST, - GAME_DIFFICULTY_AI_SPEED, - GAME_DIFFICULTY_AI_INTELLIGENCE, ///< no longer in use - GAME_DIFFICULTY_VEHICLES_BREAKDOWN, - GAME_DIFFICULTY_SUBSIDY_MULTIPLIER, - GAME_DIFFICULTY_CONSTRUCTION_COST, - GAME_DIFFICULTY_TYPE_TERRAIN, - GAME_DIFFICULTY_SEALAKE_NUMBER, - GAME_DIFFICULTY_ECONOMY, - GAME_DIFFICULTY_LINE_REVERSEMODE, - GAME_DIFFICULTY_DISASTERS, - GAME_DIFFICULTY_TOWNCOUNCIL_TOLERANCE, ///< minimum required town ratings to be allowed to demolish stuff - GAME_DIFFICULTY_NUM, -}; - -/** Specific type for Game Difficulty to ease changing the type */ -typedef uint16 GDType; /** Settings related to the difficulty of the game */ struct DifficultySettings { - GDType max_no_competitors; ///< the number of competitors (AIs) - GDType competitor_start_time; ///< how long to wait for the first competitors (AIs) - GDType number_towns; ///< the amount of towns - GDType number_industries; ///< the amount of industries - GDType max_loan; ///< the maximum initial loan - GDType initial_interest; ///< amount of interest (to pay over the loan) - GDType vehicle_costs; ///< amount of money spent on vehicle running cost - GDType competitor_speed; ///< the speed at which the AI builds - GDType competitor_intelligence; ///< the competior's (AI) intelligence - GDType vehicle_breakdowns; ///< likelihood of vehicles breaking down - GDType subsidy_multiplier; ///< amount of subsidy - GDType construction_cost; ///< how expensive is building - GDType terrain_type; ///< the mountainousness of the landscape - GDType quantity_sea_lakes; ///< the amount of seas/lakes - GDType economy; ///< how volatile is the economy - GDType line_reverse_mode; ///< reversing at stations or not - GDType disasters; ///< are disasters enabled - GDType town_council_tolerance; ///< minimum required town ratings to be allowed to demolish stuff - GDType diff_level; ///< the difficulty level + byte max_no_competitors; ///< the number of competitors (AIs) + byte competitor_start_time; ///< how long to wait for the first competitors (AIs) + byte number_towns; ///< the amount of towns + byte number_industries; ///< the amount of industries + uint32 max_loan; ///< the maximum initial loan + byte initial_interest; ///< amount of interest (to pay over the loan) + byte vehicle_costs; ///< amount of money spent on vehicle running cost + byte competitor_speed; ///< the speed at which the AI builds + byte competitor_intelligence; ///< the competior's (AI) intelligence + byte vehicle_breakdowns; ///< likelihood of vehicles breaking down + byte subsidy_multiplier; ///< amount of subsidy + byte construction_cost; ///< how expensive is building + byte terrain_type; ///< the mountainousness of the landscape + byte quantity_sea_lakes; ///< the amount of seas/lakes + byte economy; ///< how volatile is the economy + byte line_reverse_mode; ///< reversing at stations or not + byte disasters; ///< are disasters enabled + byte town_council_tolerance; ///< minimum required town ratings to be allowed to demolish stuff + byte diff_level; ///< the difficulty level }; /** Settings related to the GUI and other stuff that is not saved in the savegame. */