OpenTTD Source 20251213-master-g1091fa6071
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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
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 "tree_cmd.h"
33#include "company_func.h"
34#include "company_gui.h"
35#include "saveload/saveload.h"
36#include "framerate_type.h"
37#include "landscape_cmd.h"
38#include "terraform_cmd.h"
39#include "station_func.h"
42
43#include "table/strings.h"
44#include "table/sprites.h"
45
46#include <unordered_set>
47
48#include "safeguards.h"
49
50extern const TileTypeProcs
51 _tile_type_clear_procs,
52 _tile_type_rail_procs,
55 _tile_type_trees_procs,
56 _tile_type_station_procs,
57 _tile_type_water_procs,
58 _tile_type_void_procs,
59 _tile_type_industry_procs,
60 _tile_type_tunnelbridge_procs,
61 _tile_type_object_procs;
62
68const TileTypeProcs * const _tile_type_procs[16] = {
69 &_tile_type_clear_procs,
70 &_tile_type_rail_procs,
73 &_tile_type_trees_procs,
74 &_tile_type_station_procs,
75 &_tile_type_water_procs,
76 &_tile_type_void_procs,
77 &_tile_type_industry_procs,
78 &_tile_type_tunnelbridge_procs,
79 &_tile_type_object_procs,
80};
81
83extern const uint8_t _slope_to_sprite_offset[32] = {
84 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0,
85 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 17, 0, 15, 18, 0,
86};
87
88static const uint TILE_UPDATE_FREQUENCY_LOG = 8;
90
99static std::unique_ptr<SnowLine> _snow_line;
100
114Point InverseRemapCoords2(int x, int y, bool clamp_to_map, bool *clamped)
115{
116 if (clamped != nullptr) *clamped = false; // Not clamping yet.
117
118 /* Initial x/y world coordinate is like if the landscape
119 * was completely flat on height 0. */
120 Point pt = InverseRemapCoords(x, y);
121
122 const uint min_coord = _settings_game.construction.freeform_edges ? TILE_SIZE : 0;
123 const uint max_x = Map::MaxX() * TILE_SIZE - 1;
124 const uint max_y = Map::MaxY() * TILE_SIZE - 1;
125
126 if (clamp_to_map) {
127 /* Bring the coordinates near to a valid range. At the top we allow a number
128 * of extra tiles. This is mostly due to the tiles on the north side of
129 * the map possibly being drawn higher due to the extra height levels. */
131 Point old_pt = pt;
132 pt.x = Clamp(pt.x, -extra_tiles * TILE_SIZE, max_x);
133 pt.y = Clamp(pt.y, -extra_tiles * TILE_SIZE, max_y);
134 if (clamped != nullptr) *clamped = (pt.x != old_pt.x) || (pt.y != old_pt.y);
135 }
136
137 /* Now find the Z-world coordinate by fix point iteration.
138 * This is a bit tricky because the tile height is non-continuous at foundations.
139 * The clicked point should be approached from the back, otherwise there are regions that are not clickable.
140 * (FOUNDATION_HALFTILE_LOWER on SLOPE_STEEP_S hides north halftile completely)
141 * So give it a z-malus of 4 in the first iterations. */
142 int z = 0;
143 if (clamp_to_map) {
144 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;
145 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;
146 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;
147 } else {
148 for (int i = 0; i < 5; i++) z = GetSlopePixelZOutsideMap(pt.x + std::max(z, 4) - 4, pt.y + std::max(z, 4) - 4) / 2;
149 for (int m = 3; m > 0; m--) z = GetSlopePixelZOutsideMap(pt.x + std::max(z, m) - m, pt.y + std::max(z, m) - m) / 2;
150 for (int i = 0; i < 5; i++) z = GetSlopePixelZOutsideMap(pt.x + z, pt.y + z ) / 2;
151 }
152
153 pt.x += z;
154 pt.y += z;
155 if (clamp_to_map) {
156 Point old_pt = pt;
157 pt.x = Clamp(pt.x, min_coord, max_x);
158 pt.y = Clamp(pt.y, min_coord, max_y);
159 if (clamped != nullptr) *clamped = *clamped || (pt.x != old_pt.x) || (pt.y != old_pt.y);
160 }
161
162 return pt;
163}
164
174{
175 if (!IsFoundation(f)) return 0;
176
177 if (IsLeveledFoundation(f)) {
178 uint dz = 1 + (IsSteepSlope(s) ? 1 : 0);
179 s = SLOPE_FLAT;
180 return dz;
181 }
182
185 return 0;
186 }
187
190 return 0;
191 }
192
193 uint dz = IsSteepSlope(s) ? 1 : 0;
194 Corner highest_corner = GetHighestSlopeCorner(s);
195
196 switch (f) {
198 s = (((highest_corner == CORNER_W) || (highest_corner == CORNER_S)) ? SLOPE_SW : SLOPE_NE);
199 break;
200
202 s = (((highest_corner == CORNER_S) || (highest_corner == CORNER_E)) ? SLOPE_SE : SLOPE_NW);
203 break;
204
206 s = SlopeWithOneCornerRaised(highest_corner);
207 break;
208
210 s = HalftileSlope(SlopeWithOneCornerRaised(highest_corner), highest_corner);
211 break;
212
213 default: NOT_REACHED();
214 }
215 return dz;
216}
217
218
231uint GetPartialPixelZ(int x, int y, Slope corners)
232{
233 if (IsHalftileSlope(corners)) {
234 /* A foundation is placed on half the tile at a specific corner. This means that,
235 * depending on the corner, that one half of the tile is at the maximum height. */
236 switch (GetHalftileSlopeCorner(corners)) {
237 case CORNER_W:
238 if (x > y) return GetSlopeMaxPixelZ(corners);
239 break;
240
241 case CORNER_S:
242 if (x + y >= (int)TILE_SIZE) return GetSlopeMaxPixelZ(corners);
243 break;
244
245 case CORNER_E:
246 if (x <= y) return GetSlopeMaxPixelZ(corners);
247 break;
248
249 case CORNER_N:
250 if (x + y < (int)TILE_SIZE) return GetSlopeMaxPixelZ(corners);
251 break;
252
253 default: NOT_REACHED();
254 }
255 }
256
257 switch (RemoveHalftileSlope(corners)) {
258 case SLOPE_FLAT: return 0;
259
260 /* One corner is up.*/
261 case SLOPE_N: return x + y <= (int)TILE_SIZE ? (TILE_SIZE - x - y) >> 1 : 0;
262 case SLOPE_E: return y >= x ? (1 + y - x) >> 1 : 0;
263 case SLOPE_S: return x + y >= (int)TILE_SIZE ? (1 + x + y - TILE_SIZE) >> 1 : 0;
264 case SLOPE_W: return x >= y ? (x - y) >> 1 : 0;
265
266 /* Two corners next to each other are up. */
267 case SLOPE_NE: return (TILE_SIZE - x) >> 1;
268 case SLOPE_SE: return (y + 1) >> 1;
269 case SLOPE_SW: return (x + 1) >> 1;
270 case SLOPE_NW: return (TILE_SIZE - y) >> 1;
271
272 /* Three corners are up on the same level. */
273 case SLOPE_ENW: return x + y >= (int)TILE_SIZE ? TILE_HEIGHT - ((1 + x + y - TILE_SIZE) >> 1) : TILE_HEIGHT;
274 case SLOPE_SEN: return y < x ? TILE_HEIGHT - ((x - y) >> 1) : TILE_HEIGHT;
275 case SLOPE_WSE: return x + y <= (int)TILE_SIZE ? TILE_HEIGHT - ((TILE_SIZE - x - y) >> 1) : TILE_HEIGHT;
276 case SLOPE_NWS: return x < y ? TILE_HEIGHT - ((1 + y - x) >> 1) : TILE_HEIGHT;
277
278 /* Two corners at opposite sides are up. */
279 case SLOPE_NS: return x + y < (int)TILE_SIZE ? (TILE_SIZE - x - y) >> 1 : (1 + x + y - TILE_SIZE) >> 1;
280 case SLOPE_EW: return x >= y ? (x - y) >> 1 : (1 + y - x) >> 1;
281
282 /* Very special cases. */
283 case SLOPE_ELEVATED: return TILE_HEIGHT;
284
285 /* Steep slopes. The top is at 2 * TILE_HEIGHT. */
286 case SLOPE_STEEP_N: return (TILE_SIZE - x + TILE_SIZE - y) >> 1;
287 case SLOPE_STEEP_E: return (TILE_SIZE + 1 + y - x) >> 1;
288 case SLOPE_STEEP_S: return (1 + x + y) >> 1;
289 case SLOPE_STEEP_W: return (TILE_SIZE + x - y) >> 1;
290
291 default: NOT_REACHED();
292 }
293}
294
306int GetSlopePixelZ(int x, int y, bool ground_vehicle)
307{
308 TileIndex tile = TileVirtXY(x, y);
309
310 return _tile_type_procs[GetTileType(tile)]->get_slope_z_proc(tile, x, y, ground_vehicle);
311}
312
322{
323 if (IsInsideBS(x, 0, Map::SizeX() * TILE_SIZE) && IsInsideBS(y, 0, Map::SizeY() * TILE_SIZE)) {
324 return GetSlopePixelZ(x, y, false);
325 } else {
326 return _tile_type_procs[MP_VOID]->get_slope_z_proc(INVALID_TILE, x, y, false);
327 }
328}
329
340{
341 assert(!IsHalftileSlope(tileh));
342 return ((tileh & SlopeWithOneCornerRaised(corner)) != 0 ? 1 : 0) + (tileh == SteepSlope(corner) ? 1 : 0);
343}
344
357void GetSlopePixelZOnEdge(Slope tileh, DiagDirection edge, int &z1, int &z2)
358{
359 static const Slope corners[4][4] = {
360 /* corner | steep slope
361 * z1 z2 | z1 z2 */
362 {SLOPE_E, SLOPE_N, SLOPE_STEEP_E, SLOPE_STEEP_N}, // DIAGDIR_NE, z1 = E, z2 = N
363 {SLOPE_S, SLOPE_E, SLOPE_STEEP_S, SLOPE_STEEP_E}, // DIAGDIR_SE, z1 = S, z2 = E
364 {SLOPE_S, SLOPE_W, SLOPE_STEEP_S, SLOPE_STEEP_W}, // DIAGDIR_SW, z1 = S, z2 = W
365 {SLOPE_W, SLOPE_N, SLOPE_STEEP_W, SLOPE_STEEP_N}, // DIAGDIR_NW, z1 = W, z2 = N
366 };
367
368 int halftile_test = (IsHalftileSlope(tileh) ? SlopeWithOneCornerRaised(GetHalftileSlopeCorner(tileh)) : 0);
369 if (halftile_test == corners[edge][0]) z2 += TILE_HEIGHT; // The slope is non-continuous in z2. z2 is on the upper side.
370 if (halftile_test == corners[edge][1]) z1 += TILE_HEIGHT; // The slope is non-continuous in z1. z1 is on the upper side.
371
372 if ((tileh & corners[edge][0]) != 0) z1 += TILE_HEIGHT; // z1 is raised
373 if ((tileh & corners[edge][1]) != 0) z2 += TILE_HEIGHT; // z2 is raised
374 if (RemoveHalftileSlope(tileh) == corners[edge][2]) z1 += TILE_HEIGHT; // z1 is highest corner of a steep slope
375 if (RemoveHalftileSlope(tileh) == corners[edge][3]) z2 += TILE_HEIGHT; // z2 is highest corner of a steep slope
376}
377
385std::tuple<Slope, int> GetFoundationSlope(TileIndex tile)
386{
387 auto [tileh, z] = GetTileSlopeZ(tile);
388 Foundation f = _tile_type_procs[GetTileType(tile)]->get_foundation_proc(tile, tileh);
389 z += ApplyFoundationToSlope(f, tileh);
390 return {tileh, z};
391}
392
393
394bool HasFoundationNW(TileIndex tile, Slope slope_here, uint z_here)
395{
396 int z_W_here = z_here;
397 int z_N_here = z_here;
398 GetSlopePixelZOnEdge(slope_here, DIAGDIR_NW, z_W_here, z_N_here);
399
400 auto [slope, z] = GetFoundationPixelSlope(TileAddXY(tile, 0, -1));
401 int z_W = z;
402 int z_N = z;
403 GetSlopePixelZOnEdge(slope, DIAGDIR_SE, z_W, z_N);
404
405 return (z_N_here > z_N) || (z_W_here > z_W);
406}
407
408
409bool HasFoundationNE(TileIndex tile, Slope slope_here, uint z_here)
410{
411 int z_E_here = z_here;
412 int z_N_here = z_here;
413 GetSlopePixelZOnEdge(slope_here, DIAGDIR_NE, z_E_here, z_N_here);
414
415 auto [slope, z] = GetFoundationPixelSlope(TileAddXY(tile, -1, 0));
416 int z_E = z;
417 int z_N = z;
418 GetSlopePixelZOnEdge(slope, DIAGDIR_SW, z_E, z_N);
419
420 return (z_N_here > z_N) || (z_E_here > z_E);
421}
422
429{
430 if (!IsFoundation(f)) return;
431
432 /* Two part foundations must be drawn separately */
433 assert(f != FOUNDATION_STEEP_BOTH);
434
435 uint sprite_block = 0;
436 auto [slope, z] = GetFoundationPixelSlope(ti->tile);
437
438 /* Select the needed block of foundations sprites
439 * Block 0: Walls at NW and NE edge
440 * Block 1: Wall at NE edge
441 * Block 2: Wall at NW edge
442 * Block 3: No walls at NW or NE edge
443 */
444 if (!HasFoundationNW(ti->tile, slope, z)) sprite_block += 1;
445 if (!HasFoundationNE(ti->tile, slope, z)) sprite_block += 2;
446
447 /* Use the original slope sprites if NW and NE borders should be visible */
448 SpriteID leveled_base = (sprite_block == 0 ? (int)SPR_FOUNDATION_BASE : (SPR_SLOPES_VIRTUAL_BASE + sprite_block * TRKFOUND_BLOCK_SIZE));
449 SpriteID inclined_base = SPR_SLOPES_VIRTUAL_BASE + SLOPES_INCLINED_OFFSET + sprite_block * TRKFOUND_BLOCK_SIZE;
450 SpriteID halftile_base = SPR_HALFTILE_FOUNDATION_BASE + sprite_block * HALFTILE_BLOCK_SIZE;
451
452 if (IsSteepSlope(ti->tileh)) {
454 /* Lower part of foundation */
455 static constexpr SpriteBounds bounds{{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT - 1}, {}};
456 AddSortableSpriteToDraw(leveled_base + (ti->tileh & ~SLOPE_STEEP), PAL_NONE, *ti, bounds);
457 }
458
459 Corner highest_corner = GetHighestSlopeCorner(ti->tileh);
460 ti->z += ApplyPixelFoundationToSlope(f, ti->tileh);
461
462 if (IsInclinedFoundation(f)) {
463 /* inclined foundation */
464 uint8_t inclined = highest_corner * 2 + (f == FOUNDATION_INCLINED_Y ? 1 : 0);
465
466 SpriteBounds bounds{{}, {1, 1, TILE_HEIGHT}, {}};
467 if (f == FOUNDATION_INCLINED_X) bounds.extent.x = TILE_SIZE;
468 if (f == FOUNDATION_INCLINED_Y) bounds.extent.y = TILE_SIZE;
469 AddSortableSpriteToDraw(inclined_base + inclined, PAL_NONE, *ti, bounds);
470 OffsetGroundSprite(0, 0);
471 } else if (IsLeveledFoundation(f)) {
472 static constexpr SpriteBounds bounds{{0, 0, -(int)TILE_HEIGHT}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT - 1}, {}};
473 AddSortableSpriteToDraw(leveled_base + SlopeWithOneCornerRaised(highest_corner), PAL_NONE, *ti, bounds);
475 } else if (f == FOUNDATION_STEEP_LOWER) {
476 /* one corner raised */
478 } else {
479 /* halftile foundation */
480 int8_t x_bb = (((highest_corner == CORNER_W) || (highest_corner == CORNER_S)) ? TILE_SIZE / 2 : 0);
481 int8_t y_bb = (((highest_corner == CORNER_S) || (highest_corner == CORNER_E)) ? TILE_SIZE / 2 : 0);
482
483 SpriteBounds bounds{{x_bb, y_bb, TILE_HEIGHT}, {TILE_SIZE / 2, TILE_SIZE / 2, TILE_HEIGHT - 1}, {}};
484 AddSortableSpriteToDraw(halftile_base + highest_corner, PAL_NONE, *ti, bounds);
485 /* Reposition ground sprite back to original position after bounding box change above. This is similar to
486 * RemapCoords() but without zoom scaling. */
487 Point pt = {(y_bb - x_bb) * 2, y_bb + x_bb};
488 OffsetGroundSprite(-pt.x, -pt.y);
489 }
490 } else {
491 if (IsLeveledFoundation(f)) {
492 /* leveled foundation */
493 static constexpr SpriteBounds bounds{{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT - 1}, {}};
494 AddSortableSpriteToDraw(leveled_base + ti->tileh, PAL_NONE, *ti, bounds);
496 } else if (IsNonContinuousFoundation(f)) {
497 /* halftile foundation */
498 Corner halftile_corner = GetHalftileFoundationCorner(f);
499 int8_t x_bb = (((halftile_corner == CORNER_W) || (halftile_corner == CORNER_S)) ? TILE_SIZE / 2 : 0);
500 int8_t y_bb = (((halftile_corner == CORNER_S) || (halftile_corner == CORNER_E)) ? TILE_SIZE / 2 : 0);
501
502 SpriteBounds bounds{{x_bb, y_bb, 0}, {TILE_SIZE / 2, TILE_SIZE / 2, TILE_HEIGHT - 1}, {}};
503 AddSortableSpriteToDraw(halftile_base + halftile_corner, PAL_NONE, *ti, bounds);
504 /* Reposition ground sprite back to original position after bounding box change above. This is similar to
505 * RemapCoords() but without zoom scaling. */
506 Point pt = {(y_bb - x_bb) * 2, y_bb + x_bb};
507 OffsetGroundSprite(-pt.x, -pt.y);
508 } else if (IsSpecialRailFoundation(f)) {
509 /* anti-zig-zag foundation */
510 SpriteID spr;
511 if (ti->tileh == SLOPE_NS || ti->tileh == SLOPE_EW) {
512 /* half of leveled foundation under track corner */
514 } else {
515 /* tile-slope = sloped along X/Y, foundation-slope = three corners raised */
516 spr = inclined_base + 2 * GetRailFoundationCorner(f) + ((ti->tileh == SLOPE_SW || ti->tileh == SLOPE_NE) ? 1 : 0);
517 }
518 static constexpr SpriteBounds bounds{{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT - 1}, {}};
519 AddSortableSpriteToDraw(spr, PAL_NONE, *ti, bounds);
520 OffsetGroundSprite(0, 0);
521 } else {
522 /* inclined foundation */
523 uint8_t inclined = GetHighestSlopeCorner(ti->tileh) * 2 + (f == FOUNDATION_INCLINED_Y ? 1 : 0);
524
525 SpriteBounds bounds{{}, {1, 1, TILE_HEIGHT}, {}};
526 if (f == FOUNDATION_INCLINED_X) bounds.extent.x = TILE_SIZE;
527 if (f == FOUNDATION_INCLINED_Y) bounds.extent.y = TILE_SIZE;
528 AddSortableSpriteToDraw(inclined_base + inclined, PAL_NONE, *ti, bounds);
529 OffsetGroundSprite(0, 0);
530 }
531 ti->z += ApplyPixelFoundationToSlope(f, ti->tileh);
532 }
533}
534
535void DoClearSquare(TileIndex tile)
536{
537 /* If the tile can have animation and we clear it, delete it from the animated tile list. */
538 if (MayAnimateTile(tile)) DeleteAnimatedTile(tile, true);
539
540 bool remove = IsDockingTile(tile);
543 if (remove) RemoveDockingTile(tile);
544
547}
548
559TrackStatus GetTileTrackStatus(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
560{
561 return _tile_type_procs[GetTileType(tile)]->get_tile_track_status_proc(tile, mode, sub_mode, side);
562}
563
570void ChangeTileOwner(TileIndex tile, Owner old_owner, Owner new_owner)
571{
572 _tile_type_procs[GetTileType(tile)]->change_tile_owner_proc(tile, old_owner, new_owner);
573}
574
575void GetTileDesc(TileIndex tile, TileDesc &td)
576{
578}
579
586{
587 return _snow_line != nullptr;
588}
589
595void SetSnowLine(std::unique_ptr<SnowLine> &&snow_line)
596{
597 _snow_line = std::move(snow_line);
598}
599
605uint8_t GetSnowLine()
606{
608
609 TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date);
610 return _snow_line->table[ymd.month][ymd.day];
611}
612
619{
620 return _snow_line == nullptr ? _settings_game.game_creation.snow_line_height : _snow_line->highest_value;
621}
622
629{
630 return _snow_line == nullptr ? _settings_game.game_creation.snow_line_height : _snow_line->lowest_value;
631}
632
638{
639 _snow_line = nullptr;
640}
641
647{
648 auto check_tile = [](uint x, uint y) -> bool {
649 auto [slope, h] = GetTilePixelSlopeOutsideMap(x, y);
650 return ((slope == SLOPE_FLAT) && (h == 0));
651 };
652
653 /* Check the map corners. */
654 if (!check_tile(0, 0)) return false;
655 if (!check_tile(0, Map::SizeY())) return false;
656 if (!check_tile(Map::SizeX(), 0)) return false;
657 if (!check_tile(Map::SizeX(), Map::SizeY())) return false;
658
659 /* Check the map edges.*/
660 for (uint x = 0; x <= Map::SizeX(); x++) {
661 if (!check_tile(x, 0)) return false;
662 if (!check_tile(x, Map::SizeY())) return false;
663 }
664 for (uint y = 1; y < Map::SizeY(); y++) {
665 if (!check_tile(0, y)) return false;
666 if (!check_tile(Map::SizeX(), y)) return false;
667 }
668
669 return true;
670}
671
679{
681 bool do_clear = false;
682 /* Test for stuff which results in water when cleared. Then add the cost to also clear the water. */
683 if (flags.Test(DoCommandFlag::ForceClearTile) && HasTileWaterClass(tile) && IsTileOnWater(tile) && !IsWaterTile(tile) && !IsCoastTile(tile)) {
684 if (flags.Test(DoCommandFlag::Auto) && GetWaterClass(tile) == WaterClass::Canal) return CommandCost(STR_ERROR_MUST_DEMOLISH_CANAL_FIRST);
685 do_clear = true;
686 cost.AddCost(GetWaterClass(tile) == WaterClass::Canal ? _price[PR_CLEAR_CANAL] : _price[PR_CLEAR_WATER]);
687 }
688
690 if (c != nullptr && (int)GB(c->clear_limit, 16, 16) < 1) {
691 return CommandCost(STR_ERROR_CLEARING_LIMIT_REACHED);
692 }
693
694 const ClearedObjectArea *coa = FindClearedObject(tile);
695
696 /* If this tile was the first tile which caused object destruction, always
697 * pass it on to the tile_type_proc. That way multiple test runs and the exec run stay consistent. */
698 if (coa != nullptr && coa->first_tile != tile) {
699 /* If this tile belongs to an object which was already cleared via another tile, pretend it has been
700 * already removed.
701 * However, we need to check stuff, which is not the same for all object tiles. (e.g. being on water or not) */
702
703 /* If a object is removed, it leaves either bare land or water. */
704 if (flags.Test(DoCommandFlag::NoWater) && HasTileWaterClass(tile) && IsTileOnWater(tile)) {
705 return CommandCost(STR_ERROR_CAN_T_BUILD_ON_WATER);
706 }
707 } else {
708 cost.AddCost(_tile_type_procs[GetTileType(tile)]->clear_tile_proc(tile, flags));
709 }
710
711 if (flags.Test(DoCommandFlag::Execute)) {
712 if (c != nullptr) c->clear_limit -= 1 << 16;
713 if (do_clear) {
714 if (IsWaterTile(tile) && IsCanal(tile)) {
715 Owner owner = GetTileOwner(tile);
716 if (Company::IsValidID(owner)) {
717 Company::Get(owner)->infrastructure.water--;
719 }
720 }
721 DoClearSquare(tile);
723 }
724 }
725 return cost;
726}
727
736std::tuple<CommandCost, Money> CmdClearArea(DoCommandFlags flags, TileIndex tile, TileIndex start_tile, bool diagonal)
737{
738 if (start_tile >= Map::Size()) return { CMD_ERROR, 0 };
739
742 CommandCost last_error = CMD_ERROR;
743 bool had_success = false;
744
746 int limit = (c == nullptr ? INT32_MAX : GB(c->clear_limit, 16, 16));
747
748 if (tile != start_tile) flags.Set(DoCommandFlag::ForceClearTile);
749
750 std::unique_ptr<TileIterator> iter = TileIterator::Create(tile, start_tile, diagonal);
751 for (; *iter != INVALID_TILE; ++(*iter)) {
752 TileIndex t = *iter;
754 if (ret.Failed()) {
755 last_error = std::move(ret);
756
757 /* We may not clear more tiles. */
758 if (c != nullptr && GB(c->clear_limit, 16, 16) < 1) break;
759 continue;
760 }
761
762 had_success = true;
763 if (flags.Test(DoCommandFlag::Execute)) {
764 money -= ret.GetCost();
765 if (ret.GetCost() > 0 && money < 0) {
766 return { cost, ret.GetCost() };
767 }
769
770 /* draw explosion animation...
771 * Disable explosions when game is paused. Looks silly and blocks the view. */
772 if ((t == tile || t == start_tile) && _pause_mode.None()) {
773 /* big explosion in two corners, or small explosion for single tiles */
775 TileX(tile) == TileX(start_tile) && TileY(tile) == TileY(start_tile) ? EV_EXPLOSION_SMALL : EV_EXPLOSION_LARGE
776 );
777 }
778 } else {
779 /* When we're at the clearing limit we better bail (unneed) testing as well. */
780 if (ret.GetCost() != 0 && --limit <= 0) break;
781 }
782 cost.AddCost(ret.GetCost());
783 }
784
785 return { had_success ? cost : last_error, 0 };
786}
787
788
789TileIndex _cur_tileloop_tile;
790
795{
797
798 /* The pseudorandom sequence of tiles is generated using a Galois linear feedback
799 * shift register (LFSR). This allows a deterministic pseudorandom ordering, but
800 * still with minimal state and fast iteration. */
801
802 /* Maximal length LFSR feedback terms, from 12-bit (for 64x64 maps) to 24-bit (for 4096x4096 maps).
803 * Extracted from http://www.ece.cmu.edu/~koopman/lfsr/ */
804 static const uint32_t feedbacks[] = {
805 0xD8F, 0x1296, 0x2496, 0x4357, 0x8679, 0x1030E, 0x206CD, 0x403FE, 0x807B8, 0x1004B2, 0x2006A8, 0x4004B2, 0x800B87
806 };
807 static_assert(lengthof(feedbacks) == 2 * MAX_MAP_SIZE_BITS - 2 * MIN_MAP_SIZE_BITS + 1);
808 const uint32_t feedback = feedbacks[Map::LogX() + Map::LogY() - 2 * MIN_MAP_SIZE_BITS];
809
810 /* We update every tile every TILE_UPDATE_FREQUENCY ticks, so divide the map size by 2^TILE_UPDATE_FREQUENCY_LOG = TILE_UPDATE_FREQUENCY */
811 static_assert(2 * MIN_MAP_SIZE_BITS >= TILE_UPDATE_FREQUENCY_LOG);
812 uint count = 1 << (Map::LogX() + Map::LogY() - TILE_UPDATE_FREQUENCY_LOG);
813
814 TileIndex tile = _cur_tileloop_tile;
815 /* The LFSR cannot have a zeroed state. */
816 assert(tile != 0);
817
818 /* Manually update tile 0 every TILE_UPDATE_FREQUENCY ticks - the LFSR never iterates over it itself. */
820 _tile_type_procs[GetTileType(0)]->tile_loop_proc(TileIndex{});
821 count--;
822 }
823
824 while (count--) {
825 _tile_type_procs[GetTileType(tile)]->tile_loop_proc(tile);
826
827 /* Get the next tile in sequence using a Galois LFSR. */
828 tile = TileIndex{(tile.base() >> 1) ^ (-(int32_t)(tile.base() & 1) & feedback)};
829 }
830
831 _cur_tileloop_tile = tile;
832}
833
834void InitializeLandscape()
835{
836 for (uint y = _settings_game.construction.freeform_edges ? 1 : 0; y < Map::MaxY(); y++) {
837 for (uint x = _settings_game.construction.freeform_edges ? 1 : 0; x < Map::MaxX(); x++) {
838 MakeClear(TileXY(x, y), CLEAR_GRASS, 3);
839 SetTileHeight(TileXY(x, y), 0);
842 }
843 }
844
845 for (uint x = 0; x < Map::SizeX(); x++) MakeVoid(TileXY(x, Map::MaxY()));
846 for (uint y = 0; y < Map::SizeY(); y++) MakeVoid(TileXY(Map::MaxX(), y));
847}
848
849static const uint8_t _genterrain_tbl_1[5] = { 10, 22, 33, 37, 4 };
850static const uint8_t _genterrain_tbl_2[5] = { 0, 0, 0, 0, 33 };
851
852static void GenerateTerrain(int type, uint flag)
853{
854 uint32_t r = Random();
855
856 /* Choose one of the templates from the graphics file. */
857 const Sprite *templ = GetSprite((((r >> 24) * _genterrain_tbl_1[type]) >> 8) + _genterrain_tbl_2[type] + SPR_MAPGEN_BEGIN, SpriteType::MapGen);
858 if (templ == nullptr) UserError("Map generator sprites could not be loaded");
859
860 /* Chose a random location to apply the template to. */
861 uint x = r & Map::MaxX();
862 uint y = (r >> Map::LogX()) & Map::MaxY();
863
864 /* Make sure the template is not too close to the upper edges; bottom edges are checked later. */
865 uint edge_distance = 1 + (_settings_game.construction.freeform_edges ? 1 : 0);
866 if (x <= edge_distance || y <= edge_distance) return;
867
868 DiagDirection direction = (DiagDirection)GB(r, 22, 2);
869 uint w = templ->width;
870 uint h = templ->height;
871
872 if (DiagDirToAxis(direction) == AXIS_Y) std::swap(w, h);
873
874 const uint8_t *p = reinterpret_cast<const uint8_t *>(templ->data);
875
876 if ((flag & 4) != 0) {
877 /* This is only executed in secondary/tertiary loops to generate the terrain for arctic and tropic.
878 * It prevents the templates to be applied to certain parts of the map based on the flags, thus
879 * creating regions with different elevations/topography. */
880 uint xw = x * Map::SizeY();
881 uint yw = y * Map::SizeX();
882 uint bias = (Map::SizeX() + Map::SizeY()) * 16;
883
884 switch (flag & 3) {
885 default: NOT_REACHED();
886 case 0:
887 if (xw + yw > Map::Size() - bias) return;
888 break;
889
890 case 1:
891 if (yw < xw + bias) return;
892 break;
893
894 case 2:
895 if (xw + yw < Map::Size() + bias) return;
896 break;
897
898 case 3:
899 if (xw < yw + bias) return;
900 break;
901 }
902 }
903
904 /* Ensure the template does not overflow at the bottom edges of the map; upper edges were checked before. */
905 if (x + w >= Map::MaxX()) return;
906 if (y + h >= Map::MaxY()) return;
907
908 TileIndex tile = TileXY(x, y);
909
910 /* Get the template and overlay in a particular direction over the map's height from the given
911 * origin point (tile), and update the map's height everywhere where the height from the template
912 * is higher than the height of the map. In other words, this only raises the tile heights. */
913 switch (direction) {
914 default: NOT_REACHED();
915 case DIAGDIR_NE:
916 do {
917 TileIndex tile_cur = tile;
918
919 for (uint w_cur = w; w_cur != 0; --w_cur) {
920 if (GB(*p, 0, 4) >= TileHeight(tile_cur)) SetTileHeight(tile_cur, GB(*p, 0, 4));
921 p++;
922 tile_cur += TileDiffXY(1, 0);
923 }
924 tile += TileDiffXY(0, 1);
925 } while (--h != 0);
926 break;
927
928 case DIAGDIR_SE:
929 do {
930 TileIndex tile_cur = tile;
931
932 for (uint h_cur = h; h_cur != 0; --h_cur) {
933 if (GB(*p, 0, 4) >= TileHeight(tile_cur)) SetTileHeight(tile_cur, GB(*p, 0, 4));
934 p++;
935 tile_cur += TileDiffXY(0, 1);
936 }
937 tile += TileDiffXY(1, 0);
938 } while (--w != 0);
939 break;
940
941 case DIAGDIR_SW:
942 tile += TileDiffXY(w - 1, 0);
943 do {
944 TileIndex tile_cur = tile;
945
946 for (uint w_cur = w; w_cur != 0; --w_cur) {
947 if (GB(*p, 0, 4) >= TileHeight(tile_cur)) SetTileHeight(tile_cur, GB(*p, 0, 4));
948 p++;
949 tile_cur -= TileDiffXY(1, 0);
950 }
951 tile += TileDiffXY(0, 1);
952 } while (--h != 0);
953 break;
954
955 case DIAGDIR_NW:
956 tile += TileDiffXY(0, h - 1);
957 do {
958 TileIndex tile_cur = tile;
959
960 for (uint h_cur = h; h_cur != 0; --h_cur) {
961 if (GB(*p, 0, 4) >= TileHeight(tile_cur)) SetTileHeight(tile_cur, GB(*p, 0, 4));
962 p++;
963 tile_cur -= TileDiffXY(0, 1);
964 }
965 tile += TileDiffXY(1, 0);
966 } while (--w != 0);
967 break;
968 }
969}
970
971
972#include "table/genland.h"
973
974static void CreateDesertOrRainForest(uint desert_tropic_line)
975{
976 uint update_freq = Map::Size() / 4;
977
978 for (const auto tile : Map::Iterate()) {
979 if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
980
981 if (!IsValidTile(tile)) continue;
982
983 auto allows_desert = [tile, desert_tropic_line](auto &offset) {
984 TileIndex t = AddTileIndexDiffCWrap(tile, offset);
985 return t == INVALID_TILE || (TileHeight(t) < desert_tropic_line && !IsTileType(t, MP_WATER));
986 };
987 if (std::all_of(std::begin(_make_desert_or_rainforest_data), std::end(_make_desert_or_rainforest_data), allows_desert)) {
989 }
990 }
991
992 for (uint i = 0; i != TILE_UPDATE_FREQUENCY; i++) {
994
995 RunTileLoop();
996 }
997
998 for (const auto tile : Map::Iterate()) {
999 if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
1000
1001 if (!IsValidTile(tile)) continue;
1002
1003 auto allows_rainforest = [tile](auto &offset) {
1004 TileIndex t = AddTileIndexDiffCWrap(tile, offset);
1005 return t == INVALID_TILE || !IsTileType(t, MP_CLEAR) || !IsClearGround(t, CLEAR_DESERT);
1006 };
1007 if (std::all_of(std::begin(_make_desert_or_rainforest_data), std::end(_make_desert_or_rainforest_data), allows_rainforest)) {
1009 }
1010 }
1011}
1012
1018static bool FindSpring(TileIndex tile)
1019{
1020 int reference_height;
1021 if (!IsTileFlat(tile, &reference_height) || IsWaterTile(tile)) return false;
1022
1023 /* In the tropics rivers start in the rainforest. */
1024 if (_settings_game.game_creation.landscape == LandscapeType::Tropic && GetTropicZone(tile) != TROPICZONE_RAINFOREST) return false;
1025
1026 /* Are there enough higher tiles to warrant a 'spring'? */
1027 uint num = 0;
1028 for (int dx = -1; dx <= 1; dx++) {
1029 for (int dy = -1; dy <= 1; dy++) {
1030 TileIndex t = TileAddWrap(tile, dx, dy);
1031 if (t != INVALID_TILE && GetTileMaxZ(t) > reference_height) num++;
1032 }
1033 }
1034
1035 if (num < 4) return false;
1036
1037 /* Are we near the top of a hill? */
1038 for (int dx = -16; dx <= 16; dx++) {
1039 for (int dy = -16; dy <= 16; dy++) {
1040 TileIndex t = TileAddWrap(tile, dx, dy);
1041 if (t != INVALID_TILE && GetTileMaxZ(t) > reference_height + 2) return false;
1042 }
1043 }
1044
1045 return true;
1046}
1047
1054static bool IsValidRiverTerminusTile(TileIndex tile, uint height)
1055{
1056 if (!IsValidTile(tile) || TileHeight(tile) != height || !IsTileFlat(tile)) return false;
1057 if (_settings_game.game_creation.landscape == LandscapeType::Tropic && GetTropicZone(tile) == TROPICZONE_DESERT) return false;
1058
1059 return true;
1060}
1061
1067static void MakeLake(TileIndex lake_centre, uint height_lake)
1068{
1070 uint diameter = RandomRange(8) + 3;
1071
1072 /* Run the loop twice, so artefacts from going circular in one direction get (mostly) hidden. */
1073 for (uint loops = 0; loops < 2; ++loops) {
1074 for (TileIndex tile : SpiralTileSequence(lake_centre, diameter)) {
1075 if (!IsValidRiverTerminusTile(tile, height_lake)) continue;
1076 for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
1077 TileIndex t = tile + TileOffsByDiagDir(d);
1078 if (IsWaterTile(t)) {
1080 break;
1081 }
1082 }
1083 }
1084 }
1085}
1086
1093static void MakeWetlands(TileIndex centre, uint height, uint river_length)
1094{
1096
1097 uint diameter = std::max((river_length), 16u);
1098
1099 /* Some wetlands have trees planted among the water tiles. */
1100 bool has_trees = Chance16(1, 2);
1101
1102 /* Create the main wetland area. */
1103 for (TileIndex tile : SpiralTileSequence(centre, diameter)) {
1104 if (!IsValidRiverTerminusTile(tile, height)) continue;
1105
1106 /* Don't make a perfect square, but a circle with a noisy border. */
1107 uint radius = diameter / 2;
1108 if ((DistanceSquare(tile, centre) > radius * radius) && Chance16(3, 4)) continue;
1109
1110 if (Chance16(1, 3)) {
1111 /* This tile is water. */
1113 } else if (IsTileType(tile, MP_CLEAR)) {
1114 /* This tile is ground, which we always make rough. */
1116 /* Maybe place trees? */
1117 if (has_trees && _settings_game.game_creation.tree_placer != TP_NONE) {
1118 PlaceTree(tile, Random(), true);
1119 }
1120 }
1121 }
1122}
1123
1131{
1132 if (!IsValidTile(tile)) return false;
1133
1134 /* We don't want to end the river at the entry of the valley. */
1135 if (tile == begin) return false;
1136
1137 /* We don't want the river to end in the desert. */
1138 if (_settings_game.game_creation.landscape == LandscapeType::Tropic && GetTropicZone(tile) == TROPICZONE_DESERT) return false;
1139
1140 /* Only end on flat slopes. */
1141 int height_lake;
1142 if (!IsTileFlat(tile, &height_lake)) return false;
1143
1144 /* Only build at the height of the river. */
1145 int height_begin = TileHeight(begin);
1146 if (height_lake != height_begin) return false;
1147
1148 /* Checks successful, time to build.
1149 * Chance of water feature is split evenly between a lake, a wetland with trees, and a wetland with grass. */
1150 if (Chance16(1, 3)) {
1151 MakeLake(tile, height_lake);
1152 } else {
1153 MakeWetlands(tile, height_lake, DistanceManhattan(tile, begin));
1154 }
1155
1156 /* This is the new end of the river. */
1157 return true;
1158}
1159
1165void RiverMakeWider(TileIndex tile, TileIndex origin_tile)
1166{
1167 /* Don't expand into void tiles. */
1168 if (!IsValidTile(tile)) return;
1169
1170 /* If the tile is already sea or river, don't expand. */
1171 if (IsWaterTile(tile)) return;
1172
1173 /* If the tile is at height 0 after terraforming but the ocean hasn't flooded yet, don't build river. */
1174 if (GetTileMaxZ(tile) == 0) return;
1175
1176 Slope cur_slope = GetTileSlope(tile);
1177 Slope desired_slope = GetTileSlope(origin_tile); // Initialize matching the origin tile as a shortcut if no terraforming is needed.
1178
1179 /* Never flow uphill. */
1180 if (GetTileMaxZ(tile) > GetTileMaxZ(origin_tile)) return;
1181
1182 /* If the new tile can't hold a river tile, try terraforming. */
1183 if (!IsTileFlat(tile) && !IsInclinedSlope(cur_slope)) {
1184 /* Don't try to terraform steep slopes. */
1185 if (IsSteepSlope(cur_slope)) return;
1186
1187 bool flat_river_found = false;
1188 bool sloped_river_found = false;
1189
1190 /* There are two common possibilities:
1191 * 1. River flat, adjacent tile has one corner lowered.
1192 * 2. River descending, adjacent tile has either one or three corners raised.
1193 */
1194
1195 /* First, determine the desired slope based on adjacent river tiles. This doesn't necessarily match the origin tile for the SpiralTileSequence. */
1196 for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
1197 TileIndex other_tile = TileAddByDiagDir(tile, d);
1198 Slope other_slope = GetTileSlope(other_tile);
1199
1200 /* Only consider river tiles. */
1201 if (IsWaterTile(other_tile) && IsRiver(other_tile)) {
1202 /* If the adjacent river tile flows downhill, we need to check where we are relative to the slope. */
1203 if (IsInclinedSlope(other_slope) && GetTileMaxZ(tile) == GetTileMaxZ(other_tile)) {
1204 /* Check for a parallel slope. If we don't find one, we're above or below the slope instead. */
1207 desired_slope = other_slope;
1208 sloped_river_found = true;
1209 break;
1210 }
1211 }
1212 /* If we find an adjacent river tile, remember it. We'll terraform to match it later if we don't find a slope. */
1213 if (IsTileFlat(other_tile)) flat_river_found = true;
1214 }
1215 }
1216 /* We didn't find either an inclined or flat river, so we're climbing the wrong slope. Bail out. */
1217 if (!sloped_river_found && !flat_river_found) return;
1218
1219 /* We didn't find an inclined river, but there is a flat river. */
1220 if (!sloped_river_found && flat_river_found) desired_slope = SLOPE_FLAT;
1221
1222 /* Now that we know the desired slope, it's time to terraform! */
1223
1224 /* If the river is flat and the adjacent tile has one corner lowered, we want to raise it. */
1225 if (desired_slope == SLOPE_FLAT && IsSlopeWithThreeCornersRaised(cur_slope)) {
1226 /* Make sure we're not affecting an existing river slope tile. */
1227 for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
1228 TileIndex other_tile = TileAddByDiagDir(tile, d);
1229 if (IsInclinedSlope(GetTileSlope(other_tile)) && IsWaterTile(other_tile)) return;
1230 }
1232
1233 /* If the river is descending and the adjacent tile has either one or three corners raised, we want to make it match the slope. */
1234 } else if (IsInclinedSlope(desired_slope)) {
1235 /* Don't break existing flat river tiles by terraforming under them. */
1236 DiagDirection river_direction = ReverseDiagDir(GetInclinedSlopeDirection(desired_slope));
1237
1238 for (DiagDirDiff d = DIAGDIRDIFF_BEGIN; d < DIAGDIRDIFF_END; d++) {
1239 /* We don't care about downstream or upstream tiles, just the riverbanks. */
1240 if (d == DIAGDIRDIFF_SAME || d == DIAGDIRDIFF_REVERSE) continue;
1241
1242 TileIndex other_tile = (TileAddByDiagDir(tile, ChangeDiagDir(river_direction, d)));
1243 if (IsWaterTile(other_tile) && IsRiver(other_tile) && IsTileFlat(other_tile)) return;
1244 }
1245
1246 /* Get the corners which are different between the current and desired slope. */
1247 Slope to_change = cur_slope ^ desired_slope;
1248
1249 /* Lower unwanted corners first. If only one corner is raised, no corners need lowering. */
1250 if (!IsSlopeWithOneCornerRaised(cur_slope)) {
1251 to_change = to_change & ComplementSlope(desired_slope);
1253 }
1254
1255 /* Now check the match and raise any corners needed. */
1256 cur_slope = GetTileSlope(tile);
1257 if (cur_slope != desired_slope && IsSlopeWithOneCornerRaised(cur_slope)) {
1258 to_change = cur_slope ^ desired_slope;
1260 }
1261 }
1262 /* Update cur_slope after possibly terraforming. */
1263 cur_slope = GetTileSlope(tile);
1264 }
1265
1266 /* Sloped rivers need water both upstream and downstream. */
1267 if (IsInclinedSlope(cur_slope)) {
1268 DiagDirection slope_direction = GetInclinedSlopeDirection(cur_slope);
1269
1270 TileIndex upstream_tile = TileAddByDiagDir(tile, slope_direction);
1271 TileIndex downstream_tile = TileAddByDiagDir(tile, ReverseDiagDir(slope_direction));
1272
1273 /* Don't look outside the map. */
1274 if (!IsValidTile(upstream_tile) || !IsValidTile(downstream_tile)) return;
1275
1276 /* Downstream might be new ocean created by our terraforming, and it hasn't flooded yet. */
1277 bool downstream_is_ocean = GetTileZ(downstream_tile) == 0 && (GetTileSlope(downstream_tile) == SLOPE_FLAT || IsSlopeWithOneCornerRaised(GetTileSlope(downstream_tile)));
1278
1279 /* If downstream is dry, flat, and not ocean, try making it a river tile. */
1280 if (!IsWaterTile(downstream_tile) && !downstream_is_ocean) {
1281 /* If the tile upstream isn't flat, don't bother. */
1282 if (GetTileSlope(downstream_tile) != SLOPE_FLAT) return;
1283
1284 MakeRiverAndModifyDesertZoneAround(downstream_tile);
1285 }
1286
1287 /* If upstream is dry and flat, try making it a river tile. */
1288 if (!IsWaterTile(upstream_tile)) {
1289 /* If the tile upstream isn't flat, don't bother. */
1290 if (GetTileSlope(upstream_tile) != SLOPE_FLAT) return;
1291
1293 }
1294 }
1295
1296 /* If the tile slope matches the desired slope, add a river tile. */
1297 if (cur_slope == desired_slope) {
1299 }
1300}
1301
1309{
1310 assert(DistanceManhattan(begin, end) == 1);
1311
1312 auto [slope_end, height_end] = GetTileSlopeZ(end);
1313
1314 /* Slope either is inclined or flat; rivers don't support other slopes. */
1315 if (slope_end != SLOPE_FLAT && !IsInclinedSlope(slope_end)) return false;
1316
1317 auto [slope_begin, height_begin] = GetTileSlopeZ(begin);
1318
1319 /* It can't flow uphill. */
1320 if (height_end > height_begin) return false;
1321
1322 /* Slope continues, then it must be lower... */
1323 if (slope_end == slope_begin && height_end < height_begin) return true;
1324
1325 /* ... or either end must be flat. */
1326 return slope_end == SLOPE_FLAT || slope_begin == SLOPE_FLAT;
1327}
1328
1336static bool CountConnectedSeaTiles(TileIndex tile, std::unordered_set<TileIndex> &sea, const uint limit)
1337{
1338 /* This tile might not be sea. */
1339 if (!IsWaterTile(tile) || GetWaterClass(tile) != WaterClass::Sea || !IsTileFlat(tile)) return false;
1340
1341 /* If we've found an edge tile, we are "connected to the sea outside the map." */
1342 if (DistanceFromEdge(tile) <= 1) return true;
1343
1344 /* We have now evaluated this tile and don't want to check it again. */
1345 sea.insert(tile);
1346
1347 /* We might want to cut our search short if the size of the sea is "big enough".
1348 * Count this tile but don't check its neighbors. */
1349 if (sea.size() > limit) return false;
1350
1351 /* Count adjacent tiles using recusion. */
1352 for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
1353 TileIndex t = tile + TileOffsByDiagDir(d);
1354 if (IsValidTile(t) && !sea.contains(t)) {
1355 if (CountConnectedSeaTiles(t, sea, limit)) return true;
1356 }
1357 }
1358
1359 return false;
1360}
1361
1369static std::tuple<bool, bool> FlowRiver(TileIndex spring, TileIndex begin, uint min_river_length)
1370{
1371 if (IsWaterTile(begin)) {
1372 return { DistanceManhattan(spring, begin) > min_river_length, GetTileZ(begin) == 0 };
1373 }
1374
1375 int height_begin = TileHeight(begin);
1376
1377 std::unordered_set<TileIndex> marks;
1378 marks.insert(begin);
1379
1380 std::vector<TileIndex> queue;
1381 queue.push_back(begin);
1382
1383 /* Breadth first search for the closest tile we can flow down to.
1384 * We keep the queue to find the Nth tile for lake guessing. The tiles
1385 * in the queue are neatly ordered by insertion.
1386 */
1387 bool found = false;
1388 TileIndex end;
1389 for (size_t i = 0; i != queue.size(); i++) {
1390 end = queue[i];
1391
1392 int height_end;
1393 if (IsTileFlat(end, &height_end) && (height_end < height_begin || (height_end == height_begin && IsWaterTile(end)))) {
1394 if (IsWaterTile(end) && GetWaterClass(end) == WaterClass::Sea) {
1395 /* If we've found the sea, make sure it's large enough. Scale by the map size but set a cap to avoid performance issues on large maps. */
1396 const uint MAX_SEA_SIZE_THRESHOLD = 1024;
1397 const uint SEA_SIZE_THRESHOLD = std::min(static_cast<uint>(2 * std::sqrt(Map::SizeX() * Map::SizeY())), MAX_SEA_SIZE_THRESHOLD);
1398 std::unordered_set<TileIndex> sea;
1399 /* Count the connected tiles, if the sea is large we can end the river here. */
1400 bool found_edge = CountConnectedSeaTiles(end, sea, SEA_SIZE_THRESHOLD);
1401 if (found_edge || sea.size() > SEA_SIZE_THRESHOLD) {
1402 found = true;
1403 break;
1404 } else {
1405 /* Sea is too small, flatten it so the river keeps looking or forms a lake / wetland. */
1406 for (TileIndex sea_tile : sea) {
1408 Slope slope = ComplementSlope(GetTileSlope(sea_tile));
1410 }
1411 }
1412 } else {
1413 /* We've found a river. */
1414 found = true;
1415 break;
1416 }
1417 }
1418
1419 for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
1420 TileIndex t = end + TileOffsByDiagDir(d);
1421 if (IsValidTile(t) && !marks.contains(t) && RiverFlowsDown(end, t)) {
1422 marks.insert(t);
1423 queue.push_back(t);
1424 }
1425 }
1426 }
1427
1428 bool main_river = false;
1429 if (found) {
1430 /* Flow further down hill. */
1431 std::tie(found, main_river) = FlowRiver(spring, end, min_river_length);
1432 } else if (queue.size() > 32) {
1433 /* Maybe we can make a lake. Find the Nth of the considered tiles. */
1434 TileIndex lake_centre = queue[RandomRange(static_cast<uint32_t>(queue.size()))];
1435 if (DistanceManhattan(spring, lake_centre) > min_river_length) {
1436 if (TryMakeRiverTerminus(lake_centre, begin)) {
1437 /* If successful, this becomes the new end of the river. */
1438 end = lake_centre;
1439 found = true;
1440 }
1441 }
1442 }
1443
1444 if (found) YapfBuildRiver(begin, end, spring, main_river);
1445 return { found, main_river };
1446}
1447
1451static void CreateRivers()
1452{
1454 if (amount == 0) return;
1455
1457 const uint num_short_rivers = wells - std::max(1u, wells / 10);
1458 SetGeneratingWorldProgress(GWP_RIVER, wells + TILE_UPDATE_FREQUENCY / 64); // Include the tile loop calls below.
1459
1460 /* Try to create long rivers. */
1461 for (; wells > num_short_rivers; wells--) {
1463 bool done = false;
1464 for (int tries = 0; tries < 512; tries++) {
1465 for (auto t : SpiralTileSequence(RandomTile(), 8)) {
1466 if (FindSpring(t)) {
1467 done = std::get<0>(FlowRiver(t, t, _settings_game.game_creation.min_river_length * 4));
1468 break;
1469 }
1470 }
1471 if (done) break;
1472 }
1473 }
1474
1475 /* Try to create short rivers. */
1476 for (; wells != 0; wells--) {
1478 bool done = false;
1479 for (int tries = 0; tries < 128; tries++) {
1480 for (auto t : SpiralTileSequence(RandomTile(), 8)) {
1481 if (FindSpring(t)) {
1482 done = std::get<0>(FlowRiver(t, t, _settings_game.game_creation.min_river_length));
1483 break;
1484 }
1485 }
1486 if (done) break;
1487 }
1488 }
1489
1490 /* Widening rivers may have left some tiles requiring to be watered. */
1491 ConvertGroundTilesIntoWaterTiles();
1492
1493 /* Run tile loop to update the ground density. */
1494 for (uint i = 0; i != TILE_UPDATE_FREQUENCY; i++) {
1496 RunTileLoop();
1497 }
1498}
1499
1517static uint CalculateCoverageLine(uint coverage, uint edge_multiplier)
1518{
1519 /* Histogram of how many tiles per height level exist. */
1520 std::array<int, MAX_TILE_HEIGHT + 1> histogram = {};
1521 /* Histogram of how many neighbour tiles are lower than the tiles of the height level. */
1522 std::array<int, MAX_TILE_HEIGHT + 1> edge_histogram = {};
1523
1524 /* Build a histogram of the map height. */
1525 for (const auto tile : Map::Iterate()) {
1526 uint h = TileHeight(tile);
1527 histogram[h]++;
1528
1529 if (edge_multiplier != 0) {
1530 /* Check if any of our neighbours is below us. */
1531 for (DiagDirection dir = DIAGDIR_BEGIN; dir != DIAGDIR_END; dir++) {
1532 TileIndex neighbour_tile = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDiagDir(dir));
1533 if (IsValidTile(neighbour_tile) && TileHeight(neighbour_tile) < h) {
1534 edge_histogram[h]++;
1535 }
1536 }
1537 }
1538 }
1539
1540 /* The amount of land we have is the map size minus the first (sea) layer. */
1541 uint land_tiles = Map::Size() - histogram[0];
1542 int best_score = land_tiles;
1543
1544 /* Our goal is the coverage amount of the land-mass. */
1545 int goal_tiles = land_tiles * coverage / 100;
1546
1547 /* We scan from top to bottom. */
1548 uint h = MAX_TILE_HEIGHT;
1549 uint best_h = h;
1550
1551 int current_tiles = 0;
1552 for (; h > 0; h--) {
1553 current_tiles += histogram[h];
1554 int current_score = goal_tiles - current_tiles;
1555
1556 /* Tropic grows from water and mountains into the desert. This is a
1557 * great visual, but it also means we* need to take into account how
1558 * much less desert tiles are being created if we are on this
1559 * height-level. We estimate this based on how many neighbouring
1560 * tiles are below us for a given length, assuming that is where
1561 * tropic is growing from.
1562 */
1563 if (edge_multiplier != 0 && h > 1) {
1564 /* From water tropic tiles grow for a few tiles land inward. */
1565 current_score -= edge_histogram[1] * edge_multiplier;
1566 /* Tropic tiles grow into the desert for a few tiles. */
1567 current_score -= edge_histogram[h] * edge_multiplier;
1568 }
1569
1570 if (std::abs(current_score) < std::abs(best_score)) {
1571 best_score = current_score;
1572 best_h = h;
1573 }
1574
1575 /* Always scan all height-levels, as h == 1 might give a better
1576 * score than any before. This is true for example with 0% desert
1577 * coverage. */
1578 }
1579
1580 return best_h;
1581}
1582
1587{
1588 /* We do not have snow sprites on coastal tiles, so never allow "1" as height. */
1590}
1591
1596static uint8_t CalculateDesertLine()
1597{
1598 /* CalculateCoverageLine() runs from top to bottom, so we need to invert the coverage. */
1600}
1601
1602bool GenerateLandscape(uint8_t mode)
1603{
1604 /* Number of steps of landscape generation */
1605 static constexpr uint GLS_HEIGHTMAP = 3;
1606 static constexpr uint GLS_TERRAGENESIS = 4;
1607 static constexpr uint GLS_ORIGINAL = 2;
1608 static constexpr uint GLS_TROPIC = 12;
1609 static constexpr uint GLS_OTHER = 0;
1610 uint steps = (_settings_game.game_creation.landscape == LandscapeType::Tropic) ? GLS_TROPIC : GLS_OTHER;
1611
1612 if (mode == GWM_HEIGHTMAP) {
1613 SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_HEIGHTMAP);
1615 return false;
1616 }
1619 SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_TERRAGENESIS);
1621 } else {
1622 SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_ORIGINAL);
1624 for (uint x = 0; x < Map::SizeX(); x++) MakeVoid(TileXY(x, 0));
1625 for (uint y = 0; y < Map::SizeY(); y++) MakeVoid(TileXY(0, y));
1626 }
1628 case LandscapeType::Arctic: {
1629 uint32_t r = Random();
1630
1631 for (uint i = Map::ScaleBySize(GB(r, 0, 7) + 950); i != 0; --i) {
1632 GenerateTerrain(2, 0);
1633 }
1634
1635 uint flag = GB(r, 7, 2) | 4;
1636 for (uint i = Map::ScaleBySize(GB(r, 9, 7) + 450); i != 0; --i) {
1637 GenerateTerrain(4, flag);
1638 }
1639 break;
1640 }
1641
1642 case LandscapeType::Tropic: {
1643 uint32_t r = Random();
1644
1645 for (uint i = Map::ScaleBySize(GB(r, 0, 7) + 170); i != 0; --i) {
1646 GenerateTerrain(0, 0);
1647 }
1648
1649 uint flag = GB(r, 7, 2) | 4;
1650 for (uint i = Map::ScaleBySize(GB(r, 9, 8) + 1700); i != 0; --i) {
1651 GenerateTerrain(0, flag);
1652 }
1653
1654 flag ^= 2;
1655
1656 for (uint i = Map::ScaleBySize(GB(r, 17, 7) + 410); i != 0; --i) {
1657 GenerateTerrain(3, flag);
1658 }
1659 break;
1660 }
1661
1662 default: {
1663 uint32_t r = Random();
1664
1666 uint i = Map::ScaleBySize(GB(r, 0, 7) + (3 - _settings_game.difficulty.quantity_sea_lakes) * 256 + 100);
1667 for (; i != 0; --i) {
1668 /* Make sure we do not overflow. */
1669 GenerateTerrain(Clamp(_settings_game.difficulty.terrain_type, 0, 3), 0);
1670 }
1671 break;
1672 }
1673 }
1674 }
1675
1676 /* Do not call IncreaseGeneratingWorldProgress() before FixSlopes(),
1677 * it allows screen redraw. Drawing of broken slopes crashes the game */
1678 FixSlopes();
1681
1682 ConvertGroundTilesIntoWaterTiles();
1685
1687 case LandscapeType::Arctic:
1689 break;
1690
1691 case LandscapeType::Tropic: {
1692 uint desert_tropic_line = CalculateDesertLine();
1693 CreateDesertOrRainForest(desert_tropic_line);
1694 break;
1695 }
1696
1697 default:
1698 break;
1699 }
1700
1701 CreateRivers();
1702 return true;
1703}
1704
1705void OnTick_Town();
1706void OnTick_Trees();
1707void OnTick_Station();
1708void OnTick_Industry();
1709
1710void OnTick_Companies();
1711void OnTick_LinkGraph();
1712
1713void CallLandscapeTick()
1714{
1715 {
1717
1718 OnTick_Town();
1719 OnTick_Trees();
1720 OnTick_Station();
1721 OnTick_Industry();
1722 }
1723
1726}
void DeleteAnimatedTile(TileIndex tile, bool immediate)
Stops animation on the given tile.
Tile animation!
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
@ CLEAR_ROUGH
3
Definition clear_map.h:21
void MakeClear(Tile t, ClearGround g, uint density)
Make a clear tile.
Definition clear_map.h:247
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:146
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:50
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:99
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:1543
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.
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 bool TryMakeRiverTerminus(TileIndex tile, TileIndex begin)
Try to end a river at a tile which is not the sea.
static uint CalculateCoverageLine(uint coverage, uint edge_multiplier)
Calculate what height would be needed to cover N% of the landmass.
static bool IsValidRiverTerminusTile(TileIndex tile, uint height)
Is this a valid tile for the water feature at the end of a river?
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:88
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.
static void MakeWetlands(TileIndex centre, uint height, uint river_length)
Make wetlands around the given tile.
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:68
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:54
static void MakeLake(TileIndex lake_centre, uint height_lake)
Make a lake centred on the given tile, of a random diameter.
void OnTick_Town()
Iterate through all towns and call their tick handler.
Definition town_cmd.cpp:940
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:53
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.
static bool CountConnectedSeaTiles(TileIndex tile, std::unordered_set< TileIndex > &sea, const uint limit)
Find the size of a patch of connected sea tiles.
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:89
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.
uint DistanceSquare(TileIndex t0, TileIndex t1)
Gets the 'Square' distance between the two given tiles.
Definition map.cpp:175
uint DistanceFromEdge(TileIndex tile)
Param the minimum distance to an edge.
Definition map.cpp:218
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
static TileIndex TileVirtXY(uint x, uint y)
Get a tile from the virtual XY-coordinate.
Definition map_func.h:416
TileIndex AddTileIndexDiffCWrap(TileIndex tile, TileIndexDiffC diff)
Add a TileIndexDiffC to a TileIndex and returns the new one.
Definition map_func.h:527
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
static TileIndex TileXY(uint x, uint y)
Returns the TileIndex of a coordinate.
Definition map_func.h:385
static uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition map_func.h:437
TileIndexDiffC TileIndexDiffCByDiagDir(DiagDirection dir)
Returns the TileIndexDiffC offset from a DiagDirection.
Definition map_func.h:495
static uint TileX(TileIndex tile)
Get the X component of a tile.
Definition map_func.h:427
#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:582
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.
bool Chance16(const uint32_t a, const uint32_t b, const std::source_location location=std::source_location::current())
Flips a coin with given probability.
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
@ TP_NONE
No tree placer algorithm.
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:430
std::string name
Name of the file.
Definition saveload.h:431
DetailedFileType detailed
Detailed file type.
Definition fileio_type.h:65
uint8_t tree_placer
the tree placer algorithm
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 SizeX()
Get the size of the map along the X.
Definition map_func.h:272
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 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 uint MaxX()
Gets the maximum X coordinate within the map, including MP_VOID.
Definition map_func.h:299
static uint Size()
Get the size of the map.
Definition map_func.h:290
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
static bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition tile_map.h:150
static uint TileHeight(Tile tile)
Returns the height of a tile.
Definition tile_map.h:29
Owner GetTileOwner(Tile tile)
Returns the owner of a tile.
Definition tile_map.h:178
bool IsValidTile(Tile tile)
Checks if a tile is valid.
Definition tile_map.h:161
TropicZone GetTropicZone(Tile tile)
Get the tropic zone.
Definition tile_map.h:238
void SetTileHeight(Tile tile, uint height)
Sets the height of a tile.
Definition tile_map.h:57
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 TileType GetTileType(Tile tile)
Get the tiletype of a given tile.
Definition tile_map.h:96
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 PlaceTree(TileIndex tile, uint32_t r, bool keep_density)
Make a random tree tile of the given tile.
Definition tree_cmd.cpp:161
Command definitions related to tree tiles.
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
@ Canal
Canal.
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.