* Place an individual house. * @param flags Type of operation. * @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. */
| 2945 | * @return Empty cost or an error. |
| 2946 | */ |
| 2947 | CommandCost CmdPlaceHouse(DoCommandFlags flags, TileIndex tile, HouseID house, bool is_protected, bool replace) |
| 2948 | { |
| 2949 | if (_game_mode != GM_EDITOR && _settings_game.economy.place_houses == PH_FORBIDDEN) return CMD_ERROR; |
| 2950 | |
| 2951 | if (Town::GetNumItems() == 0) return CommandCost(STR_ERROR_MUST_FOUND_TOWN_FIRST); |
| 2952 | |
| 2953 | if (static_cast<size_t>(house) >= HouseSpec::Specs().size()) return CMD_ERROR; |
| 2954 | const HouseSpec *hs = HouseSpec::Get(house); |
| 2955 | if (!hs->enabled) return CMD_ERROR; |
| 2956 | |
| 2957 | int maxz = GetTileMaxZ(tile); |
| 2958 | |
| 2959 | /* Check each tile of a multi-tile house. */ |
| 2960 | TileArea ta(tile, 1, 1); |
| 2961 | if (hs->building_flags.Test(BuildingFlag::Size2x2)) ta.Add(TileAddXY(tile, 1, 1)); |
| 2962 | if (hs->building_flags.Test(BuildingFlag::Size2x1)) ta.Add(TileAddByDiagDir(tile, DIAGDIR_SW)); |
| 2963 | if (hs->building_flags.Test(BuildingFlag::Size1x2)) ta.Add(TileAddByDiagDir(tile, DIAGDIR_SE)); |
| 2964 | |
| 2965 | for (const TileIndex subtile : ta) { |
| 2966 | /* Houses cannot be built on steep slopes. */ |
| 2967 | Slope slope = GetTileSlope(subtile); |
| 2968 | if (IsSteepSlope(slope)) return CommandCost(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION); |
| 2969 | |
| 2970 | /* Houses cannot be built under bridges. */ |
| 2971 | if (IsBridgeAbove(subtile)) return CommandCost(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST); |
| 2972 | |
| 2973 | /* Make sure there is no slope? */ |
| 2974 | bool noslope = hs->building_flags.Test(BuildingFlag::NotSloped); |
| 2975 | if (noslope && slope != SLOPE_FLAT) return CommandCost(STR_ERROR_FLAT_LAND_REQUIRED); |
| 2976 | |
| 2977 | /* All tiles of a multi-tile house must have the same z-level. */ |
| 2978 | if (GetTileMaxZ(subtile) != maxz) return CommandCost(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION); |
| 2979 | |
| 2980 | /* We might be replacing an existing house, otherwise check if we can clear land. */ |
| 2981 | if (!(replace && GetTileType(subtile) == MP_HOUSE)) { |
| 2982 | CommandCost cost = Command<CMD_LANDSCAPE_CLEAR>::Do({DoCommandFlag::Auto, DoCommandFlag::NoWater}, subtile); |
| 2983 | if (!cost.Succeeded()) return cost; |
| 2984 | } |
| 2985 | } |
| 2986 | |
| 2987 | if (flags.Test(DoCommandFlag::Execute)) { |
| 2988 | /* If replacing, clear any existing houses first. */ |
| 2989 | if (replace) { |
| 2990 | for (const TileIndex &subtile : ta) { |
| 2991 | if (GetTileType(subtile) == MP_HOUSE) ClearTownHouse(Town::GetByTile(subtile), subtile); |
| 2992 | } |
| 2993 | } |
| 2994 | |
| 2995 | Town *t = ClosestTownFromTile(tile, UINT_MAX); |
| 2996 | bool house_completed = _settings_game.economy.place_houses == PH_ALLOWED_CONSTRUCTED; |
| 2997 | BuildTownHouse(t, tile, hs, house, Random(), house_completed, is_protected); |
| 2998 | } |
| 2999 | |
| 3000 | return CommandCost(); |
| 3001 | } |
| 3002 | |
| 3003 | /** |
| 3004 | * Update data structures when a house is removed |
nothing calls this directly
no test coverage detected