Add: Allow separate expansion of town buildings and roads in scenario editor. (#14341)

This commit is contained in:
Peter Nelson 2025-06-07 14:56:43 +01:00 committed by GitHub
parent 6b5cde463a
commit ecafbf884e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 123 additions and 53 deletions

View File

@ -501,7 +501,7 @@ void LoadTownData()
do {
uint before = t->cache.num_houses;
Command<CMD_EXPAND_TOWN>::Post(t->index, HOUSES_TO_GROW);
Command<CMD_EXPAND_TOWN>::Post(t->index, HOUSES_TO_GROW, {TownExpandMode::Buildings, TownExpandMode::Roads});
if (t->cache.num_houses <= before) fail_limit--;
} while (fail_limit > 0 && try_limit-- > 0 && t->cache.population < population);
}

View File

@ -3073,6 +3073,12 @@ STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP :{BLACK}Select t
STR_FOUND_TOWN_CITY :{BLACK}City
STR_FOUND_TOWN_CITY_TOOLTIP :{BLACK}Cities grow faster than regular towns{}Depending on settings, they are bigger when founded
STR_FOUND_TOWN_EXPAND_MODE :{YELLOW}Town expansion:
STR_FOUND_TOWN_EXPAND_BUILDINGS :Buildings
STR_FOUND_TOWN_EXPAND_BUILDINGS_TOOLTIP :Increase buildings of towns
STR_FOUND_TOWN_EXPAND_ROADS :Roads
STR_FOUND_TOWN_EXPAND_ROADS_TOOLTIP :Increase roads of towns
STR_FOUND_TOWN_ROAD_LAYOUT :{YELLOW}Town road layout:
STR_FOUND_TOWN_SELECT_LAYOUT_TOOLTIP :{BLACK}Select road layout used for this town
STR_FOUND_TOWN_SELECT_LAYOUT_ORIGINAL :{BLACK}Original
@ -3696,6 +3702,10 @@ STR_TOWN_VIEW_RENAME_TOOLTIP :{BLACK}Change t
STR_TOWN_VIEW_EXPAND_BUTTON :{BLACK}Expand
STR_TOWN_VIEW_EXPAND_TOOLTIP :{BLACK}Increase size of town
STR_TOWN_VIEW_EXPAND_BUILDINGS_BUTTON :{BLACK}Expand buildings
STR_TOWN_VIEW_EXPAND_BUILDINGS_TOOLTIP :{BLACK}Increase buildings of town
STR_TOWN_VIEW_EXPAND_ROADS_BUTTON :{BLACK}Expand roads
STR_TOWN_VIEW_EXPAND_ROADS_TOOLTIP :{BLACK}Increase roads of town
STR_TOWN_VIEW_DELETE_BUTTON :{BLACK}Delete
STR_TOWN_VIEW_DELETE_TOOLTIP :{BLACK}Delete this town completely

View File

@ -278,7 +278,7 @@
houses = std::min<SQInteger>(houses, UINT32_MAX);
return ScriptObject::Command<CMD_EXPAND_TOWN>::Do(town_id, houses);
return ScriptObject::Command<CMD_EXPAND_TOWN>::Do(town_id, houses, {TownExpandMode::Buildings, TownExpandMode::Roads});
}
/* static */ bool ScriptTown::FoundTown(TileIndex tile, TownSize size, bool city, RoadLayout layout, Text *name)

View File

