OpenTTD Source 20251116-master-g21329071df
landscape.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
12#include "stdafx.h"
13#include "heightmap.h"
14#include "clear_map.h"
15#include "spritecache.h"
16#include "viewport_func.h"
17#include "command_func.h"
18#include "landscape.h"
19#include "void_map.h"
20#include "tgp.h"
21#include "genworld.h"
22#include "fios.h"
23#include "error_func.h"
26#include "water.h"
27#include "effectvehicle_func.h"
28#include "landscape_type.h"
29#include "animated_tile_func.h"
30#include "core/random_func.hpp"
31#include "object_base.h"
32#include "company_func.h"
33#include "company_gui.h"
34#include "saveload/saveload.h"
35#include "framerate_type.h"
36#include "landscape_cmd.h"
37#include "terraform_cmd.h"
38#include "station_func.h"
41
42#include "table/strings.h"
43#include "table/sprites.h"
44
45#include <unordered_set>
46
47#include "safeguards.h"
48
49extern const TileTypeProcs
50 _tile_type_clear_procs,
51 _tile_type_rail_procs,
54 _tile_type_trees_procs,
55 _tile_type_station_procs,
56 _tile_type_water_procs,
57 _tile_type_void_procs,
58 _tile_type_industry_procs,
59 _tile_type_tunnelbridge_procs,
60 _tile_type_object_procs;
61
67const TileTypeProcs * const _tile_type_procs[16] = {
68 &_tile_type_clear_procs,
69 &_tile_type_rail_procs,
72 &_tile_type_trees_procs,
73 &_tile_type_station_procs,
74 &_tile_type_water_procs,
75 &_tile_type_void_procs,
76 &_tile_type_industry_procs,
77 &_tile_type_tunnelbridge_procs,
78 &_tile_type_object_procs,
79};
80
82extern const uint8_t _slope_to_sprite_offset[32] = {
83 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0,
84 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 17, 0, 15, 18, 0,
85};
86
87static const uint TILE_UPDATE_FREQUENCY_LOG = 8;
89
98static std::unique_ptr<SnowLine> _snow_line;
99
113Point InverseRemapCoords2(int x, int y, bool clamp_to_map, bool *clamped)
114{
115 if (clamped != nullptr) *clamped = false; // Not clamping yet.
116
117 /* Initial x/y world coordinate is like if the landscape
118 * was completely flat on height 0. */
119 Point pt = InverseRemapCoords(x, y);
120
121 const uint min_coord = _settings_game.construction.freeform_edges ? TILE_SIZE : 0;
122 const uint max_x = Map::MaxX() * TILE_SIZE - 1;
123 const uint max_y = Map::MaxY() * TILE_SIZE - 1;
124
125 if (clamp_to_map) {
126 /* Bring the coordinates near to a valid range. At the top we allow a number
127 * of extra tiles. This is mostly due to the tiles on the north side of
128 * the map possibly being drawn higher due to the extra height levels. */
130 Point old_pt = pt;
131 pt.x = Clamp(pt.x, -extra_tiles * TILE_SIZE, max_x);
132 pt.y = Clamp(pt.y, -extra_tiles * TILE_SIZE, max_y);
133 if (clamped != nullptr) *clamped = (pt.x != old_pt.x) || (pt.y != old_pt.y);
134 }
135
136 /* Now find the Z-world coordinate by fix point iteration.
137 * This is a bit tricky because the tile height is non-continuous at foundations.
138 * The clicked point should be approached from the back, otherwise there are regions that are not clickable.
139 * (FOUNDATION_HALFTILE_LOWER on SLOPE_STEEP_S hides north halftile completely)
140 * So give it a z-malus of 4 in the first iterations. */
141 int z = 0;
142 if (clamp_to_map) {
143 for (int i = 0; i < 5; i++) z = GetSlopePixelZ(Clamp(pt.x + std::max(z, 4) - 4, min_coord, max_x), Clamp(pt.y + std::max(z, 4) - 4, min_coord, max_y)) / 2;
144 for (int m = 3; m > 0; m--) z = GetSlopePixelZ(Clamp(pt.x + std::max(z, m) - m, min_coord, max_x), Clamp(pt.y + std::max(z, m) - m, min_coord, max_y)) / 2;
145 for (int i = 0; i < 5; i++) z = GetSlopePixelZ(Clamp(pt.x + z, min_coord, max_x), Clamp(pt.y + z, min_coord, max_y)) / 2;
146 } else {
147 for (int i = 0; i < 5; i++) z = GetSlopePixelZOutsideMap(pt.x + std::max(z, 4) - 4, pt.y + std::max(z, 4) - 4) / 2;
148 for (int m = 3; m > 0; m--) z = GetSlopePixelZOutsideMap(pt.x + std::max(z, m) - m, pt.y + std::max(z, m) - m) / 2;
149 for (int i = 0; i < 5; i++) z = GetSlopePixelZOutsideMap(pt.x + z, pt.y + z ) / 2;
150 }
151
152 pt.x += z;
153 pt.y += z;
154 if (clamp_to_map) {
155 Point old_pt = pt;
156 pt.x = Clamp(pt.x, min_coord, max_x);
157 pt.y = Clamp(pt.y, min_coord, max_y);
158 if (clamped != nullptr) *clamped = *clamped || (pt.x != old_pt.x) || (pt.y != old_pt.y);
159 }
160
161 return pt;
162}
163
173{
174 if (!IsFoundation(f)) return 0;
175
176 if (IsLeveledFoundation(f)) {
177 uint dz = 1 + (IsSteepSlope(s) ? 1 : 0);
178 s = SLOPE_FLAT;
179 return dz;
180 }
181
184 return 0;
185 }
186
189 return 0;
190 }
191
192 uint dz = IsSteepSlope(s) ? 1 : 0;
193 Corner highest_corner = GetHighestSlopeCorner(s);
194
195 switch (f) {
197 s = (((highest_corner == CORNER_W) || (highest_corner == CORNER_S)) ? SLOPE_SW : SLOPE_NE);
198 break;
199
201 s = (((highest_corner == CORNER_S) || (highest_corner == CORNER_E)) ? SLOPE_SE : SLOPE_NW);
202 break;
203
205 s = SlopeWithOneCornerRaised(highest_corner);
206 break;
207
209 s = HalftileSlope(SlopeWithOneCornerRaised(highest_corner), highest_corner);
210 break;
211
212 default: NOT_REACHED();
213 }
214 return dz;
215}
216
217
230uint GetPartialPixelZ(int x, int y, Slope corners)
231{
232 if (IsHalftileSlope(corners)) {
233 /* A foundation is placed on half the tile at a specific corner. This means that,
234 * depending on the corner, that one half of the tile is at the maximum height. */
235 switch (GetHalftileSlopeCorner(corners)) {
236 case CORNER_W:
237 if (x > y) return GetSlopeMaxPixelZ(corners);
238 break;
239
240 case CORNER_S:
241 if (x + y >= (int)TILE_SIZE) return GetSlopeMaxPixelZ(corners);
242 break;
243
244 case CORNER_E:
245 if (x <= y) return GetSlopeMaxPixelZ(corners);
246 break;
247
248 case CORNER_N:
249 if (x + y < (int)TILE_SIZE) return GetSlopeMaxPixelZ(corners);
250 break;
251
252 default: NOT_REACHED();
253 }
254 }
255
256 switch (RemoveHalftileSlope(corners)) {
257 case SLOPE_FLAT: return 0;
258
259 /* One corner is up.*/
260 case SLOPE_N: return x + y <= (int)TILE_SIZE ? (TILE_SIZE - x - y) >> 1 : 0;
261 case SLOPE_E: return y >= x ? (1 + y - x) >> 1 : 0;
262 case SLOPE_S: return x + y >= (int)TILE_SIZE ? (1 + x + y - TILE_SIZE) >> 1 : 0;
263 case SLOPE_W: return x >= y ? (x - y) >> 1 : 0;
264
265 /* Two corners next to each other are up. */
266 case SLOPE_NE: return (TILE_SIZE - x) >> 1;
267 case SLOPE_SE: return (y + 1) >> 1;
268 case SLOPE_SW: return (x + 1) >> 1;
269 case SLOPE_NW: return (TILE_SIZE - y) >> 1;
270
271 /* Three corners are up on the same level. */
272 case SLOPE_ENW: return x + y >= (int)TILE_SIZE ? TILE_HEIGHT - ((1 + x + y - TILE_SIZE) >> 1) : TILE_HEIGHT;
273 case SLOPE_SEN: return y < x ? TILE_HEIGHT - ((x - y) >> 1) : TILE_HEIGHT;
274 case SLOPE_WSE: return x + y <= (int)TILE_SIZE ? TILE_HEIGHT - ((TILE_SIZE - x - y) >> 1) : TILE_HEIGHT;
275 case SLOPE_NWS: return x < y ? TILE_HEIGHT - ((1 + y - x) >> 1) : TILE_HEIGHT;
276
277 /* Two corners at opposite sides are up. */
278 case SLOPE_NS: return x + y < (int)TILE_SIZE ? (TILE_SIZE - x - y) >> 1 : (1 + x + y - TILE_SIZE) >> 1;
279 case SLOPE_EW: return x >= y ? (x - y) >> 1 : (1 + y - x) >> 1;
280
281 /* Very special cases. */
282 case SLOPE_ELEVATED: return TILE_HEIGHT;
283
284 /* Steep slopes. The top is at 2 * TILE_HEIGHT. */
285 case SLOPE_STEEP_N: return (TILE_SIZE - x + TILE_SIZE - y) >> 1;
286 case SLOPE_STEEP_E: return (TILE_SIZE + 1 + y - x) >> 1;
287 case SLOPE_STEEP_S: return (1 + x + y) >> 1;
288 case SLOPE_STEEP_W: return (TILE_SIZE + x - y) >> 1;
289
290 default: NOT_REACHED();
291 }
292}
293
305int GetSlopePixelZ(int x, int y, bool ground_vehicle)
306{
307 TileIndex tile = TileVirtXY(x, y);
308
309 return _tile_type_procs[GetTileType(tile)]->get_slope_z_proc(tile, x, y, ground_vehicle);
310}
311
321{
322 if (IsInsideBS(x, 0, Map::SizeX() * TILE_SIZE) && IsInsideBS(y, 0, Map::SizeY() * TILE_SIZE)) {
323 return GetSlopePixelZ(x, y, false);
324 } else {
325 return _tile_type_procs[MP_VOID]->get_slope_z_proc(INVALID_TILE, x, y, false);
326 }
327}
328
339{
340 assert(!IsHalftileSlope(tileh));
341 return ((tileh & SlopeWithOneCornerRaised(corner)) != 0 ? 1 : 0) + (tileh == SteepSlope(corner) ? 1 : 0);
342}
343
356void GetSlopePixelZOnEdge(Slope tileh, DiagDirection edge, int &z1, int &z2)
357{
358 static const Slope corners[4][4] = {
359 /* corner | steep slope
360 * z1 z2 | z1 z2 */
361 {SLOPE_E, SLOPE_N, SLOPE_STEEP_E, SLOPE_STEEP_N}, // DIAGDIR_NE, z1 = E, z2 = N
362 {SLOPE_S, SLOPE_E, SLOPE_STEEP_S, SLOPE_STEEP_E}, // DIAGDIR_SE, z1 = S, z2 = E
363 {SLOPE_S, SLOPE_W, SLOPE_STEEP_S, SLOPE_STEEP_W}, // DIAGDIR_SW, z1 = S, z2 = W
364 {SLOPE_W, SLOPE_N, SLOPE_STEEP_W, SLOPE_STEEP_N}, // DIAGDIR_NW, z1 = W, z2 = N
365 };
366
367 int halftile_test = (IsHalftileSlope(tileh) ? SlopeWithOneCornerRaised(GetHalftileSlopeCorner(tileh)) : 0);
368 if (halftile_test == corners[edge][0]) z2 += TILE_HEIGHT; // The slope is non-continuous in z2. z2 is on the upper side.
369 if (halftile_test == corners[edge][1]) z1 += TILE_HEIGHT; // The slope is non-continuous in z1. z1 is on the upper side.
370
371 if ((tileh & corners[edge][0]) != 0) z1 += TILE_HEIGHT; // z1 is raised
372 if ((tileh & corners[edge][1]) != 0) z2 += TILE_HEIGHT; // z2 is raised
373 if (RemoveHalftileSlope(tileh) == corners[edge][2]) z1 += TILE_HEIGHT; // z1 is highest corner of a steep slope
374 if (RemoveHalftileSlope(tileh) == corners[edge][3]) z2 += TILE_HEIGHT; // z2 is highest corner of a steep slope
375}
376
384std::tuple<Slope, int> GetFoundationSlope(TileIndex tile)
385{
386 auto [tileh, z] = GetTileSlopeZ(tile);
387 Foundation f = _tile_type_procs[GetTileType(tile)]->get_foundation_proc(tile, tileh);
388 z += ApplyFoundationToSlope(f, tileh);
389 return {tileh, z};
390}
391
392
393bool HasFoundationNW(TileIndex tile, Slope slope_here, uint z_here)
394{
395 int z_W_here = z_here;
396 int z_N_here = z_here;
397 GetSlopePixelZOnEdge(slope_here, DIAGDIR_NW, z_W_here, z_N_here);
398
399 auto [slope, z] = GetFoundationPixelSlope(TileAddXY(tile, 0, -1));
400 int z_W = z;
401 int z_N = z;
402 GetSlopePixelZOnEdge(slope, DIAGDIR_SE, z_W, z_N);
403
404 return (z_N_here > z_N) || (z_W_here > z_W);
405}
406
407
408bool HasFoundationNE(TileIndex tile, Slope slope_here, uint z_here)
409{
410 int z_E_here = z_here;
411 int z_N_here = z_here;
412 GetSlopePixelZOnEdge(slope_here, DIAGDIR_NE, z_E_here, z_N_here);
413
414 auto [slope, z] = GetFoundationPixelSlope(TileAddXY(tile, -1, 0));
415 int z_E = z;
416 int z_N = z;
417 GetSlopePixelZOnEdge(slope, DIAGDIR_SW, z_E, z_N);
418
419 return (z_N_here > z_N) || (z_E_here > z_E);
420}
421
428{
429 if (!IsFoundation(f)) return;
430
431 /* Two part foundations must be drawn separately */
432 assert(f != FOUNDATION_STEEP_BOTH);
433
434 uint sprite_block = 0;
435 auto [slope, z] = GetFoundationPixelSlope(ti->tile);
436
437 /* Select the needed block of foundations sprites
438 * Block 0: Walls at NW and NE edge
439 * Block 1: Wall at NE edge
440 * Block 2: Wall at NW edge
441 * Block 3: No walls at NW or NE edge
442 */
443 if (!HasFoundationNW(ti->tile, slope, z)) sprite_block += 1;
444 if (!HasFoundationNE(ti->tile, slope, z)) sprite_block += 2;
445
446 /* Use the original slope sprites if NW and NE borders should be visible */
447 SpriteID leveled_base = (sprite_block == 0 ? (int)SPR_FOUNDATION_BASE : (SPR_SLOPES_VIRTUAL_BASE + sprite_block * TRKFOUND_BLOCK_SIZE));
448 SpriteID inclined_base = SPR_SLOPES_VIRTUAL_BASE + SLOPES_INCLINED_OFFSET + sprite_block * TRKFOUND_BLOCK_SIZE;
449 SpriteID halftile_base = SPR_HALFTILE_FOUNDATION_BASE + sprite_block * HALFTILE_BLOCK_SIZE;
450
451 if (IsSteepSlope(ti->tileh)) {
453 /* Lower part of foundation */
454 static constexpr SpriteBounds bounds{{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT - 1}, {}};
455 AddSortableSpriteToDraw(leveled_base + (ti->tileh & ~SLOPE_STEEP), PAL_NONE, *ti, bounds);
456 }
457
458 Corner highest_corner = GetHighestSlopeCorner(ti->tileh);
459 ti->z += ApplyPixelFoundationToSlope(f, ti->tileh);
460
461 if (IsInclinedFoundation(f)) {
462 /* inclined foundation */
463 uint8_t inclined = highest_corner * 2 + (f == FOUNDATION_INCLINED_Y ? 1 : 0);
464
465 SpriteBounds bounds{{}, {1, 1, TILE_HEIGHT}, {}};
466 if (f == FOUNDATION_INCLINED_X) bounds.extent.x = TILE_SIZE;
467 if (f == FOUNDATION_INCLINED_Y) bounds.extent.y = TILE_SIZE;
468 AddSortableSpriteToDraw(inclined_base + inclined, PAL_NONE, *ti, bounds);
469 OffsetGroundSprite(0, 0);
470 } else if (IsLeveledFoundation(f)) {
471 static constexpr SpriteBounds bounds{{0, 0, -(int)TILE_HEIGHT}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT - 1}, {}};
472 AddSortableSpriteToDraw(leveled_base + SlopeWithOneCornerRaised(highest_corner), PAL_NONE, *ti, bounds);
474 } else if (f == FOUNDATION_STEEP_LOWER) {
475 /* one corner raised */
477 } else {
478 /* halftile foundation */
479 int8_t x_bb = (((highest_corner == CORNER_W) || (highest_corner == CORNER_S)) ? TILE_SIZE / 2 : 0);
480 int8_t y_bb = (((highest_corner == CORNER_S) || (highest_corner == CORNER_E)) ? TILE_SIZE / 2 : 0);
481
482 SpriteBounds bounds{{x_bb, y_bb, TILE_HEIGHT}, {TILE_SIZE / 2, TILE_SIZE / 2, TILE_HEIGHT - 1}, {}};
483 AddSortableSpriteToDraw(halftile_base + highest_corner, PAL_NONE, *ti, bounds);
484 /* Reposition ground sprite back to original position after bounding box change above. This is similar to
485 * RemapCoords() but without zoom scaling. */
486 Point pt = {(y_bb - x_bb) * 2, y_bb + x_bb};
487 OffsetGroundSprite(-pt.x, -pt.y);
488 }
489 } else {
490 if (IsLeveledFoundation(f)) {
491 /* leveled foundation */
492 static constexpr SpriteBounds bounds{{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT - 1}, {}};
493 AddSortableSpriteToDraw(leveled_base + ti->tileh, PAL_NONE, *ti, bounds);
495 } else if (IsNonContinuousFoundation(f)) {
496 /* halftile foundation */
497 Corner halftile_corner = GetHalftileFoundationCorner(f);
498 int8_t x_bb = (((halftile_corner == CORNER_W) || (halftile_corner == CORNER_S)) ? TILE_SIZE / 2 : 0);
499 int8_t y_bb = (((halftile_corner == CORNER_S) || (halftile_corner == CORNER_E)) ? TILE_SIZE / 2 : 0);
500
501 SpriteBounds bounds{{x_bb, y_bb, 0}, {TILE_SIZE / 2, TILE_SIZE / 2, TILE_HEIGHT - 1}, {}};
502 AddSortableSpriteToDraw(halftile_base + halftile_corner, PAL_NONE, *ti, bounds);
503 /* Reposition ground sprite back to original position after bounding box change above. This is similar to
504 * RemapCoords() but without zoom scaling. */
505 Point pt = {(y_bb - x_bb) * 2, y_bb + x_bb};
506 OffsetGroundSprite(-pt.x, -pt.y);
507 } else if (IsSpecialRailFoundation(f)) {
508 /* anti-zig-zag foundation */
509 SpriteID spr;
510 if (ti->tileh == SLOPE_NS || ti->tileh == SLOPE_EW) {
511 /* half of leveled foundation under track corner */
513 } else {
514 /* tile-slope = sloped along X/Y, foundation-slope = three corners raised */
515 spr = inclined_base + 2 * GetRailFoundationCorner(f) + ((ti->tileh == SLOPE_SW || ti->tileh == SLOPE_NE) ? 1 : 0);
516 }
517 static constexpr SpriteBounds bounds{{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT - 1}, {}};
518 AddSortableSpriteToDraw(spr, PAL_NONE, *ti, bounds);
519 OffsetGroundSprite(0, 0);
520 } else {
521 /* inclined foundation */
522 uint8_t inclined = GetHighestSlopeCorner(ti->tileh) * 2 + (f == FOUNDATION_INCLINED_Y ? 1 : 0);
523
524 SpriteBounds bounds{{}, {1, 1, TILE_HEIGHT}, {}};
525 if (f == FOUNDATION_INCLINED_X) bounds.extent.x = TILE_SIZE;
526 if (f == FOUNDATION_INCLINED_Y) bounds.extent.y = TILE_SIZE;
527 AddSortableSpriteToDraw(inclined_base + inclined, PAL_NONE, *ti, bounds);
528 OffsetGroundSprite(0, 0);
529 }
530 ti->z += ApplyPixelFoundationToSlope(f, ti->tileh);
531 }
532}
533
534void DoClearSquare(TileIndex tile)
535{
536 /* If the tile can have animation and we clear it, delete it from the animated tile list. */
537 if (MayAnimateTile(tile)) DeleteAnimatedTile(tile, true);
538
539 bool remove = IsDockingTile(tile);
542 if (remove) RemoveDockingTile(tile);
543
546}
547
558TrackStatus GetTileTrackStatus(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
559{
560 return _tile_type_procs[GetTileType(tile)]->get_tile_track_status_proc(tile, mode, sub_mode, side);
561}
562
569void ChangeTileOwner(TileIndex tile, Owner old_owner, Owner new_owner)
570{
571 _tile_type_procs[GetTileType(tile)]->change_tile_owner_proc(tile, old_owner, new_owner);
572}
573
574void GetTileDesc(TileIndex tile, TileDesc &td)
575{
577}
578
585{
586 return _snow_line != nullptr;
587}
588
594void SetSnowLine(std::unique_ptr<SnowLine> &&snow_line)
595{
596 _snow_line = std::move(snow_line);
597}
598
604uint8_t GetSnowLine()
605{
607
608 TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date);
609 return _snow_line->table[ymd.month][ymd.day];
610}
611
618{
619 return _snow_line == nullptr ? _settings_game.game_creation.snow_line_height : _snow_line->highest_value;
620}
621
628{
629 return _snow_line == nullptr ? _settings_game.game_creation.snow_line_height : _snow_line->lowest_value;
630}
631
637{
638 _snow_line = nullptr;
639}
640
646{
647 auto check_tile = [](uint x, uint y) -> bool {
648 auto [slope, h] = GetTilePixelSlopeOutsideMap(x, y);
649 return ((slope == SLOPE_FLAT) && (h == 0));
650 };
651
652 /* Check the map corners. */
653 if (!check_tile(0, 0)) return false;
654 if (!check_tile(0, Map::SizeY())) return false;
655 if (!check_tile(Map::SizeX(), 0)) return false;
656 if (!check_tile(Map::SizeX(), Map::SizeY())) return false;
657
658 /* Check the map edges.*/
659 for (uint x = 0; x <= Map::SizeX(); x++) {
660 if (!check_tile(x, 0)) return false;
661 if (!check_tile(x, Map::SizeY())) return false;
662 }
663 for (uint y = 1; y < Map::SizeY(); y++) {
664 if (!check_tile(0, y)) return false;
665 if (!check_tile(Map::SizeX(), y)) return false;
666 }
667
668 return true;
669}
670
678{
680 bool do_clear = false;
681 /* Test for stuff which results in water when cleared. Then add the cost to also clear the water. */
682 if (flags.Test(DoCommandFlag::ForceClearTile) && HasTileWaterClass(tile) && IsTileOnWater(tile) && !IsWaterTile(tile) && !IsCoastTile(tile)) {
683 if (flags.Test(DoCommandFlag::Auto) && GetWaterClass(tile) == WATER_CLASS_CANAL) return CommandCost(STR_ERROR_MUST_DEMOLISH_CANAL_FIRST);
684 do_clear = true;
685 cost.AddCost(GetWaterClass(tile) == WATER_CLASS_CANAL ? _price[PR_CLEAR_CANAL] : _price[PR_CLEAR_WATER]);
686 }
687
689 if (c != nullptr && (int)GB(c->clear_limit, 16, 16) < 1) {
690 return CommandCost(STR_ERROR_CLEARING_LIMIT_REACHED);
691 }
692
693 const ClearedObjectArea *coa = FindClearedObject(tile);
694
695 /* If this tile was the first tile which caused object destruction, always
696 * pass it on to the tile_type_proc. That way multiple test runs and the exec run stay consistent. */
697 if (coa != nullptr && coa->first_tile != tile) {
698 /* If this tile belongs to an object which was already cleared via another tile, pretend it has been
699 * already removed.
700 * However, we need to check stuff, which is not the same for all object tiles. (e.g. being on water or not) */
701
702 /* If a object is removed, it leaves either bare land or water. */
703 if (flags.Test(DoCommandFlag::NoWater) && HasTileWaterClass(tile) && IsTileOnWater(tile)) {
704 return CommandCost(STR_ERROR_CAN_T_BUILD_ON_WATER);
705 }
706 } else {
707 cost.AddCost(_tile_type_procs[GetTileType(tile)]->clear_tile_proc(tile, flags));
708 }
709
710 if (flags.Test(DoCommandFlag::Execute)) {
711 if (c != nullptr) c->clear_limit -= 1 << 16;
712 if (do_clear) {
713 if (IsWaterTile(tile) && IsCanal(tile)) {
714 Owner owner = GetTileOwner(tile);
715 if (Company::IsValidID(owner)) {
716 Company::Get(owner)->infrastructure.water--;
718 }
719 }
720 DoClearSquare(tile);
722 }
723 }
724 return cost;
725}
726
735std::tuple<CommandCost, Money> CmdClearArea(DoCommandFlags flags, TileIndex tile, TileIndex start_tile, bool diagonal)
736{
737 if (start_tile >= Map::Size()) return { CMD_ERROR, 0 };
738
741 CommandCost last_error = CMD_ERROR;
742 bool had_success = false;
743
745 int limit = (c == nullptr ? INT32_MAX : GB(c->clear_limit, 16, 16));
746
747 if (tile != start_tile) flags.Set(DoCommandFlag::ForceClearTile);
748
749 std::unique_ptr<TileIterator> iter = TileIterator::Create(tile, start_tile, diagonal);
750 for (; *iter != INVALID_TILE; ++(*iter)) {
751 TileIndex t = *iter;
753 if (ret.Failed()) {
754 last_error = std::move(ret);
755
756 /* We may not clear more tiles. */
757 if (c != nullptr && GB(c->clear_limit, 16, 16) < 1) break;
758 continue;
759 }
760
761 had_success = true;
762 if (flags.Test(DoCommandFlag::Execute)) {
763 money -= ret.GetCost();
764 if (ret.GetCost() > 0 && money < 0) {
765 return { cost, ret.GetCost() };
766 }
768
769 /* draw explosion animation...
770 * Disable explosions when game is paused. Looks silly and blocks the view. */
771 if ((t == tile || t == start_tile) && _pause_mode.None()) {
772 /* big explosion in two corners, or small explosion for single tiles */
774 TileX(tile) == TileX(start_tile) && TileY(tile) == TileY(start_tile) ? EV_EXPLOSION_SMALL : EV_EXPLOSION_LARGE
775 );
776 }
777 } else {
778 /* When we're at the clearing limit we better bail (unneed) testing as well. */
779 if (ret.GetCost() != 0 && --limit <= 0) break;
780 }
781 cost.AddCost(ret.GetCost());
782 }
783
784 return { had_success ? cost : last_error, 0 };
785}
786
787
788TileIndex _cur_tileloop_tile;
789
794{
796
797 /* The pseudorandom sequence of tiles is generated using a Galois linear feedback
798 * shift register (LFSR). This allows a deterministic pseudorandom ordering, but
799 * still with minimal state and fast iteration. */
800
801 /* Maximal length LFSR feedback terms, from 12-bit (for 64x64 maps) to 24-bit (for 4096x4096 maps).
802 * Extracted from http://www.ece.cmu.edu/~koopman/lfsr/ */
803 static const uint32_t feedbacks[] = {
804 0xD8F, 0x1296, 0x2496, 0x4357, 0x8679, 0x1030E, 0x206CD, 0x403FE, 0x807B8, 0x1004B2, 0x2006A8, 0x4004B2, 0x800B87
805 };
806 static_assert(lengthof(feedbacks) == 2 * MAX_MAP_SIZE_BITS - 2 * MIN_MAP_SIZE_BITS + 1);
807 const uint32_t feedback = feedbacks[Map::LogX() + Map::LogY() - 2 * MIN_MAP_SIZE_BITS];
808
809 /* We update every tile every TILE_UPDATE_FREQUENCY ticks, so divide the map size by 2^TILE_UPDATE_FREQUENCY_LOG = TILE_UPDATE_FREQUENCY */
810 static_assert(2 * MIN_MAP_SIZE_BITS >= TILE_UPDATE_FREQUENCY_LOG);
811 uint count = 1 << (Map::LogX() + Map::LogY() - TILE_UPDATE_FREQUENCY_LOG);
812
813 TileIndex tile = _cur_tileloop_tile;
814 /* The LFSR cannot have a zeroed state. */
815 assert(tile != 0);
816
817 /* Manually update tile 0 every TILE_UPDATE_FREQUENCY ticks - the LFSR never iterates over it itself. */
819 _tile_type_procs[GetTileType(0)]->tile_loop_proc(TileIndex{});
820 count--;
821 }
822
823 while (count--) {
824 _tile_type_procs[GetTileType(tile)]->tile_loop_proc(tile);
825
826 /* Get the next tile in sequence using a Galois LFSR. */
827 tile = TileIndex{(tile.base() >> 1) ^ (-(int32_t)(tile.base() & 1) & feedback)};
828 }
829
830 _cur_tileloop_tile = tile;
831}
832
833void InitializeLandscape()
834{
835 for (uint y = _settings_game.construction.freeform_edges ? 1 : 0; y < Map::MaxY(); y++) {
836 for (uint x = _settings_game.construction.freeform_edges ? 1 : 0; x < Map::MaxX(); x++) {
837 MakeClear(TileXY(x, y), CLEAR_GRASS, 3);
838 SetTileHeight(TileXY(x, y), 0);
841 }
842 }
843
844 for (uint x = 0; x < Map::SizeX(); x++) MakeVoid(TileXY(x, Map::MaxY()));
845 for (uint y = 0; y < Map::SizeY(); y++) MakeVoid(TileXY(Map::MaxX(), y));
846}
847
848static const uint8_t _genterrain_tbl_1[5] = { 10, 22, 33, 37, 4 };
849static const uint8_t _genterrain_tbl_2[5] = { 0, 0, 0, 0, 33 };
850
851static void GenerateTerrain(int type, uint flag)
852{
853 uint32_t r = Random();
854
855 /* Choose one of the templates from the graphics file. */
856 const Sprite *templ = GetSprite((((r >> 24) * _genterrain_tbl_1[type]) >> 8) + _genterrain_tbl_2[type] + SPR_MAPGEN_BEGIN, SpriteType::MapGen);
857 if (templ == nullptr) UserError("Map generator sprites could not be loaded");
858
859 /* Chose a random location to apply the template to. */
860 uint x = r & Map::MaxX();
861 uint y = (r >> Map::LogX()) & Map::MaxY();
862
863 /* Make sure the template is not too close to the upper edges; bottom edges are checked later. */
864 uint edge_distance = 1 + (_settings_game.construction.freeform_edges ? 1 : 0);
865 if (x <= edge_distance || y <= edge_distance) return;
866
867 DiagDirection direction = (DiagDirection)GB(r, 22, 2);
868 uint w = templ->width;
869 uint h = templ->height;
870
871 if (DiagDirToAxis(direction) == AXIS_Y) std::swap(w, h);
872
873 const uint8_t *p = reinterpret_cast<const uint8_t *>(templ->data);
874
875 if ((flag & 4) != 0) {
876 /* This is only executed in secondary/tertiary loops to generate the terrain for arctic and tropic.
877 * It prevents the templates to be applied to certain parts of the map based on the flags, thus
878 * creating regions with different elevations/topography. */
879 uint xw = x * Map::SizeY();
880 uint yw = y * Map::SizeX();
881 uint bias = (Map::SizeX() + Map::SizeY()) * 16;
882
883 switch (flag & 3) {
884 default: NOT_REACHED();
885 case 0:
886 if (xw + yw > Map::Size() - bias) return;
887 break;
888
889 case 1:
890 if (yw < xw + bias) return;
891 break;
892
893 case 2:
894 if (xw + yw < Map::Size() + bias) return;
895 break;
896
897 case 3:
898 if (xw < yw + bias) return;
899 break;
900 }
901 }
902
903 /* Ensure the template does not overflow at the bottom edges of the map; upper edges were checked before. */
904 if (x + w >= Map::MaxX()) return;
905 if (y + h >= Map::MaxY()) return;
906
907 TileIndex tile = TileXY(x, y);
908
909 /* Get the template and overlay in a particular direction over the map's height from the given
910 * origin point (tile), and update the map's height everywhere where the height from the template
911 * is higher than the height of the map. In other words, this only raises the tile heights. */
912 switch (direction) {
913 default: NOT_REACHED();
914 case DIAGDIR_NE:
915 do {
916 TileIndex tile_cur = tile;
917
918 for (uint w_cur = w; w_cur != 0; --w_cur) {
919 if (GB(*p, 0, 4) >= TileHeight(tile_cur)) SetTileHeight(tile_cur, GB(*p, 0, 4));
920 p++;
921 tile_cur += TileDiffXY(1, 0);
922 }
923 tile += TileDiffXY(0, 1);
924 } while (--h != 0);
925 break;
926
927 case DIAGDIR_SE:
928 do {
929 TileIndex tile_cur = tile;
930
931 for (uint h_cur = h; h_cur != 0; --h_cur) {
932 if (GB(*p, 0, 4) >= TileHeight(tile_cur)) SetTileHeight(tile_cur, GB(*p, 0, 4));
933 p++;
934 tile_cur += TileDiffXY(0, 1);
935 }
936 tile += TileDiffXY(1, 0);
937 } while (--w != 0);
938 break;
939
940 case DIAGDIR_SW:
941 tile += TileDiffXY(w - 1, 0);
942 do {
943 TileIndex tile_cur = tile;
944
945 for (uint w_cur = w; w_cur != 0; --w_cur) {
946 if (GB(*p, 0, 4) >= TileHeight(tile_cur)) SetTileHeight(tile_cur, GB(*p, 0, 4));
947 p++;
948 tile_cur -= TileDiffXY(1, 0);
949 }
950 tile += TileDiffXY(0, 1);
951 } while (--h != 0);
952 break;
953
954 case DIAGDIR_NW:
955 tile += TileDiffXY(0, h - 1);
956 do {
957 TileIndex tile_cur = tile;
958
959 for (uint h_cur = h; h_cur != 0; --h_cur) {
960 if (GB(*p, 0, 4) >= TileHeight(tile_cur)) SetTileHeight(tile_cur, GB(*p, 0, 4));
961 p++;
962 tile_cur -= TileDiffXY(0, 1);
963 }
964 tile += TileDiffXY(1, 0);
965 } while (--w != 0);
966 break;
967 }
968}
969
970
971#include "table/genland.h"
972
973static void CreateDesertOrRainForest(uint desert_tropic_line)
974{
975 uint update_freq = Map::Size() / 4;
976
977 for (const auto tile : Map::Iterate()) {
978 if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
979
980 if (!IsValidTile(tile)) continue;
981
982 auto allows_desert = [tile, desert_tropic_line](auto &offset) {
983 TileIndex t = AddTileIndexDiffCWrap(tile, offset);
984 return t == INVALID_TILE || (TileHeight(t) < desert_tropic_line && !IsTileType(t, MP_WATER));
985 };
986 if (std::all_of(std::begin(_make_desert_or_rainforest_data), std::end(_make_desert_or_rainforest_data), allows_desert)) {
988 }
989 }
990
991 for (uint i = 0; i != TILE_UPDATE_FREQUENCY; i++) {
993
994 RunTileLoop();
995 }
996
997 for (const auto tile : Map::Iterate()) {
998 if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
999
1000 if (!IsValidTile(tile)) continue;
1001
1002 auto allows_rainforest = [tile](auto &offset) {
1003 TileIndex t = AddTileIndexDiffCWrap(tile, offset);
1004 return t == INVALID_TILE || !IsTileType(t, MP_CLEAR) || !IsClearGround(t, CLEAR_DESERT);
1005 };
1006 if (std::all_of(std::begin(_make_desert_or_rainforest_data), std::end(_make_desert_or_rainforest_data), allows_rainforest)) {
1008 }
1009 }
1010}
1011
1017static bool FindSpring(TileIndex tile)
1018{
1019 int reference_height;
1020 if (!IsTileFlat(tile, &reference_height) || IsWaterTile(tile)) return false;
1021
1022 /* In the tropics rivers start in the rainforest. */
1023 if (_settings_game.game_creation.landscape == LandscapeType::Tropic && GetTropicZone(tile) != TROPICZONE_RAINFOREST) return false;
1024
1025 /* Are there enough higher tiles to warrant a 'spring'? */
1026 uint num = 0;
1027 for (int dx = -1; dx <= 1; dx++) {
1028 for (int dy = -1; dy <= 1; dy++) {
1029 TileIndex t = TileAddWrap(tile, dx, dy);
1030 if (t != INVALID_TILE && GetTileMaxZ(t) > reference_height) num++;
1031 }
1032 }
1033
1034 if (num < 4) return false;
1035
1036 /* Are we near the top of a hill? */
1037 for (int dx = -16; dx <= 16; dx++) {
1038 for (int dy = -16; dy <= 16; dy++) {
1039 TileIndex t = TileAddWrap(tile, dx, dy);
1040 if (t != INVALID_TILE && GetTileMaxZ(t) > reference_height + 2) return false;
1041 }
1042 }
1043
1044 return true;
1045}
1046
1052static void MakeLake(TileIndex tile, uint height_lake)
1053{
1054 if (!IsValidTile(tile) || TileHeight(tile) != height_lake || !IsTileFlat(tile)) return;
1055 if (_settings_game.game_creation.landscape == LandscapeType::Tropic && GetTropicZone(tile) == TROPICZONE_DESERT) return;
1056
1057 for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
1058 TileIndex t = tile + TileOffsByDiagDir(d);
1059 if (IsWaterTile(t)) {
1061 return;
1062 }
1063 }
1064}
1065
1071void RiverMakeWider(TileIndex tile, TileIndex origin_tile)
1072{
1073 /* Don't expand into void tiles. */
1074 if (!IsValidTile(tile)) return;
1075
1076 /* If the tile is already sea or river, don't expand. */
1077 if (IsWaterTile(tile)) return;
1078
1079 /* If the tile is at height 0 after terraforming but the ocean hasn't flooded yet, don't build river. */
1080 if (GetTileMaxZ(tile) == 0) return;
1081
1082 Slope cur_slope = GetTileSlope(tile);
1083 Slope desired_slope = GetTileSlope(origin_tile); // Initialize matching the origin tile as a shortcut if no terraforming is needed.
1084
1085 /* Never flow uphill. */
1086 if (GetTileMaxZ(tile) > GetTileMaxZ(origin_tile)) return;
1087
1088 /* If the new tile can't hold a river tile, try terraforming. */
1089 if (!IsTileFlat(tile) && !IsInclinedSlope(cur_slope)) {
1090 /* Don't try to terraform steep slopes. */
1091 if (IsSteepSlope(cur_slope)) return;
1092
1093 bool flat_river_found = false;
1094 bool sloped_river_found = false;
1095
1096 /* There are two common possibilities:
1097 * 1. River flat, adjacent tile has one corner lowered.
1098 * 2. River descending, adjacent tile has either one or three corners raised.
1099 */
1100
1101 /* First, determine the desired slope based on adjacent river tiles. This doesn't necessarily match the origin tile for the SpiralTileSequence. */
1102 for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
1103 TileIndex other_tile = TileAddByDiagDir(tile, d);
1104 Slope other_slope = GetTileSlope(other_tile);
1105
1106 /* Only consider river tiles. */
1107 if (IsWaterTile(other_tile) && IsRiver(other_tile)) {
1108 /* If the adjacent river tile flows downhill, we need to check where we are relative to the slope. */
1109 if (IsInclinedSlope(other_slope) && GetTileMaxZ(tile) == GetTileMaxZ(other_tile)) {
1110 /* Check for a parallel slope. If we don't find one, we're above or below the slope instead. */
1113 desired_slope = other_slope;
1114 sloped_river_found = true;
1115 break;
1116 }
1117 }
1118 /* If we find an adjacent river tile, remember it. We'll terraform to match it later if we don't find a slope. */
1119 if (IsTileFlat(other_tile)) flat_river_found = true;
1120 }
1121 }
1122 /* We didn't find either an inclined or flat river, so we're climbing the wrong slope. Bail out. */
1123 if (!sloped_river_found && !flat_river_found) return;
1124
1125 /* We didn't find an inclined river, but there is a flat river. */
1126 if (!sloped_river_found && flat_river_found) desired_slope = SLOPE_FLAT;
1127
1128 /* Now that we know the desired slope, it's time to terraform! */
1129
1130 /* If the river is flat and the adjacent tile has one corner lowered, we want to raise it. */
1131 if (desired_slope == SLOPE_FLAT && IsSlopeWithThreeCornersRaised(cur_slope)) {
1132 /* Make sure we're not affecting an existing river slope tile. */
1133 for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
1134 TileIndex other_tile = TileAddByDiagDir(tile, d);
1135 if (IsInclinedSlope(GetTileSlope(other_tile)) && IsWaterTile(other_tile)) return;
1136 }
1138
1139 /* If the river is descending and the adjacent tile has either one or three corners raised, we want to make it match the slope. */
1140 } else if (IsInclinedSlope(desired_slope)) {
1141 /* Don't break existing flat river tiles by terraforming under them. */
1142 DiagDirection river_direction = ReverseDiagDir(GetInclinedSlopeDirection(desired_slope));
1143
1144 for (DiagDirDiff d = DIAGDIRDIFF_BEGIN; d < DIAGDIRDIFF_END; d++) {
1145 /* We don't care about downstream or upstream tiles, just the riverbanks. */
1146 if (d == DIAGDIRDIFF_SAME || d == DIAGDIRDIFF_REVERSE) continue;
1147
1148 TileIndex other_tile = (TileAddByDiagDir(tile, ChangeDiagDir(river_direction, d)));
1149 if (IsWaterTile(other_tile) && IsRiver(other_tile) && IsTileFlat(other_tile)) return;
1150 }
1151
1152 /* Get the corners which are different between the current and desired slope. */
1153 Slope to_change = cur_slope ^ desired_slope;
1154
1155 /* Lower unwanted corners first. If only one corner is raised, no corners need lowering. */
1156 if (!IsSlopeWithOneCornerRaised(cur_slope)) {
1157 to_change = to_change & ComplementSlope(desired_slope);
1159 }
1160
1161 /* Now check the match and raise any corners needed. */
1162 cur_slope = GetTileSlope(tile);
1163 if (cur_slope != desired_slope && IsSlopeWithOneCornerRaised(cur_slope)) {
1164 to_change = cur_slope ^ desired_slope;
1166 }
1167 }
1168 /* Update cur_slope after possibly terraforming. */
1169 cur_slope = GetTileSlope(tile);
1170 }
1171
1172 /* Sloped rivers need water both upstream and downstream. */
1173 if (IsInclinedSlope(cur_slope)) {
1174 DiagDirection slope_direction = GetInclinedSlopeDirection(cur_slope);
1175
1176 TileIndex upstream_tile = TileAddByDiagDir(tile, slope_direction);
1177 TileIndex downstream_tile = TileAddByDiagDir(tile, ReverseDiagDir(slope_direction));
1178
1179 /* Don't look outside the map. */
1180 if (!IsValidTile(upstream_tile) || !IsValidTile(downstream_tile)) return;
1181
1182 /* Downstream might be new ocean created by our terraforming, and it hasn't flooded yet. */
1183 bool downstream_is_ocean = GetTileZ(downstream_tile) == 0 && (GetTileSlope(downstream_tile) == SLOPE_FLAT || IsSlopeWithOneCornerRaised(GetTileSlope(downstream_tile)));
1184
1185 /* If downstream is dry, flat, and not ocean, try making it a river tile. */
1186 if (!IsWaterTile(downstream_tile) && !downstream_is_ocean) {
1187 /* If the tile upstream isn't flat, don't bother. */
1188 if (GetTileSlope(downstream_tile) != SLOPE_FLAT) return;
1189
1190 MakeRiverAndModifyDesertZoneAround(downstream_tile);
1191 }
1192
1193 /* If upstream is dry and flat, try making it a river tile. */
1194 if (!IsWaterTile(upstream_tile)) {
1195 /* If the tile upstream isn't flat, don't bother. */
1196 if (GetTileSlope(upstream_tile) != SLOPE_FLAT) return;
1197
1199 }
1200 }
1201
1202 /* If the tile slope matches the desired slope, add a river tile. */
1203 if (cur_slope == desired_slope) {
1205 }
1206}
1207
1215{
1216 assert(DistanceManhattan(begin, end) == 1);
1217
1218 auto [slope_end, height_end] = GetTileSlopeZ(end);
1219
1220 /* Slope either is inclined or flat; rivers don't support other slopes. */
1221 if (slope_end != SLOPE_FLAT && !IsInclinedSlope(slope_end)) return false;
1222
1223 auto [slope_begin, height_begin] = GetTileSlopeZ(begin);
1224
1225 /* It can't flow uphill. */
1226 if (height_end > height_begin) return false;
1227
1228 /* Slope continues, then it must be lower... */
1229 if (slope_end == slope_begin && height_end < height_begin) return true;
1230
1231 /* ... or either end must be flat. */
1232 return slope_end == SLOPE_FLAT || slope_begin == SLOPE_FLAT;
1233}
1234
1242static std::tuple<bool, bool> FlowRiver(TileIndex spring, TileIndex begin, uint min_river_length)
1243{
1244 if (IsWaterTile(begin)) {
1245 return { DistanceManhattan(spring, begin) > min_river_length, GetTileZ(begin) == 0 };
1246 }
1247
1248 int height_begin = TileHeight(begin);
1249
1250 std::unordered_set<TileIndex> marks;
1251 marks.insert(begin);
1252
1253 std::vector<TileIndex> queue;
1254 queue.push_back(begin);
1255
1256 /* Breadth first search for the closest tile we can flow down to.
1257 * We keep the queue to find the Nth tile for lake guessing. The tiles
1258 * in the queue are neatly ordered by insertion.
1259 */
1260 bool found = false;
1261 TileIndex end;
1262 for (size_t i = 0; i != queue.size(); i++) {
1263 end = queue[i];
1264
1265 int height_end;
1266 if (IsTileFlat(end, &height_end) && (height_end < height_begin || (height_end == height_begin && IsWaterTile(end)))) {
1267 found = true;
1268 break;
1269 }
1270
1271 for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
1272 TileIndex t = end + TileOffsByDiagDir(d);
1273 if (IsValidTile(t) && !marks.contains(t) && RiverFlowsDown(end, t)) {
1274 marks.insert(t);
1275 queue.push_back(t);
1276 }
1277 }
1278 }
1279
1280 bool main_river = false;
1281 if (found) {
1282 /* Flow further down hill. */
1283 std::tie(found, main_river) = FlowRiver(spring, end, min_river_length);
1284 } else if (queue.size() > 32) {
1285 /* Maybe we can make a lake. Find the Nth of the considered tiles. */
1286 TileIndex lake_centre = queue[RandomRange(static_cast<uint32_t>(queue.size()))];
1287 int height_lake;
1288
1289 if (IsValidTile(lake_centre) &&
1290 /* We don't want the lake at the entry of the valley. */
1291 lake_centre != begin &&
1292 /* We don't want lakes in the desert. */
1293 (_settings_game.game_creation.landscape != LandscapeType::Tropic || GetTropicZone(lake_centre) != TROPICZONE_DESERT) &&
1294 /* A river, or lake, can only be built on flat slopes. */
1295 IsTileFlat(lake_centre, &height_lake) &&
1296 /* We want the lake to be built at the height of the river. */
1297 height_lake == height_begin &&
1298 /* We only want a lake if the river is long enough. */
1299 DistanceManhattan(spring, lake_centre) > min_river_length) {
1300 end = lake_centre;
1302 uint diameter = RandomRange(8) + 3;
1303
1304 /* Run the loop twice, so artefacts from going circular in one direction get (mostly) hidden. */
1305 for (uint loops = 0; loops < 2; ++loops) {
1306 for (auto tile : SpiralTileSequence(lake_centre, diameter)) {
1307 MakeLake(tile, height_lake);
1308 }
1309 }
1310
1311 found = true;
1312 }
1313 }
1314
1315 if (found) YapfBuildRiver(begin, end, spring, main_river);
1316 return { found, main_river };
1317}
1318
1322static void CreateRivers()
1323{
1325 if (amount == 0) return;
1326
1328 const uint num_short_rivers = wells - std::max(1u, wells / 10);
1329 SetGeneratingWorldProgress(GWP_RIVER, wells + TILE_UPDATE_FREQUENCY / 64); // Include the tile loop calls below.
1330
1331 /* Try to create long rivers. */
1332 for (; wells > num_short_rivers; wells--) {
1334 bool done = false;
1335 for (int tries = 0; tries < 512; tries++) {
1336 for (auto t : SpiralTileSequence(RandomTile(), 8)) {
1337 if (FindSpring(t)) {
1338 done = std::get<0>(FlowRiver(t, t, _settings_game.game_creation.min_river_length * 4));
1339 break;
1340 }
1341 }
1342 if (done) break;
1343 }
1344 }
1345
1346 /* Try to create short rivers. */
1347 for (; wells != 0; wells--) {
1349 bool done = false;
1350 for (int tries = 0; tries < 128; tries++) {
1351 for (auto t : SpiralTileSequence(RandomTile(), 8)) {
1352 if (FindSpring(t)) {
1353 done = std::get<0>(FlowRiver(t, t, _settings_game.game_creation.min_river_length));
1354 break;
1355 }
1356 }
1357 if (done) break;
1358 }
1359 }
1360
1361 /* Widening rivers may have left some tiles requiring to be watered. */
1362 ConvertGroundTilesIntoWaterTiles();
1363
1364 /* Run tile loop to update the ground density. */
1365 for (uint i = 0; i != TILE_UPDATE_FREQUENCY; i++) {
1367 RunTileLoop();
1368 }
1369}
1370
1388static uint CalculateCoverageLine(uint coverage, uint edge_multiplier)
1389{
1390 /* Histogram of how many tiles per height level exist. */
1391 std::array<int, MAX_TILE_HEIGHT + 1> histogram = {};
1392 /* Histogram of how many neighbour tiles are lower than the tiles of the height level. */
1393 std::array<int, MAX_TILE_HEIGHT + 1> edge_histogram = {};
1394
1395 /* Build a histogram of the map height. */
1396 for (const auto tile : Map::Iterate()) {
1397 uint h = TileHeight(tile);
1398 histogram[h]++;
1399
1400 if (edge_multiplier != 0) {
1401 /* Check if any of our neighbours is below us. */
1402 for (DiagDirection dir = DIAGDIR_BEGIN; dir != DIAGDIR_END; dir++) {
1403 TileIndex neighbour_tile = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDiagDir(dir));
1404 if (IsValidTile(neighbour_tile) && TileHeight(neighbour_tile) < h) {
1405 edge_histogram[h]++;
1406 }
1407 }
1408 }
1409 }
1410
1411 /* The amount of land we have is the map size minus the first (sea) layer. */
1412 uint land_tiles = Map::Size() - histogram[0];
1413 int best_score = land_tiles;
1414
1415 /* Our goal is the coverage amount of the land-mass. */
1416 int goal_tiles = land_tiles * coverage / 100;
1417
1418 /* We scan from top to bottom. */
1419 uint h = MAX_TILE_HEIGHT;
1420 uint best_h = h;
1421
1422 int current_tiles = 0;
1423 for (; h > 0; h--) {
1424 current_tiles += histogram[h];
1425 int current_score = goal_tiles - current_tiles;
1426
1427 /* Tropic grows from water and mountains into the desert. This is a
1428 * great visual, but it also means we* need to take into account how
1429 * much less desert tiles are being created if we are on this
1430 * height-level. We estimate this based on how many neighbouring
1431 * tiles are below us for a given length, assuming that is where
1432 * tropic is growing from.
1433 */
1434 if (edge_multiplier != 0 && h > 1) {
1435 /* From water tropic tiles grow for a few tiles land inward. */
1436 current_score -= edge_histogram[1] * edge_multiplier;
1437 /* Tropic tiles grow into the desert for a few tiles. */
1438 current_score -= edge_histogram[h] * edge_multiplier;
1439 }
1440
1441 if (std::abs(current_score) < std::abs(best_score)) {
1442 best_score = current_score;
1443 best_h = h;
1444 }
1445
1446 /* Always scan all height-levels, as h == 1 might give a better
1447 * score than any before. This is true for example with 0% desert
1448 * coverage. */
1449 }
1450
1451 return best_h;
1452}
1453
1458{
1459 /* We do not have snow sprites on coastal tiles, so never allow "1" as height. */
1461}
1462
1467static uint8_t CalculateDesertLine()
1468{
1469 /* CalculateCoverageLine() runs from top to bottom, so we need to invert the coverage. */
1471}
1472
1473bool GenerateLandscape(uint8_t mode)
1474{
1475 /* Number of steps of landscape generation */
1476 static constexpr uint GLS_HEIGHTMAP = 3;
1477 static constexpr uint GLS_TERRAGENESIS = 4;
1478 static constexpr uint GLS_ORIGINAL = 2;
1479 static constexpr uint GLS_TROPIC = 12;
1480 static constexpr uint GLS_OTHER = 0;
1481 uint steps = (_settings_game.game_creation.landscape == LandscapeType::Tropic) ? GLS_TROPIC : GLS_OTHER;
1482
1483 if (mode == GWM_HEIGHTMAP) {
1484 SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_HEIGHTMAP);
1486 return false;
1487 }
1490 SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_TERRAGENESIS);
1492 } else {
1493 SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_ORIGINAL);
1495 for (uint x = 0; x < Map::SizeX(); x++) MakeVoid(TileXY(x, 0));
1496 for (uint y = 0; y < Map::SizeY(); y++) MakeVoid(TileXY(0, y));
1497 }
1499 case LandscapeType::Arctic: {
1500 uint32_t r = Random();
1501
1502 for (uint i = Map::ScaleBySize(GB(r, 0, 7) + 950); i != 0; --i) {
1503 GenerateTerrain(2, 0);
1504 }
1505
1506 uint flag = GB(r, 7, 2) | 4;
1507 for (uint i = Map::ScaleBySize(GB(r, 9, 7) + 450); i != 0; --i) {
1508 GenerateTerrain(4, flag);
1509 }
1510 break;
1511 }
1512
1513 case LandscapeType::Tropic: {
1514 uint32_t r = Random();
1515
1516 for (uint i = Map::ScaleBySize(GB(r, 0, 7) + 170); i != 0; --i) {
1517 GenerateTerrain(0, 0);
1518 }
1519
1520 uint flag = GB(r, 7, 2) | 4;
1521 for (uint i = Map::ScaleBySize(GB(r, 9, 8) + 1700); i != 0; --i) {
1522 GenerateTerrain(0, flag);
1523 }
1524
1525 flag ^= 2;
1526
1527 for (uint i = Map::ScaleBySize(GB(r, 17, 7) + 410); i != 0; --i) {
1528 GenerateTerrain(3, flag);
1529 }
1530 break;
1531 }
1532
1533 default: {
1534 uint32_t r = Random();
1535
1537 uint i = Map::ScaleBySize(GB(r, 0, 7) + (3 - _settings_game.difficulty.quantity_sea_lakes) * 256 + 100);
1538 for (; i != 0; --i) {
1539 /* Make sure we do not overflow. */
1540 GenerateTerrain(Clamp(_settings_game.difficulty.terrain_type, 0, 3), 0);
1541 }
1542 break;
1543 }
1544 }
1545 }
1546
1547 /* Do not call IncreaseGeneratingWorldProgress() before FixSlopes(),
1548 * it allows screen redraw. Drawing of broken slopes crashes the game */
1549 FixSlopes();
1552
1553 ConvertGroundTilesIntoWaterTiles();
1556
1558 case LandscapeType::Arctic:
1560 break;
1561
1562 case LandscapeType::Tropic: {
1563 uint desert_tropic_line = CalculateDesertLine();
1564 CreateDesertOrRainForest(desert_tropic_line);
1565 break;
1566 }
1567
1568 default:
1569 break;
1570 }
1571
1572 CreateRivers();
1573 return true;
1574}
1575
1576void OnTick_Town();
1577void OnTick_Trees();
1578void OnTick_Station();
1579void OnTick_Industry();
1580
1581void OnTick_Companies();
1582void OnTick_LinkGraph();
1583
1584void CallLandscapeTick()
1585{
1586 {
1588
1589 OnTick_Town();
1590 OnTick_Trees();
1591 OnTick_Station();
1592 OnTick_Industry();
1593 }
1594
1597}
void DeleteAnimatedTile(TileIndex tile, bool immediate)
Stops animation on the given tile.
Tile animation!
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 ClearBridgeMiddle(Tile t)
Removes bridges from the given, that is bridges along the X and Y axis.
Definition bridge_map.h:103
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr bool None() const
Test if none of the values are set.
constexpr Timpl & Reset()
Reset all bits.
constexpr Timpl & Set()
Set all bits.
constexpr bool Any(const Timpl &other) const
Test if any of the given values are set.
Common return value for all commands.
void AddCost(const Money &cost)
Adds the given cost to the cost of the command.
Money GetCost() const
The costs as made up to this moment.
bool Failed() const
Did this command fail?
Enum-as-bit-set wrapper.
RAII class for measuring multi-step elements of performance.
Generate TileIndices around a center tile or tile area, with increasing distance.
static std::unique_ptr< TileIterator > Create(TileIndex corner1, TileIndex corner2, bool diagonal)
Create either an OrthogonalTileIterator or DiagonalTileIterator given the diagonal parameter.
Definition tilearea.cpp:291
static YearMonthDay ConvertDateToYMD(Date date)
Converts a Date to a Year, Month & Day.
static Date date
Current date in days (day counter).
static TickCounter counter
Monotonic counter, in ticks, since start of game.
Map accessors for 'clear' tiles.
bool IsClearGround(Tile t, ClearGround ct)
Set the type of clear tile.
Definition clear_map.h:59
@ CLEAR_GRASS
0-3
Definition clear_map.h:20
@ CLEAR_DESERT
1,3
Definition clear_map.h:25
void MakeClear(Tile t, ClearGround g, uint density)
Make a clear tile.
Definition clear_map.h:247
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
@ Auto
don't allow building on structures
@ NoWater
don't allow building on water
@ Execute
execute the given command
@ Bankrupt
company bankrupts, skip money check, skip vehicle on tile check in some cases
@ ForceClearTile
do not only remove the object on the tile, but also clear any water left on it
Money GetAvailableMoneyForCommand()
This functions returns the money which can be used to execute a command.
CompanyID _current_company
Company currently doing an action.
Functions related to companies.
void DirtyCompanyInfrastructureWindows(CompanyID company)
Redraw all windows with company infrastructure counts.
GUI Functions related to companies.
DiagDirection ReverseDiagDir(DiagDirection d)
Returns the reverse direction of the given DiagDirection.
DiagDirection ChangeDiagDir(DiagDirection d, DiagDirDiff delta)
Applies a difference on a DiagDirection.
Axis DiagDirToAxis(DiagDirection d)
Convert a DiagDirection to the axis.
DiagDirDiff
Enumeration for the difference between to DiagDirection.
@ DIAGDIRDIFF_END
Used for iterations.
@ DIAGDIRDIFF_90RIGHT
90 degrees right
@ DIAGDIRDIFF_90LEFT
90 degrees left
@ DIAGDIRDIFF_REVERSE
Reverse directions.
@ DIAGDIRDIFF_SAME
Same directions.
@ DIAGDIRDIFF_BEGIN
Used for iterations.
@ AXIS_Y
The y axis.
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.
EffectVehicle * CreateEffectVehicleAbove(int x, int y, int z, EffectVehicleType type)
Create an effect vehicle above a particular location.
Functions related to effect vehicles.
@ EV_EXPLOSION_SMALL
Various explosions.
@ EV_EXPLOSION_LARGE
Various explosions.
Error reporting related functions.
Declarations for savegames operations.
Types for recording game performance data.
@ PFE_GL_LANDSCAPE
Time spent processing other world features.
Table used to generate deserts and/or rainforests.
bool _generating_world
Whether we are generating the map or not.
Definition genworld.cpp:74
Functions related to world/map generation.
void IncreaseGeneratingWorldProgress(GenWorldProgress cls)
Increases the current stage of the world generation with one.
@ LG_TERRAGENESIS
TerraGenesis Perlin landscape generator.
Definition genworld.h:22
static const uint CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY
Value for custom sea level in difficulty settings.
Definition genworld.h:48
@ GWP_LANDSCAPE
Create the landscape.
Definition genworld.h:63
@ GWP_RIVER
Create the rivers.
Definition genworld.h:64
void SetGeneratingWorldProgress(GenWorldProgress cls, uint total)
Set the total of a stage of the world generation.
@ GWM_HEIGHTMAP
Generate a newgame from a heightmap.
Definition genworld.h:32
PauseModes _pause_mode
The current pause mode.
Definition gfx.cpp:51
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:17
@ MapGen
Special sprite for the map generator.
uint8_t LowestSnowLine()
Get the lowest possible snow line height, either variable or static.
uint8_t GetSnowLine()
Get the current snow line, either variable or static.
bool IsSnowLineSet()
Has a snow line table already been loaded.
void ClearSnowLine()
Clear the variable snow line table and free the memory.
static std::unique_ptr< SnowLine > _snow_line
Description of the snow line throughout the year.
Definition landscape.cpp:98
void SetSnowLine(std::unique_ptr< SnowLine > &&snow_line)
Set a variable snow line, as loaded from a newgrf file.
uint8_t HighestSnowLine()
Get the highest possible snow line height, either variable or static.
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
Definition gfx.cpp:1547
void MarkTileDirtyByTile(TileIndex tile, int bridge_level_offset, int tile_height_override)
Mark a tile given by its index dirty for repaint.
bool LoadHeightmap(DetailedFileType dft, std::string_view filename)
Load a heightmap from file and change the map in its current dimensions to a landscape representing t...
void FixSlopes()
This function takes care of the fact that land in OpenTTD can never differ more than 1 in height.
Functions related to creating heightmaps from files.
static void MakeLake(TileIndex tile, uint height_lake)
Make a connected lake; fill all tiles in the circular tile search that are connected.
uint GetPartialPixelZ(int x, int y, Slope corners)
Determines height at given coordinate of a slope.
static std::tuple< bool, bool > FlowRiver(TileIndex spring, TileIndex begin, uint min_river_length)
Try to flow the river down from a given begin.
int GetSlopePixelZOutsideMap(int x, int y)
Return world z coordinate of a given point of a tile, also for tiles outside the map (virtual "black"...
TrackStatus GetTileTrackStatus(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
Returns information about trackdirs and signal states.
void OnTick_Companies()
Called every tick for updating some company info.
static uint CalculateCoverageLine(uint coverage, uint edge_multiplier)
Calculate what height would be needed to cover N% of the landmass.
static void CalculateSnowLine()
Calculate the line from which snow begins.
static const uint TILE_UPDATE_FREQUENCY_LOG
The logarithm of how many ticks it takes between tile updates (log base 2).
Definition landscape.cpp:87
void ChangeTileOwner(TileIndex tile, Owner old_owner, Owner new_owner)
Change the owner of a tile.
void RunTileLoop()
Gradually iterate over all tiles on the map, calling their TileLoopProcs once every TILE_UPDATE_FREQU...
static bool FindSpring(TileIndex tile)
Find the spring of a river.
bool RiverFlowsDown(TileIndex begin, TileIndex end)
Check whether a river at begin could (logically) flow down to end.
static void CreateRivers()
Actually (try to) create some rivers.
void DrawFoundation(TileInfo *ti, Foundation f)
Draw foundation f at tile ti.
int GetSlopeZInCorner(Slope tileh, Corner corner)
Determine the Z height of a corner relative to TileZ.
std::tuple< Slope, int > GetFoundationSlope(TileIndex tile)
Get slope of a tile on top of a (possible) foundation If a tile does not have a foundation,...
void GetSlopePixelZOnEdge(Slope tileh, DiagDirection edge, int &z1, int &z2)
Determine the Z height of the corners of a specific tile edge.
void OnTick_LinkGraph()
Spawn or join a link graph job or compress a link graph if any link graph is due to do so.
const TileTypeProcs *const _tile_type_procs[16]
Tile callback functions for each type of tile.
Definition landscape.cpp:67
Point InverseRemapCoords2(int x, int y, bool clamp_to_map, bool *clamped)
Map 2D viewport or smallmap coordinate to 3D world or tile coordinate.
const TileTypeProcs _tile_type_town_procs
Tile callback functions for a town.
Definition landscape.cpp:53
void OnTick_Town()
Iterate through all towns and call their tick handler.
Definition town_cmd.cpp:938
static uint8_t CalculateDesertLine()
Calculate the line (in height) between desert and tropic.
const uint8_t _slope_to_sprite_offset[32]
landscape slope => sprite
std::tuple< CommandCost, Money > CmdClearArea(DoCommandFlags flags, TileIndex tile, TileIndex start_tile, bool diagonal)
Clear a big piece of landscape.
const TileTypeProcs _tile_type_road_procs
Tile callback functions for road tiles.
Definition landscape.cpp:52
uint ApplyFoundationToSlope(Foundation f, Slope &s)
Applies a foundation to a slope.
bool IsMapSurroundedByWater()
Check if all tiles on the map edge should be considered water borders.
bool GenerateLandscape(uint8_t mode)
CommandCost CmdLandscapeClear(DoCommandFlags flags, TileIndex tile)
Clear a piece of landscape.
void RiverMakeWider(TileIndex tile, TileIndex origin_tile)
Widen a river by expanding into adjacent tiles via circular tile search.
static const uint TILE_UPDATE_FREQUENCY
How many ticks it takes between tile updates (has to be a power of 2).
Definition landscape.cpp:88
int GetSlopePixelZ(int x, int y, bool ground_vehicle)
Return world Z coordinate of a given point of a tile.
Functions related to OTTD's landscape.
std::tuple< Slope, int > GetFoundationPixelSlope(TileIndex tile)
Get slope of a tile on top of a (possible) foundation If a tile does not have a foundation,...
Definition landscape.h:67
uint ApplyPixelFoundationToSlope(Foundation f, Slope &s)
Applies a foundation to a slope.
Definition landscape.h:128
Point InverseRemapCoords(int x, int y)
Map 2D viewport or smallmap coordinate to 3D world or tile coordinate.
Definition landscape.h:111
Command definitions related to landscape (slopes etc.).
Types related to the landscape.
@ Random
Randomise borders.
TileIndex TileAddWrap(TileIndex tile, int addx, int addy)
This function checks if we add addx/addy to tile, if we do wrap around the edges.
Definition map.cpp:109
uint DistanceManhattan(TileIndex t0, TileIndex t1)
Gets the Manhattan distance between the two given tiles.
Definition map.cpp:158
TileIndex TileAddXY(TileIndex tile, int x, int y)
Adds a given offset to a tile.
Definition map_func.h:482
TileIndex AddTileIndexDiffCWrap(TileIndex tile, TileIndexDiffC diff)
Add a TileIndexDiffC to a TileIndex and returns the new one.
Definition map_func.h:527
static debug_inline TileIndex TileXY(uint x, uint y)
Returns the TileIndex of a coordinate.
Definition map_func.h:385
TileIndex TileAddByDiagDir(TileIndex tile, DiagDirection dir)
Adds a DiagDir to a tile.
Definition map_func.h:623
TileIndexDiff TileDiffXY(int x, int y)
Calculates an offset for the given coordinate(-offset).
Definition map_func.h:401
TileIndexDiffC TileIndexDiffCByDiagDir(DiagDirection dir)
Returns the TileIndexDiffC offset from a DiagDirection.
Definition map_func.h:495
#define RandomTile()
Get a valid random tile.
Definition map_func.h:664
static debug_inline uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition map_func.h:437
static debug_inline uint TileX(TileIndex tile)
Get the X component of a tile.
Definition map_func.h:427
TileIndexDiff TileOffsByDiagDir(DiagDirection dir)
Convert a DiagDirection to a TileIndexDiff.
Definition map_func.h:582
static debug_inline TileIndex TileVirtXY(uint x, uint y)
Get a tile from the virtual XY-coordinate.
Definition map_func.h:416
static const uint MIN_MAP_SIZE_BITS
Minimal and maximal map width and height.
Definition map_type.h:37
static const uint MAX_MAP_SIZE_BITS
Maximal size of map is equal to 2 ^ MAX_MAP_SIZE_BITS.
Definition map_type.h:38
constexpr bool IsInsideBS(const T x, const size_t base, const size_t size)
Checks if a value is between a window started at some base point.
constexpr uint CeilDiv(uint a, uint b)
Computes ceil(a / b) for non-negative a and b.
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition math_func.hpp:79
Base for all objects.
ClearedObjectArea * FindClearedObject(TileIndex tile)
Find the entry in _cleared_object_areas which occupies a certain tile.
Pseudo random number generator.
uint32_t RandomRange(uint32_t limit, const std::source_location location=std::source_location::current())
Pick a random number between 0 and limit - 1, inclusive.
A number of safeguards to prevent using unsafe methods.
FileToSaveLoad _file_to_saveload
File to save or load in the openttd loop.
Definition saveload.cpp:78
Functions/types related to saving and loading games.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:61
bool IsSpecialRailFoundation(Foundation f)
Tests if a foundation is a special rail foundation for single horizontal/vertical track.
Definition slope_func.h:345
Slope SlopeWithThreeCornersRaised(Corner corner)
Returns the slope with all except one corner raised.
Definition slope_func.h:206
Corner OppositeCorner(Corner corner)
Returns the opposite corner.
Definition slope_func.h:184
static constexpr Corner GetHalftileSlopeCorner(Slope s)
Returns the leveled halftile of a halftile slope.
Definition slope_func.h:148
static constexpr Slope RemoveHalftileSlope(Slope s)
Removes a halftile slope from a slope.
Definition slope_func.h:60
bool IsSlopeWithOneCornerRaised(Slope s)
Tests if a specific slope has exactly one corner raised.
Definition slope_func.h:88
bool IsNonContinuousFoundation(Foundation f)
Tests if a foundation is a non-continuous foundation, i.e.
Definition slope_func.h:320
Corner GetHighestSlopeCorner(Slope s)
Returns the highest corner of a slope (one corner raised or a steep slope).
Definition slope_func.h:126
Corner GetHalftileFoundationCorner(Foundation f)
Returns the halftile corner of a halftile-foundation.
Definition slope_func.h:333
bool IsLeveledFoundation(Foundation f)
Tests if the foundation is a leveled foundation.
Definition slope_func.h:298
bool IsFoundation(Foundation f)
Tests for FOUNDATION_NONE.
Definition slope_func.h:287
static constexpr bool IsSteepSlope(Slope s)
Checks if a slope is steep.
Definition slope_func.h:36
bool IsSlopeWithThreeCornersRaised(Slope s)
Tests if a specific slope has exactly three corners raised.
Definition slope_func.h:195
bool IsInclinedSlope(Slope s)
Tests if a specific slope is an inclined slope.
Definition slope_func.h:228
Slope SteepSlope(Corner corner)
Returns a specific steep slope.
Definition slope_func.h:217
Corner GetRailFoundationCorner(Foundation f)
Returns the track corner of a special rail foundation.
Definition slope_func.h:356
static constexpr bool IsHalftileSlope(Slope s)
Checks for non-continuous slope on halftile foundations.
Definition slope_func.h:47
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
DiagDirection GetInclinedSlopeDirection(Slope s)
Returns the direction of an inclined slope.
Definition slope_func.h:239
static constexpr Slope HalftileSlope(Slope s, Corner corner)
Adds a halftile slope to a slope.
Definition slope_func.h:274
Slope ComplementSlope(Slope s)
Return the complement of a slope.
Definition slope_func.h:76
Slope SlopeWithOneCornerRaised(Corner corner)
Returns the slope with a specific corner raised.
Definition slope_func.h:99
bool IsInclinedFoundation(Foundation f)
Tests if the foundation is an inclined foundation.
Definition slope_func.h:309
Corner
Enumeration of tile corners.
Definition slope_type.h:22
Slope
Enumeration for the slope-type.
Definition slope_type.h:48
@ SLOPE_W
the west corner of the tile is raised
Definition slope_type.h:50
@ SLOPE_ELEVATED
bit mask containing all 'simple' slopes
Definition slope_type.h:61
@ SLOPE_NS
north and south corner are raised
Definition slope_type.h:60
@ SLOPE_E
the east corner of the tile is raised
Definition slope_type.h:52
@ SLOPE_WSE
west, south and east corner are raised
Definition slope_type.h:63
@ SLOPE_S
the south corner of the tile is raised
Definition slope_type.h:51
@ SLOPE_N
the north corner of the tile is raised
Definition slope_type.h:53
@ SLOPE_SEN
south, east and north corner are raised
Definition slope_type.h:64
@ SLOPE_ENW
east, north and west corner are raised
Definition slope_type.h:65
@ SLOPE_SW
south and west corner are raised
Definition slope_type.h:56
@ SLOPE_FLAT
a flat tile
Definition slope_type.h:49
@ SLOPE_STEEP_W
a steep slope falling to east (from west)
Definition slope_type.h:66
@ SLOPE_NE
north and east corner are raised
Definition slope_type.h:58
@ SLOPE_STEEP_E
a steep slope falling to west (from east)
Definition slope_type.h:68
@ SLOPE_SE
south and east corner are raised
Definition slope_type.h:57
@ SLOPE_NWS
north, west and south corner are raised
Definition slope_type.h:62
@ SLOPE_NW
north and west corner are raised
Definition slope_type.h:55
@ SLOPE_STEEP_N
a steep slope falling to south (from north)
Definition slope_type.h:69
@ SLOPE_STEEP_S
a steep slope falling to north (from south)
Definition slope_type.h:67
@ SLOPE_EW
east and west corner are raised
Definition slope_type.h:59
@ SLOPE_STEEP
indicates the slope is steep
Definition slope_type.h:54
Foundation
Enumeration for Foundations.
Definition slope_type.h:93
@ FOUNDATION_INCLINED_X
The tile has an along X-axis inclined foundation.
Definition slope_type.h:96
@ FOUNDATION_STEEP_BOTH
The tile has a steep slope. The lowest corner is raised by a foundation and the upper halftile is lev...
Definition slope_type.h:101
@ FOUNDATION_INCLINED_Y
The tile has an along Y-axis inclined foundation.
Definition slope_type.h:97
@ FOUNDATION_STEEP_LOWER
The tile has a steep slope. The lowest corner is raised by a foundation to allow building railroad on...
Definition slope_type.h:98
Functions to cache sprites in memory.
This file contains all sprite-related enums and defines.
static const SpriteID SPR_HALFTILE_FOUNDATION_BASE
Halftile foundations.
Definition sprites.h:212
Functions related to stations.
Definition of base types and functions in a cross-platform compatible way.
#define lengthof(array)
Return the length of an fixed size array.
Definition stdafx.h:271
Keeps track of removed objects during execution/testruns of commands.
Definition object_base.h:86
TileIndex first_tile
The first tile being cleared, which then causes the whole object to be cleared.
Definition object_base.h:87
uint32_t clear_limit
Amount of tiles we can (still) clear (times 65536).
bool freeform_edges
allow terraforming the tiles at the map edges
uint8_t map_height_limit
the maximum allowed heightlevel
T y
Y coordinate.
T x
X coordinate.
T x
X coordinate.
T z
Z coordinate.
uint8_t terrain_type
the mountainousness of the landscape
uint8_t quantity_sea_lakes
the amount of seas/lakes
FiosType ftype
File type.
Definition saveload.h:429
std::string name
Name of the file.
Definition saveload.h:430
DetailedFileType detailed
Detailed file type.
Definition fileio_type.h:65
uint8_t amount_of_rivers
the amount of rivers
uint8_t min_river_length
the minimum river length
uint8_t snow_coverage
the amount of snow coverage on the map
uint8_t desert_coverage
the amount of desert coverage on the map
LandscapeType landscape
the landscape we're currently in
uint8_t snow_line_height
the configured snow line height (deduced from "snow_coverage")
uint8_t land_generator
the landscape generator
ConstructionSettings construction
construction of things in-game
DifficultySettings difficulty
settings related to the difficulty
GameCreationSettings game_creation
settings used during the creation of a game (map)
Size related data of the map.
Definition map_func.h:206
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:340
static uint SizeY()
Get the size of the map along the Y.
Definition map_func.h:281
static IterateWrapper Iterate()
Returns an iterable ensemble of all Tiles.
Definition map_func.h:375
static debug_inline uint SizeX()
Get the size of the map along the X.
Definition map_func.h:272
static debug_inline uint LogX()
Logarithm of the map size along the X side.
Definition map_func.h:253
static uint LogY()
Logarithm of the map size along the y side.
Definition map_func.h:263
static uint MaxY()
Gets the maximum Y coordinate within the map, including MP_VOID.
Definition map_func.h:308
static debug_inline uint Size()
Get the size of the map.
Definition map_func.h:290
static debug_inline uint MaxX()
Gets the maximum X coordinate within the map, including MP_VOID.
Definition map_func.h:299
static Titem * Get(auto index)
Returns Titem with given index.
static bool IsValidID(auto index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
static Titem * GetIfValid(auto index)
Returns Titem with given index.
Coord3D< uint8_t > extent
Size of bounding box.
Definition sprite.h:20
Data structure describing a sprite.
uint16_t width
Width of the sprite.
uint16_t height
Height of the sprite.
std::byte data[]
Sprite data.
Tile description for the 'land area information' tool.
Definition tile_cmd.h:36
Tile information, used while rendering the tile.
Definition tile_cmd.h:30
Slope tileh
Slope of the tile.
Definition tile_cmd.h:31
TileIndex tile
Tile index.
Definition tile_cmd.h:32
Set of callback functions for performing tile operations of a given tile type.
Definition tile_cmd.h:152
GetTileDescProc * get_tile_desc_proc
Get a description of a tile (for the 'land area information' tool)
Definition tile_cmd.h:157
GetTileTrackStatusProc * get_tile_track_status_proc
Get available tracks and status of a tile.
Definition tile_cmd.h:158
Command definitions related to terraforming.
void GenerateTerrainPerlin()
The main new land generator using Perlin noise.
Definition tgp.cpp:979
Functions for the Perlin noise enhanced map generator.
bool MayAnimateTile(TileIndex tile)
Test if a tile may be animated.
Definition tile_cmd.h:197
bool IsTileFlat(TileIndex tile, int *h)
Check if a given tile is flat.
Definition tile_map.cpp:95
std::tuple< Slope, int > GetTilePixelSlopeOutsideMap(int x, int y)
Return the slope of a given tile, also for tiles outside the map (virtual "black" tiles).
Definition tile_map.cpp:78
std::tuple< Slope, int > GetTileSlopeZ(TileIndex tile)
Return the slope of a given tile inside the map.
Definition tile_map.cpp:55
int GetTileMaxZ(TileIndex t)
Get top height of the tile inside the map.
Definition tile_map.cpp:136
int GetTileZ(TileIndex tile)
Get bottom height of the tile.
Definition tile_map.cpp:116
Owner GetTileOwner(Tile tile)
Returns the owner of a tile.
Definition tile_map.h:178
static debug_inline TileType GetTileType(Tile tile)
Get the tiletype of a given tile.
Definition tile_map.h:96
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
void SetTileHeight(Tile tile, uint height)
Sets the height of a tile.
Definition tile_map.h:57
static debug_inline bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition tile_map.h:150
Slope GetTileSlope(TileIndex tile)
Return the slope of a given tile inside the map.
Definition tile_map.h:279
void SetTropicZone(Tile tile, TropicZone type)
Set the tropic zone.
Definition tile_map.h:225
static debug_inline uint TileHeight(Tile tile)
Returns the height of a tile.
Definition tile_map.h:29
static constexpr uint MAX_TILE_HEIGHT
Maximum allowed tile height.
Definition tile_type.h:24
@ TROPICZONE_RAINFOREST
Rainforest tile.
Definition tile_type.h:79
@ TROPICZONE_DESERT
Tile is desert.
Definition tile_type.h:78
@ TROPICZONE_NORMAL
Normal tropiczone.
Definition tile_type.h:77
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:95
static constexpr uint TILE_SIZE
Tile size in world coordinates.
Definition tile_type.h:15
static constexpr uint TILE_PIXELS
Pixel distance between tile columns/rows in ZOOM_BASE.
Definition tile_type.h:17
static constexpr uint TILE_HEIGHT
Height of a height level in world coordinate AND in pixels in ZOOM_BASE.
Definition tile_type.h:18
@ MP_CLEAR
A tile without any structures, i.e. grass, rocks, farm fields etc.
Definition tile_type.h:48
@ MP_WATER
Water tile.
Definition tile_type.h:54
@ MP_VOID
Invisible tiles at the SW and SE border.
Definition tile_type.h:55
Definition of the game-calendar-timer.
Definition of the tick-based game-timer.
TransportType
Available types of transport.
void OffsetGroundSprite(int x, int y)
Called when a foundation has been drawn for the current tile.
Definition viewport.cpp:591
void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int z, const SpriteBounds &bounds, bool transparent, const SubSprite *sub)
Draw a (transparent) sprite at given coordinates with a given bounding box.
Definition viewport.cpp:663
Functions related to (drawing on) viewports.
Map accessors for void tiles.
void MakeVoid(Tile t)
Make a nice void tile ;)
Definition void_map.h:19
Functions related to water (management)
void ClearNeighbourNonFloodingStates(TileIndex tile)
Clear non-flooding state of the tiles around a tile.
Definition water_cmd.cpp:97
void MakeRiverAndModifyDesertZoneAround(TileIndex tile)
Make a river tile and remove desert directly around it.
bool IsTileOnWater(Tile t)
Tests if the tile was built on water.
Definition water_map.h:138
bool IsRiver(Tile t)
Is it a river water tile?
Definition water_map.h:182
@ WATER_CLASS_CANAL
Canal.
Definition water_map.h:41
bool HasTileWaterClass(Tile t)
Checks whether the tile has an waterclass associated.
Definition water_map.h:103
bool IsCanal(Tile t)
Is it a canal tile?
Definition water_map.h:171
WaterClass GetWaterClass(Tile t)
Get the water class at a tile.
Definition water_map.h:114
bool IsCoastTile(Tile t)
Is it a coast tile.
Definition water_map.h:213
bool IsDockingTile(Tile t)
Checks whether the tile is marked as a dockling tile.
Definition water_map.h:373
bool IsWaterTile(Tile t)
Is it a water tile with plain water?
Definition water_map.h:192
void InvalidateWaterRegion(TileIndex tile)
Marks the water region that tile is part of as invalid.
Handles dividing the water in the map into regions to assist pathfinding.
void YapfBuildRiver(TileIndex start_tile, TileIndex end_tile, TileIndex spring_tile, bool main_river)
Builds a river from the start tile to the end tile.
Pathfinder for river building.