OpenTTD Source 20250205-master-gfd85ab1e2c
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
26static 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
47void DrawClearLandTile(const TileInfo *ti, uint8_t set)
48{
49 DrawGroundSprite(SPR_FLAT_BARE_LAND + SlopeToSpriteOffset(ti->tileh) + set * 19, PAL_NONE);
50}
51
52void 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
61static 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
101static 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
128}
129
130static 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
137static Foundation GetFoundation_Clear(TileIndex, Slope)
138{
139 return FOUNDATION_NONE;
140}
141
142static 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
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);
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
187}
188
194static 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
205static 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
227}
228
229static void TileLoop_Clear(TileIndex tile)
230{
231 AmbientSoundEffect(tile);
232
234 case LandscapeType::Tropic: TileLoopClearDesert(tile); break;
235 case LandscapeType::Arctic: TileLoopClearAlps(tile); break;
236 default: break;
237 }
238
239 switch (GetClearGround(tile)) {
240 case CLEAR_GRASS:
241 if (GetClearDensity(tile) == 3) return;
242
243 if (_game_mode != GM_EDITOR) {
244 if (GetClearCounter(tile) < 7) {
245 AddClearCounter(tile, 1);
246 return;
247 } else {
248 SetClearCounter(tile, 0);
249 AddClearDensity(tile, 1);
250 }
251 } else {
252 SetClearGroundDensity(tile, GB(Random(), 0, 8) > 21 ? CLEAR_GRASS : CLEAR_ROUGH, 3);
253 }
254 break;
255
256 case CLEAR_FIELDS:
257 UpdateFences(tile);
258
259 if (_game_mode == GM_EDITOR) return;
260
261 if (GetClearCounter(tile) < 7) {
262 AddClearCounter(tile, 1);
263 return;
264 } else {
265 SetClearCounter(tile, 0);
266 }
267
268 if (GetIndustryIndexOfField(tile) == INVALID_INDUSTRY && GetFieldType(tile) >= 7) {
269 /* This farmfield is no longer farmfield, so make it grass again */
270 MakeClear(tile, CLEAR_GRASS, 2);
271 } else {
272 uint field_type = GetFieldType(tile);
273 field_type = (field_type < 8) ? field_type + 1 : 0;
274 SetFieldType(tile, field_type);
275 }
276 break;
277
278 default:
279 return;
280 }
281
283}
284
285void GenerateClearTile()
286{
287 uint i, gi;
288 TileIndex tile;
289
290 /* add rough tiles */
291 i = Map::ScaleBySize(GB(Random(), 0, 10) + 0x400);
292 gi = Map::ScaleBySize(GB(Random(), 0, 7) + 0x80);
293
295 do {
297 tile = RandomTile();
299 } while (--i);
300
301 /* add rocky tiles */
302 i = gi;
303 do {
304 uint32_t r = Random();
305 tile = RandomTileSeed(r);
306
308 if (IsTileType(tile, MP_CLEAR) && !IsClearGround(tile, CLEAR_DESERT)) {
309 uint j = GB(r, 16, 4) + 5;
310 for (;;) {
311 TileIndex tile_new;
312
315 do {
316 if (--j == 0) goto get_out;
317 tile_new = tile + TileOffsByDiagDir((DiagDirection)GB(Random(), 0, 2));
318 } while (!IsTileType(tile_new, MP_CLEAR) || IsClearGround(tile_new, CLEAR_DESERT));
319 tile = tile_new;
320 }
321get_out:;
322 }
323 } while (--i);
324}
325
326static TrackStatus GetTileTrackStatus_Clear(TileIndex, TransportType, uint, DiagDirection)
327{
328 return 0;
329}
330
331static const StringID _clear_land_str[] = {
332 STR_LAI_CLEAR_DESCRIPTION_GRASS,
333 STR_LAI_CLEAR_DESCRIPTION_ROUGH_LAND,
334 STR_LAI_CLEAR_DESCRIPTION_ROCKS,
335 STR_LAI_CLEAR_DESCRIPTION_FIELDS,
336 STR_LAI_CLEAR_DESCRIPTION_SNOW_COVERED_LAND,
337 STR_LAI_CLEAR_DESCRIPTION_DESERT
338};
339
340static void GetTileDesc_Clear(TileIndex tile, TileDesc *td)
341{
342 if (IsClearGround(tile, CLEAR_GRASS) && GetClearDensity(tile) == 0) {
343 td->str = STR_LAI_CLEAR_DESCRIPTION_BARE_LAND;
344 } else {
345 td->str = _clear_land_str[GetClearGround(tile)];
346 }
347 td->owner[0] = GetTileOwner(tile);
348}
349
350static void ChangeTileOwner_Clear(TileIndex, Owner, Owner)
351{
352 return;
353}
354
355static CommandCost TerraformTile_Clear(TileIndex tile, DoCommandFlag flags, int, Slope)
356{
357 return Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile);
358}
359
360extern const TileTypeProcs _tile_type_clear_procs = {
361 DrawTile_Clear,
362 GetSlopePixelZ_Clear,
363 ClearTile_Clear,
364 nullptr,
365 GetTileDesc_Clear,
366 GetTileTrackStatus_Clear,
367 nullptr,
368 nullptr,
369 TileLoop_Clear,
370 ChangeTileOwner_Clear,
371 nullptr,
372 nullptr,
373 GetFoundation_Clear,
374 TerraformTile_Clear,
375};
debug_inline static constexpr 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.
static bool NeighbourIsNormal(TileIndex tile)
Tests if at least one surrounding tile is non-desert.
static void TileLoopClearAlps(TileIndex tile)
Convert to or from snowy tiles.
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
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
@ 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 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.
@ DC_EXEC
execute the given command
Owner
Enum for all companies/owners.
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.
Price
Enumeration of all base prices for use with Prices.
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:76
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:17
uint8_t GetSnowLine()
Get the current snow line, either variable or static.
void MarkTileDirtyByTile(TileIndex tile, int bridge_level_offset, int tile_height_override)
Mark a tile given by its index dirty for repaint.
uint GetPartialPixelZ(int x, int y, Slope corners)
Determines height at given coordinate of a slope.
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.).
@ Random
Randomise borders.
TileIndex RandomTileSeed(uint32_t r)
Get a random tile out of a given seed.
Definition map_func.h:653
#define RandomTile()
Get a valid random tile.
Definition map_func.h:664
TileIndexDiff TileOffsByDiagDir(DiagDirection dir)
Convert a DiagDirection to a TileIndexDiff.
Definition map_func.h:570
bool HasGrfMiscBit(GrfMiscBit bit)
Check for grf miscellaneous bits.
Definition newgrf.h:188
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.
LandscapeType 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
std::tuple< Slope, int > GetTilePixelSlope(TileIndex tile)
Return the slope of a given tile.
Definition tile_map.h:289
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
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