OpenTTD Source  20241108-master-g80f628063a
clear_cmd.cpp
Go to the documentation of this file.
1 /*
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/>.
6  */
7 
10 #include "stdafx.h"
11 #include "clear_map.h"
12 #include "command_func.h"
13 #include "landscape.h"
14 #include "genworld.h"
15 #include "viewport_func.h"
16 #include "core/random_func.hpp"
17 #include "newgrf_generic.h"
18 #include "landscape_cmd.h"
19 
20 #include "table/strings.h"
21 #include "table/sprites.h"
22 #include "table/clear_land.h"
23 
24 #include "safeguards.h"
25 
26 static CommandCost ClearTile_Clear(TileIndex tile, DoCommandFlag flags)
27 {
28  static const Price clear_price_table[] = {
29  PR_CLEAR_GRASS,
30  PR_CLEAR_ROUGH,
31  PR_CLEAR_ROCKS,
32  PR_CLEAR_FIELDS,
33  PR_CLEAR_ROUGH,
34  PR_CLEAR_ROUGH,
35  };
37 
38  if (!IsClearGround(tile, CLEAR_GRASS) || GetClearDensity(tile) != 0) {
39  price.AddCost(_price[clear_price_table[GetClearGround(tile)]]);
40  }
41 
42  if (flags & DC_EXEC) DoClearSquare(tile);
43 
44  return price;
45 }
46 
47 void DrawClearLandTile(const TileInfo *ti, uint8_t set)
48 {
49  DrawGroundSprite(SPR_FLAT_BARE_LAND + SlopeToSpriteOffset(ti->tileh) + set * 19, PAL_NONE);
50 }
51 
52 void DrawHillyLandTile(const TileInfo *ti)
53 {
54  if (ti->tileh != SLOPE_FLAT) {
55  DrawGroundSprite(SPR_FLAT_ROUGH_LAND + SlopeToSpriteOffset(ti->tileh), PAL_NONE);
56  } else {
57  DrawGroundSprite(_landscape_clear_sprites_rough[GB(TileHash(ti->x, ti->y), 0, 3)], PAL_NONE);
58  }
59 }
60 
61 static void DrawClearLandFence(const TileInfo *ti)
62 {
63  /* combine fences into one sprite object */
65 
66  int maxz = GetSlopeMaxPixelZ(ti->tileh);
67 
68  uint fence_nw = GetFence(ti->tile, DIAGDIR_NW);
69  if (fence_nw != 0) {
70  int z = GetSlopePixelZInCorner(ti->tileh, CORNER_W);
71  SpriteID sprite = _clear_land_fence_sprites[fence_nw - 1] + _fence_mod_by_tileh_nw[ti->tileh];
72  AddSortableSpriteToDraw(sprite, PAL_NONE, ti->x, ti->y - 16, 16, 32, maxz - z + 4, ti->z + z, false, 0, 16, -z);
73  }
74 
75  uint fence_ne = GetFence(ti->tile, DIAGDIR_NE);
76  if (fence_ne != 0) {
77  int z = GetSlopePixelZInCorner(ti->tileh, CORNER_E);
78  SpriteID sprite = _clear_land_fence_sprites[fence_ne - 1] + _fence_mod_by_tileh_ne[ti->tileh];
79  AddSortableSpriteToDraw(sprite, PAL_NONE, ti->x - 16, ti->y, 32, 16, maxz - z + 4, ti->z + z, false, 16, 0, -z);
80  }
81 
82  uint fence_sw = GetFence(ti->tile, DIAGDIR_SW);
83  uint fence_se = GetFence(ti->tile, DIAGDIR_SE);
84 
85  if (fence_sw != 0 || fence_se != 0) {
86  int z = GetSlopePixelZInCorner(ti->tileh, CORNER_S);
87 
88  if (fence_sw != 0) {
89  SpriteID sprite = _clear_land_fence_sprites[fence_sw - 1] + _fence_mod_by_tileh_sw[ti->tileh];
90  AddSortableSpriteToDraw(sprite, PAL_NONE, ti->x, ti->y, 16, 16, maxz - z + 4, ti->z + z, false, 0, 0, -z);
91  }
92 
93  if (fence_se != 0) {
94  SpriteID sprite = _clear_land_fence_sprites[fence_se - 1] + _fence_mod_by_tileh_se[ti->tileh];
95  AddSortableSpriteToDraw(sprite, PAL_NONE, ti->x, ti->y, 16, 16, maxz - z + 4, ti->z + z, false, 0, 0, -z);
96  }
97  }
99 }
100 
101 static void DrawTile_Clear(TileInfo *ti)
102 {
103  switch (GetClearGround(ti->tile)) {
104  case CLEAR_GRASS:
105  DrawClearLandTile(ti, GetClearDensity(ti->tile));
106  break;
107 
108  case CLEAR_ROUGH:
109  DrawHillyLandTile(ti);
110  break;
111 
112  case CLEAR_ROCKS:
113  DrawGroundSprite((HasGrfMiscBit(GMB_SECOND_ROCKY_TILE_SET) && (TileHash(ti->x, ti->y) & 1) ? SPR_FLAT_ROCKY_LAND_2 : SPR_FLAT_ROCKY_LAND_1) + SlopeToSpriteOffset(ti->tileh), PAL_NONE);
114  break;
115 
116  case CLEAR_FIELDS:
117  DrawGroundSprite(_clear_land_sprites_farmland[GetFieldType(ti->tile)] + SlopeToSpriteOffset(ti->tileh), PAL_NONE);
118  DrawClearLandFence(ti);
119  break;
120 
121  case CLEAR_SNOW:
122  case CLEAR_DESERT:
123  DrawGroundSprite(_clear_land_sprites_snow_desert[GetClearDensity(ti->tile)] + SlopeToSpriteOffset(ti->tileh), PAL_NONE);
124  break;
125  }
126 
127  DrawBridgeMiddle(ti);
128 }
129 
130 static int GetSlopePixelZ_Clear(TileIndex tile, uint x, uint y, bool)
131 {
132  auto [tileh, z] = GetTilePixelSlope(tile);
133 
134  return z + GetPartialPixelZ(x & 0xF, y & 0xF, tileh);
135 }
136 
137 static Foundation GetFoundation_Clear(TileIndex, Slope)
138 {
139  return FOUNDATION_NONE;
140 }
141 
142 static void UpdateFences(TileIndex tile)
143 {
144  assert(IsTileType(tile, MP_CLEAR) && IsClearGround(tile, CLEAR_FIELDS));
145  bool dirty = false;
146 
147  for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) {
148  if (GetFence(tile, dir) != 0) continue;
149  TileIndex neighbour = tile + TileOffsByDiagDir(dir);
150  if (IsTileType(neighbour, MP_CLEAR) && IsClearGround(neighbour, CLEAR_FIELDS)) continue;
151  SetFence(tile, dir, 3);
152  dirty = true;
153  }
154 
155  if (dirty) MarkTileDirtyByTile(tile);
156 }
157 
158 
160 static void TileLoopClearAlps(TileIndex tile)
161 {
162  int k = GetTileZ(tile) - GetSnowLine() + 1;
163 
164  if (!IsSnowTile(tile)) {
165  /* Below the snow line, do nothing if no snow. */
166  /* At or above the snow line, make snow tile if needed. */
167  if (k >= 0) {
168  MakeSnow(tile);
169  MarkTileDirtyByTile(tile);
170  }
171  return;
172  }
173 
174  /* Update snow density. */
175  uint current_density = GetClearDensity(tile);
176  uint req_density = (k < 0) ? 0u : std::min<uint>(k, 3u);
177 
178  if (current_density == req_density) {
179  /* Density at the required level. */
180  if (k >= 0) return;
181  ClearSnow(tile);
182  } else {
183  AddClearDensity(tile, current_density < req_density ? 1 : -1);
184  }
185 
186  MarkTileDirtyByTile(tile);
187 }
188 
194 static inline bool NeighbourIsNormal(TileIndex tile)
195 {
196  for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) {
197  TileIndex t = tile + TileOffsByDiagDir(dir);
198  if (!IsValidTile(t)) continue;
199  if (GetTropicZone(t) != TROPICZONE_DESERT) return true;
200  if (HasTileWaterClass(t) && GetWaterClass(t) == WATER_CLASS_SEA) return true;
201  }
202  return false;
203 }
204 
205 static void TileLoopClearDesert(TileIndex tile)
206 {
207  /* Current desert level - 0 if it is not desert */
208  uint current = 0;
209  if (IsClearGround(tile, CLEAR_DESERT)) current = GetClearDensity(tile);
210 
211  /* Expected desert level - 0 if it shouldn't be desert */
212  uint expected = 0;
213  if (GetTropicZone(tile) == TROPICZONE_DESERT) {
214  expected = NeighbourIsNormal(tile) ? 1 : 3;
215  }
216 
217  if (current == expected) return;
218 
219  if (expected == 0) {
221  } else {
222  /* Transition from clear to desert is not smooth (after clearing desert tile) */
223  SetClearGroundDensity(tile, CLEAR_DESERT, expected);
224  }
225 
226  MarkTileDirtyByTile(tile);
227 }
228 
229 static void TileLoop_Clear(TileIndex tile)
230 {
231  AmbientSoundEffect(tile);
232 
234  case LT_TROPIC: TileLoopClearDesert(tile); break;
235  case LT_ARCTIC: TileLoopClearAlps(tile); break;
236  }
237 
238  switch (GetClearGround(tile)) {
239  case CLEAR_GRASS:
240  if (GetClearDensity(tile) == 3) return;
241 
242  if (_game_mode != GM_EDITOR) {
243  if (GetClearCounter(tile) < 7) {
244  AddClearCounter(tile, 1);
245  return;
246  } else {
247  SetClearCounter(tile, 0);
248  AddClearDensity(tile, 1);
249  }
250  } else {
251  SetClearGroundDensity(tile, GB(Random(), 0, 8) > 21 ? CLEAR_GRASS : CLEAR_ROUGH, 3);
252  }
253  break;
254 
255  case CLEAR_FIELDS:
256  UpdateFences(tile);
257 
258  if (_game_mode == GM_EDITOR) return;
259 
260  if (GetClearCounter(tile) < 7) {
261  AddClearCounter(tile, 1);
262  return;
263  } else {
264  SetClearCounter(tile, 0);
265  }
266 
267  if (GetIndustryIndexOfField(tile) == INVALID_INDUSTRY && GetFieldType(tile) >= 7) {
268  /* This farmfield is no longer farmfield, so make it grass again */
269  MakeClear(tile, CLEAR_GRASS, 2);
270  } else {
271  uint field_type = GetFieldType(tile);
272  field_type = (field_type < 8) ? field_type + 1 : 0;
273  SetFieldType(tile, field_type);
274  }
275  break;
276 
277  default:
278  return;
279  }
280 
281  MarkTileDirtyByTile(tile);
282 }
283 
284 void GenerateClearTile()
285 {
286  uint i, gi;
287  TileIndex tile;
288 
289  /* add rough tiles */
290  i = Map::ScaleBySize(GB(Random(), 0, 10) + 0x400);
291  gi = Map::ScaleBySize(GB(Random(), 0, 7) + 0x80);
292 
294  do {
296  tile = RandomTile();
298  } while (--i);
299 
300  /* add rocky tiles */
301  i = gi;
302  do {
303  uint32_t r = Random();
304  tile = RandomTileSeed(r);
305 
307  if (IsTileType(tile, MP_CLEAR) && !IsClearGround(tile, CLEAR_DESERT)) {
308  uint j = GB(r, 16, 4) + 5;
309  for (;;) {
310  TileIndex tile_new;
311 
313  MarkTileDirtyByTile(tile);
314  do {
315  if (--j == 0) goto get_out;
316  tile_new = tile + TileOffsByDiagDir((DiagDirection)GB(Random(), 0, 2));
317  } while (!IsTileType(tile_new, MP_CLEAR) || IsClearGround(tile_new, CLEAR_DESERT));
318  tile = tile_new;
319  }
320 get_out:;
321  }
322  } while (--i);
323 }
324 
325 static TrackStatus GetTileTrackStatus_Clear(TileIndex, TransportType, uint, DiagDirection)
326 {
327  return 0;
328 }
329 
330 static const StringID _clear_land_str[] = {
331  STR_LAI_CLEAR_DESCRIPTION_GRASS,
332  STR_LAI_CLEAR_DESCRIPTION_ROUGH_LAND,
333  STR_LAI_CLEAR_DESCRIPTION_ROCKS,
334  STR_LAI_CLEAR_DESCRIPTION_FIELDS,
335  STR_LAI_CLEAR_DESCRIPTION_SNOW_COVERED_LAND,
336  STR_LAI_CLEAR_DESCRIPTION_DESERT
337 };
338 
339 static void GetTileDesc_Clear(TileIndex tile, TileDesc *td)
340 {
341  if (IsClearGround(tile, CLEAR_GRASS) && GetClearDensity(tile) == 0) {
342  td->str = STR_LAI_CLEAR_DESCRIPTION_BARE_LAND;
343  } else {
344  td->str = _clear_land_str[GetClearGround(tile)];
345  }
346  td->owner[0] = GetTileOwner(tile);
347 }
348 
349 static void ChangeTileOwner_Clear(TileIndex, Owner, Owner)
350 {
351  return;
352 }
353 
354 static CommandCost TerraformTile_Clear(TileIndex tile, DoCommandFlag flags, int, Slope)
355 {
356  return Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile);
357 }
358 
359 extern const TileTypeProcs _tile_type_clear_procs = {
360  DrawTile_Clear,
361  GetSlopePixelZ_Clear,
362  ClearTile_Clear,
363  nullptr,
364  GetTileDesc_Clear,
365  GetTileTrackStatus_Clear,
366  nullptr,
367  nullptr,
368  TileLoop_Clear,
369  ChangeTileOwner_Clear,
370  nullptr,
371  nullptr,
372  GetFoundation_Clear,
373  TerraformTile_Clear,
374 };
constexpr static debug_inline uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
void DrawBridgeMiddle(const TileInfo *ti)
Draw the middle bits of a bridge.
Common return value for all commands.
Definition: command_type.h:23
static bool NeighbourIsNormal(TileIndex tile)
Tests if at least one surrounding tile is non-desert.
Definition: clear_cmd.cpp:194
static void TileLoopClearAlps(TileIndex tile)
Convert to or from snowy tiles.
Definition: clear_cmd.cpp:160
Tables with sprites for clear land and fences.
Map accessors for 'clear' tiles.
void SetFieldType(Tile t, uint f)
Set the field type (production stage) of the field.
Definition: clear_map.h:183
void AddClearCounter(Tile t, int c)
Increments the counter used to advance to the next clear density/field type.
Definition: clear_map.h:132
uint GetFieldType(Tile t)
Get the field type (production stage) of the field.
Definition: clear_map.h:171
void AddClearDensity(Tile t, int d)
Increment the density of a non-field clear tile.
Definition: clear_map.h:95
void ClearSnow(Tile t)
Clear the snow from a tile and return it to its previous type.
Definition: clear_map.h:316
bool IsClearGround(Tile t, ClearGround ct)
Set the type of clear tile.
Definition: clear_map.h:71
@ CLEAR_GRASS
0-3
Definition: clear_map.h:20
@ CLEAR_FIELDS
3
Definition: clear_map.h:23
@ CLEAR_DESERT
1,3
Definition: clear_map.h:25
@ CLEAR_SNOW
0-3
Definition: clear_map.h:24
@ CLEAR_ROUGH
3
Definition: clear_map.h:21
@ CLEAR_ROCKS
3
Definition: clear_map.h:22
void MakeSnow(Tile t, uint density=0)
Make a snow tile.
Definition: clear_map.h:300
void SetFence(Tile t, DiagDirection side, uint h)
Sets the type of fence (and whether there is one) for the given border.
Definition: clear_map.h:240
IndustryID GetIndustryIndexOfField(Tile t)
Get the industry (farm) that made the field.
Definition: clear_map.h:195
void MakeClear(Tile t, ClearGround g, uint density)
Make a clear tile.
Definition: clear_map.h:259
ClearGround GetClearGround(Tile t)
Get the type of clear tile.
Definition: clear_map.h:59
void SetClearCounter(Tile t, uint c)
Sets the counter used to advance to the next clear density/field type.
Definition: clear_map.h:144
void SetClearGroundDensity(Tile t, ClearGround type, uint density)
Sets ground type and density in one go, also sets the counter to 0.
Definition: clear_map.h:158
uint GetFence(Tile t, DiagDirection side)
Is there a fence at the given border?
Definition: clear_map.h:221
uint GetClearCounter(Tile t)
Get the counter used to advance to the next clear density/field type.
Definition: clear_map.h:120
bool IsSnowTile(Tile t)
Test if a tile is covered with snow.
Definition: clear_map.h:35
uint GetClearDensity(Tile t)
Get the density of a non-field clear tile.
Definition: clear_map.h:83
Functions related to commands.
DoCommandFlag
List of flags for a command.
Definition: command_type.h:374
@ DC_EXEC
execute the given command
Definition: command_type.h:376
Owner
Enum for all companies/owners.
Definition: company_type.h:18
DiagDirection
Enumeration for diagonal directions.
@ DIAGDIR_NE
Northeast, upper right on your monitor.
@ DIAGDIR_NW
Northwest.
@ DIAGDIR_SE
Southeast.
@ DIAGDIR_END
Used for iterations.
@ DIAGDIR_BEGIN
Used for iterations.
@ DIAGDIR_SW
Southwest.
@ EXPENSES_CONSTRUCTION
Construction costs.
Definition: economy_type.h:173
Price
Enumeration of all base prices for use with Prices.
Definition: economy_type.h:89
Functions related to world/map generation.
void IncreaseGeneratingWorldProgress(GenWorldProgress cls)
Increases the current stage of the world generation with one.
@ GWP_ROUGH_ROCKY
Make rough and rocky areas.
Definition: genworld.h:73
void SetGeneratingWorldProgress(GenWorldProgress cls, uint total)
Set the total of a stage of the world generation.
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition: gfx_type.h:18
uint8_t GetSnowLine()
Get the current snow line, either variable or static.
Definition: landscape.cpp:609
void MarkTileDirtyByTile(TileIndex tile, int bridge_level_offset, int tile_height_override)
Mark a tile given by its index dirty for repaint.
Definition: viewport.cpp:2057
uint GetPartialPixelZ(int x, int y, Slope corners)
Determines height at given coordinate of a slope.
Definition: landscape.cpp:228
Functions related to OTTD's landscape.
int GetSlopePixelZInCorner(Slope tileh, Corner corner)
Determine the Z height of a corner relative to TileZ.
Definition: landscape.h:53
Command definitions related to landscape (slopes etc.).
TileIndex RandomTileSeed(uint32_t r)
Get a random tile out of a given seed.
Definition: map_func.h:650
#define RandomTile()
Get a valid random tile.
Definition: map_func.h:661
TileIndexDiff TileOffsByDiagDir(DiagDirection dir)
Convert a DiagDirection to a TileIndexDiff.
Definition: map_func.h:567
bool HasGrfMiscBit(GrfMiscBit bit)
Check for grf miscellaneous bits.
Definition: newgrf.h:189
Functions related to generic callbacks.
void AmbientSoundEffect(TileIndex tile)
Play an ambient sound effect for an empty tile.
Pseudo random number generator.
A number of safeguards to prevent using unsafe methods.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition: settings.cpp:57
uint SlopeToSpriteOffset(Slope s)
Returns the Sprite offset for a given Slope.
Definition: slope_func.h:415
static constexpr int GetSlopeMaxPixelZ(Slope s)
Returns the height of the highest corner of a slope relative to TileZ (= minimal height)
Definition: slope_func.h:173
Slope
Enumeration for the slope-type.
Definition: slope_type.h:48
@ SLOPE_FLAT
a flat tile
Definition: slope_type.h:49
Foundation
Enumeration for Foundations.
Definition: slope_type.h:93
@ FOUNDATION_NONE
The tile has no foundation, the slope remains unchanged.
Definition: slope_type.h:94
This file contains all sprite-related enums and defines.
Definition of base types and functions in a cross-platform compatible way.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:16
uint8_t landscape
the landscape we're currently in
GameCreationSettings game_creation
settings used during the creation of a game (map)
static uint ScaleBySize(uint n)
Scales the given value by the map size, where the given value is for a 256 by 256 map.
Definition: map_func.h:328
Tile description for the 'land area information' tool.
Definition: tile_cmd.h:52
StringID str
Description of the tile.
Definition: tile_cmd.h:53
Owner owner[4]
Name of the owner(s)
Definition: tile_cmd.h:55
Tile information, used while rendering the tile.
Definition: tile_cmd.h:43
int z
Height.
Definition: tile_cmd.h:48
int x
X position of the tile in unit coordinates.
Definition: tile_cmd.h:44
Slope tileh
Slope of the tile.
Definition: tile_cmd.h:46
TileIndex tile
Tile index.
Definition: tile_cmd.h:47
int y
Y position of the tile in unit coordinates.
Definition: tile_cmd.h:45
Set of callback functions for performing tile operations of a given tile type.
Definition: tile_cmd.h:158
int GetTileZ(TileIndex tile)
Get bottom height of the tile.
Definition: tile_map.cpp:116
uint TileHash(uint x, uint y)
Calculate a hash value from a tile position.
Definition: tile_map.h:324
Owner GetTileOwner(Tile tile)
Returns the owner of a tile.
Definition: tile_map.h:178
bool IsValidTile(Tile tile)
Checks if a tile is valid.
Definition: tile_map.h:161
TropicZone GetTropicZone(Tile tile)
Get the tropic zone.
Definition: tile_map.h:238
std::tuple< Slope, int > GetTilePixelSlope(TileIndex tile)
Return the slope of a given tile.
Definition: tile_map.h:289
static debug_inline bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition: tile_map.h:150
@ TROPICZONE_DESERT
Tile is desert.
Definition: tile_type.h:78
@ MP_CLEAR
A tile without any structures, i.e. grass, rocks, farm fields etc.
Definition: tile_type.h:48
TransportType
Available types of transport.
void StartSpriteCombine()
Starts a block of sprites, which are "combined" into a single bounding box.
Definition: viewport.cpp:767
void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w, int h, int dz, int z, bool transparent, int bb_offset_x, int bb_offset_y, int bb_offset_z, const SubSprite *sub)
Draw a (transparent) sprite at given coordinates with a given bounding box.
Definition: viewport.cpp:671
void EndSpriteCombine()
Terminates a block of sprites started by StartSpriteCombine.
Definition: viewport.cpp:777
void DrawGroundSprite(SpriteID image, PaletteID pal, const SubSprite *sub, int extra_offs_x, int extra_offs_y)
Draws a ground sprite for the current tile.
Definition: viewport.cpp:587
Functions related to (drawing on) viewports.
@ WATER_CLASS_SEA
Sea.
Definition: water_map.h:40
bool HasTileWaterClass(Tile t)
Checks whether the tile has an waterclass associated.
Definition: water_map.h:101
WaterClass GetWaterClass(Tile t)
Get the water class at a tile.
Definition: water_map.h:112