@ -228,7 +228,7 @@ Money HouseSpec::GetRemovalCost() const
return (_price[PR_CLEAR_HOUSE] * this->removal_cost) >> 8;
}
static bool TryBuildTownHouse(Town *t, TileIndex tile);
static bool TryBuildTownHouse(Town *t, TileIndex tile, TownExpandModes modes);
static Town *CreateRandomTown(uint attempts, uint32_t townnameparts, TownSize size, bool city, TownLayout layout);
static void TownDrawHouseLift(const TileInfo *ti)
@ -691,7 +691,10 @@ static void TileLoop_Town(TileIndex tile)
}
}
TryBuildTownHouse(t, tile);
TownExpandModes modes{TownExpandMode::Buildings};
if (_settings_game.economy.allow_town_roads) modes.Set(TownExpandMode::Roads);
TryBuildTownHouse(t, tile, modes);
}
}
@ -902,7 +905,7 @@ static void ChangeTileOwner_Town(TileIndex, Owner, Owner)
/* not used */
}
static bool GrowTown(Town *t);
static bool GrowTown(Town *t, TownExpandModes modes);
/**
* Handle the town tick for a single town, by growing the town if desired.
@ -911,9 +914,11 @@ static bool GrowTown(Town *t);
static void TownTickHandler(Town *t)
{
if (HasBit(t->flags, TOWN_IS_GROWING)) {
TownExpandModes modes{TownExpandMode::Buildings};
if (_settings_game.economy.allow_town_roads) modes.Set(TownExpandMode::Roads);
int i = (int)t->grow_counter - 1;
if (i < 0) {
if (GrowTown(t)) {
if (GrowTown(t, modes)) {
i = t->growth_rate;
} else {
/* If growth failed wait a bit before retrying */
@ -1204,7 +1209,7 @@ static RoadBits GetTownRoadGridElement(Town *t, TileIndex tile, DiagDirection di
* @param tile The target tile for the extra house.
* @return true if an extra house has been added.
*/
static bool GrowTownWithExtraHouse(Town *t, TileIndex tile)
static bool GrowTownWithExtraHouse(Town *t, TileIndex tile, TownExpandModes modes)
{
/* We can't look further than that. */
if (DistanceFromEdge(tile) == 0) return false;
@ -1228,7 +1233,7 @@ static bool GrowTownWithExtraHouse(Town *t, TileIndex tile)
/* If there are enough neighbours stop here */
if (counter >= 3) {
return TryBuildTownHouse(t, tile);
return TryBuildTownHouse(t, tile, modes);
}
}
return false;
@ -1498,9 +1503,9 @@ static bool TownCanGrowRoad(TileIndex tile)
* Check if the town is allowed to build roads.
* @return true If the town is allowed to build roads.
*/
static inline bool TownAllowedToBuildRoads()
static inline bool TownAllowedToBuildRoads(TownExpandModes modes)
{
return _settings_game.economy.allow_town_roads || _generating_world || _game_mode == GM_EDITOR;
return modes.Test(TownExpandMode::Roads);
}
/* The possible states of town growth. */
@ -1528,7 +1533,7 @@ enum class TownGrowthResult {
* @param t1 The current town
* @return Result so far.
*/
static TownGrowthResult GrowTownInTile(TileIndex *tile_ptr, RoadBits cur_rb, DiagDirection target_dir, Town *t1)
static TownGrowthResult GrowTownInTile(TileIndex *tile_ptr, RoadBits cur_rb, DiagDirection target_dir, Town *t1, TownExpandModes modes)
{
RoadBits rcmd = ROAD_NONE; // RoadBits for the road construction command
TileIndex tile = *tile_ptr; // The main tile on which we base our growth
@ -1539,7 +1544,7 @@ static TownGrowthResult GrowTownInTile(TileIndex *tile_ptr, RoadBits cur_rb, Dia
/* Tile has no road.
* We will return TownGrowthResult::SearchStopped to say that this is the last iteration. */
if (!TownAllowedToBuildRoads()) return TownGrowthResult::SearchStopped;
if (!TownAllowedToBuildRoads(modes)) return TownGrowthResult::SearchStopped;
if (!_settings_game.economy.allow_town_level_crossings && IsTileType(tile, MP_RAILWAY)) return TownGrowthResult::SearchStopped;
/* Remove hills etc */
@ -1588,7 +1593,7 @@ static TownGrowthResult GrowTownInTile(TileIndex *tile_ptr, RoadBits cur_rb, Dia
} else if (target_dir < DIAGDIR_END && !(cur_rb & DiagDirToRoadBits(ReverseDiagDir(target_dir)))) {
if (!TownCanGrowRoad(tile)) return TownGrowthResult::Continue;
if (!TownAllowedToBuildRoads()) return TownGrowthResult::SearchStopped;
if (!TownAllowedToBuildRoads(modes)) return TownGrowthResult::SearchStopped;
/* Continue building on a partial road.
* Should be always OK, so we only generate
@ -1664,12 +1669,12 @@ static TownGrowthResult GrowTownInTile(TileIndex *tile_ptr, RoadBits cur_rb, Dia
TownGrowthResult result = TownGrowthResult::Continue;
if (target_dir != DIAGDIR_END && TownAllowedToBuildRoads()) {
if (target_dir != DIAGDIR_END && TownAllowedToBuildRoads(modes)) {
switch (t1->layout) {
default: NOT_REACHED();
case TL_3X3_GRID: // Use 2x2 grid afterwards!
if (GrowTownWithExtraHouse(t1, TileAddByDiagDir(house_tile, target_dir))) {
if (GrowTownWithExtraHouse(t1, TileAddByDiagDir(house_tile, target_dir), modes)) {
result = TownGrowthResult::Succeed;
}
[[fallthrough]];
@ -1680,7 +1685,7 @@ static TownGrowthResult GrowTownInTile(TileIndex *tile_ptr, RoadBits cur_rb, Dia
break;
case TL_BETTER_ROADS: // Use original afterwards!
if (GrowTownWithExtraHouse(t1, TileAddByDiagDir(house_tile, target_dir))) {
if (GrowTownWithExtraHouse(t1, TileAddByDiagDir(house_tile, target_dir), modes)) {
result = TownGrowthResult::Succeed;
}
[[fallthrough]];
@ -1704,7 +1709,7 @@ static TownGrowthResult GrowTownInTile(TileIndex *tile_ptr, RoadBits cur_rb, Dia
/* And build a house.
* Set result to -1 if we managed to build it. */
if (TryBuildTownHouse(t1, house_tile)) {
if (TryBuildTownHouse(t1, house_tile, modes)) {
result = TownGrowthResult::Succeed;
}
}
@ -1744,14 +1749,14 @@ static TownGrowthResult GrowTownInTile(TileIndex *tile_ptr, RoadBits cur_rb, Dia
* @param dir Direction for road to follow or build.
* @return true If road is or can be connected in the specified direction.
*/
static bool CanFollowRoad(TileIndex tile, DiagDirection dir)
static bool CanFollowRoad(TileIndex tile, DiagDirection dir, TownExpandModes modes)
{
TileIndex target_tile = tile + TileOffsByDiagDir(dir);
if (!IsValidTile(target_tile)) return false;
if (HasTileWaterGround(target_tile)) return false;
RoadBits target_rb = GetTownRoadBits(target_tile);
if (TownAllowedToBuildRoads()) {
if (TownAllowedToBuildRoads(modes)) {
/* Check whether a road connection exists or can be build. */
switch (GetTileType(target_tile)) {
case MP_ROAD:
@ -1786,7 +1791,7 @@ static bool CanFollowRoad(TileIndex tile, DiagDirection dir)
* @param tile The road tile to try growing from.
* @return true if we successfully expanded the town.
*/
static bool GrowTownAtRoad(Town *t, TileIndex tile)
static bool GrowTownAtRoad(Town *t, TileIndex tile, TownExpandModes modes)
{
/* Special case.
* @see GrowTownInTile Check the else if
@ -1818,7 +1823,7 @@ static bool GrowTownAtRoad(Town *t, TileIndex tile)
RoadBits cur_rb = GetTownRoadBits(tile); // The RoadBits of the current tile
/* Try to grow the town from this point */
switch (GrowTownInTile(&tile, cur_rb, target_dir, t)) {
switch (GrowTownInTile(&tile, cur_rb, target_dir, t, modes)) {
case TownGrowthResult::Succeed:
return true;
case TownGrowthResult::SearchStopped:
@ -1847,7 +1852,7 @@ static bool GrowTownAtRoad(Town *t, TileIndex tile)
target_bits = DiagDirToRoadBits(target_dir);
} while (!(cur_rb & target_bits));
cur_rb &= ~target_bits;
} while (!CanFollowRoad(tile, target_dir));
} while (!CanFollowRoad(tile, target_dir, modes));
}
tile = TileAddByDiagDir(tile, target_dir);
@ -1890,7 +1895,7 @@ static RoadBits GenRandomRoadBits()
* @param t The town to grow
* @return true if we successfully grew the town with a road or house.
*/
static bool GrowTown(Town *t)
static bool GrowTown(Town *t, TownExpandModes modes)
{
static const TileIndexDiffC _town_coord_mod[] = {
{-1, 0},
@ -1916,7 +1921,7 @@ static bool GrowTown(Town *t)
/* Find a road that we can base the construction on. */
for (const auto &ptr : _town_coord_mod) {
if (GetTownRoadBits(tile) != ROAD_NONE) {
bool success = GrowTownAtRoad(t, tile);
bool success = GrowTownAtRoad(t, tile, modes);
cur_company.Restore();
return success;
}
@ -1925,7 +1930,7 @@ static bool GrowTown(Town *t)
/* No road available, try to build a random road block by
* clearing some land and then building a road there. */
if (TownAllowedToBuildRoads()) {
if (TownAllowedToBuildRoads(modes)) {
tile = t->xy;
for (const auto &ptr : _town_coord_mod) {
/* Only work with plain land that not already has a house */
@ -2084,7 +2089,7 @@ static void DoCreateTown(Town *t, TileIndex tile, uint32_t townnameparts, TownSi
int i = x * 4;
do {
GrowTown(t);
GrowTown(t, {TownExpandMode::Buildings, TownExpandMode::Roads});
} while (--i);
t->UpdateVirtCoord();
@ -2605,10 +2610,12 @@ static bool CheckFree2x2Area(TileIndex tile, int z, bool noslope)
* @return true iff town layout allows building here.
* @note see layouts
*/
static inline bool TownLayoutAllowsHouseHere(Town *t, TileIndex tile)
static inline bool TownLayoutAllowsHouseHere(Town *t, TileIndex tile, TownExpandModes modes)
{
if (!modes.Test(TownExpandMode::Buildings)) return false;
/* Allow towns everywhere when we don't build roads */
if (!TownAllowedToBuildRoads()) return true;
if (!TownAllowedToBuildRoads(modes)) return true;
TileIndexDiffC grid_pos = TileIndexToTileIndexDiffC(t->xy, tile);
@ -2636,10 +2643,12 @@ static inline bool TownLayoutAllowsHouseHere(Town *t, TileIndex tile)
* @return true iff town layout allows a 2x2 building here.
* @note see layouts
*/
static inline bool TownLayoutAllows2x2HouseHere(Town *t, TileIndex tile)
static inline bool TownLayoutAllows2x2HouseHere(Town *t, TileIndex tile, TownExpandModes modes)
{
if (!modes.Test(TownExpandMode::Buildings)) return false;
/* Allow towns everywhere when we don't build roads */
if (!TownAllowedToBuildRoads()) return true;
if (!TownAllowedToBuildRoads(modes)) return true;
/* Compute relative position of tile. (Positive offsets are towards north) */
TileIndexDiffC grid_pos = TileIndexToTileIndexDiffC(t->xy, tile);
@ -2673,15 +2682,15 @@ static inline bool TownLayoutAllows2x2HouseHere(Town *t, TileIndex tile)
* @param noslope Are foundations disallowed for this house?
* @param second The diagdir from the first tile to the second tile.
*/
static bool CheckTownBuild2House(TileIndex *tile, Town *t, int maxz, bool noslope, DiagDirection second)
static bool CheckTownBuild2House(TileIndex *tile, Town *t, int maxz, bool noslope, DiagDirection second, TownExpandModes modes)
{
/* 'tile' is already checked in BuildTownHouse() - CanBuildHouseHere() and slope test */
TileIndex tile2 = *tile + TileOffsByDiagDir(second);
if (TownLayoutAllowsHouseHere(t, tile2) && CheckBuildHouseSameZ(tile2, maxz, noslope)) return true;
if (TownLayoutAllowsHouseHere(t, tile2, modes) && CheckBuildHouseSameZ(tile2, maxz, noslope)) return true;
tile2 = *tile + TileOffsByDiagDir(ReverseDiagDir(second));
if (TownLayoutAllowsHouseHere(t, tile2) && CheckBuildHouseSameZ(tile2, maxz, noslope)) {
if (TownLayoutAllowsHouseHere(t, tile2, modes) && CheckBuildHouseSameZ(tile2, maxz, noslope)) {
*tile = tile2;
return true;
}
@ -2698,12 +2707,12 @@ static bool CheckTownBuild2House(TileIndex *tile, Town *t, int maxz, bool noslop
* @param maxz The maximum Z level, since all tiles must have the same height.
* @param noslope Are foundations disallowed for this house?
*/
static bool CheckTownBuild2x2House(TileIndex *tile, Town *t, int maxz, bool noslope)
static bool CheckTownBuild2x2House(TileIndex *tile, Town *t, int maxz, bool noslope, TownExpandModes modes)
{
TileIndex tile2 = *tile;
for (DiagDirection d = DIAGDIR_SE;; d++) { // 'd' goes through DIAGDIR_SE, DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_END
if (TownLayoutAllows2x2HouseHere(t, tile2) && CheckFree2x2Area(tile2, maxz, noslope)) {
if (TownLayoutAllows2x2HouseHere(t, tile2, modes) && CheckFree2x2Area(tile2, maxz, noslope)) {
*tile = tile2;
return true;
}
@ -2763,10 +2772,10 @@ static void BuildTownHouse(Town *t, TileIndex tile, const HouseSpec *hs, HouseID
* @param tile The tile to try building on.
* @return false iff no house can be built on this tile.
*/
static bool TryBuildTownHouse(Town *t, TileIndex tile)
static bool TryBuildTownHouse(Town *t, TileIndex tile, TownExpandModes modes)
{
/* forbidden building here by town layout */
if (!TownLayoutAllowsHouseHere(t, tile)) return false;
if (!TownLayoutAllowsHouseHere(t, tile, modes)) return false;
/* no house allowed at all, bail out */
if (!CanBuildHouseHere(tile, false)) return false;
@ -2860,11 +2869,11 @@ static bool TryBuildTownHouse(Town *t, TileIndex tile)
if (noslope && slope != SLOPE_FLAT) continue;
if (hs->building_flags.Test(BuildingFlag::Size2x2)) {
if (!CheckTownBuild2x2House(&tile, t, maxz, noslope)) continue;
if (!CheckTownBuild2x2House(&tile, t, maxz, noslope, modes)) continue;
} else if (hs->building_flags.Test(BuildingFlag::Size2x1)) {
if (!CheckTownBuild2House(&tile, t, maxz, noslope, DIAGDIR_SW)) continue;
if (!CheckTownBuild2House(&tile, t, maxz, noslope, DIAGDIR_SW, modes)) continue;
} else if (hs->building_flags.Test(BuildingFlag::Size1x2)) {
if (!CheckTownBuild2House(&tile, t, maxz, noslope, DIAGDIR_SE)) continue;
if (!CheckTownBuild2House(&tile, t, maxz, noslope, DIAGDIR_SE, modes)) continue;
} else {
/* 1x1 house checks are already done */
}
@ -3199,9 +3208,10 @@ CommandCost CmdTownRating(DoCommandFlags flags, TownID town_id, CompanyID compan
* @param grow_amount Amount to grow, or 0 to grow a random size up to the current amount of houses.
* @return Empty cost or an error.
*/
CommandCost CmdExpandTown(DoCommandFlags flags, TownID town_id, uint32_t grow_amount)
CommandCost CmdExpandTown(DoCommandFlags flags, TownID town_id, uint32_t grow_amount, TownExpandModes modes)
{
if (_game_mode != GM_EDITOR && _current_company != OWNER_DEITY) return CMD_ERROR;
if (modes.None()) return CMD_ERROR;
Town *t = Town::GetIfValid(town_id);
if (t == nullptr) return CMD_ERROR;
@ -3213,13 +3223,13 @@ CommandCost CmdExpandTown(DoCommandFlags flags, TownID town_id, uint32_t grow_am
UpdateTownRadius(t);
uint n = amount * 10;
do GrowTown(t); while (--n);
do GrowTown(t, modes); while (--n);
t->cache.num_houses -= amount;
} else {
for (; grow_amount > 0; grow_amount--) {
/* Try several times to grow, as we are really suppose to grow */
for (uint i = 0; i < 25; i++) if (GrowTown(t)) break;
for (uint i = 0; i < 25; i++) if (GrowTown(t, modes)) break;
}
}
UpdateTownRadius(t);

View File

@ -25,7 +25,7 @@ CommandCost CmdTownGrowthRate(DoCommandFlags flags, TownID town_id, uint16_t gro
CommandCost CmdTownRating(DoCommandFlags flags, TownID town_id, CompanyID company_id, int16_t rating);
CommandCost CmdTownCargoGoal(DoCommandFlags flags, TownID town_id, TownAcceptanceEffect tae, uint32_t goal);
CommandCost CmdTownSetText(DoCommandFlags flags, TownID town_id, const EncodedString &text);
CommandCost CmdExpandTown(DoCommandFlags flags, TownID town_id, uint32_t grow_amount);
CommandCost CmdExpandTown(DoCommandFlags flags, TownID town_id, uint32_t grow_amount, TownExpandModes modes);
CommandCost CmdDeleteTown(DoCommandFlags flags, TownID town_id);
CommandCost CmdPlaceHouse(DoCommandFlags flags, TileIndex tile, HouseID house, bool house_protected);

View File

@ -488,10 +488,17 @@ public:
SetViewportCatchmentTown(Town::Get(this->window_number), !this->IsWidgetLowered(WID_TV_CATCHMENT));
break;
case WID_TV_EXPAND: { // expand town - only available on Scenario editor
Command<CMD_EXPAND_TOWN>::Post(STR_ERROR_CAN_T_EXPAND_TOWN, static_cast<TownID>(this->window_number), 0);
case WID_TV_EXPAND: // expand town - only available on Scenario editor
Command<CMD_EXPAND_TOWN>::Post(STR_ERROR_CAN_T_EXPAND_TOWN, static_cast<TownID>(this->window_number), 0, {TownExpandMode::Buildings, TownExpandMode::Roads});
break;
case WID_TV_EXPAND_BUILDINGS: // expand buildings of town - only available on Scenario editor
Command<CMD_EXPAND_TOWN>::Post(STR_ERROR_CAN_T_EXPAND_TOWN, static_cast<TownID>(this->window_number), 0, {TownExpandMode::Buildings});
break;
case WID_TV_EXPAND_ROADS: // expand roads of town - only available on Scenario editor
Command<CMD_EXPAND_TOWN>::Post(STR_ERROR_CAN_T_EXPAND_TOWN, static_cast<TownID>(this->window_number), 0, {TownExpandMode::Roads});
break;
}
case WID_TV_DELETE: // delete town - only available on Scenario editor
Command<CMD_DELETE_TOWN>::Post(STR_ERROR_TOWN_CAN_T_DELETE, static_cast<TownID>(this->window_number));
@ -638,10 +645,14 @@ static constexpr NWidgetPart _nested_town_editor_view_widgets[] = {
EndContainer(),
EndContainer(),
NWidget(WWT_PANEL, COLOUR_BROWN, WID_TV_INFO), SetMinimalSize(260, 32), SetResize(1, 0), SetFill(1, 0), EndContainer(),
NWidget(NWID_HORIZONTAL, NWidContainerFlag::EqualSize),
NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_EXPAND), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_TOWN_VIEW_EXPAND_BUTTON, STR_TOWN_VIEW_EXPAND_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_DELETE), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_TOWN_VIEW_DELETE_BUTTON, STR_TOWN_VIEW_DELETE_TOOLTIP),
NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TV_CATCHMENT), SetMinimalSize(40, 12), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_BUTTON_CATCHMENT, STR_TOOLTIP_CATCHMENT),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_EXPAND), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_TOWN_VIEW_EXPAND_BUTTON, STR_TOWN_VIEW_EXPAND_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_EXPAND_BUILDINGS), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_TOWN_VIEW_EXPAND_BUILDINGS_BUTTON, STR_TOWN_VIEW_EXPAND_BUILDINGS_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_EXPAND_ROADS), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_TOWN_VIEW_EXPAND_ROADS_BUTTON, STR_TOWN_VIEW_EXPAND_ROADS_TOOLTIP),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_DELETE), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_TOWN_VIEW_DELETE_BUTTON, STR_TOWN_VIEW_DELETE_TOOLTIP),
NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TV_CATCHMENT), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_BUTTON_CATCHMENT, STR_TOOLTIP_CATCHMENT),
NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
EndContainer(),
};
@ -1078,7 +1089,6 @@ static constexpr NWidgetPart _nested_found_town_widgets[] = {
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_RANDOM_TOWN), SetStringTip(STR_FOUND_TOWN_RANDOM_TOWN_BUTTON, STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP), SetFill(1, 0),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_MANY_RANDOM_TOWNS), SetStringTip(STR_FOUND_TOWN_MANY_RANDOM_TOWNS, STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP), SetFill(1, 0),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_LOAD_FROM_FILE), SetStringTip(STR_FOUND_TOWN_LOAD_FROM_FILE, STR_FOUND_TOWN_LOAD_FROM_FILE_TOOLTIP), SetFill(1, 0),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_EXPAND_ALL_TOWNS), SetStringTip(STR_FOUND_TOWN_EXPAND_ALL_TOWNS, STR_FOUND_TOWN_EXPAND_ALL_TOWNS_TOOLTIP), SetFill(1, 0),
EndContainer(),
EndContainer(),
@ -1120,6 +1130,18 @@ static constexpr NWidgetPart _nested_found_town_widgets[] = {
EndContainer(),
EndContainer(),
EndContainer(),
/* Town expansion selection. */
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_TF_TOWN_EXPAND_SEL),
NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_normal, 0),
NWidget(WWT_LABEL, INVALID_COLOUR), SetStringTip(STR_FOUND_TOWN_EXPAND_MODE),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_EXPAND_ALL_TOWNS), SetStringTip(STR_FOUND_TOWN_EXPAND_ALL_TOWNS, STR_FOUND_TOWN_EXPAND_ALL_TOWNS_TOOLTIP), SetFill(1, 0),
NWidget(NWID_HORIZONTAL, NWidContainerFlag::EqualSize),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_EXPAND_BUILDINGS), SetStringTip(STR_FOUND_TOWN_EXPAND_BUILDINGS, STR_FOUND_TOWN_EXPAND_BUILDINGS_TOOLTIP), SetFill(1, 0),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_EXPAND_ROADS), SetStringTip(STR_FOUND_TOWN_EXPAND_ROADS, STR_FOUND_TOWN_EXPAND_ROADS_TOOLTIP), SetFill(1, 0),
EndContainer(),
EndContainer(),
EndContainer(),
EndContainer(),
EndContainer(),
};
@ -1134,6 +1156,7 @@ private:
bool townnamevalid = false; ///< Is generated town name valid?
uint32_t townnameparts = 0; ///< Generated town name
TownNameParams params; ///< Town name parameters
static inline TownExpandModes expand_modes{TownExpandMode::Buildings, TownExpandMode::Roads};
public:
FoundTownWindow(WindowDesc &desc, WindowNumber window_number) :
@ -1153,6 +1176,7 @@ public:
if (_game_mode == GM_EDITOR) return;
this->GetWidget<NWidgetStacked>(WID_TF_TOWN_ACTION_SEL)->SetDisplayedPlane(SZSP_HORIZONTAL);
this->GetWidget<NWidgetStacked>(WID_TF_TOWN_EXPAND_SEL)->SetDisplayedPlane(SZSP_HORIZONTAL);
this->GetWidget<NWidgetStacked>(WID_TF_SIZE_SEL)->SetDisplayedPlane(SZSP_VERTICAL);
if (_settings_game.economy.found_town != TF_CUSTOM_LAYOUT) {
this->GetWidget<NWidgetStacked>(WID_TF_ROAD_LAYOUT_SEL)->SetDisplayedPlane(SZSP_HORIZONTAL);
@ -1192,6 +1216,9 @@ public:
this->SetWidgetLoweredState(i, i == WID_TF_LAYOUT_ORIGINAL + this->town_layout);
}
this->SetWidgetLoweredState(WID_TF_EXPAND_BUILDINGS, FoundTownWindow::expand_modes.Test(TownExpandMode::Buildings));
this->SetWidgetLoweredState(WID_TF_EXPAND_ROADS, FoundTownWindow::expand_modes.Test(TownExpandMode::Roads));
this->SetDirty();
}
@ -1242,7 +1269,7 @@ public:
case WID_TF_EXPAND_ALL_TOWNS:
for (Town *t : Town::Iterate()) {
Command<CMD_EXPAND_TOWN>::Do(DoCommandFlag::Execute, t->index, 0);
Command<CMD_EXPAND_TOWN>::Do(DoCommandFlag::Execute, t->index, 0, FoundTownWindow::expand_modes);
}
break;
@ -1257,6 +1284,16 @@ public:
this->SetDirty();
break;
case WID_TF_EXPAND_BUILDINGS:
FoundTownWindow::expand_modes.Flip(TownExpandMode::Buildings);
this->UpdateButtons(false);
break;
case WID_TF_EXPAND_ROADS:
FoundTownWindow::expand_modes.Flip(TownExpandMode::Roads);
this->UpdateButtons(false);
break;
case WID_TF_LAYOUT_ORIGINAL: case WID_TF_LAYOUT_BETTER: case WID_TF_LAYOUT_GRID2:
case WID_TF_LAYOUT_GRID3: case WID_TF_LAYOUT_RANDOM:
this->town_layout = (TownLayout)(widget - WID_TF_LAYOUT_ORIGINAL);

View File

@ -91,6 +91,14 @@ enum TownLayout : uint8_t {
};
DECLARE_ENUM_AS_ADDABLE(TownLayout)
/** Options for growing towns. */
enum class TownExpandMode : uint8_t {
Buildings, ///< Allow town to place buildings.
Roads, ///< Allow town to place roads.
};
using TownExpandModes = EnumBitSet<TownExpandMode, uint8_t>;
/** Town founding setting values. It needs to be 8bits, because we save and load it as such */
enum TownFounding : uint8_t {
TF_BEGIN = 0, ///< Used for iterations and limit testing

View File

@ -42,6 +42,8 @@ enum TownViewWidgets : WidgetID {
WID_TV_CHANGE_NAME, ///< Change the name of this town.
WID_TV_CATCHMENT, ///< Toggle catchment area highlight.
WID_TV_EXPAND, ///< Expand this town (scenario editor only).
WID_TV_EXPAND_BUILDINGS, ///< Expand number of buildings this town (scenario editor only).
WID_TV_EXPAND_ROADS, ///< Expand roads of this town (scenario editor only).
WID_TV_DELETE, ///< Delete this town (scenario editor only).
};
@ -67,6 +69,9 @@ enum TownFoundingWidgets : WidgetID {
WID_TF_LAYOUT_GRID2, ///< Selection for the 2x2 grid town layout.
WID_TF_LAYOUT_GRID3, ///< Selection for the 3x3 grid town layout.
WID_TF_LAYOUT_RANDOM, ///< Selection for a randomly chosen town layout.
WID_TF_TOWN_EXPAND_SEL, ///< Container of town expansion buttons.
WID_TF_EXPAND_BUILDINGS, ///< Expand buildings toggle.
WID_TF_EXPAND_ROADS, ///< Expand roads toggle.
};
/** Widgets of the #BuildHouseWindow class. */