From ab99c1660131f5b13accd32238169359c0c38fd5 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Tue, 14 Apr 2020 22:04:41 +0100 Subject: [PATCH] Add support for money cheat in multiplayer Add a setting for whether this is permitted by multiplayer clients --- src/cheat_gui.cpp | 32 +++++++++++++++++++++++++------- src/command.cpp | 4 +++- src/command_type.h | 1 + src/lang/english.txt | 2 ++ src/main_gui.cpp | 8 ++++++-- src/misc_cmd.cpp | 23 +++++++++++++++++++++++ src/settings.cpp | 6 ++++++ src/settings_gui.cpp | 1 + src/settings_type.h | 1 + src/table/settings.ini | 11 +++++++++++ src/toolbar_gui.cpp | 2 +- 11 files changed, 80 insertions(+), 11 deletions(-) diff --git a/src/cheat_gui.cpp b/src/cheat_gui.cpp index f84112be17..6bf6b1a1e6 100644 --- a/src/cheat_gui.cpp +++ b/src/cheat_gui.cpp @@ -54,7 +54,7 @@ static int32 _money_cheat_amount = 10000000; */ static int32 ClickMoneyCheat(int32 p1, int32 p2) { - DoCommandP(0, (uint32)(p2 * _money_cheat_amount), 0, CMD_MONEY_CHEAT); + DoCommandP(0, (uint32)(p2 * _money_cheat_amount), 0, _network_server || _network_settings_access ? CMD_MONEY_CHEAT_ADMIN : CMD_MONEY_CHEAT); return _money_cheat_amount; } @@ -158,6 +158,7 @@ typedef int32 CheckButtonClick(int32 p1, int32 p2); enum CheatNetworkMode { CNM_ALL, CNM_LOCAL_ONLY, + CNM_MONEY, }; /** Information of a cheat. */ @@ -175,7 +176,7 @@ struct CheatEntry { * Order matches with the values of #CheatNumbers */ static const CheatEntry _cheats_ui[] = { - {CNM_LOCAL_ONLY, SLE_INT32, STR_CHEAT_MONEY, &_money_cheat_amount, &_cheats.money.been_used, &ClickMoneyCheat }, + {CNM_MONEY, SLE_INT32, STR_CHEAT_MONEY, &_money_cheat_amount, &_cheats.money.been_used, &ClickMoneyCheat }, {CNM_LOCAL_ONLY, SLE_UINT8, STR_CHEAT_CHANGE_COMPANY, &_local_company, &_cheats.switch_company.been_used, &ClickChangeCompanyCheat }, {CNM_ALL, SLE_BOOL, STR_CHEAT_EXTRA_DYNAMITE, &_cheats.magic_bulldozer.value, &_cheats.magic_bulldozer.been_used, nullptr }, {CNM_ALL, SLE_BOOL, STR_CHEAT_CROSSINGTUNNELS, &_cheats.crossing_tunnels.value, &_cheats.crossing_tunnels.been_used, nullptr }, @@ -185,6 +186,21 @@ static const CheatEntry _cheats_ui[] = { {CNM_LOCAL_ONLY, SLE_INT32, STR_CHEAT_CHANGE_DATE, &_cur_year, &_cheats.change_date.been_used, &ClickChangeDateCheat }, }; +static bool IsCheatAllowed(CheatNetworkMode mode) +{ + switch (mode) { + case CNM_ALL: + return !_networking || _network_server || _network_settings_access; + + case CNM_LOCAL_ONLY: + return !_networking; + + case CNM_MONEY: + return !_networking || _network_server || _network_settings_access || _settings_game.difficulty.money_cheat_in_multiplayer; + } + return false; +} + assert_compile(CHT_NUM_CHEATS == lengthof(_cheats_ui)); /** Widget definitions of the cheat GUI. */ @@ -230,7 +246,7 @@ struct CheatWindow : Window { for (int i = 0; i != lengthof(_cheats_ui); i++) { const CheatEntry *ce = &_cheats_ui[i]; - if (_networking && ce->mode == CNM_LOCAL_ONLY) continue; + if (!IsCheatAllowed(ce->mode)) continue; DrawSprite((*ce->been_used) ? SPR_BOX_CHECKED : SPR_BOX_EMPTY, PAL_NONE, box_left, y + icon_y_offset + 2); @@ -283,7 +299,7 @@ struct CheatWindow : Window { uint lines = 0; for (int i = 0; i != lengthof(_cheats_ui); i++) { const CheatEntry *ce = &_cheats_ui[i]; - if (_networking && ce->mode == CNM_LOCAL_ONLY) continue; + if (!IsCheatAllowed(ce->mode)) continue; lines++; switch (ce->type) { case SLE_BOOL: @@ -335,7 +351,7 @@ struct CheatWindow : Window { for (uint i = 0; i != lengthof(_cheats_ui) && i <= btn; i++) { const CheatEntry *ce = &_cheats_ui[i]; - if (_networking && ce->mode == CNM_LOCAL_ONLY) btn++; + if (!IsCheatAllowed(ce->mode)) btn++; } if (btn >= lengthof(_cheats_ui)) return; @@ -379,7 +395,7 @@ struct CheatWindow : Window { if (value != oldvalue) { if (_networking) { - DoCommandP(0, (uint32)btn, (uint32)value, CMD_CHEAT_SETTING); + if (btn != CHT_MONEY) DoCommandP(0, (uint32)btn, (uint32)value, CMD_CHEAT_SETTING); } else { WriteValue(ce->variable, ce->type, (int64)value); } @@ -426,5 +442,7 @@ static WindowDesc _cheats_desc( void ShowCheatWindow() { DeleteWindowById(WC_CHEATS, 0); - new CheatWindow(&_cheats_desc); + if (!_networking || _network_server || _network_settings_access || _settings_game.difficulty.money_cheat_in_multiplayer) { + new CheatWindow(&_cheats_desc); + } } diff --git a/src/command.cpp b/src/command.cpp index 72bdc5fc8a..6bdeffb807 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -159,6 +159,7 @@ CommandProc CmdClearArea; CommandProc CmdGiveMoney; CommandProc CmdMoneyCheat; +CommandProc CmdMoneyCheatAdmin; CommandProc CmdChangeBankBalance; CommandProc CmdCheatSetting; CommandProc CmdBuildCanal; @@ -379,7 +380,8 @@ static const Command _command_proc_table[] = { DEF_CMD(CmdClearArea, CMD_NO_TEST, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_CLEAR_AREA; destroying multi-tile houses makes town rating differ between test and execution - DEF_CMD(CmdMoneyCheat, CMD_OFFLINE, CMDT_CHEAT ), // CMD_MONEY_CHEAT + DEF_CMD(CmdMoneyCheat, 0, CMDT_CHEAT ), // CMD_MONEY_CHEAT + DEF_CMD(CmdMoneyCheatAdmin, CMD_SERVER_NS, CMDT_CHEAT ), // CMD_MONEY_CHEAT_ADMIN DEF_CMD(CmdChangeBankBalance, CMD_DEITY, CMDT_MONEY_MANAGEMENT ), // CMD_CHANGE_BANK_BALANCE DEF_CMD(CmdCheatSetting, CMD_SERVER, CMDT_CHEAT ), // CMD_CHEAT_SETTING DEF_CMD(CmdBuildCanal, CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_CANAL diff --git a/src/command_type.h b/src/command_type.h index 7386fa4114..514f03923c 100644 --- a/src/command_type.h +++ b/src/command_type.h @@ -317,6 +317,7 @@ enum Commands { CMD_CLEAR_AREA, ///< clear an area CMD_MONEY_CHEAT, ///< do the money cheat + CMD_MONEY_CHEAT_ADMIN, ///< do the money cheat (admin mode) CMD_CHANGE_BANK_BALANCE, ///< change bank balance to charge costs or give money from a GS CMD_CHEAT_SETTING, ///< change a cheat setting CMD_BUILD_CANAL, ///< build a canal diff --git a/src/lang/english.txt b/src/lang/english.txt index c1aac3e0c4..c64ab32099 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1188,6 +1188,8 @@ STR_CONFIG_SETTING_DISASTERS :Disasters: {STR STR_CONFIG_SETTING_DISASTERS_HELPTEXT :Toggle disasters which may occasionally block or destroy vehicles or infrastructure STR_CONFIG_SETTING_CITY_APPROVAL :Town council's attitude towards area restructuring: {STRING2} STR_CONFIG_SETTING_CITY_APPROVAL_HELPTEXT :Choose how much noise and environmental damage by companies affect their town rating and further construction actions in their area +STR_MONEY_CHEAT_MULTIPLAYER :Allow multiplayer clients to use the money cheat: {STRING2} +STR_MONEY_CHEAT_MULTIPLAYER_HELPTEXT :If enabled, non-admin multiplayer clients can use the money cheat. The money cheat is always available in single-player mode, and to the multiplayer server admin. STR_CONFIG_SETTING_MAX_HEIGHTLEVEL :Maximum map height: {STRING2} STR_CONFIG_SETTING_MAX_HEIGHTLEVEL_HELPTEXT :Set the maximum allowed height for mountains on the map diff --git a/src/main_gui.cpp b/src/main_gui.cpp index 292d9b624d..b5e0b7270a 100644 --- a/src/main_gui.cpp +++ b/src/main_gui.cpp @@ -339,8 +339,12 @@ struct MainWindow : Window break; case GHK_MONEY: // Gimme money - /* You can only cheat for money in single player. */ - if (!_networking) DoCommandP(0, 10000000, 0, CMD_MONEY_CHEAT); + /* You can only cheat for money in single player or when otherwise suitably authorised. */ + if (!_networking || _settings_game.difficulty.money_cheat_in_multiplayer) { + DoCommandP(0, 10000000, 0, CMD_MONEY_CHEAT); + } else if (_network_server || _network_settings_access) { + DoCommandP(0, 10000000, 0, CMD_MONEY_CHEAT_ADMIN); + } break; case GHK_UPDATE_COORDS: // Update the coordinates of all station signs diff --git a/src/misc_cmd.cpp b/src/misc_cmd.cpp index 0ba0c9673e..b49e36260b 100644 --- a/src/misc_cmd.cpp +++ b/src/misc_cmd.cpp @@ -198,6 +198,29 @@ CommandCost CmdPause(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, */ CommandCost CmdMoneyCheat(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { + if (_networking && !_settings_game.difficulty.money_cheat_in_multiplayer) return CMD_ERROR; + if (flags & DC_EXEC) { + _cheats.money.been_used = true; + SetWindowDirty(WC_CHEATS, 0); + } + return CommandCost(EXPENSES_OTHER, -(int32)p1); +} + +/** + * Change the financial flow of your company (admin). + * @param tile unused + * @param flags operation to perform + * @param p1 the amount of money to receive (if positive), or spend (if negative) + * @param p2 unused + * @param text unused + * @return the cost of this operation or an error + */ +CommandCost CmdMoneyCheatAdmin(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + if (flags & DC_EXEC) { + _cheats.money.been_used = true; + SetWindowDirty(WC_CHEATS, 0); + } return CommandCost(EXPENSES_OTHER, -(int32)p1); } diff --git a/src/settings.cpp b/src/settings.cpp index e365911913..7e6a9a78c3 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1273,6 +1273,12 @@ static bool DifficultyNoiseChange(int32 i) return true; } +static bool DifficultyMoneyCheatMultiplayerChange(int32 i) +{ + DeleteWindowById(WC_CHEATS, 0); + return true; +} + static bool MaxNoAIsChange(int32 i) { if (GetGameSettings().difficulty.max_no_competitors != 0 && diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 1a16034b7f..a8976c3715 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -1983,6 +1983,7 @@ static SettingsContainer &GetSettingsTree() ai->Add(new SettingEntry("economy.give_money")); ai->Add(new SettingEntry("economy.allow_shares")); ai->Add(new SettingEntry("economy.min_years_for_shares")); + ai->Add(new SettingEntry("difficulty.money_cheat_in_multiplayer")); } main->Init(); diff --git a/src/settings_type.h b/src/settings_type.h index 355a5aeff7..440bead2b4 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -67,6 +67,7 @@ struct DifficultySettings { bool line_reverse_mode; ///< reversing at stations or not bool disasters; ///< are disasters enabled byte town_council_tolerance; ///< minimum required town ratings to be allowed to demolish stuff + bool money_cheat_in_multiplayer; ///< is the money cheat permitted for non-admin multiplayer clients }; /** Settings relating to viewport/smallmap scrolling. */ diff --git a/src/table/settings.ini b/src/table/settings.ini index 44ac5aa39c..4aebe98ec6 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -26,6 +26,7 @@ static bool ProgrammableSignalsShownChanged(int32); static bool VehListCargoFilterShownChanged(int32); static bool TownFoundingChanged(int32 p1); static bool DifficultyNoiseChange(int32 i); +static bool DifficultyMoneyCheatMultiplayerChange(int32 i); static bool MaxNoAIsChange(int32 i); static bool CheckRoadSide(int p1); static bool ChangeMaxHeightLevel(int32 p1); @@ -378,6 +379,16 @@ strhelp = STR_CONFIG_SETTING_CITY_APPROVAL_HELPTEXT strval = STR_CITY_APPROVAL_PERMISSIVE proc = DifficultyNoiseChange +[SDT_BOOL] +base = GameSettings +var = difficulty.money_cheat_in_multiplayer +def = false +str = STR_MONEY_CHEAT_MULTIPLAYER +strhelp = STR_MONEY_CHEAT_MULTIPLAYER_HELPTEXT +proc = DifficultyMoneyCheatMultiplayerChange +cat = SC_EXPERT +patxname = ""cheat.difficulty.money_cheat_in_multiplayer"" + [SDTG_VAR] name = ""diff_level"" var = _old_diff_level diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 62a5714405..b32d14266b 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -2154,7 +2154,7 @@ struct MainToolbarWindow : Window { case MTHK_ZOOMEDIN_SCREENSHOT: MenuClickScreenshot(SC_ZOOMEDIN); break; case MTHK_DEFAULTZOOM_SCREENSHOT: MenuClickScreenshot(SC_DEFAULTZOOM); break; case MTHK_GIANT_SCREENSHOT: MenuClickScreenshot(SC_WORLD); break; - case MTHK_CHEATS: if (!_networking || _network_server || _network_settings_access) ShowCheatWindow(); break; + case MTHK_CHEATS: ShowCheatWindow(); break; case MTHK_TERRAFORM: ShowTerraformToolbar(); break; case MTHK_EXTRA_VIEWPORT: ShowExtraViewPortWindowForTileUnderCursor(); break; case MTHK_CLIENT_LIST: if (_networking) ShowClientList(); break;