4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
10 /** @file clear_cmd.cpp Commands related to clear tiles. */
13 #include "clear_map.h"
14 #include "command_func.h"
15 #include "landscape.h"
17 #include "landscape_type.h"
18 #include "clear_func.h"
19 #include "economy_func.h"
20 #include "viewport_func.h"
22 #include "core/random_func.hpp"
24 #include "table/strings.h"
25 #include "table/sprites.h"
26 #include "table/clear_land.h"
28 static CommandCost
ClearTile_Clear(TileIndex tile
, DoCommandFlag flags
)
30 static const Price clear_price_table
[] = {
38 CommandCost
price(EXPENSES_CONSTRUCTION
);
40 if (!IsClearGround(tile
, CLEAR_GRASS
) || GetClearDensity(tile
) != 0) {
41 price
.AddCost(_price
[clear_price_table
[GetClearGround(tile
)]]);
44 if (flags
& DC_EXEC
) DoClearSquare(tile
);
49 void DrawClearLandTile(const TileInfo
*ti
, byte set
)
51 DrawGroundSprite(SPR_FLAT_BARE_LAND
+ SlopeToSpriteOffset(ti
->tileh
) + set
* 19, PAL_NONE
);
54 void DrawHillyLandTile(const TileInfo
*ti
)
56 if (ti
->tileh
!= SLOPE_FLAT
) {
57 DrawGroundSprite(SPR_FLAT_ROUGH_LAND
+ SlopeToSpriteOffset(ti
->tileh
), PAL_NONE
);
59 DrawGroundSprite(_landscape_clear_sprites_rough
[GB(ti
->x
^ ti
->y
, 4, 3)], PAL_NONE
);
63 void DrawClearLandFence(const TileInfo
*ti
)
65 bool fence_sw
= GetFenceSW(ti
->tile
) != 0;
66 bool fence_se
= GetFenceSE(ti
->tile
) != 0;
68 if (!fence_sw
&& !fence_se
) return;
70 int z
= GetSlopeZInCorner(ti
->tileh
, CORNER_S
);
73 DrawGroundSpriteAt(_clear_land_fence_sprites
[GetFenceSW(ti
->tile
) - 1] + _fence_mod_by_tileh_sw
[ti
->tileh
], PAL_NONE
, 0, 0, z
);
77 DrawGroundSpriteAt(_clear_land_fence_sprites
[GetFenceSE(ti
->tile
) - 1] + _fence_mod_by_tileh_se
[ti
->tileh
], PAL_NONE
, 0, 0, z
);
81 static void DrawTile_Clear(TileInfo
*ti
)
83 switch (GetClearGround(ti
->tile
)) {
85 DrawClearLandTile(ti
, GetClearDensity(ti
->tile
));
89 DrawHillyLandTile(ti
);
93 DrawGroundSprite(SPR_FLAT_ROCKY_LAND_1
+ SlopeToSpriteOffset(ti
->tileh
), PAL_NONE
);
97 DrawGroundSprite(_clear_land_sprites_farmland
[GetFieldType(ti
->tile
)] + SlopeToSpriteOffset(ti
->tileh
), PAL_NONE
);
102 DrawGroundSprite(_clear_land_sprites_snow_desert
[GetClearDensity(ti
->tile
)] + SlopeToSpriteOffset(ti
->tileh
), PAL_NONE
);
106 DrawClearLandFence(ti
);
107 DrawBridgeMiddle(ti
);
110 static uint
GetSlopeZ_Clear(TileIndex tile
, uint x
, uint y
)
113 Slope tileh
= GetTileSlope(tile
, &z
);
115 return z
+ GetPartialZ(x
& 0xF, y
& 0xF, tileh
);
118 static Foundation
GetFoundation_Clear(TileIndex tile
, Slope tileh
)
120 return FOUNDATION_NONE
;
123 void TileLoopClearHelper(TileIndex tile
)
125 bool self
= (IsTileType(tile
, MP_CLEAR
) && IsClearGround(tile
, CLEAR_FIELDS
));
128 bool neighbour
= (IsTileType(TILE_ADDXY(tile
, 1, 0), MP_CLEAR
) && IsClearGround(TILE_ADDXY(tile
, 1, 0), CLEAR_FIELDS
));
129 if (GetFenceSW(tile
) == 0) {
130 if (self
!= neighbour
) {
135 if (self
== 0 && neighbour
== 0) {
141 neighbour
= (IsTileType(TILE_ADDXY(tile
, 0, 1), MP_CLEAR
) && IsClearGround(TILE_ADDXY(tile
, 0, 1), CLEAR_FIELDS
));
142 if (GetFenceSE(tile
) == 0) {
143 if (self
!= neighbour
) {
148 if (self
== 0 && neighbour
== 0) {
154 if (dirty
) MarkTileDirtyByTile(tile
);
158 /** Convert to or from snowy tiles. */
159 static void TileLoopClearAlps(TileIndex tile
)
161 int k
= GetTileZ(tile
) - GetSnowLine() + TILE_HEIGHT
;
164 /* Below the snow line, do nothing if no snow. */
165 if (!IsSnowTile(tile
)) return;
167 /* At or above the snow line, make snow tile if needed. */
168 if (!IsSnowTile(tile
)) {
170 MarkTileDirtyByTile(tile
);
174 /* Update snow density. */
175 uint curent_density
= GetClearDensity(tile
);
176 uint req_density
= (k
< 0) ? 0u : min((uint
)k
/ TILE_HEIGHT
, 3);
178 if (curent_density
< req_density
) {
179 AddClearDensity(tile
, 1);
180 } else if (curent_density
> req_density
) {
181 AddClearDensity(tile
, -1);
183 /* Density at the required level. */
187 MarkTileDirtyByTile(tile
);
191 * Tests if at least one surrounding tile is desert
192 * @param tile tile to check
193 * @return does this tile have at least one desert tile around?
195 static inline bool NeighbourIsDesert(TileIndex tile
)
197 return GetTropicZone(tile
+ TileDiffXY( 1, 0)) == TROPICZONE_DESERT
||
198 GetTropicZone(tile
+ TileDiffXY( -1, 0)) == TROPICZONE_DESERT
||
199 GetTropicZone(tile
+ TileDiffXY( 0, 1)) == TROPICZONE_DESERT
||
200 GetTropicZone(tile
+ TileDiffXY( 0, -1)) == TROPICZONE_DESERT
;
203 static void TileLoopClearDesert(TileIndex tile
)
205 /* Current desert level - 0 if it is not desert */
207 if (IsClearGround(tile
, CLEAR_DESERT
)) current
= GetClearDensity(tile
);
209 /* Expected desert level - 0 if it shouldn't be desert */
211 if (GetTropicZone(tile
) == TROPICZONE_DESERT
) {
213 } else if (NeighbourIsDesert(tile
)) {
217 if (current
== expected
) return;
220 SetClearGroundDensity(tile
, CLEAR_GRASS
, 3);
222 /* Transition from clear to desert is not smooth (after clearing desert tile) */
223 SetClearGroundDensity(tile
, CLEAR_DESERT
, expected
);
226 MarkTileDirtyByTile(tile
);
229 static void TileLoop_Clear(TileIndex tile
)
231 /* If the tile is at any edge flood it to prevent maps without water. */
232 if (_settings_game
.construction
.freeform_edges
&& DistanceFromEdge(tile
) == 1) {
234 Slope slope
= GetTileSlope(tile
, &z
);
235 if (z
== 0 && slope
== SLOPE_FLAT
) {
237 MarkTileDirtyByTile(tile
);
241 TileLoopClearHelper(tile
);
243 switch (_settings_game
.game_creation
.landscape
) {
244 case LT_TROPIC
: TileLoopClearDesert(tile
); break;
245 case LT_ARCTIC
: TileLoopClearAlps(tile
); break;
248 switch (GetClearGround(tile
)) {
250 if (GetClearDensity(tile
) == 3) return;
252 if (_game_mode
!= GM_EDITOR
) {
253 if (GetClearCounter(tile
) < 7) {
254 AddClearCounter(tile
, 1);
257 SetClearCounter(tile
, 0);
258 AddClearDensity(tile
, 1);
261 SetClearGroundDensity(tile
, GB(Random(), 0, 8) > 21 ? CLEAR_GRASS
: CLEAR_ROUGH
, 3);
268 if (_game_mode
== GM_EDITOR
) return;
270 if (GetClearCounter(tile
) < 7) {
271 AddClearCounter(tile
, 1);
274 SetClearCounter(tile
, 0);
277 if (GetIndustryIndexOfField(tile
) == INVALID_INDUSTRY
&& GetFieldType(tile
) >= 7) {
278 /* This farmfield is no longer farmfield, so make it grass again */
279 MakeClear(tile
, CLEAR_GRASS
, 2);
281 field_type
= GetFieldType(tile
);
282 field_type
= (field_type
< 8) ? field_type
+ 1 : 0;
283 SetFieldType(tile
, field_type
);
292 MarkTileDirtyByTile(tile
);
295 void GenerateClearTile()
300 /* add rough tiles */
301 i
= ScaleByMapSize(GB(Random(), 0, 10) + 0x400);
302 gi
= ScaleByMapSize(GB(Random(), 0, 7) + 0x80);
304 SetGeneratingWorldProgress(GWP_ROUGH_ROCKY
, gi
+ i
);
306 IncreaseGeneratingWorldProgress(GWP_ROUGH_ROCKY
);
308 if (IsTileType(tile
, MP_CLEAR
) && !IsClearGround(tile
, CLEAR_DESERT
)) SetClearGroundDensity(tile
, CLEAR_ROUGH
, 3);
311 /* add rocky tiles */
315 tile
= RandomTileSeed(r
);
317 IncreaseGeneratingWorldProgress(GWP_ROUGH_ROCKY
);
318 if (IsTileType(tile
, MP_CLEAR
) && !IsClearGround(tile
, CLEAR_DESERT
)) {
319 uint j
= GB(r
, 16, 4) + 5;
323 SetClearGroundDensity(tile
, CLEAR_ROCKS
, 3);
325 if (--j
== 0) goto get_out
;
326 tile_new
= tile
+ TileOffsByDiagDir((DiagDirection
)GB(Random(), 0, 2));
327 } while (!IsTileType(tile_new
, MP_CLEAR
) || IsClearGround(tile_new
, CLEAR_DESERT
));
335 static TrackStatus
GetTileTrackStatus_Clear(TileIndex tile
, TransportType mode
, uint sub_mode
, DiagDirection side
)
340 static const StringID _clear_land_str
[] = {
341 STR_LAI_CLEAR_DESCRIPTION_GRASS
,
342 STR_LAI_CLEAR_DESCRIPTION_ROUGH_LAND
,
343 STR_LAI_CLEAR_DESCRIPTION_ROCKS
,
344 STR_LAI_CLEAR_DESCRIPTION_FIELDS
,
345 STR_LAI_CLEAR_DESCRIPTION_SNOW_COVERED_LAND
,
346 STR_LAI_CLEAR_DESCRIPTION_DESERT
349 static void GetTileDesc_Clear(TileIndex tile
, TileDesc
*td
)
351 if (IsClearGround(tile
, CLEAR_GRASS
) && GetClearDensity(tile
) == 0) {
352 td
->str
= STR_LAI_CLEAR_DESCRIPTION_BARE_LAND
;
354 td
->str
= _clear_land_str
[GetClearGround(tile
)];
356 td
->owner
[0] = GetTileOwner(tile
);
359 static void ChangeTileOwner_Clear(TileIndex tile
, Owner old_owner
, Owner new_owner
)
364 void InitializeClearLand()
366 _settings_game
.game_creation
.snow_line
= _settings_game
.game_creation
.snow_line_height
* TILE_HEIGHT
;
369 static CommandCost
TerraformTile_Clear(TileIndex tile
, DoCommandFlag flags
, uint z_new
, Slope tileh_new
)
371 return DoCommand(tile
, 0, 0, flags
, CMD_LANDSCAPE_CLEAR
);
374 extern const TileTypeProcs _tile_type_clear_procs
= {
375 DrawTile_Clear
, ///< draw_tile_proc
376 GetSlopeZ_Clear
, ///< get_slope_z_proc
377 ClearTile_Clear
, ///< clear_tile_proc
378 NULL
, ///< add_accepted_cargo_proc
379 GetTileDesc_Clear
, ///< get_tile_desc_proc
380 GetTileTrackStatus_Clear
, ///< get_tile_track_status_proc
381 NULL
, ///< click_tile_proc
382 NULL
, ///< animate_tile_proc
383 TileLoop_Clear
, ///< tile_loop_clear
384 ChangeTileOwner_Clear
, ///< change_tile_owner_clear
385 NULL
, ///< add_produced_cargo_proc
386 NULL
, ///< vehicle_enter_tile_proc
387 GetFoundation_Clear
, ///< get_foundation_proc
388 TerraformTile_Clear
, ///< terraform_tile_proc