2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
8 /** @file script_tile.cpp Implementation of ScriptTile. */
10 #include "../../stdafx.h"
11 #include "script_tile.hpp"
12 #include "script_map.hpp"
13 #include "script_town.hpp"
14 #include "../../station_func.h"
15 #include "../../water_map.h"
16 #include "../../clear_map.h"
17 #include "../../tree_map.h"
18 #include "../../town.h"
19 #include "../../landscape.h"
20 #include "../../landscape_cmd.h"
21 #include "../../terraform_cmd.h"
22 #include "../../tree_cmd.h"
24 #include "../../safeguards.h"
26 /* static */ bool ScriptTile::IsBuildable(TileIndex tile
)
28 if (!::IsValidTile(tile
)) return false;
30 switch (::GetTileType(tile
)) {
31 default: return false;
32 case MP_CLEAR
: return true;
33 case MP_TREES
: return true;
34 case MP_WATER
: return IsCoast(tile
);
36 /* Tram bits aren't considered buildable */
37 if (::GetRoadTypeTram(tile
) != INVALID_ROADTYPE
) return false;
38 /* Depots and crossings aren't considered buildable */
39 if (::GetRoadTileType(tile
) != ROAD_TILE_NORMAL
) return false;
40 if (!HasExactlyOneBit(::GetRoadBits(tile
, RTT_ROAD
))) return false;
41 if (::IsRoadOwner(tile
, RTT_ROAD
, OWNER_TOWN
)) return true;
42 if (::IsRoadOwner(tile
, RTT_ROAD
, ScriptObject::GetCompany())) return true;
47 /* static */ bool ScriptTile::IsBuildableRectangle(TileIndex tile
, uint width
, uint height
)
49 /* Check whether we can extract valid X and Y */
50 if (!::IsValidTile(tile
)) return false;
52 uint tx
= ScriptMap::GetTileX(tile
);
53 uint ty
= ScriptMap::GetTileY(tile
);
55 for (uint x
= tx
; x
< width
+ tx
; x
++) {
56 for (uint y
= ty
; y
< height
+ ty
; y
++) {
57 if (!IsBuildable(ScriptMap::GetTileIndex(x
, y
))) return false;
64 /* static */ bool ScriptTile::IsSeaTile(TileIndex tile
)
66 if (!::IsValidTile(tile
)) return false;
68 return ::IsTileType(tile
, MP_WATER
) && ::IsSea(tile
);
71 /* static */ bool ScriptTile::IsRiverTile(TileIndex tile
)
73 if (!::IsValidTile(tile
)) return false;
75 return ::IsTileType(tile
, MP_WATER
) && ::IsRiver(tile
);
78 /* static */ bool ScriptTile::IsWaterTile(TileIndex tile
)
80 if (!::IsValidTile(tile
)) return false;
82 return ::IsTileType(tile
, MP_WATER
) && !::IsCoast(tile
);
85 /* static */ bool ScriptTile::IsCoastTile(TileIndex tile
)
87 if (!::IsValidTile(tile
)) return false;
89 return (::IsTileType(tile
, MP_WATER
) && ::IsCoast(tile
)) ||
90 (::IsTileType(tile
, MP_TREES
) && ::GetTreeGround(tile
) == TREE_GROUND_SHORE
);
93 /* static */ bool ScriptTile::IsStationTile(TileIndex tile
)
95 if (!::IsValidTile(tile
)) return false;
97 return ::IsTileType(tile
, MP_STATION
);
100 /* static */ bool ScriptTile::IsSteepSlope(Slope slope
)
102 if ((slope
& ~(SLOPE_ELEVATED
| SLOPE_STEEP
| SLOPE_HALFTILE_MASK
)) != 0) return false;
104 return ::IsSteepSlope((::Slope
)slope
);
107 /* static */ bool ScriptTile::IsHalftileSlope(Slope slope
)
109 if ((slope
& ~(SLOPE_ELEVATED
| SLOPE_STEEP
| SLOPE_HALFTILE_MASK
)) != 0) return false;
111 return ::IsHalftileSlope((::Slope
)slope
);
114 /* static */ bool ScriptTile::HasTreeOnTile(TileIndex tile
)
116 if (!::IsValidTile(tile
)) return false;
118 return ::IsTileType(tile
, MP_TREES
);
121 /* static */ bool ScriptTile::IsFarmTile(TileIndex tile
)
123 if (!::IsValidTile(tile
)) return false;
125 return (::IsTileType(tile
, MP_CLEAR
) && ::IsClearGround(tile
, CLEAR_FIELDS
));
128 /* static */ bool ScriptTile::IsRockTile(TileIndex tile
)
130 if (!::IsValidTile(tile
)) return false;
132 return (::IsTileType(tile
, MP_CLEAR
) && ::GetRawClearGround(tile
) == ::CLEAR_ROCKS
);
135 /* static */ bool ScriptTile::IsRoughTile(TileIndex tile
)
137 if (!::IsValidTile(tile
)) return false;
139 return (::IsTileType(tile
, MP_CLEAR
) && ::GetRawClearGround(tile
) == ::CLEAR_ROUGH
);
142 /* static */ bool ScriptTile::IsSnowTile(TileIndex tile
)
144 if (!::IsValidTile(tile
)) return false;
146 return (::IsTileType(tile
, MP_CLEAR
) && ::IsSnowTile(tile
));
149 /* static */ bool ScriptTile::IsDesertTile(TileIndex tile
)
151 if (!::IsValidTile(tile
)) return false;
153 return (::IsTileType(tile
, MP_CLEAR
) && ::IsClearGround(tile
, CLEAR_DESERT
));
156 /* static */ ScriptTile::TerrainType
ScriptTile::GetTerrainType(TileIndex tile
)
158 if (!::IsValidTile(tile
)) return TERRAIN_NORMAL
;
160 switch (::GetTerrainType(tile
)) {
162 case 0: return TERRAIN_NORMAL
;
163 case 1: return TERRAIN_DESERT
;
164 case 2: return TERRAIN_RAINFOREST
;
165 case 4: return TERRAIN_SNOW
;
169 /* static */ ScriptTile::Slope
ScriptTile::GetSlope(TileIndex tile
)
171 if (!::IsValidTile(tile
)) return SLOPE_INVALID
;
173 return (Slope
)::GetTileSlope(tile
);
176 /* static */ ScriptTile::Slope
ScriptTile::GetComplementSlope(Slope slope
)
178 if ((slope
& ~SLOPE_ELEVATED
) != 0) return SLOPE_INVALID
;
180 return (Slope
)::ComplementSlope((::Slope
)slope
);
183 /* static */ int32
ScriptTile::GetMinHeight(TileIndex tile
)
185 if (!::IsValidTile(tile
)) return -1;
187 return ::GetTileZ(tile
);
190 /* static */ int32
ScriptTile::GetMaxHeight(TileIndex tile
)
192 if (!::IsValidTile(tile
)) return -1;
194 return ::GetTileMaxZ(tile
);
197 /* static */ int32
ScriptTile::GetCornerHeight(TileIndex tile
, Corner corner
)
199 if (!::IsValidTile(tile
) || !::IsValidCorner((::Corner
)corner
)) return -1;
202 ::Slope slope
= ::GetTileSlope(tile
, &z
);
203 return (z
+ ::GetSlopeZInCorner(slope
, (::Corner
)corner
));
206 /* static */ ScriptCompany::CompanyID
ScriptTile::GetOwner(TileIndex tile
)
208 if (!::IsValidTile(tile
)) return ScriptCompany::COMPANY_INVALID
;
209 if (::IsTileType(tile
, MP_HOUSE
)) return ScriptCompany::COMPANY_INVALID
;
210 if (::IsTileType(tile
, MP_INDUSTRY
)) return ScriptCompany::COMPANY_INVALID
;
212 return ScriptCompany::ResolveCompanyID((ScriptCompany::CompanyID
)(byte
)::GetTileOwner(tile
));
215 /* static */ bool ScriptTile::HasTransportType(TileIndex tile
, TransportType transport_type
)
217 if (!::IsValidTile(tile
)) return false;
219 if (transport_type
== TRANSPORT_ROAD
) {
220 return ::TrackStatusToTrackdirBits(::GetTileTrackStatus(tile
, (::TransportType
)transport_type
, 0)) != TRACKDIR_BIT_NONE
||
221 ::TrackStatusToTrackdirBits(::GetTileTrackStatus(tile
, (::TransportType
)transport_type
, 1)) != TRACKDIR_BIT_NONE
;
223 return ::TrackStatusToTrackdirBits(::GetTileTrackStatus(tile
, (::TransportType
)transport_type
, 0)) != TRACKDIR_BIT_NONE
;
227 /* static */ int32
ScriptTile::GetCargoAcceptance(TileIndex tile
, CargoID cargo_type
, int width
, int height
, int radius
)
229 if (!::IsValidTile(tile
) || width
<= 0 || height
<= 0 || radius
< 0 || !ScriptCargo::IsValidCargo(cargo_type
)) return -1;
231 CargoArray acceptance
= ::GetAcceptanceAroundTiles(tile
, width
, height
, _settings_game
.station
.modified_catchment
? radius
: (int)CA_UNMODIFIED
);
232 return acceptance
[cargo_type
];
235 /* static */ int32
ScriptTile::GetCargoProduction(TileIndex tile
, CargoID cargo_type
, int width
, int height
, int radius
)
237 if (!::IsValidTile(tile
) || width
<= 0 || height
<= 0 || radius
< 0 || !ScriptCargo::IsValidCargo(cargo_type
)) return -1;
239 CargoArray produced
= ::GetProductionAroundTiles(tile
, width
, height
, _settings_game
.station
.modified_catchment
? radius
: (int)CA_UNMODIFIED
);
240 return produced
[cargo_type
];
243 /* static */ int32
ScriptTile::GetDistanceManhattanToTile(TileIndex tile_from
, TileIndex tile_to
)
245 return ScriptMap::DistanceManhattan(tile_from
, tile_to
);
248 /* static */ int32
ScriptTile::GetDistanceSquareToTile(TileIndex tile_from
, TileIndex tile_to
)
250 return ScriptMap::DistanceSquare(tile_from
, tile_to
);
253 /* static */ bool ScriptTile::RaiseTile(TileIndex tile
, int32 slope
)
255 EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY
);
256 EnforcePrecondition(false, tile
< ::MapSize());
258 return ScriptObject::Command
<CMD_TERRAFORM_LAND
>::Do(tile
, (::Slope
)slope
, true);
261 /* static */ bool ScriptTile::LowerTile(TileIndex tile
, int32 slope
)
263 EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY
);
264 EnforcePrecondition(false, tile
< ::MapSize());
266 return ScriptObject::Command
<CMD_TERRAFORM_LAND
>::Do(tile
, (::Slope
)slope
, false);
269 /* static */ bool ScriptTile::LevelTiles(TileIndex start_tile
, TileIndex end_tile
)
271 EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY
);
272 EnforcePrecondition(false, start_tile
< ::MapSize());
273 EnforcePrecondition(false, end_tile
< ::MapSize());
275 return ScriptObject::Command
<CMD_LEVEL_LAND
>::Do(end_tile
, start_tile
, false, LM_LEVEL
);
278 /* static */ bool ScriptTile::DemolishTile(TileIndex tile
)
280 EnforcePrecondition(false, ::IsValidTile(tile
));
282 return ScriptObject::Command
<CMD_LANDSCAPE_CLEAR
>::Do(tile
);
285 /* static */ bool ScriptTile::PlantTree(TileIndex tile
)
287 EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY
);
288 EnforcePrecondition(false, ::IsValidTile(tile
));
290 return ScriptObject::Command
<CMD_PLANT_TREE
>::Do(tile
, TREE_INVALID
, tile
, {});
293 /* static */ bool ScriptTile::PlantTreeRectangle(TileIndex tile
, uint width
, uint height
)
295 EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY
);
296 EnforcePrecondition(false, ::IsValidTile(tile
));
297 EnforcePrecondition(false, width
>= 1 && width
<= 20);
298 EnforcePrecondition(false, height
>= 1 && height
<= 20);
299 TileIndex end_tile
= tile
+ ::TileDiffXY(width
- 1, height
- 1);
301 return ScriptObject::Command
<CMD_PLANT_TREE
>::Do(tile
, TREE_INVALID
, end_tile
, {});
304 /* static */ bool ScriptTile::IsWithinTownInfluence(TileIndex tile
, TownID town_id
)
306 return ScriptTown::IsWithinTownInfluence(town_id
, tile
);
309 /* static */ TownID
ScriptTile::GetTownAuthority(TileIndex tile
)
311 if (!::IsValidTile(tile
)) return INVALID_TOWN
;
313 Town
*town
= ::ClosestTownFromTile(tile
, _settings_game
.economy
.dist_local_authority
);
314 if (town
== nullptr) return INVALID_TOWN
;
319 /* static */ TownID
ScriptTile::GetClosestTown(TileIndex tile
)
321 if (!::IsValidTile(tile
)) return INVALID_TOWN
;
323 Town
*town
= ::ClosestTownFromTile(tile
, UINT_MAX
);
324 if (town
== nullptr) return INVALID_TOWN
;
329 /* static */ Money
ScriptTile::GetBuildCost(BuildType build_type
)
331 switch (build_type
) {
332 case BT_FOUNDATION
: return ::GetPrice(PR_BUILD_FOUNDATION
, 1, nullptr);
333 case BT_TERRAFORM
: return ::GetPrice(PR_TERRAFORM
, 1, nullptr);
334 case BT_BUILD_TREES
: return ::GetPrice(PR_BUILD_TREES
, 1, nullptr);
335 case BT_CLEAR_GRASS
: return ::GetPrice(PR_CLEAR_GRASS
, 1, nullptr);
336 case BT_CLEAR_ROUGH
: return ::GetPrice(PR_CLEAR_ROUGH
, 1, nullptr);
337 case BT_CLEAR_ROCKY
: return ::GetPrice(PR_CLEAR_ROCKS
, 1, nullptr);
338 case BT_CLEAR_FIELDS
: return ::GetPrice(PR_CLEAR_FIELDS
, 1, nullptr);
339 case BT_CLEAR_HOUSE
: return ::GetPrice(PR_CLEAR_HOUSE
, 1, nullptr);
340 case BT_CLEAR_WATER
: return ::GetPrice(PR_CLEAR_WATER
, 1, nullptr);