diff --git a/src/lang/english.txt b/src/lang/english.txt index 8a1b2e31da..b0d64e3a7f 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -2001,6 +2001,9 @@ STR_CONFIG_OCCUPANCY_SMOOTHNESS_HELPTEXT :0% sets the mea STR_CONFIG_SETTING_ADVANCE_ORDER_ON_CLONE :Advance order after cloning/copying/sharing: {STRING2} STR_CONFIG_SETTING_ADVANCE_ORDER_ON_CLONE_HELPTEXT :After cloning a vehicle or copying/sharing orders from an existing vehicle.{}For trains, road vehicles and ships: if the vehicle is in a depot which is in the order list, skip to the order which follows one of the orders for that depot.{}For aircraft: if the aircraft is in a hangar and the associated airport is in the order list, skip to one of the orders for that airport. +STR_CONFIG_SETTING_SCENARIO_MULTIPLE_BUILDINGS :Allow multiple churches/stadiums: {STRING2} +STR_CONFIG_SETTING_SCENARIO_MULTIPLE_BUILDINGS_HELPTEXT :Allow manually adding churches and stadiums when there is already one present in the town. + # Config errors STR_CONFIG_ERROR :{WHITE}Error with the configuration file... STR_CONFIG_ERROR_ARRAY :{WHITE}... error in array '{RAW_STRING}' diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 644c0c2a6a..cd9a208ec6 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -3773,6 +3773,13 @@ bool AfterLoadGame() _settings_game.game_creation.generation_unique_id = _interactive_random.Next(UINT32_MAX-1) + 1; /* Generates between [1;UINT32_MAX] */ } + if (SlXvIsFeatureMissing(XSLFI_TOWN_MULTI_BUILDING)) { + for (Town *t : Town::Iterate()) { + t->church_count = HasBit(t->flags, 1) ? 1 : 0; + t->stadium_count = HasBit(t->flags, 2) ? 1 : 0; + } + } + /* This needs to be done after conversion. */ RebuildViewportKdtree(); ViewportMapBuildTunnelCache(); diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp index 7180d9de8e..09b9b624ff 100644 --- a/src/saveload/extended_ver_sl.cpp +++ b/src/saveload/extended_ver_sl.cpp @@ -124,6 +124,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_STATION_GOODS_EXTRA, XSCF_NULL, 1, 1, "station_goods_extra", nullptr, nullptr, nullptr }, { XSLFI_DOCKING_CACHE_VER, XSCF_IGNORABLE_ALL, 1, 1, "docking_cache_ver", nullptr, nullptr, nullptr }, { XSLFI_EXTRA_CHEATS, XSCF_NULL, 1, 1, "extra_cheats", nullptr, nullptr, "CHTX" }, + { XSLFI_TOWN_MULTI_BUILDING, XSCF_NULL, 1, 1, "town_multi_building", nullptr, nullptr, nullptr }, { XSLFI_NULL, XSCF_NULL, 0, 0, nullptr, nullptr, nullptr, nullptr },// This is the end marker }; diff --git a/src/saveload/extended_ver_sl.h b/src/saveload/extended_ver_sl.h index 0c928ebab4..fcfd047db4 100644 --- a/src/saveload/extended_ver_sl.h +++ b/src/saveload/extended_ver_sl.h @@ -81,6 +81,7 @@ enum SlXvFeatureIndex { XSLFI_STATION_GOODS_EXTRA, ///< Extra station goods entry statuses XSLFI_DOCKING_CACHE_VER, ///< Multiple docks - docking tile cache version XSLFI_EXTRA_CHEATS, ///< Extra cheats + XSLFI_TOWN_MULTI_BUILDING, ///< Allow multiple stadium/church buildings in a single town XSLFI_RIFF_HEADER_60_BIT, ///< Size field in RIFF chunk header is 60 bit XSLFI_HEIGHT_8_BIT, ///< Map tile height is 8 bit instead of 4 bit, but savegame version may be before this became true in trunk diff --git a/src/saveload/town_sl.cpp b/src/saveload/town_sl.cpp index cee8f266d7..377f67c892 100644 --- a/src/saveload/town_sl.cpp +++ b/src/saveload/town_sl.cpp @@ -130,6 +130,7 @@ static const SaveLoad _town_desc[] = { SLE_CONDSTR(Town, name, SLE_STR | SLF_ALLOW_CONTROL, 0, SLV_84, SL_MAX_VERSION), SLE_VAR(Town, flags, SLE_UINT8), + SLE_CONDVAR_X(Town, church_count, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SPRINGPP)), SLE_CONDVAR(Town, statues, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_104), SLE_CONDVAR(Town, statues, SLE_UINT16, SLV_104, SL_MAX_VERSION), diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 0eabb96b24..dc127d8036 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -2011,6 +2011,7 @@ static SettingsContainer &GetSettingsTree() if (_game_mode != GM_NORMAL) { SettingsPage *scenario = main->Add(new SettingsPage(STR_CONFIG_SETTING_SCENARIO_EDITOR)); { + scenario->Add(new SettingEntry("scenario.multiple_buildings")); } } diff --git a/src/settings_type.h b/src/settings_type.h index f929c577cf..76370d6ca2 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -661,6 +661,7 @@ struct DebugSettings { /** Scenario editor settings. */ struct ScenarioSettings { + bool multiple_buildings; ///< allow manually adding more than one church/stadium }; /** All settings together for the game. */ diff --git a/src/table/settings.ini b/src/table/settings.ini index ad67c67994..c7873f55ac 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -5327,6 +5327,13 @@ str = STR_CONFIG_SETTING_NEWS_GENERAL_INFORMATION strhelp = STR_CONFIG_SETTING_NEWS_GENERAL_INFORMATION_HELPTEXT strval = STR_CONFIG_SETTING_NEWS_MESSAGES_OFF +[SDTC_BOOL] +var = scenario.multiple_buildings +flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC +def = false +str = STR_CONFIG_SETTING_SCENARIO_MULTIPLE_BUILDINGS +strhelp = STR_CONFIG_SETTING_SCENARIO_MULTIPLE_BUILDINGS_HELPTEXT + [SDTC_VAR] var = gui.network_chat_box_width_pct type = SLE_UINT16 diff --git a/src/town.h b/src/town.h index 82a31a222f..c9a99f5017 100644 --- a/src/town.h +++ b/src/town.h @@ -65,6 +65,8 @@ struct Town : TownPool::PoolItem<&_town_pool> { mutable std::string cached_name; ///< NOSAVE: Cache of the resolved name of the town, if not using a custom town name byte flags; ///< See #TownFlags. + byte church_count; ///< Number of church buildings in the town. + byte stadium_count; ///< Number of stadium buildings in the town. uint16 noise_reached; ///< level of noise that all the airports are generating @@ -209,8 +211,8 @@ enum TownDirectoryInvalidateWindowData { */ enum TownFlags { TOWN_IS_GROWING = 0, ///< Conditions for town growth are met. Grow according to Town::growth_rate. - TOWN_HAS_CHURCH = 1, ///< There can be only one church by town. - TOWN_HAS_STADIUM = 2, ///< There can be only one stadium by town. +// TOWN_HAS_CHURCH = 1, ///< There can be only one church per town. Replaced by church_count. +// TOWN_HAS_STADIUM = 2, ///< There can be only one stadium per town. Replaced by stadium_count. TOWN_CUSTOM_GROWTH = 3, ///< Growth rate is controlled by GS. }; diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index f0704a685e..6fe7c096f5 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -2605,7 +2605,7 @@ static TileIndex FindPlaceForTownHouseAroundTile(TileIndex tile, Town *t, HouseI * @param t the town * @return success if house can be built, error message otherwise */ -static CommandCost CheckCanBuildHouse(HouseID house, const Town *t) +static CommandCost CheckCanBuildHouse(HouseID house, const Town *t, bool manual) { const HouseSpec *hs = HouseSpec::Get(house); @@ -2618,9 +2618,9 @@ static CommandCost CheckCanBuildHouse(HouseID house, const Town *t) /* Special houses that there can be only one of. */ if (hs->building_flags & BUILDING_IS_CHURCH) { - if (HasBit(t->flags, TOWN_HAS_CHURCH)) return_cmd_error(STR_ERROR_ONLY_ONE_BUILDING_ALLOWED_PER_TOWN); + if (t->church_count >= ((manual && _settings_client.scenario.multiple_buildings) ? 255 : 1)) return_cmd_error(STR_ERROR_ONLY_ONE_BUILDING_ALLOWED_PER_TOWN); } else if (hs->building_flags & BUILDING_IS_STADIUM) { - if (HasBit(t->flags, TOWN_HAS_STADIUM)) return_cmd_error(STR_ERROR_ONLY_ONE_BUILDING_ALLOWED_PER_TOWN); + if (t->stadium_count >= ((manual && _settings_client.scenario.multiple_buildings) ? 255 : 1)) return_cmd_error(STR_ERROR_ONLY_ONE_BUILDING_ALLOWED_PER_TOWN); } return CommandCost(); @@ -2642,9 +2642,9 @@ static void DoBuildHouse(Town *t, TileIndex tile, HouseID house, byte random_bit /* Special houses that there can be only one of. */ if (hs->building_flags & BUILDING_IS_CHURCH) { - SetBit(t->flags, TOWN_HAS_CHURCH); + t->church_count++; } else if (hs->building_flags & BUILDING_IS_STADIUM) { - SetBit(t->flags, TOWN_HAS_STADIUM); + t->stadium_count++; } byte construction_counter = 0; @@ -2696,9 +2696,11 @@ CommandCost CmdBuildHouse(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 int max_z = GetTileMaxZ(tile); bool above_snowline = (_settings_game.game_creation.landscape == LT_ARCTIC) && (max_z > HighestSnowLine()); + bool manual = (_game_mode == GM_EDITOR); + CommandCost ret = IsHouseTypeAllowed(house, above_snowline, TryGetTownRadiusGroup(t, tile)); if (ret.Succeeded()) ret = IsAnotherHouseTypeAllowedInTown(t, house); - if (ret.Succeeded()) ret = CheckCanBuildHouse(house, t); + if (ret.Succeeded()) ret = CheckCanBuildHouse(house, t, manual); if (ret.Succeeded()) { /* While placing a house manually, try only at exact position and ignore the layout */ const HouseSpec *hs = HouseSpec::Get(house); @@ -2777,7 +2779,7 @@ static bool BuildTownHouse(Town *t, TileIndex tile) houses[i] = houses[num]; probs[i] = probs[num]; - CommandCost ret = CheckCanBuildHouse(house, t); + CommandCost ret = CheckCanBuildHouse(house, t, false); if (ret.Failed()) continue; tile = FindPlaceForTownHouseAroundTile(tile, t, house); @@ -2858,9 +2860,9 @@ void ClearTownHouse(Town *t, TileIndex tile) /* Clear flags for houses that only may exist once/town. */ if (hs->building_flags & BUILDING_IS_CHURCH) { - ClrBit(t->flags, TOWN_HAS_CHURCH); + t->church_count--; } else if (hs->building_flags & BUILDING_IS_STADIUM) { - ClrBit(t->flags, TOWN_HAS_STADIUM); + t->stadium_count--; } /* Do the actual clearing of tiles */