1
0
mirror of https://github.com/OpenTTD/OpenTTD synced 2026-01-21 03:12:41 +01:00

Feature: House placer mode to replace existing houses (#14469)

This commit is contained in:
Tyler Trahan
2025-12-07 12:05:47 -05:00
committed by GitHub
parent 0bf3de7658
commit 7f196c6652
5 changed files with 56 additions and 46 deletions

View File

@@ -2932,9 +2932,10 @@ static bool TryBuildTownHouse(Town *t, TileIndex tile, TownExpandModes modes)
* @param tile Tile on which to place the house.
* @param HouseID The HouseID of the house spec.
* @param is_protected Whether the house is protected from the town upgrading it.
* @param replace Whether to automatically demolish an existing house on this tile, if present.
* @return Empty cost or an error.
*/
CommandCost CmdPlaceHouse(DoCommandFlags flags, TileIndex tile, HouseID house, bool is_protected)
CommandCost CmdPlaceHouse(DoCommandFlags flags, TileIndex tile, HouseID house, bool is_protected, bool replace)
{
if (_game_mode != GM_EDITOR && _settings_game.economy.place_houses == PH_FORBIDDEN) return CMD_ERROR;
@@ -2944,39 +2945,45 @@ CommandCost CmdPlaceHouse(DoCommandFlags flags, TileIndex tile, HouseID house, b
const HouseSpec *hs = HouseSpec::Get(house);
if (!hs->enabled) return CMD_ERROR;
Town *t = ClosestTownFromTile(tile, UINT_MAX);
/* cannot build on these slopes... */
Slope slope = GetTileSlope(tile);
if (IsSteepSlope(slope)) return CommandCost(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
/* building under a bridge? */
if (IsBridgeAbove(tile)) return CommandCost(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
/* can we clear the land? */
CommandCost cost = Command<CMD_LANDSCAPE_CLEAR>::Do({DoCommandFlag::Auto, DoCommandFlag::NoWater}, tile);
if (!cost.Succeeded()) return cost;
int maxz = GetTileMaxZ(tile);
/* Make sure there is no slope? */
bool noslope = hs->building_flags.Test(BuildingFlag::NotSloped);
if (noslope && slope != SLOPE_FLAT) return CommandCost(STR_ERROR_FLAT_LAND_REQUIRED);
TileArea ta = tile;
/* Check each tile of a multi-tile house. */
TileArea ta(tile, 1, 1);
if (hs->building_flags.Test(BuildingFlag::Size2x2)) ta.Add(TileAddXY(tile, 1, 1));
if (hs->building_flags.Test(BuildingFlag::Size2x1)) ta.Add(TileAddByDiagDir(tile, DIAGDIR_SW));
if (hs->building_flags.Test(BuildingFlag::Size1x2)) ta.Add(TileAddByDiagDir(tile, DIAGDIR_SE));
/* Check additional tiles covered by this house. */
for (const TileIndex &subtile : ta) {
cost = Command<CMD_LANDSCAPE_CLEAR>::Do({DoCommandFlag::Auto, DoCommandFlag::NoWater}, subtile);
if (!cost.Succeeded()) return cost;
for (const TileIndex subtile : ta) {
/* Houses cannot be built on steep slopes. */
Slope slope = GetTileSlope(subtile);
if (IsSteepSlope(slope)) return CommandCost(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
if (!CheckBuildHouseSameZ(subtile, maxz, noslope)) return CommandCost(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
/* Houses cannot be built under bridges. */
if (IsBridgeAbove(subtile)) return CommandCost(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
/* Make sure there is no slope? */
bool noslope = hs->building_flags.Test(BuildingFlag::NotSloped);
if (noslope && slope != SLOPE_FLAT) return CommandCost(STR_ERROR_FLAT_LAND_REQUIRED);
/* All tiles of a multi-tile house must have the same z-level. */
if (GetTileMaxZ(subtile) != maxz) return CommandCost(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
/* We might be replacing an existing house, otherwise check if we can clear land. */
if (!(replace && GetTileType(subtile) == MP_HOUSE)) {
CommandCost cost = Command<CMD_LANDSCAPE_CLEAR>::Do({DoCommandFlag::Auto, DoCommandFlag::NoWater}, subtile);
if (!cost.Succeeded()) return cost;
}
}
if (flags.Test(DoCommandFlag::Execute)) {
/* If replacing, clear any existing houses first. */
if (replace) {
for (const TileIndex &subtile : ta) {
if (GetTileType(subtile) == MP_HOUSE) ClearTownHouse(Town::GetByTile(subtile), subtile);
}
}
Town *t = ClosestTownFromTile(tile, UINT_MAX);
bool house_completed = _settings_game.economy.place_houses == PH_ALLOWED_CONSTRUCTED;
BuildTownHouse(t, tile, hs, house, Random(), house_completed, is_protected);
}