OpenTTD Source 20250816-master-g94ba9b1454
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/flatset_type.hpp"
31#include "core/random_func.hpp"
32#include "object_base.h"
33#include "company_func.h"
34#include "company_gui.h"
35#include "pathfinder/aystar.h"
36#include "saveload/saveload.h"
37#include "framerate_type.h"
38#include "landscape_cmd.h"
39#include "terraform_cmd.h"
40#include "station_func.h"
42
43#include "table/strings.h"
44#include "table/sprites.h"
45
46#include "safeguards.h"
47
48extern const TileTypeProcs
49 _tile_type_clear_procs,
50 _tile_type_rail_procs,
53 _tile_type_trees_procs,
54 _tile_type_station_procs,
55 _tile_type_water_procs,
56 _tile_type_void_procs,
57 _tile_type_industry_procs,
58 _tile_type_tunnelbridge_procs,
59 _tile_type_object_procs;
60
66const TileTypeProcs * const _tile_type_procs[16] = {
67 &_tile_type_clear_procs,
68 &_tile_type_rail_procs,
71 &_tile_type_trees_procs,
72 &_tile_type_station_procs,
73 &_tile_type_water_procs,
74 &_tile_type_void_procs,
75 &_tile_type_industry_procs,
76 &_tile_type_tunnelbridge_procs,
77 &_tile_type_object_procs,
78};
79
81extern const uint8_t _slope_to_sprite_offset[32] = {
82 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0,
83 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 17, 0, 15, 18, 0,
84};
85
86static const uint TILE_UPDATE_FREQUENCY_LOG = 8;
88
97static std::unique_ptr<SnowLine> _snow_line;
98
112Point InverseRemapCoords2(int x, int y, bool clamp_to_map, bool *clamped)
113{
114 if (clamped != nullptr) *clamped = false; // Not clamping yet.
115
116 /* Initial x/y world coordinate is like if the landscape
117 * was completely flat on height 0. */
118 Point pt = InverseRemapCoords(x, y);
119
120 const uint min_coord = _settings_game.construction.freeform_edges ? TILE_SIZE : 0;
121 const uint max_x = Map::MaxX() * TILE_SIZE - 1;
122 const uint max_y = Map::MaxY() * TILE_SIZE - 1;
123
124 if (clamp_to_map) {
125 /* Bring the coordinates near to a valid range. At the top we allow a number
126 * of extra tiles. This is mostly due to the tiles on the north side of
127 * the map possibly being drawn higher due to the extra height levels. */
129 Point old_pt = pt;
130 pt.x = Clamp(pt.x, -extra_tiles * TILE_SIZE, max_x);
131 pt.y = Clamp(pt.y, -extra_tiles * TILE_SIZE, max_y);
132 if (clamped != nullptr) *clamped = (pt.x != old_pt.x) || (pt.y != old_pt.y);
133 }
134
135 /* Now find the Z-world coordinate by fix point iteration.
136 * This is a bit tricky because the tile height is non-continuous at foundations.
137 * The clicked point should be approached from the back, otherwise there are regions that are not clickable.
138 * (FOUNDATION_HALFTILE_LOWER on SLOPE_STEEP_S hides north halftile completely)
139 * So give it a z-malus of 4 in the first iterations. */
140 int z = 0;
141 if (clamp_to_map) {
142 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;
143 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;
144 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;
145 } else {
146 for (int i = 0; i < 5; i++) z = GetSlopePixelZOutsideMap(pt.x + std::max(z, 4) - 4, pt.y + std::max(z, 4) - 4) / 2;
147 for (int m = 3; m > 0; m--) z = GetSlopePixelZOutsideMap(pt.x + std::max(z, m) - m, pt.y + std::max(z, m) - m) / 2;
148 for (int i = 0; i < 5; i++) z = GetSlopePixelZOutsideMap(pt.x + z, pt.y + z ) / 2;
149 }
150
151 pt.x += z;
152 pt.y += z;
153 if (clamp_to_map) {
154 Point old_pt = pt;
155 pt.x = Clamp(pt.x, min_coord, max_x);
156 pt.y = Clamp(pt.y, min_coord, max_y);
157 if (clamped != nullptr) *clamped = *clamped || (pt.x != old_pt.x) || (pt.y != old_pt.y);
158 }
159
160 return pt;
161}
162
172{
173 if (!IsFoundation(f)) return 0;
174
175 if (IsLeveledFoundation(f)) {
176 uint dz = 1 + (IsSteepSlope(s) ? 1 : 0);
177 s = SLOPE_FLAT;
178 return dz;
179 }
180
183 return 0;
184 }
185
188 return 0;
189 }
190
191 uint dz = IsSteepSlope(s) ? 1 : 0;
192 Corner highest_corner = GetHighestSlopeCorner(s);
193
194 switch (f) {
196 s = (((highest_corner == CORNER_W) || (highest_corner == CORNER_S)) ? SLOPE_SW : SLOPE_NE);
197 break;
198
200 s = (((highest_corner == CORNER_S) || (highest_corner == CORNER_E)) ? SLOPE_SE : SLOPE_NW);
201 break;
202
204 s = SlopeWithOneCornerRaised(highest_corner);
205 break;
206
208 s = HalftileSlope(SlopeWithOneCornerRaised(highest_corner), highest_corner);
209 break;
210
211 default: NOT_REACHED();
212 }
213 return dz;
214}
215
216
229uint GetPartialPixelZ(int x, int y, Slope corners)
230{
231 if (IsHalftileSlope(corners)) {
232 /* A foundation is placed on half the tile at a specific corner. This means that,
233 * depending on the corner, that one half of the tile is at the maximum height. */
234 switch (GetHalftileSlopeCorner(corners)) {
235 case CORNER_W:
236 if (x > y) return GetSlopeMaxPixelZ(corners);
237 break;
238
239 case CORNER_S:
240 if (x + y >= (int)TILE_SIZE) return GetSlopeMaxPixelZ(corners);
241 break;
242
243 case CORNER_E:
244 if (x <= y) return GetSlopeMaxPixelZ(corners);
245 break;
246
247 case CORNER_N:
248 if (x + y < (int)TILE_SIZE) return GetSlopeMaxPixelZ(corners);
249 break;
250
251 default: NOT_REACHED();
252 }
253 }
254
255 switch (RemoveHalftileSlope(corners)) {
256 case SLOPE_FLAT: return 0;
257
258 /* One corner is up.*/
259 case SLOPE_N: return x + y <= (int)TILE_SIZE ? (TILE_SIZE - x - y) >> 1 : 0;
260 case SLOPE_E: return y >= x ? (1 + y - x) >> 1 : 0;
261 case SLOPE_S: return x + y >= (int)TILE_SIZE ? (1 + x + y - TILE_SIZE) >> 1 : 0;
262 case SLOPE_W: return x >= y ? (x - y) >> 1 : 0;
263
264 /* Two corners next to each other are up. */
265 case SLOPE_NE: return (TILE_SIZE - x) >> 1;
266 case SLOPE_SE: return (y + 1) >> 1;
267 case SLOPE_SW: return (x + 1) >> 1;
268 case SLOPE_NW: return (TILE_SIZE - y) >> 1;
269
270 /* Three corners are up on the same level. */
271 case SLOPE_ENW: return x + y >= (int)TILE_SIZE ? TILE_HEIGHT - ((1 + x + y - TILE_SIZE) >> 1) : TILE_HEIGHT;
272 case SLOPE_SEN: return y < x ? TILE_HEIGHT - ((x - y) >> 1) : TILE_HEIGHT;
273 case SLOPE_WSE: return x + y <= (int)TILE_SIZE ? TILE_HEIGHT - ((TILE_SIZE - x - y) >> 1) : TILE_HEIGHT;
274 case SLOPE_NWS: return x < y ? TILE_HEIGHT - ((1 + y - x) >> 1) : TILE_HEIGHT;
275
276 /* Two corners at opposite sides are up. */
277 case SLOPE_NS: return x + y < (int)TILE_SIZE ? (TILE_SIZE - x - y) >> 1 : (1 + x + y - TILE_SIZE) >> 1;
278 case SLOPE_EW: return x >= y ? (x - y) >> 1 : (1 + y - x) >> 1;
279
280 /* Very special cases. */
281 case SLOPE_ELEVATED: return TILE_HEIGHT;
282
283 /* Steep slopes. The top is at 2 * TILE_HEIGHT. */
284 case SLOPE_STEEP_N: return (TILE_SIZE - x + TILE_SIZE - y) >> 1;
285 case SLOPE_STEEP_E: return (TILE_SIZE + 1 + y - x) >> 1;
286 case SLOPE_STEEP_S: return (1 + x + y) >> 1;
287 case SLOPE_STEEP_W: return (TILE_SIZE + x - y) >> 1;
288
289 default: NOT_REACHED();
290 }
291}
292
304int GetSlopePixelZ(int x, int y, bool ground_vehicle)
305{
306 TileIndex tile = TileVirtXY(x, y);
307
308 return _tile_type_procs[GetTileType(tile)]->get_slope_z_proc(tile, x, y, ground_vehicle);
309}
310
320{
321 if (IsInsideBS(x, 0, Map::SizeX() * TILE_SIZE) && IsInsideBS(y, 0, Map::SizeY() * TILE_SIZE)) {
322 return GetSlopePixelZ(x, y, false);
323 } else {
324 return _tile_type_procs[MP_VOID]->get_slope_z_proc(INVALID_TILE, x, y, false);
325 }
326}
327
338{
339 assert(!IsHalftileSlope(tileh));
340 return ((tileh & SlopeWithOneCornerRaised(corner)) != 0 ? 1 : 0) + (tileh == SteepSlope(corner) ? 1 : 0);
341}
342
355void GetSlopePixelZOnEdge(Slope tileh, DiagDirection edge, int &z1, int &z2)
356{
357 static const Slope corners[4][4] = {
358 /* corner | steep slope
359 * z1 z2 | z1 z2 */
360 {SLOPE_E, SLOPE_N, SLOPE_STEEP_E, SLOPE_STEEP_N}, // DIAGDIR_NE, z1 = E, z2 = N
361 {SLOPE_S, SLOPE_E, SLOPE_STEEP_S, SLOPE_STEEP_E}, // DIAGDIR_SE, z1 = S, z2 = E
362 {SLOPE_S, SLOPE_W, SLOPE_STEEP_S, SLOPE_STEEP_W}, // DIAGDIR_SW, z1 = S, z2 = W
363 {SLOPE_W, SLOPE_N, SLOPE_STEEP_W, SLOPE_STEEP_N}, // DIAGDIR_NW, z1 = W, z2 = N
364 };
365
366 int halftile_test = (IsHalftileSlope(tileh) ? SlopeWithOneCornerRaised(GetHalftileSlopeCorner(tileh)) : 0);
367 if (halftile_test == corners[edge][0]) z2 += TILE_HEIGHT; // The slope is non-continuous in z2. z2 is on the upper side.
368 if (halftile_test == corners[edge][1]) z1 += TILE_HEIGHT; // The slope is non-continuous in z1. z1 is on the upper side.
369
370 if ((tileh & corners[edge][0]) != 0) z1 += TILE_HEIGHT; // z1 is raised
371 if ((tileh & corners[edge][1]) != 0) z2 += TILE_HEIGHT; // z2 is raised
372 if (RemoveHalftileSlope(tileh) == corners[edge][2]) z1 += TILE_HEIGHT; // z1 is highest corner of a steep slope
373 if (RemoveHalftileSlope(tileh) == corners[edge][3]) z2 += TILE_HEIGHT; // z2 is highest corner of a steep slope
374}
375
383std::tuple<Slope, int> GetFoundationSlope(TileIndex tile)
384{
385 auto [tileh, z] = GetTileSlopeZ(tile);
386 Foundation f = _tile_type_procs[GetTileType(tile)]->get_foundation_proc(tile, tileh);
387 z += ApplyFoundationToSlope(f, tileh);
388 return {tileh, z};
389}
390
391
392bool HasFoundationNW(TileIndex tile, Slope slope_here, uint z_here)
393{
394 int z_W_here = z_here;
395 int z_N_here = z_here;
396 GetSlopePixelZOnEdge(slope_here, DIAGDIR_NW, z_W_here, z_N_here);
397
398 auto [slope, z] = GetFoundationPixelSlope(TileAddXY(tile, 0, -1));
399 int z_W = z;
400 int z_N = z;
401 GetSlopePixelZOnEdge(slope, DIAGDIR_SE, z_W, z_N);
402
403 return (z_N_here > z_N) || (z_W_here > z_W);
404}
405
406
407bool HasFoundationNE(TileIndex tile, Slope slope_here, uint z_here)
408{
409 int z_E_here = z_here;
410 int z_N_here = z_here;
411 GetSlopePixelZOnEdge(slope_here, DIAGDIR_NE, z_E_here, z_N_here);
412
413 auto [slope, z] = GetFoundationPixelSlope(TileAddXY(tile, -1, 0));
414 int z_E = z;
415 int z_N = z;
416 GetSlopePixelZOnEdge(slope, DIAGDIR_SW, z_E, z_N);
417
418 return (z_N_here > z_N) || (z_E_here > z_E);
419}
420
427{
428 if (!IsFoundation(f)) return;
429
430 /* Two part foundations must be drawn separately */
431 assert(f != FOUNDATION_STEEP_BOTH);
432
433 uint sprite_block = 0;
434 auto [slope, z] = GetFoundationPixelSlope(ti->tile);
435
436 /* Select the needed block of foundations sprites
437 * Block 0: Walls at NW and NE edge
438 * Block 1: Wall at NE edge
439 * Block 2: Wall at NW edge
440 * Block 3: No walls at NW or NE edge
441 */
442 if (!HasFoundationNW(ti->tile, slope, z)) sprite_block += 1;
443 if (!HasFoundationNE(ti->tile, slope, z)) sprite_block += 2;
444
445 /* Use the original slope sprites if NW and NE borders should be visible */
446 SpriteID leveled_base = (sprite_block == 0 ? (int)SPR_FOUNDATION_BASE : (SPR_SLOPES_VIRTUAL_BASE + sprite_block * TRKFOUND_BLOCK_SIZE));
447 SpriteID inclined_base = SPR_SLOPES_VIRTUAL_BASE + SLOPES_INCLINED_OFFSET + sprite_block * TRKFOUND_BLOCK_SIZE;
448 SpriteID halftile_base = SPR_HALFTILE_FOUNDATION_BASE + sprite_block * HALFTILE_BLOCK_SIZE;
449
450 if (IsSteepSlope(ti->tileh)) {
452 /* Lower part of foundation */
453 static constexpr SpriteBounds bounds{{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT - 1}, {}};
454 AddSortableSpriteToDraw(leveled_base + (ti->tileh & ~SLOPE_STEEP), PAL_NONE, *ti, bounds);
455 }
456
457 Corner highest_corner = GetHighestSlopeCorner(ti->tileh);
458 ti->z += ApplyPixelFoundationToSlope(f, ti->tileh);
459
460 if (IsInclinedFoundation(f)) {
461 /* inclined foundation */
462 uint8_t inclined = highest_corner * 2 + (f == FOUNDATION_INCLINED_Y ? 1 : 0);
463
464 SpriteBounds bounds{{}, {1, 1, TILE_HEIGHT}, {}};
465 if (f == FOUNDATION_INCLINED_X) bounds.extent.x = TILE_SIZE;
466 if (f == FOUNDATION_INCLINED_Y) bounds.extent.y = TILE_SIZE;
467 AddSortableSpriteToDraw(inclined_base + inclined, PAL_NONE, *ti, bounds);
468 OffsetGroundSprite(0, 0);
469 } else if (IsLeveledFoundation(f)) {
470 static constexpr SpriteBounds bounds{{0, 0, -(int)TILE_HEIGHT}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT - 1}, {}};
471 AddSortableSpriteToDraw(leveled_base + SlopeWithOneCornerRaised(highest_corner), PAL_NONE, *ti, bounds);
473 } else if (f == FOUNDATION_STEEP_LOWER) {
474 /* one corner raised */
476 } else {
477 /* halftile foundation */
478 int8_t x_bb = (((highest_corner == CORNER_W) || (highest_corner == CORNER_S)) ? TILE_SIZE / 2 : 0);
479 int8_t y_bb = (((highest_corner == CORNER_S) || (highest_corner == CORNER_E)) ? TILE_SIZE / 2 : 0);
480
481 SpriteBounds bounds{{x_bb, y_bb, TILE_HEIGHT}, {TILE_SIZE / 2, TILE_SIZE / 2, TILE_HEIGHT - 1}, {}};
482 AddSortableSpriteToDraw(halftile_base + highest_corner, PAL_NONE, *ti, bounds);
483 /* Reposition ground sprite back to original position after bounding box change above. This is similar to
484 * RemapCoords() but without zoom scaling. */
485 Point pt = {(y_bb - x_bb) * 2, y_bb + x_bb};
486 OffsetGroundSprite(-pt.x, -pt.y);
487 }
488 } else {
489 if (IsLeveledFoundation(f)) {
490 /* leveled foundation */
491 static constexpr SpriteBounds bounds{{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT - 1}, {}};
492 AddSortableSpriteToDraw(leveled_base + ti->tileh, PAL_NONE, *ti, bounds);
494 } else if (IsNonContinuousFoundation(f)) {
495 /* halftile foundation */
496 Corner halftile_corner = GetHalftileFoundationCorner(f);
497 int8_t x_bb = (((halftile_corner == CORNER_W) || (halftile_corner == CORNER_S)) ? TILE_SIZE / 2 : 0);
498 int8_t y_bb = (((halftile_corner == CORNER_S) || (halftile_corner == CORNER_E)) ? TILE_SIZE / 2 : 0);
499
500 SpriteBounds bounds{{x_bb, y_bb, 0}, {TILE_SIZE / 2, TILE_SIZE / 2, TILE_HEIGHT - 1}, {}};
501 AddSortableSpriteToDraw(halftile_base + halftile_corner, PAL_NONE, *ti, bounds);
502 /* Reposition ground sprite back to original position after bounding box change above. This is similar to
503 * RemapCoords() but without zoom scaling. */
504 Point pt = {(y_bb - x_bb) * 2, y_bb + x_bb};
505 OffsetGroundSprite(-pt.x, -pt.y);
506 } else if (IsSpecialRailFoundation(f)) {
507 /* anti-zig-zag foundation */
508 SpriteID spr;
509 if (ti->tileh == SLOPE_NS || ti->tileh == SLOPE_EW) {
510 /* half of leveled foundation under track corner */
512 } else {
513 /* tile-slope = sloped along X/Y, foundation-slope = three corners raised */
514 spr = inclined_base + 2 * GetRailFoundationCorner(f) + ((ti->tileh == SLOPE_SW || ti->tileh == SLOPE_NE) ? 1 : 0);
515 }
516 static constexpr SpriteBounds bounds{{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT - 1}, {}};
517 AddSortableSpriteToDraw(spr, PAL_NONE, *ti, bounds);
518 OffsetGroundSprite(0, 0);
519 } else {
520 /* inclined foundation */
521 uint8_t inclined = GetHighestSlopeCorner(ti->tileh) * 2 + (f == FOUNDATION_INCLINED_Y ? 1 : 0);
522
523 SpriteBounds bounds{{}, {1, 1, TILE_HEIGHT}, {}};
524 if (f == FOUNDATION_INCLINED_X) bounds.extent.x = TILE_SIZE;
525 if (f == FOUNDATION_INCLINED_Y) bounds.extent.y = TILE_SIZE;
526 AddSortableSpriteToDraw(inclined_base + inclined, PAL_NONE, *ti, bounds);
527 OffsetGroundSprite(0, 0);
528 }
529 ti->z += ApplyPixelFoundationToSlope(f, ti->tileh);
530 }
531}
532
533void DoClearSquare(TileIndex tile)
534{
535 /* If the tile can have animation and we clear it, delete it from the animated tile list. */
536 if (MayAnimateTile(tile)) DeleteAnimatedTile(tile, true);
537
538 bool remove = IsDockingTile(tile);
541 if (remove) RemoveDockingTile(tile);
542
545}
546
557TrackStatus GetTileTrackStatus(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
558{
559 return _tile_type_procs[GetTileType(tile)]->get_tile_track_status_proc(tile, mode, sub_mode, side);
560}
561
568void ChangeTileOwner(TileIndex tile, Owner old_owner, Owner new_owner)
569{
570 _tile_type_procs[GetTileType(tile)]->change_tile_owner_proc(tile, old_owner, new_owner);
571}
572
573void GetTileDesc(TileIndex tile, TileDesc &td)
574{
576}
577
584{
585 return _snow_line != nullptr;
586}
587
593void SetSnowLine(std::unique_ptr<SnowLine> &&snow_line)
594{
595 _snow_line = std::move(snow_line);
596}
597
603uint8_t GetSnowLine()
604{
606
607 TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date);
608 return _snow_line->table[ymd.month][ymd.day];
609}
610
617{
618 return _snow_line == nullptr ? _settings_game.game_creation.snow_line_height : _snow_line->highest_value;
619}
620
627{
628 return _snow_line == nullptr ? _settings_game.game_creation.snow_line_height : _snow_line->lowest_value;
629}
630
636{
637 _snow_line = nullptr;
638}
639
647{
649 bool do_clear = false;
650 /* Test for stuff which results in water when cleared. Then add the cost to also clear the water. */
651 if (flags.Test(DoCommandFlag::ForceClearTile) && HasTileWaterClass(tile) && IsTileOnWater(tile) && !IsWaterTile(tile) && !IsCoastTile(tile)) {
652 if (flags.Test(DoCommandFlag::Auto) && GetWaterClass(tile) == WATER_CLASS_CANAL) return CommandCost(STR_ERROR_MUST_DEMOLISH_CANAL_FIRST);
653 do_clear = true;
654 cost.AddCost(GetWaterClass(tile) == WATER_CLASS_CANAL ? _price[PR_CLEAR_CANAL] : _price[PR_CLEAR_WATER]);
655 }
656
658 if (c != nullptr && (int)GB(c->clear_limit, 16, 16) < 1) {
659 return CommandCost(STR_ERROR_CLEARING_LIMIT_REACHED);
660 }
661
662 const ClearedObjectArea *coa = FindClearedObject(tile);
663
664 /* If this tile was the first tile which caused object destruction, always
665 * pass it on to the tile_type_proc. That way multiple test runs and the exec run stay consistent. */
666 if (coa != nullptr && coa->first_tile != tile) {
667 /* If this tile belongs to an object which was already cleared via another tile, pretend it has been
668 * already removed.
669 * However, we need to check stuff, which is not the same for all object tiles. (e.g. being on water or not) */
670
671 /* If a object is removed, it leaves either bare land or water. */
672 if (flags.Test(DoCommandFlag::NoWater) && HasTileWaterClass(tile) && IsTileOnWater(tile)) {
673 return CommandCost(STR_ERROR_CAN_T_BUILD_ON_WATER);
674 }
675 } else {
676 cost.AddCost(_tile_type_procs[GetTileType(tile)]->clear_tile_proc(tile, flags));
677 }
678
679 if (flags.Test(DoCommandFlag::Execute)) {
680 if (c != nullptr) c->clear_limit -= 1 << 16;
681 if (do_clear) {
682 if (IsWaterTile(tile) && IsCanal(tile)) {
683 Owner owner = GetTileOwner(tile);
684 if (Company::IsValidID(owner)) {
685 Company::Get(owner)->infrastructure.water--;
687 }
688 }
689 DoClearSquare(tile);
691 }
692 }
693 return cost;
694}
695
704std::tuple<CommandCost, Money> CmdClearArea(DoCommandFlags flags, TileIndex tile, TileIndex start_tile, bool diagonal)
705{
706 if (start_tile >= Map::Size()) return { CMD_ERROR, 0 };
707
710 CommandCost last_error = CMD_ERROR;
711 bool had_success = false;
712
714 int limit = (c == nullptr ? INT32_MAX : GB(c->clear_limit, 16, 16));
715
716 if (tile != start_tile) flags.Set(DoCommandFlag::ForceClearTile);
717
718 std::unique_ptr<TileIterator> iter = TileIterator::Create(tile, start_tile, diagonal);
719 for (; *iter != INVALID_TILE; ++(*iter)) {
720 TileIndex t = *iter;
722 if (ret.Failed()) {
723 last_error = std::move(ret);
724
725 /* We may not clear more tiles. */
726 if (c != nullptr && GB(c->clear_limit, 16, 16) < 1) break;
727 continue;
728 }
729
730 had_success = true;
731 if (flags.Test(DoCommandFlag::Execute)) {
732 money -= ret.GetCost();
733 if (ret.GetCost() > 0 && money < 0) {
734 return { cost, ret.GetCost() };
735 }
737
738 /* draw explosion animation...
739 * Disable explosions when game is paused. Looks silly and blocks the view. */
740 if ((t == tile || t == start_tile) && _pause_mode.None()) {
741 /* big explosion in two corners, or small explosion for single tiles */
743 TileX(tile) == TileX(start_tile) && TileY(tile) == TileY(start_tile) ? EV_EXPLOSION_SMALL : EV_EXPLOSION_LARGE
744 );
745 }
746 } else {
747 /* When we're at the clearing limit we better bail (unneed) testing as well. */
748 if (ret.GetCost() != 0 && --limit <= 0) break;
749 }
750 cost.AddCost(ret.GetCost());
751 }
752
753 return { had_success ? cost : last_error, 0 };
754}
755
756
757TileIndex _cur_tileloop_tile;
758
763{
765
766 /* The pseudorandom sequence of tiles is generated using a Galois linear feedback
767 * shift register (LFSR). This allows a deterministic pseudorandom ordering, but
768 * still with minimal state and fast iteration. */
769
770 /* Maximal length LFSR feedback terms, from 12-bit (for 64x64 maps) to 24-bit (for 4096x4096 maps).
771 * Extracted from http://www.ece.cmu.edu/~koopman/lfsr/ */
772 static const uint32_t feedbacks[] = {
773 0xD8F, 0x1296, 0x2496, 0x4357, 0x8679, 0x1030E, 0x206CD, 0x403FE, 0x807B8, 0x1004B2, 0x2006A8, 0x4004B2, 0x800B87
774 };
775 static_assert(lengthof(feedbacks) == 2 * MAX_MAP_SIZE_BITS - 2 * MIN_MAP_SIZE_BITS + 1);
776 const uint32_t feedback = feedbacks[Map::LogX() + Map::LogY() - 2 * MIN_MAP_SIZE_BITS];
777
778 /* We update every tile every TILE_UPDATE_FREQUENCY ticks, so divide the map size by 2^TILE_UPDATE_FREQUENCY_LOG = TILE_UPDATE_FREQUENCY */
779 static_assert(2 * MIN_MAP_SIZE_BITS >= TILE_UPDATE_FREQUENCY_LOG);
780 uint count = 1 << (Map::LogX() + Map::LogY() - TILE_UPDATE_FREQUENCY_LOG);
781
782 TileIndex tile = _cur_tileloop_tile;
783 /* The LFSR cannot have a zeroed state. */
784 assert(tile != 0);
785
786 /* Manually update tile 0 every TILE_UPDATE_FREQUENCY ticks - the LFSR never iterates over it itself. */
788 _tile_type_procs[GetTileType(0)]->tile_loop_proc(TileIndex{});
789 count--;
790 }
791
792 while (count--) {
793 _tile_type_procs[GetTileType(tile)]->tile_loop_proc(tile);
794
795 /* Get the next tile in sequence using a Galois LFSR. */
796 tile = TileIndex{(tile.base() >> 1) ^ (-(int32_t)(tile.base() & 1) & feedback)};
797 }
798
799 _cur_tileloop_tile = tile;
800}
801
802void InitializeLandscape()
803{
804 for (uint y = _settings_game.construction.freeform_edges ? 1 : 0; y < Map::MaxY(); y++) {
805 for (uint x = _settings_game.construction.freeform_edges ? 1 : 0; x < Map::MaxX(); x++) {
806 MakeClear(TileXY(x, y), CLEAR_GRASS, 3);
807 SetTileHeight(TileXY(x, y), 0);
810 }
811 }
812
813 for (uint x = 0; x < Map::SizeX(); x++) MakeVoid(TileXY(x, Map::MaxY()));
814 for (uint y = 0; y < Map::SizeY(); y++) MakeVoid(TileXY(Map::MaxX(), y));
815}
816
817static const uint8_t _genterrain_tbl_1[5] = { 10, 22, 33, 37, 4 };
818static const uint8_t _genterrain_tbl_2[5] = { 0, 0, 0, 0, 33 };
819
820static void GenerateTerrain(int type, uint flag)
821{
822 uint32_t r = Random();
823
824 /* Choose one of the templates from the graphics file. */
825 const Sprite *templ = GetSprite((((r >> 24) * _genterrain_tbl_1[type]) >> 8) + _genterrain_tbl_2[type] + SPR_MAPGEN_BEGIN, SpriteType::MapGen);
826 if (templ == nullptr) UserError("Map generator sprites could not be loaded");
827
828 /* Chose a random location to apply the template to. */
829 uint x = r & Map::MaxX();
830 uint y = (r >> Map::LogX()) & Map::MaxY();
831
832 /* Make sure the template is not too close to the upper edges; bottom edges are checked later. */
833 uint edge_distance = 1 + (_settings_game.construction.freeform_edges ? 1 : 0);
834 if (x <= edge_distance || y <= edge_distance) return;
835
836 DiagDirection direction = (DiagDirection)GB(r, 22, 2);
837 uint w = templ->width;
838 uint h = templ->height;
839
840 if (DiagDirToAxis(direction) == AXIS_Y) std::swap(w, h);
841
842 const uint8_t *p = reinterpret_cast<const uint8_t *>(templ->data);
843
844 if ((flag & 4) != 0) {
845 /* This is only executed in secondary/tertiary loops to generate the terrain for arctic and tropic.
846 * It prevents the templates to be applied to certain parts of the map based on the flags, thus
847 * creating regions with different elevations/topography. */
848 uint xw = x * Map::SizeY();
849 uint yw = y * Map::SizeX();
850 uint bias = (Map::SizeX() + Map::SizeY()) * 16;
851
852 switch (flag & 3) {
853 default: NOT_REACHED();
854 case 0:
855 if (xw + yw > Map::Size() - bias) return;
856 break;
857
858 case 1:
859 if (yw < xw + bias) return;
860 break;
861
862 case 2:
863 if (xw + yw < Map::Size() + bias) return;
864 break;
865
866 case 3:
867 if (xw < yw + bias) return;
868 break;
869 }
870 }
871
872 /* Ensure the template does not overflow at the bottom edges of the map; upper edges were checked before. */
873 if (x + w >= Map::MaxX()) return;
874 if (y + h >= Map::MaxY()) return;
875
876 TileIndex tile = TileXY(x, y);
877
878 /* Get the template and overlay in a particular direction over the map's height from the given
879 * origin point (tile), and update the map's height everywhere where the height from the template
880 * is higher than the height of the map. In other words, this only raises the tile heights. */
881 switch (direction) {
882 default: NOT_REACHED();
883 case DIAGDIR_NE:
884 do {
885 TileIndex tile_cur = tile;
886
887 for (uint w_cur = w; w_cur != 0; --w_cur) {
888 if (GB(*p, 0, 4) >= TileHeight(tile_cur)) SetTileHeight(tile_cur, GB(*p, 0, 4));
889 p++;
890 tile_cur += TileDiffXY(1, 0);
891 }
892 tile += TileDiffXY(0, 1);
893 } while (--h != 0);
894 break;
895
896 case DIAGDIR_SE:
897 do {
898 TileIndex tile_cur = tile;
899
900 for (uint h_cur = h; h_cur != 0; --h_cur) {
901 if (GB(*p, 0, 4) >= TileHeight(tile_cur)) SetTileHeight(tile_cur, GB(*p, 0, 4));
902 p++;
903 tile_cur += TileDiffXY(0, 1);
904 }
905 tile += TileDiffXY(1, 0);
906 } while (--w != 0);
907 break;
908
909 case DIAGDIR_SW:
910 tile += TileDiffXY(w - 1, 0);
911 do {
912 TileIndex tile_cur = tile;
913
914 for (uint w_cur = w; w_cur != 0; --w_cur) {
915 if (GB(*p, 0, 4) >= TileHeight(tile_cur)) SetTileHeight(tile_cur, GB(*p, 0, 4));
916 p++;
917 tile_cur -= TileDiffXY(1, 0);
918 }
919 tile += TileDiffXY(0, 1);
920 } while (--h != 0);
921 break;
922
923 case DIAGDIR_NW:
924 tile += TileDiffXY(0, h - 1);
925 do {
926 TileIndex tile_cur = tile;
927
928 for (uint h_cur = h; h_cur != 0; --h_cur) {
929 if (GB(*p, 0, 4) >= TileHeight(tile_cur)) SetTileHeight(tile_cur, GB(*p, 0, 4));
930 p++;
931 tile_cur -= TileDiffXY(0, 1);
932 }
933 tile += TileDiffXY(1, 0);
934 } while (--w != 0);
935 break;
936 }
937}
938
939
940#include "table/genland.h"
941
942static void CreateDesertOrRainForest(uint desert_tropic_line)
943{
944 uint update_freq = Map::Size() / 4;
945
946 for (const auto tile : Map::Iterate()) {
947 if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
948
949 if (!IsValidTile(tile)) continue;
950
951 auto allows_desert = [tile, desert_tropic_line](auto &offset) {
952 TileIndex t = AddTileIndexDiffCWrap(tile, offset);
953 return t == INVALID_TILE || (TileHeight(t) < desert_tropic_line && !IsTileType(t, MP_WATER));
954 };
955 if (std::all_of(std::begin(_make_desert_or_rainforest_data), std::end(_make_desert_or_rainforest_data), allows_desert)) {
957 }
958 }
959
960 for (uint i = 0; i != TILE_UPDATE_FREQUENCY; i++) {
962
963 RunTileLoop();
964 }
965
966 for (const auto tile : Map::Iterate()) {
967 if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
968
969 if (!IsValidTile(tile)) continue;
970
971 auto allows_rainforest = [tile](auto &offset) {
972 TileIndex t = AddTileIndexDiffCWrap(tile, offset);
973 return t == INVALID_TILE || !IsTileType(t, MP_CLEAR) || !IsClearGround(t, CLEAR_DESERT);
974 };
975 if (std::all_of(std::begin(_make_desert_or_rainforest_data), std::end(_make_desert_or_rainforest_data), allows_rainforest)) {
977 }
978 }
979}
980
986static bool FindSpring(TileIndex tile)
987{
988 int reference_height;
989 if (!IsTileFlat(tile, &reference_height) || IsWaterTile(tile)) return false;
990
991 /* In the tropics rivers start in the rainforest. */
992 if (_settings_game.game_creation.landscape == LandscapeType::Tropic && GetTropicZone(tile) != TROPICZONE_RAINFOREST) return false;
993
994 /* Are there enough higher tiles to warrant a 'spring'? */
995 uint num = 0;
996 for (int dx = -1; dx <= 1; dx++) {
997 for (int dy = -1; dy <= 1; dy++) {
998 TileIndex t = TileAddWrap(tile, dx, dy);
999 if (t != INVALID_TILE && GetTileMaxZ(t) > reference_height) num++;
1000 }
1001 }
1002
1003 if (num < 4) return false;
1004
1005 /* Are we near the top of a hill? */
1006 for (int dx = -16; dx <= 16; dx++) {
1007 for (int dy = -16; dy <= 16; dy++) {
1008 TileIndex t = TileAddWrap(tile, dx, dy);
1009 if (t != INVALID_TILE && GetTileMaxZ(t) > reference_height + 2) return false;
1010 }
1011 }
1012
1013 return true;
1014}
1015
1021static void MakeLake(TileIndex tile, uint height_lake)
1022{
1023 if (!IsValidTile(tile) || TileHeight(tile) != height_lake || !IsTileFlat(tile)) return;
1024 if (_settings_game.game_creation.landscape == LandscapeType::Tropic && GetTropicZone(tile) == TROPICZONE_DESERT) return;
1025
1026 for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
1027 TileIndex t = tile + TileOffsByDiagDir(d);
1028 if (IsWaterTile(t)) {
1030 return;
1031 }
1032 }
1033}
1034
1040static void RiverMakeWider(TileIndex tile, TileIndex origin_tile)
1041{
1042 /* Don't expand into void tiles. */
1043 if (!IsValidTile(tile)) return;
1044
1045 /* If the tile is already sea or river, don't expand. */
1046 if (IsWaterTile(tile)) return;
1047
1048 /* If the tile is at height 0 after terraforming but the ocean hasn't flooded yet, don't build river. */
1049 if (GetTileMaxZ(tile) == 0) return;
1050
1051 Slope cur_slope = GetTileSlope(tile);
1052 Slope desired_slope = GetTileSlope(origin_tile); // Initialize matching the origin tile as a shortcut if no terraforming is needed.
1053
1054 /* Never flow uphill. */
1055 if (GetTileMaxZ(tile) > GetTileMaxZ(origin_tile)) return;
1056
1057 /* If the new tile can't hold a river tile, try terraforming. */
1058 if (!IsTileFlat(tile) && !IsInclinedSlope(cur_slope)) {
1059 /* Don't try to terraform steep slopes. */
1060 if (IsSteepSlope(cur_slope)) return;
1061
1062 bool flat_river_found = false;
1063 bool sloped_river_found = false;
1064
1065 /* There are two common possibilities:
1066 * 1. River flat, adjacent tile has one corner lowered.
1067 * 2. River descending, adjacent tile has either one or three corners raised.
1068 */
1069
1070 /* First, determine the desired slope based on adjacent river tiles. This doesn't necessarily match the origin tile for the SpiralTileSequence. */
1071 for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
1072 TileIndex other_tile = TileAddByDiagDir(tile, d);
1073 Slope other_slope = GetTileSlope(other_tile);
1074
1075 /* Only consider river tiles. */
1076 if (IsWaterTile(other_tile) && IsRiver(other_tile)) {
1077 /* If the adjacent river tile flows downhill, we need to check where we are relative to the slope. */
1078 if (IsInclinedSlope(other_slope) && GetTileMaxZ(tile) == GetTileMaxZ(other_tile)) {
1079 /* Check for a parallel slope. If we don't find one, we're above or below the slope instead. */
1082 desired_slope = other_slope;
1083 sloped_river_found = true;
1084 break;
1085 }
1086 }
1087 /* If we find an adjacent river tile, remember it. We'll terraform to match it later if we don't find a slope. */
1088 if (IsTileFlat(other_tile)) flat_river_found = true;
1089 }
1090 }
1091 /* We didn't find either an inclined or flat river, so we're climbing the wrong slope. Bail out. */
1092 if (!sloped_river_found && !flat_river_found) return;
1093
1094 /* We didn't find an inclined river, but there is a flat river. */
1095 if (!sloped_river_found && flat_river_found) desired_slope = SLOPE_FLAT;
1096
1097 /* Now that we know the desired slope, it's time to terraform! */
1098
1099 /* If the river is flat and the adjacent tile has one corner lowered, we want to raise it. */
1100 if (desired_slope == SLOPE_FLAT && IsSlopeWithThreeCornersRaised(cur_slope)) {
1101 /* Make sure we're not affecting an existing river slope tile. */
1102 for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
1103 TileIndex other_tile = TileAddByDiagDir(tile, d);
1104 if (IsInclinedSlope(GetTileSlope(other_tile)) && IsWaterTile(other_tile)) return;
1105 }
1107
1108 /* If the river is descending and the adjacent tile has either one or three corners raised, we want to make it match the slope. */
1109 } else if (IsInclinedSlope(desired_slope)) {
1110 /* Don't break existing flat river tiles by terraforming under them. */
1111 DiagDirection river_direction = ReverseDiagDir(GetInclinedSlopeDirection(desired_slope));
1112
1113 for (DiagDirDiff d = DIAGDIRDIFF_BEGIN; d < DIAGDIRDIFF_END; d++) {
1114 /* We don't care about downstream or upstream tiles, just the riverbanks. */
1115 if (d == DIAGDIRDIFF_SAME || d == DIAGDIRDIFF_REVERSE) continue;
1116
1117 TileIndex other_tile = (TileAddByDiagDir(tile, ChangeDiagDir(river_direction, d)));
1118 if (IsWaterTile(other_tile) && IsRiver(other_tile) && IsTileFlat(other_tile)) return;
1119 }
1120
1121 /* Get the corners which are different between the current and desired slope. */
1122 Slope to_change = cur_slope ^ desired_slope;
1123
1124 /* Lower unwanted corners first. If only one corner is raised, no corners need lowering. */
1125 if (!IsSlopeWithOneCornerRaised(cur_slope)) {
1126 to_change = to_change & ComplementSlope(desired_slope);
1128 }
1129
1130 /* Now check the match and raise any corners needed. */
1131 cur_slope = GetTileSlope(tile);
1132 if (cur_slope != desired_slope && IsSlopeWithOneCornerRaised(cur_slope)) {
1133 to_change = cur_slope ^ desired_slope;
1135 }
1136 }
1137 /* Update cur_slope after possibly terraforming. */
1138 cur_slope = GetTileSlope(tile);
1139 }
1140
1141 /* Sloped rivers need water both upstream and downstream. */
1142 if (IsInclinedSlope(cur_slope)) {
1143 DiagDirection slope_direction = GetInclinedSlopeDirection(cur_slope);
1144
1145 TileIndex upstream_tile = TileAddByDiagDir(tile, slope_direction);
1146 TileIndex downstream_tile = TileAddByDiagDir(tile, ReverseDiagDir(slope_direction));
1147
1148 /* Don't look outside the map. */
1149 if (!IsValidTile(upstream_tile) || !IsValidTile(downstream_tile)) return;
1150
1151 /* Downstream might be new ocean created by our terraforming, and it hasn't flooded yet. */
1152 bool downstream_is_ocean = GetTileZ(downstream_tile) == 0 && (GetTileSlope(downstream_tile) == SLOPE_FLAT || IsSlopeWithOneCornerRaised(GetTileSlope(downstream_tile)));
1153
1154 /* If downstream is dry, flat, and not ocean, try making it a river tile. */
1155 if (!IsWaterTile(downstream_tile) && !downstream_is_ocean) {
1156 /* If the tile upstream isn't flat, don't bother. */
1157 if (GetTileSlope(downstream_tile) != SLOPE_FLAT) return;
1158
1159 MakeRiverAndModifyDesertZoneAround(downstream_tile);
1160 }
1161
1162 /* If upstream is dry and flat, try making it a river tile. */
1163 if (!IsWaterTile(upstream_tile)) {
1164 /* If the tile upstream isn't flat, don't bother. */
1165 if (GetTileSlope(upstream_tile) != SLOPE_FLAT) return;
1166
1168 }
1169 }
1170
1171 /* If the tile slope matches the desired slope, add a river tile. */
1172 if (cur_slope == desired_slope) {
1174 }
1175}
1176
1183static bool FlowsDown(TileIndex begin, TileIndex end)
1184{
1185 assert(DistanceManhattan(begin, end) == 1);
1186
1187 auto [slope_end, height_end] = GetTileSlopeZ(end);
1188
1189 /* Slope either is inclined or flat; rivers don't support other slopes. */
1190 if (slope_end != SLOPE_FLAT && !IsInclinedSlope(slope_end)) return false;
1191
1192 auto [slope_begin, height_begin] = GetTileSlopeZ(begin);
1193
1194 /* It can't flow uphill. */
1195 if (height_end > height_begin) return false;
1196
1197 /* Slope continues, then it must be lower... */
1198 if (slope_end == slope_begin && height_end < height_begin) return true;
1199
1200 /* ... or either end must be flat. */
1201 return slope_end == SLOPE_FLAT || slope_begin == SLOPE_FLAT;
1202}
1203
1205class RiverBuilder : public AyStar {
1206protected:
1207 AyStarStatus EndNodeCheck(const PathNode &current) const override
1208 {
1209 return current.GetTile() == this->end ? AyStarStatus::FoundEndNode : AyStarStatus::Done;
1210 }
1211
1212 int32_t CalculateG(const AyStarNode &, const PathNode &) const override
1213 {
1215 }
1216
1217 int32_t CalculateH(const AyStarNode &current, const PathNode &) const override
1218 {
1219 return DistanceManhattan(this->end, current.tile);
1220 }
1221
1222 void GetNeighbours(const PathNode &current, std::vector<AyStarNode> &neighbours) const override
1223 {
1224 TileIndex tile = current.GetTile();
1225
1226 neighbours.clear();
1227 for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
1228 TileIndex t = tile + TileOffsByDiagDir(d);
1229 if (IsValidTile(t) && FlowsDown(tile, t)) {
1230 auto &neighbour = neighbours.emplace_back();
1231 neighbour.tile = t;
1232 neighbour.td = INVALID_TRACKDIR;
1233 }
1234 }
1235 }
1236
1237 void FoundEndNode(const PathNode &current) override
1238 {
1239 /* First, build the river without worrying about its width. */
1240 for (PathNode *path = current.parent; path != nullptr; path = path->parent) {
1241 TileIndex tile = path->GetTile();
1242 if (!IsWaterTile(tile)) {
1244 }
1245 }
1246
1247 /* If the river is a main river, go back along the path to widen it.
1248 * Don't make wide rivers if we're using the original landscape generator.
1249 */
1250 if (_settings_game.game_creation.land_generator != LG_ORIGINAL && this->main_river) {
1251 const uint long_river_length = _settings_game.game_creation.min_river_length * 4;
1252
1253 for (PathNode *path = current.parent; path != nullptr; path = path->parent) {
1254 TileIndex origin_tile = path->GetTile();
1255
1256 /* Check if we should widen river depending on how far we are away from the source. */
1257 uint current_river_length = DistanceManhattan(this->spring, origin_tile);
1258 uint diameter = std::min(3u, (current_river_length / (long_river_length / 3u)) + 1u);
1259 if (diameter <= 1) continue;
1260
1261 for (auto tile : SpiralTileSequence(origin_tile, diameter)) {
1262 RiverMakeWider(tile, origin_tile);
1263 }
1264 }
1265 }
1266 }
1267
1269
1270private:
1274
1275public:
1284 {
1285 RiverBuilder builder(end, spring, main_river);
1286 AyStarNode start;
1287 start.tile = begin;
1288 start.td = INVALID_TRACKDIR;
1289 builder.AddStartNode(&start, 0);
1290 builder.Main();
1291 }
1292};
1293
1301static std::tuple<bool, bool> FlowRiver(TileIndex spring, TileIndex begin, uint min_river_length)
1302{
1303 uint height_begin = TileHeight(begin);
1304
1305 if (IsWaterTile(begin)) {
1306 return { DistanceManhattan(spring, begin) > min_river_length, GetTileZ(begin) == 0 };
1307 }
1308
1309 FlatSet<TileIndex> marks;
1310 marks.insert(begin);
1311
1312 /* Breadth first search for the closest tile we can flow down to. */
1313 std::list<TileIndex> queue;
1314 queue.push_back(begin);
1315
1316 bool found = false;
1317 uint count = 0; // Number of tiles considered; to be used for lake location guessing.
1318 TileIndex end;
1319 do {
1320 end = queue.front();
1321 queue.pop_front();
1322
1323 uint height_end = TileHeight(end);
1324 if (IsTileFlat(end) && (height_end < height_begin || (height_end == height_begin && IsWaterTile(end)))) {
1325 found = true;
1326 break;
1327 }
1328
1329 for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
1330 TileIndex t = end + TileOffsByDiagDir(d);
1331 if (IsValidTile(t) && !marks.contains(t) && FlowsDown(end, t)) {
1332 marks.insert(t);
1333 count++;
1334 queue.push_back(t);
1335 }
1336 }
1337 } while (!queue.empty());
1338
1339 bool main_river = false;
1340 if (found) {
1341 /* Flow further down hill. */
1342 std::tie(found, main_river) = FlowRiver(spring, end, min_river_length);
1343 } else if (count > 32) {
1344 /* Maybe we can make a lake. Find the Nth of the considered tiles. */
1345 auto cit = marks.cbegin();
1346 std::advance(cit, RandomRange(count - 1));
1347 TileIndex lake_centre = *cit;
1348
1349 if (IsValidTile(lake_centre) &&
1350 /* A river, or lake, can only be built on flat slopes. */
1351 IsTileFlat(lake_centre) &&
1352 /* We want the lake to be built at the height of the river. */
1353 TileHeight(begin) == TileHeight(lake_centre) &&
1354 /* We don't want the lake at the entry of the valley. */
1355 lake_centre != begin &&
1356 /* We don't want lakes in the desert. */
1357 (_settings_game.game_creation.landscape != LandscapeType::Tropic || GetTropicZone(lake_centre) != TROPICZONE_DESERT) &&
1358 /* We only want a lake if the river is long enough. */
1359 DistanceManhattan(spring, lake_centre) > min_river_length) {
1360 end = lake_centre;
1362 uint diameter = RandomRange(8) + 3;
1363
1364 /* Run the loop twice, so artefacts from going circular in one direction get (mostly) hidden. */
1365 for (uint loops = 0; loops < 2; ++loops) {
1366 for (auto tile : SpiralTileSequence(lake_centre, diameter)) {
1367 MakeLake(tile, height_begin);
1368 }
1369 }
1370
1371 found = true;
1372 }
1373 }
1374
1375 marks.clear();
1376 if (found) RiverBuilder::Exec(begin, end, spring, main_river);
1377 return { found, main_river };
1378}
1379
1383static void CreateRivers()
1384{
1386 if (amount == 0) return;
1387
1389 const uint num_short_rivers = wells - std::max(1u, wells / 10);
1390 SetGeneratingWorldProgress(GWP_RIVER, wells + TILE_UPDATE_FREQUENCY / 64); // Include the tile loop calls below.
1391
1392 /* Try to create long rivers. */
1393 for (; wells > num_short_rivers; wells--) {
1395 bool done = false;
1396 for (int tries = 0; tries < 512; tries++) {
1397 for (auto t : SpiralTileSequence(RandomTile(), 8)) {
1398 if (FindSpring(t)) {
1399 done = std::get<0>(FlowRiver(t, t, _settings_game.game_creation.min_river_length * 4));
1400 break;
1401 }
1402 }
1403 if (done) break;
1404 }
1405 }
1406
1407 /* Try to create short rivers. */
1408 for (; wells != 0; wells--) {
1410 bool done = false;
1411 for (int tries = 0; tries < 128; tries++) {
1412 for (auto t : SpiralTileSequence(RandomTile(), 8)) {
1413 if (FindSpring(t)) {
1414 done = std::get<0>(FlowRiver(t, t, _settings_game.game_creation.min_river_length));
1415 break;
1416 }
1417 }
1418 if (done) break;
1419 }
1420 }
1421
1422 /* Widening rivers may have left some tiles requiring to be watered. */
1423 ConvertGroundTilesIntoWaterTiles();
1424
1425 /* Run tile loop to update the ground density. */
1426 for (uint i = 0; i != TILE_UPDATE_FREQUENCY; i++) {
1428 RunTileLoop();
1429 }
1430}
1431
1449static uint CalculateCoverageLine(uint coverage, uint edge_multiplier)
1450{
1451 /* Histogram of how many tiles per height level exist. */
1452 std::array<int, MAX_TILE_HEIGHT + 1> histogram = {};
1453 /* Histogram of how many neighbour tiles are lower than the tiles of the height level. */
1454 std::array<int, MAX_TILE_HEIGHT + 1> edge_histogram = {};
1455
1456 /* Build a histogram of the map height. */
1457 for (const auto tile : Map::Iterate()) {
1458 uint h = TileHeight(tile);
1459 histogram[h]++;
1460
1461 if (edge_multiplier != 0) {
1462 /* Check if any of our neighbours is below us. */
1463 for (DiagDirection dir = DIAGDIR_BEGIN; dir != DIAGDIR_END; dir++) {
1464 TileIndex neighbour_tile = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDiagDir(dir));
1465 if (IsValidTile(neighbour_tile) && TileHeight(neighbour_tile) < h) {
1466 edge_histogram[h]++;
1467 }
1468 }
1469 }
1470 }
1471
1472 /* The amount of land we have is the map size minus the first (sea) layer. */
1473 uint land_tiles = Map::Size() - histogram[0];
1474 int best_score = land_tiles;
1475
1476 /* Our goal is the coverage amount of the land-mass. */
1477 int goal_tiles = land_tiles * coverage / 100;
1478
1479 /* We scan from top to bottom. */
1480 uint h = MAX_TILE_HEIGHT;
1481 uint best_h = h;
1482
1483 int current_tiles = 0;
1484 for (; h > 0; h--) {
1485 current_tiles += histogram[h];
1486 int current_score = goal_tiles - current_tiles;
1487
1488 /* Tropic grows from water and mountains into the desert. This is a
1489 * great visual, but it also means we* need to take into account how
1490 * much less desert tiles are being created if we are on this
1491 * height-level. We estimate this based on how many neighbouring
1492 * tiles are below us for a given length, assuming that is where
1493 * tropic is growing from.
1494 */
1495 if (edge_multiplier != 0 && h > 1) {
1496 /* From water tropic tiles grow for a few tiles land inward. */
1497 current_score -= edge_histogram[1] * edge_multiplier;
1498 /* Tropic tiles grow into the desert for a few tiles. */
1499 current_score -= edge_histogram[h] * edge_multiplier;
1500 }
1501
1502 if (std::abs(current_score) < std::abs(best_score)) {
1503 best_score = current_score;
1504 best_h = h;
1505 }
1506
1507 /* Always scan all height-levels, as h == 1 might give a better
1508 * score than any before. This is true for example with 0% desert
1509 * coverage. */
1510 }
1511
1512 return best_h;
1513}
1514
1519{
1520 /* We do not have snow sprites on coastal tiles, so never allow "1" as height. */
1522}
1523
1528static uint8_t CalculateDesertLine()
1529{
1530 /* CalculateCoverageLine() runs from top to bottom, so we need to invert the coverage. */
1532}
1533
1534bool GenerateLandscape(uint8_t mode)
1535{
1536 /* Number of steps of landscape generation */
1537 static constexpr uint GLS_HEIGHTMAP = 3;
1538 static constexpr uint GLS_TERRAGENESIS = 4;
1539 static constexpr uint GLS_ORIGINAL = 2;
1540 static constexpr uint GLS_TROPIC = 12;
1541 static constexpr uint GLS_OTHER = 0;
1542 uint steps = (_settings_game.game_creation.landscape == LandscapeType::Tropic) ? GLS_TROPIC : GLS_OTHER;
1543
1544 if (mode == GWM_HEIGHTMAP) {
1545 SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_HEIGHTMAP);
1547 return false;
1548 }
1551 SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_TERRAGENESIS);
1553 } else {
1554 SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_ORIGINAL);
1556 for (uint x = 0; x < Map::SizeX(); x++) MakeVoid(TileXY(x, 0));
1557 for (uint y = 0; y < Map::SizeY(); y++) MakeVoid(TileXY(0, y));
1558 }
1560 case LandscapeType::Arctic: {
1561 uint32_t r = Random();
1562
1563 for (uint i = Map::ScaleBySize(GB(r, 0, 7) + 950); i != 0; --i) {
1564 GenerateTerrain(2, 0);
1565 }
1566
1567 uint flag = GB(r, 7, 2) | 4;
1568 for (uint i = Map::ScaleBySize(GB(r, 9, 7) + 450); i != 0; --i) {
1569 GenerateTerrain(4, flag);
1570 }
1571 break;
1572 }
1573
1574 case LandscapeType::Tropic: {
1575 uint32_t r = Random();
1576
1577 for (uint i = Map::ScaleBySize(GB(r, 0, 7) + 170); i != 0; --i) {
1578 GenerateTerrain(0, 0);
1579 }
1580
1581 uint flag = GB(r, 7, 2) | 4;
1582 for (uint i = Map::ScaleBySize(GB(r, 9, 8) + 1700); i != 0; --i) {
1583 GenerateTerrain(0, flag);
1584 }
1585
1586 flag ^= 2;
1587
1588 for (uint i = Map::ScaleBySize(GB(r, 17, 7) + 410); i != 0; --i) {
1589 GenerateTerrain(3, flag);
1590 }
1591 break;
1592 }
1593
1594 default: {
1595 uint32_t r = Random();
1596
1598 uint i = Map::ScaleBySize(GB(r, 0, 7) + (3 - _settings_game.difficulty.quantity_sea_lakes) * 256 + 100);
1599 for (; i != 0; --i) {
1600 /* Make sure we do not overflow. */
1601 GenerateTerrain(Clamp(_settings_game.difficulty.terrain_type, 0, 3), 0);
1602 }
1603 break;
1604 }
1605 }
1606 }
1607
1608 /* Do not call IncreaseGeneratingWorldProgress() before FixSlopes(),
1609 * it allows screen redraw. Drawing of broken slopes crashes the game */
1610 FixSlopes();
1613
1614 ConvertGroundTilesIntoWaterTiles();
1617
1619 case LandscapeType::Arctic:
1621 break;
1622
1623 case LandscapeType::Tropic: {
1624 uint desert_tropic_line = CalculateDesertLine();
1625 CreateDesertOrRainForest(desert_tropic_line);
1626 break;
1627 }
1628
1629 default:
1630 break;
1631 }
1632
1633 CreateRivers();
1634 return true;
1635}
1636
1637void OnTick_Town();
1638void OnTick_Trees();
1639void OnTick_Station();
1640void OnTick_Industry();
1641
1642void OnTick_Companies();
1643void OnTick_LinkGraph();
1644
1645void CallLandscapeTick()
1646{
1647 {
1649
1650 OnTick_Town();
1651 OnTick_Trees();
1652 OnTick_Station();
1653 OnTick_Industry();
1654 }
1655
1658}
void DeleteAnimatedTile(TileIndex tile, bool immediate)
Stops animation on the given tile.
Tile animation!
This file has the header for AyStar.
AyStarStatus
Return status of AyStar methods.
Definition aystar.h:25
@ FoundEndNode
An end node was found.
@ Done
Not an end-tile, or wrong direction.
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
AyStar search algorithm struct.
Definition aystar.h:44
AyStarStatus Main()
This is the function you call to run AyStar.
Definition aystar.cpp:132
void AddStartNode(AyStarNode *start_node, int g)
Adds a node from where to start an algorithm.
Definition aystar.cpp:161
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.
Flat set implementation that uses a sorted vector for storage.
bool contains(const Tkey &key)
Test if a key exists in the set.
std::pair< const_iterator, bool > insert(const Tkey &key)
Insert a key into the set, if it does not already exist.
RAII class for measuring multi-step elements of performance.
Search path and build river.
bool main_river
Whether the current river is a big river that others flow into.
TileIndex end
Destination for the river.
int32_t CalculateG(const AyStarNode &, const PathNode &) const override
Calculate the G-value for the AyStar algorithm.
void FoundEndNode(const PathNode &current) override
If the End Node is found, this function is called.
static void Exec(TileIndex begin, TileIndex end, TileIndex spring, bool main_river)
Actually build the river between the begin and end tiles using AyStar.
AyStarStatus EndNodeCheck(const PathNode &current) const override
Check whether the end-tile is found.
int32_t CalculateH(const AyStarNode &current, const PathNode &) const override
Calculate the H-value for the AyStar algorithm.
TileIndex spring
The current spring during river generation.
void GetNeighbours(const PathNode &current, std::vector< AyStarNode > &neighbours) const override
This function requests the tiles around the current tile.
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.
@ Execute
execute the given command
@ Bankrupt
company bankrupts, skip money check, skip vehicle on tile check in some cases
@ NoWater
don't allow building on water
@ Auto
don't allow building on structures
@ 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.
Flat set container implementation.
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_ORIGINAL
The original landscape generator.
Definition genworld.h:21
@ 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:97
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.
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"...
static bool FlowsDown(TileIndex begin, TileIndex end)
Check whether a river at begin could (logically) flow down to end.
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:86
void ChangeTileOwner(TileIndex tile, Owner old_owner, Owner new_owner)
Change the owner of a tile.
static void RiverMakeWider(TileIndex tile, TileIndex origin_tile)
Widen a river by expanding into adjacent tiles via circular tile search.
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.
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:66
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:52
void OnTick_Town()
Iterate through all towns and call their tick handler.
Definition town_cmd.cpp:937
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:51
uint ApplyFoundationToSlope(Foundation f, Slope &s)
Applies a foundation to a slope.
bool GenerateLandscape(uint8_t mode)
CommandCost CmdLandscapeClear(DoCommandFlags flags, TileIndex tile)
Clear a piece of landscape.
static const uint TILE_UPDATE_FREQUENCY
How many ticks it takes between tile updates (has to be a power of 2).
Definition landscape.cpp:87
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:65
uint ApplyPixelFoundationToSlope(Foundation f, Slope &s)
Applies a foundation to a slope.
Definition landscape.h:126
Point InverseRemapCoords(int x, int y)
Map 2D viewport or smallmap coordinate to 3D world or tile coordinate.
Definition landscape.h:109
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:93
uint DistanceManhattan(TileIndex t0, TileIndex t1)
Gets the Manhattan distance between the two given tiles.
Definition map.cpp:142
TileIndex TileAddXY(TileIndex tile, int x, int y)
Adds a given offset to a tile.
Definition map_func.h:469
TileIndex AddTileIndexDiffCWrap(TileIndex tile, TileIndexDiffC diff)
Add a TileIndexDiffC to a TileIndex and returns the new one.
Definition map_func.h:514
static debug_inline TileIndex TileXY(uint x, uint y)
Returns the TileIndex of a coordinate.
Definition map_func.h:372
TileIndex TileAddByDiagDir(TileIndex tile, DiagDirection dir)
Adds a DiagDir to a tile.
Definition map_func.h:610
TileIndexDiff TileDiffXY(int x, int y)
Calculates an offset for the given coordinate(-offset).
Definition map_func.h:388
TileIndexDiffC TileIndexDiffCByDiagDir(DiagDirection dir)
Returns the TileIndexDiffC offset from a DiagDirection.
Definition map_func.h:482
#define RandomTile()
Get a valid random tile.
Definition map_func.h:651
static debug_inline uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition map_func.h:424
static debug_inline uint TileX(TileIndex tile)
Get the X component of a tile.
Definition map_func.h:414
TileIndexDiff TileOffsByDiagDir(DiagDirection dir)
Convert a DiagDirection to a TileIndexDiff.
Definition map_func.h:569
static debug_inline TileIndex TileVirtXY(uint x, uint y)
Get a tile from the virtual XY-coordinate.
Definition map_func.h:403
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:66
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:424
std::string name
Name of the file.
Definition saveload.h:425
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
uint8_t river_route_random
the amount of randomicity for the route finding
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:327
static uint SizeY()
Get the size of the map along the Y.
Definition map_func.h:278
static IterateWrapper Iterate()
Returns an iterable ensemble of all Tiles.
Definition map_func.h:362
static debug_inline uint SizeX()
Get the size of the map along the X.
Definition map_func.h:269
static debug_inline uint LogX()
Logarithm of the map size along the X side.
Definition map_func.h:250
static uint LogY()
Logarithm of the map size along the y side.
Definition map_func.h:260
static uint MaxY()
Gets the maximum Y coordinate within the map, including MP_VOID.
Definition map_func.h:305
static debug_inline uint Size()
Get the size of the map.
Definition map_func.h:287
static debug_inline uint MaxX()
Gets the maximum X coordinate within the map, including MP_VOID.
Definition map_func.h:296
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:142
GetTileDescProc * get_tile_desc_proc
Get a description of a tile (for the 'land area information' tool)
Definition tile_cmd.h:147
GetTileTrackStatusProc * get_tile_track_status_proc
Get available tracks and status of a tile.
Definition tile_cmd.h:148
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:186
bool IsTileFlat(TileIndex tile, int *h)
Check if a given tile is flat.
Definition tile_map.cpp:95
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.
@ INVALID_TRACKDIR
Flag for an invalid trackdir.
Definition track_type.h:85
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:136
bool IsRiver(Tile t)
Is it a river water tile?
Definition water_map.h:180
@ 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:101
bool IsCanal(Tile t)
Is it a canal tile?
Definition water_map.h:169
WaterClass GetWaterClass(Tile t)
Get the water class at a tile.
Definition water_map.h:112
bool IsCoastTile(Tile t)
Is it a coast tile.
Definition water_map.h:211
bool IsDockingTile(Tile t)
Checks whether the tile is marked as a dockling tile.
Definition water_map.h:371
bool IsWaterTile(Tile t)
Is it a water tile with plain water?
Definition water_map.h:190
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.