From b2f5a4901b0aacdd2644a37de8d73537097976db Mon Sep 17 00:00:00 2001 From: Tyler Trahan Date: Sun, 9 Feb 2025 13:34:31 -0500 Subject: [PATCH] Add: Setting to allow placing houses manually in-game (#13266) --- src/lang/english.txt | 7 +++++++ src/settings_gui.cpp | 1 + src/settings_type.h | 8 ++++++++ src/table/settings/economy_settings.ini | 15 +++++++++++++++ src/toolbar_gui.cpp | 25 ++++++++++++++++++------- src/town_cmd.cpp | 13 ++++++++----- 6 files changed, 57 insertions(+), 12 deletions(-) diff --git a/src/lang/english.txt b/src/lang/english.txt index 74f7bcafc6..21388b667e 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1987,6 +1987,13 @@ STR_CONFIG_SETTING_TOWN_FOUNDING_FORBIDDEN :Forbidden STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED :Allowed STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED_CUSTOM_LAYOUT :Allowed, custom town layout +STR_CONFIG_SETTING_HOUSE_PLACER :Placing individual town houses: {STRING2} +STR_CONFIG_SETTING_HOUSE_PLACER_HELPTEXT :Enabling this setting allows players to place town houses manually +###length 3 +STR_CONFIG_SETTING_HOUSE_PLACER_FORBIDDEN :Forbidden +STR_CONFIG_SETTING_HOUSE_PLACER_ALLOWED :Allowed +STR_CONFIG_SETTING_HOUSE_PLACER_FULLY_CONSTRUCTED :Allowed, fully constructed + STR_CONFIG_SETTING_TOWN_CARGOGENMODE :Town cargo generation: {STRING2} STR_CONFIG_SETTING_TOWN_CARGOGENMODE_HELPTEXT :How much cargo is produced by houses in towns, relative to the overall population of the town.{}Quadratic growth: A town twice the size generates four times as many passengers.{}Linear growth: A town twice the size generates twice the amount of passengers ###length 2 diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 93dfbaca11..5081ae4fee 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -2219,6 +2219,7 @@ static SettingsContainer &GetSettingsTree() towns->Add(new SettingEntry("economy.allow_town_roads")); towns->Add(new SettingEntry("economy.allow_town_level_crossings")); towns->Add(new SettingEntry("economy.found_town")); + towns->Add(new SettingEntry("economy.place_houses")); towns->Add(new SettingEntry("economy.town_layout")); towns->Add(new SettingEntry("economy.larger_towns")); towns->Add(new SettingEntry("economy.initial_city_size")); diff --git a/src/settings_type.h b/src/settings_type.h index 9b9a56a101..a013cdcdff 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -91,6 +91,13 @@ enum RightClickClose : uint8_t { RCC_YES_EXCEPT_STICKY, }; +/** Possible values for "place_houses" setting. */ +enum PlaceHouses : uint8_t { + PH_FORBIDDEN = 0, + PH_ALLOWED, + PH_ALLOWED_CONSTRUCTED, +}; + /** Settings related to the difficulty of the game */ struct DifficultySettings { uint8_t competitor_start_time; ///< Unused value, used to load old savegames. @@ -529,6 +536,7 @@ struct EconomySettings { TownCargoGenMode town_cargogen_mode; ///< algorithm for generating cargo from houses, @see TownCargoGenMode bool allow_town_roads; ///< towns are allowed to build roads (always allowed when generating world / in SE) TownFounding found_town; ///< town founding. + PlaceHouses place_houses; ///< players are allowed to place town houses. bool station_noise_level; ///< build new airports when the town noise level is still within accepted limits uint16_t town_noise_population[4]; ///< population to base decision on noise evaluation (@see town_council_tolerance) bool allow_town_level_crossings; ///< towns are allowed to build level crossings diff --git a/src/table/settings/economy_settings.ini b/src/table/settings/economy_settings.ini index b64dd35769..dd24dd19fc 100644 --- a/src/table/settings/economy_settings.ini +++ b/src/table/settings/economy_settings.ini @@ -12,6 +12,8 @@ static void TownFoundingChanged(int32_t new_value); static void ChangeTimekeepingUnits(int32_t new_value); static void ChangeMinutesPerYear(int32_t new_value); +static constexpr std::initializer_list _place_houses{"forbidden", "allowed", "fully constructed"}; + static const SettingVariant _economy_settings_table[] = { [post-amble] }; @@ -80,6 +82,19 @@ strval = STR_CONFIG_SETTING_TOWN_FOUNDING_FORBIDDEN post_cb = TownFoundingChanged cat = SC_BASIC +[SDT_VAR] +var = economy.place_houses +type = SLE_UINT8 +flags = SettingFlag::GuiDropdown +def = PH_FORBIDDEN +min = PH_FORBIDDEN +max = PH_ALLOWED_CONSTRUCTED +full = _place_houses +str = STR_CONFIG_SETTING_HOUSE_PLACER +strhelp = STR_CONFIG_SETTING_HOUSE_PLACER_HELPTEXT +strval = STR_CONFIG_SETTING_HOUSE_PLACER_FORBIDDEN +cat = SC_ADVANCED + [SDT_BOOL] var = economy.allow_town_level_crossings from = SLV_143 diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 1b2996c2d2..313a5b6e5f 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -481,13 +481,21 @@ static CallBackFunction MenuClickMap(int index) /* --- Town button menu --- */ +enum TownMenuEntries { + TME_SHOW_DIRECTORY = 0, + TME_SHOW_FOUND_TOWN, + TME_SHOW_PLACE_HOUSES, +}; + static CallBackFunction ToolbarTownClick(Window *w) { - if (_settings_game.economy.found_town == TF_FORBIDDEN) { - PopupMainToolbarMenu(w, WID_TN_TOWNS, {STR_TOWN_MENU_TOWN_DIRECTORY}); - } else { - PopupMainToolbarMenu(w, WID_TN_TOWNS, {STR_TOWN_MENU_TOWN_DIRECTORY, STR_TOWN_MENU_FOUND_TOWN}); - } + DropDownList list; + list.push_back(MakeDropDownListStringItem(STR_TOWN_MENU_TOWN_DIRECTORY, TME_SHOW_DIRECTORY)); + if (_settings_game.economy.found_town != TF_FORBIDDEN) list.push_back(MakeDropDownListStringItem(STR_TOWN_MENU_FOUND_TOWN, TME_SHOW_FOUND_TOWN)); + if (_settings_game.economy.place_houses != PH_FORBIDDEN) list.push_back(MakeDropDownListStringItem(STR_SCENEDIT_TOWN_MENU_PACE_HOUSE, TME_SHOW_PLACE_HOUSES)); + + PopupMainToolbarMenu(w, WID_TN_TOWNS, std::move(list), 0); + return CBF_NONE; } @@ -500,10 +508,13 @@ static CallBackFunction ToolbarTownClick(Window *w) static CallBackFunction MenuClickTown(int index) { switch (index) { - case 0: ShowTownDirectory(); break; - case 1: // setting could be changed when the dropdown was open + case TME_SHOW_DIRECTORY: ShowTownDirectory(); break; + case TME_SHOW_FOUND_TOWN: // Setting could be changed when the dropdown was open if (_settings_game.economy.found_town != TF_FORBIDDEN) ShowFoundTownWindow(); break; + case TME_SHOW_PLACE_HOUSES: // Setting could be changed when the dropdown was open + if (_settings_game.economy.place_houses != PH_FORBIDDEN) ShowBuildHousePicker(nullptr); + break; } return CBF_NONE; } diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index 72816a7727..3fba7a80a0 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -2731,8 +2731,9 @@ static bool CheckTownBuild2x2House(TileIndex *tile, Town *t, int maxz, bool nosl * @param hs The @a HouseSpec of the house. * @param house The @a HouseID of the house. * @param random_bits The random data to be associated with the house. + * @param house_completed Should the house be placed already complete, instead of under construction? */ -static void BuildTownHouse(Town *t, TileIndex tile, const HouseSpec *hs, HouseID house, uint8_t random_bits) +static void BuildTownHouse(Town *t, TileIndex tile, const HouseSpec *hs, HouseID house, uint8_t random_bits, bool house_completed) { /* build the house */ t->cache.num_houses++; @@ -2740,7 +2741,7 @@ static void BuildTownHouse(Town *t, TileIndex tile, const HouseSpec *hs, HouseID uint8_t construction_counter = 0; uint8_t construction_stage = 0; - if (_generating_world || _game_mode == GM_EDITOR) { + if (_generating_world || _game_mode == GM_EDITOR || house_completed) { uint32_t construction_random = Random(); construction_stage = TOWN_HOUSE_COMPLETED; @@ -2879,7 +2880,7 @@ static bool TryBuildTownHouse(Town *t, TileIndex tile) /* Special houses that there can be only one of. */ t->flags |= oneof; - BuildTownHouse(t, tile, hs, house, random_bits); + BuildTownHouse(t, tile, hs, house, random_bits, false); return true; } @@ -2889,7 +2890,8 @@ static bool TryBuildTownHouse(Town *t, TileIndex tile) CommandCost CmdPlaceHouse(DoCommandFlag flags, TileIndex tile, HouseID house) { - if (_game_mode != GM_EDITOR) return CMD_ERROR; + if (_game_mode != GM_EDITOR && _settings_game.economy.place_houses == PH_FORBIDDEN) return CMD_ERROR; + if (Town::GetNumItems() == 0) return CommandCost(STR_ERROR_MUST_FOUND_TOWN_FIRST); if (static_cast(house) >= HouseSpec::Specs().size()) return CMD_ERROR; @@ -2929,7 +2931,8 @@ CommandCost CmdPlaceHouse(DoCommandFlag flags, TileIndex tile, HouseID house) } if (flags & DC_EXEC) { - BuildTownHouse(t, tile, hs, house, Random()); + bool house_completed = _settings_game.economy.place_houses == PH_ALLOWED_CONSTRUCTED; + BuildTownHouse(t, tile, hs, house, Random(), house_completed); } return CommandCost();