OpenTTD Source 20250924-master-gbec4e71d53
water_cmd.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
7
10#include "stdafx.h"
11#include "landscape.h"
12#include "viewport_func.h"
13#include "command_func.h"
14#include "town.h"
15#include "news_func.h"
16#include "depot_base.h"
17#include "depot_func.h"
18#include "water.h"
19#include "industry_map.h"
20#include "newgrf_canal.h"
21#include "strings_func.h"
22#include "vehicle_func.h"
23#include "sound_func.h"
24#include "company_func.h"
25#include "clear_map.h"
26#include "tree_map.h"
27#include "aircraft.h"
28#include "effectvehicle_func.h"
29#include "tunnelbridge_map.h"
30#include "station_base.h"
31#include "ai/ai.hpp"
32#include "game/game.hpp"
33#include "core/random_func.hpp"
34#include "core/backup_type.hpp"
36#include "company_base.h"
37#include "company_gui.h"
38#include "newgrf_generic.h"
39#include "industry.h"
40#include "water_cmd.h"
41#include "landscape_cmd.h"
43
44#include "table/strings.h"
45
46#include "safeguards.h"
47
51static const Directions _flood_from_dirs[] = {
52 {DIR_NW, DIR_SW, DIR_SE, DIR_NE}, // SLOPE_FLAT
53 {DIR_NE, DIR_SE}, // SLOPE_W
54 {DIR_NW, DIR_NE}, // SLOPE_S
55 {DIR_NE}, // SLOPE_SW
56 {DIR_NW, DIR_SW}, // SLOPE_E
57 {}, // SLOPE_EW
58 {DIR_NW}, // SLOPE_SE
59 {DIR_N, DIR_NW, DIR_NE}, // SLOPE_WSE, SLOPE_STEEP_S
60 {DIR_SW, DIR_SE}, // SLOPE_N
61 {DIR_SE}, // SLOPE_NW
62 {}, // SLOPE_NS
63 {DIR_E, DIR_NE, DIR_SE}, // SLOPE_NWS, SLOPE_STEEP_W
64 {DIR_SW}, // SLOPE_NE
65 {DIR_S, DIR_SW, DIR_SE}, // SLOPE_ENW, SLOPE_STEEP_N
66 {DIR_W, DIR_SW, DIR_NW}, // SLOPE_SEN, SLOPE_STEEP_E
67};
68
75static inline void MarkTileDirtyIfCanalOrRiver(TileIndex tile)
76{
77 if (IsValidTile(tile) && IsTileType(tile, MP_WATER) && (IsCanal(tile) || IsRiver(tile))) MarkTileDirtyByTile(tile);
78}
79
87{
88 for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
90 }
91}
92
98{
99 for (Direction dir = DIR_BEGIN; dir != DIR_END; dir++) {
100 TileIndex dest = tile + TileOffsByDir(dir);
101 if (IsValidTile(dest) && IsTileType(dest, MP_WATER)) SetNonFloodingWaterTile(dest, false);
102 }
103}
104
113{
114 if (!IsValidAxis(axis)) return CMD_ERROR;
115 TileIndex tile2 = tile + TileOffsByAxis(axis);
116
117 if (!HasTileWaterGround(tile) || !HasTileWaterGround(tile2)) {
118 return CommandCost(STR_ERROR_MUST_BE_BUILT_ON_WATER);
119 }
120
121 if (IsBridgeAbove(tile) || IsBridgeAbove(tile2)) return CommandCost(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
122
123 if (!IsTileFlat(tile) || !IsTileFlat(tile2)) {
124 /* Prevent depots on rapids */
125 return CommandCost(STR_ERROR_SITE_UNSUITABLE);
126 }
127
128 if (!Depot::CanAllocateItem()) return CMD_ERROR;
129
130 WaterClass wc1 = GetWaterClass(tile);
131 WaterClass wc2 = GetWaterClass(tile2);
132 CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_DEPOT_SHIP]);
133
134 bool add_cost = !IsWaterTile(tile);
136 if (ret.Failed()) return ret;
137 if (add_cost) {
138 cost.AddCost(ret.GetCost());
139 }
140 add_cost = !IsWaterTile(tile2);
142 if (ret.Failed()) return ret;
143 if (add_cost) {
144 cost.AddCost(ret.GetCost());
145 }
146
147 if (flags.Test(DoCommandFlag::Execute)) {
148 Depot *depot = new Depot(tile);
149
150 uint new_water_infra = 2 * LOCK_DEPOT_TILE_FACTOR;
151 /* Update infrastructure counts after the tile clears earlier.
152 * Clearing object tiles may result in water tiles which are already accounted for in the water infrastructure total.
153 * See: MakeWaterKeepingClass() */
154 if (wc1 == WATER_CLASS_CANAL && !(HasTileWaterClass(tile) && GetWaterClass(tile) == WATER_CLASS_CANAL && IsTileOwner(tile, _current_company))) new_water_infra++;
155 if (wc2 == WATER_CLASS_CANAL && !(HasTileWaterClass(tile2) && GetWaterClass(tile2) == WATER_CLASS_CANAL && IsTileOwner(tile2, _current_company))) new_water_infra++;
156
157 Company::Get(_current_company)->infrastructure.water += new_water_infra;
159
160 MakeShipDepot(tile, _current_company, depot->index, DEPOT_PART_NORTH, axis, wc1);
161 MakeShipDepot(tile2, _current_company, depot->index, DEPOT_PART_SOUTH, axis, wc2);
163 CheckForDockingTile(tile2);
165 MarkTileDirtyByTile(tile2);
166 MakeDefaultName(depot);
167 }
168
169 return cost;
170}
171
172bool IsPossibleDockingTile(Tile t)
173{
174 assert(IsValidTile(t));
175 switch (GetTileType(t)) {
176 case MP_WATER:
177 if (IsLock(t) && GetLockPart(t) == LOCK_PART_MIDDLE) return false;
178 [[fallthrough]];
179 case MP_RAILWAY:
180 case MP_STATION:
181 case MP_TUNNELBRIDGE:
183
184 default:
185 return false;
186 }
187}
188
195{
196 for (DiagDirection d = DIAGDIR_BEGIN; d != DIAGDIR_END; d++) {
197 TileIndex tile = t + TileOffsByDiagDir(d);
198 if (!IsValidTile(tile)) continue;
199
200 if (IsDockTile(tile) && IsDockWaterPart(tile)) {
201 Station::GetByTile(tile)->docking_station.Add(t);
202 SetDockingTile(t, true);
203 }
204 if (IsTileType(tile, MP_INDUSTRY)) {
206 if (st != nullptr) {
207 st->docking_station.Add(t);
208 SetDockingTile(t, true);
209 }
210 }
211 if (IsTileType(tile, MP_STATION) && IsOilRig(tile)) {
212 Station::GetByTile(tile)->docking_station.Add(t);
213 SetDockingTile(t, true);
214 }
215 }
216}
217
218void MakeWaterKeepingClass(TileIndex tile, Owner o)
219{
220 WaterClass wc = GetWaterClass(tile);
221
222 /* Autoslope might turn an originally canal or river tile into land */
223 auto [slope, z] = GetTileSlopeZ(tile);
224
225 if (slope != SLOPE_FLAT) {
226 if (wc == WATER_CLASS_CANAL) {
227 /* If we clear the canal, we have to remove it from the infrastructure count as well. */
229 if (c != nullptr) {
232 }
233 /* Sloped canals are locks and no natural water remains whatever the slope direction */
235 }
236
237 /* Only river water should be restored on appropriate slopes. Other water would be invalid on slopes */
240 }
241 }
242
243 if (wc == WATER_CLASS_SEA && z > 0) {
244 /* Update company infrastructure count. */
246 if (c != nullptr) {
249 }
250
252 }
253
254 /* Zero map array and terminate animation */
255 DoClearSquare(tile);
256
257 /* Maybe change to water */
258 switch (wc) {
259 case WATER_CLASS_SEA: MakeSea(tile); break;
260 case WATER_CLASS_CANAL: MakeCanal(tile, o, Random()); break;
261 case WATER_CLASS_RIVER: MakeRiver(tile, Random()); break;
262 default: break;
263 }
264
267}
268
269static CommandCost RemoveShipDepot(TileIndex tile, DoCommandFlags flags)
270{
271 if (!IsShipDepot(tile)) return CMD_ERROR;
272
274 if (ret.Failed()) return ret;
275
276 TileIndex tile2 = GetOtherShipDepotTile(tile);
277
278 /* do not check for ship on tile when company goes bankrupt */
279 if (!flags.Test(DoCommandFlag::Bankrupt)) {
280 ret = EnsureNoVehicleOnGround(tile);
281 if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile2);
282 if (ret.Failed()) return ret;
283 }
284
285 bool do_clear = flags.Test(DoCommandFlag::ForceClearTile);
286
287 if (flags.Test(DoCommandFlag::Execute)) {
288 delete Depot::GetByTile(tile);
289
291 if (c != nullptr) {
293 if (do_clear && GetWaterClass(tile) == WATER_CLASS_CANAL) c->infrastructure.water--;
295 }
296
297 if (!do_clear) MakeWaterKeepingClass(tile, GetTileOwner(tile));
298 MakeWaterKeepingClass(tile2, GetTileOwner(tile2));
299 }
300
301 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_SHIP]);
302}
303
310{
311 static constexpr uint8_t MINIMAL_BRIDGE_HEIGHT[LOCK_PART_END] = {
312 2, // LOCK_PART_MIDDLE
313 3, // LOCK_PART_LOWER
314 2, // LOCK_PART_UPPER
315 };
316 return MINIMAL_BRIDGE_HEIGHT[to_underlying(lock_part)];
317}
318
327{
329
330 TileIndexDiff delta = TileOffsByDiagDir(dir);
332 if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile + delta);
333 if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile - delta);
334 if (ret.Failed()) return ret;
335
336 /* middle tile */
338 ret = Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile);
339 if (ret.Failed()) return ret;
340 cost.AddCost(ret.GetCost());
341
342 /* lower tile */
343 if (!IsWaterTile(tile - delta)) {
344 ret = Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile - delta);
345 if (ret.Failed()) return ret;
346 cost.AddCost(ret.GetCost());
347 cost.AddCost(_price[PR_BUILD_CANAL]);
348 }
349 if (!IsTileFlat(tile - delta)) {
350 return CommandCost(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
351 }
352 WaterClass wc_lower = IsWaterTile(tile - delta) ? GetWaterClass(tile - delta) : WATER_CLASS_CANAL;
353
354 /* upper tile */
355 if (!IsWaterTile(tile + delta)) {
356 ret = Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile + delta);
357 if (ret.Failed()) return ret;
358 cost.AddCost(ret.GetCost());
359 cost.AddCost(_price[PR_BUILD_CANAL]);
360 }
361 if (!IsTileFlat(tile + delta)) {
362 return CommandCost(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
363 }
364 WaterClass wc_upper = IsWaterTile(tile + delta) ? GetWaterClass(tile + delta) : WATER_CLASS_CANAL;
365
366 for (LockPart lock_part = LOCK_PART_MIDDLE; TileIndex t : {tile, tile - delta, tile + delta}) {
368 return CommandCost(STR_ERROR_BRIDGE_TOO_LOW_FOR_LOCK);
369 }
370 ++lock_part;
371 }
372
373 if (flags.Test(DoCommandFlag::Execute)) {
374 /* Update company infrastructure counts. */
376 if (c != nullptr) {
377 /* Counts for the water. */
378 if (!IsWaterTile(tile - delta)) c->infrastructure.water++;
379 if (!IsWaterTile(tile + delta)) c->infrastructure.water++;
380 /* Count for the lock itself. */
381 c->infrastructure.water += 3 * LOCK_DEPOT_TILE_FACTOR; // Lock is three tiles.
383 }
384
385 MakeLock(tile, _current_company, dir, wc_lower, wc_upper, wc_middle);
386 CheckForDockingTile(tile - delta);
387 CheckForDockingTile(tile + delta);
389 MarkTileDirtyByTile(tile - delta);
390 MarkTileDirtyByTile(tile + delta);
391 MarkCanalsAndRiversAroundDirty(tile - delta);
392 MarkCanalsAndRiversAroundDirty(tile + delta);
393 InvalidateWaterRegion(tile - delta);
394 InvalidateWaterRegion(tile + delta);
395 }
396 cost.AddCost(_price[PR_BUILD_LOCK]);
397
398 return cost;
399}
400
408{
409 if (GetTileOwner(tile) != OWNER_NONE) {
411 if (ret.Failed()) return ret;
412 }
413
415
416 /* make sure no vehicle is on the tile. */
418 if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile + delta);
419 if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile - delta);
420 if (ret.Failed()) return ret;
421
422 if (flags.Test(DoCommandFlag::Execute)) {
423 /* Remove middle part from company infrastructure count. */
425 if (c != nullptr) {
426 c->infrastructure.water -= 3 * LOCK_DEPOT_TILE_FACTOR; // three parts of the lock.
428 }
429
430 if (GetWaterClass(tile) == WATER_CLASS_RIVER) {
431 MakeRiver(tile, Random());
432 } else {
433 DoClearSquare(tile);
435 }
436 MakeWaterKeepingClass(tile + delta, GetTileOwner(tile + delta));
437 MakeWaterKeepingClass(tile - delta, GetTileOwner(tile - delta));
439 MarkCanalsAndRiversAroundDirty(tile - delta);
440 MarkCanalsAndRiversAroundDirty(tile + delta);
441 }
442
443 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_LOCK]);
444}
445
453{
455 if (dir == INVALID_DIAGDIR) return CommandCost(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
456
457 return DoBuildLock(tile, dir, flags);
458}
459
465{
466 MakeRiver(tile, Random());
468
469 /* Remove desert directly around the river tile. */
472 }
473}
474
484CommandCost CmdBuildCanal(DoCommandFlags flags, TileIndex tile, TileIndex start_tile, WaterClass wc, bool diagonal)
485{
486 if (start_tile >= Map::Size() || !IsValidWaterClass(wc)) return CMD_ERROR;
487
488 /* Outside of the editor you can only build canals, not oceans */
489 if (wc != WATER_CLASS_CANAL && _game_mode != GM_EDITOR) return CMD_ERROR;
490
492
493 std::unique_ptr<TileIterator> iter = TileIterator::Create(tile, start_tile, diagonal);
494 for (; *iter != INVALID_TILE; ++(*iter)) {
495 TileIndex current_tile = *iter;
496 CommandCost ret;
497
498 Slope slope = GetTileSlope(current_tile);
499 if (slope != SLOPE_FLAT && (wc != WATER_CLASS_RIVER || !IsInclinedSlope(slope))) {
500 return CommandCost(STR_ERROR_FLAT_LAND_REQUIRED);
501 }
502
503 bool water = IsWaterTile(current_tile);
504
505 /* Outside the editor, prevent building canals over your own or OWNER_NONE owned canals */
506 if (water && IsCanal(current_tile) && _game_mode != GM_EDITOR && (IsTileOwner(current_tile, _current_company) || IsTileOwner(current_tile, OWNER_NONE))) continue;
507
508 ret = Command<CMD_LANDSCAPE_CLEAR>::Do(flags, current_tile);
509 if (ret.Failed()) return ret;
510
511 if (!water) cost.AddCost(ret.GetCost());
512
513 if (flags.Test(DoCommandFlag::Execute)) {
514 if (IsTileType(current_tile, MP_WATER) && IsCanal(current_tile)) {
515 Owner owner = GetTileOwner(current_tile);
516 if (Company::IsValidID(owner)) {
517 Company::Get(owner)->infrastructure.water--;
519 }
520 }
521
522 switch (wc) {
524 MakeRiver(current_tile, Random());
525 if (_game_mode == GM_EDITOR) {
526 /* Remove desert directly around the river tile. */
527 for (auto t : SpiralTileSequence(current_tile, RIVER_OFFSET_DESERT_DISTANCE)) {
529 }
530 }
531 break;
532
533 case WATER_CLASS_SEA:
534 if (TileHeight(current_tile) == 0) {
535 MakeSea(current_tile);
536 break;
537 }
538 [[fallthrough]];
539
540 default:
541 MakeCanal(current_tile, _current_company, Random());
543 Company::Get(_current_company)->infrastructure.water++;
545 }
546 break;
547 }
548 MarkTileDirtyByTile(current_tile);
549 MarkCanalsAndRiversAroundDirty(current_tile);
550 CheckForDockingTile(current_tile);
551 }
552
553 cost.AddCost(_price[PR_BUILD_CANAL]);
554 }
555
556 if (cost.GetCost() == 0) {
557 return CommandCost(STR_ERROR_ALREADY_BUILT);
558 } else {
559 return cost;
560 }
561}
562
563
564static CommandCost ClearTile_Water(TileIndex tile, DoCommandFlags flags)
565{
566 switch (GetWaterTileType(tile)) {
567 case WATER_TILE_CLEAR: {
568 if (flags.Test(DoCommandFlag::NoWater)) return CommandCost(STR_ERROR_CAN_T_BUILD_ON_WATER);
569
570 Money base_cost = IsCanal(tile) ? _price[PR_CLEAR_CANAL] : _price[PR_CLEAR_WATER];
571 /* Make sure freeform edges are allowed or it's not an edge tile. */
573 !IsInsideMM(TileY(tile), 1, Map::MaxY() - 1))) {
574 return CommandCost(STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP);
575 }
576
577 /* Make sure no vehicle is on the tile */
579 if (ret.Failed()) return ret;
580
581 Owner owner = GetTileOwner(tile);
582 if (owner != OWNER_WATER && owner != OWNER_NONE) {
583 ret = CheckTileOwnership(tile);
584 if (ret.Failed()) return ret;
585 }
586
587 if (flags.Test(DoCommandFlag::Execute)) {
588 if (IsCanal(tile) && Company::IsValidID(owner)) {
589 Company::Get(owner)->infrastructure.water--;
591 }
592 DoClearSquare(tile);
595 }
596
597 return CommandCost(EXPENSES_CONSTRUCTION, base_cost);
598 }
599
600 case WATER_TILE_COAST: {
601 Slope slope = GetTileSlope(tile);
602
603 /* Make sure no vehicle is on the tile */
605 if (ret.Failed()) return ret;
606
607 if (flags.Test(DoCommandFlag::Execute)) {
608 DoClearSquare(tile);
611 }
612 if (IsSlopeWithOneCornerRaised(slope)) {
613 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_WATER]);
614 } else {
615 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_ROUGH]);
616 }
617 }
618
619 case WATER_TILE_LOCK: {
620 static const TileIndexDiffC _lock_tomiddle_offs[][DIAGDIR_END] = {
621 /* NE SE SW NW */
622 { { 0, 0}, {0, 0}, { 0, 0}, {0, 0} }, // LOCK_PART_MIDDLE
623 { {-1, 0}, {0, 1}, { 1, 0}, {0, -1} }, // LOCK_PART_LOWER
624 { { 1, 0}, {0, -1}, {-1, 0}, {0, 1} }, // LOCK_PART_UPPER
625 };
626
627 if (flags.Test(DoCommandFlag::Auto)) return CommandCost(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
629 /* move to the middle tile.. */
630 return RemoveLock(tile + ToTileIndexDiff(_lock_tomiddle_offs[GetLockPart(tile)][GetLockDirection(tile)]), flags);
631 }
632
633 case WATER_TILE_DEPOT:
634 if (flags.Test(DoCommandFlag::Auto)) return CommandCost(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
635 return RemoveShipDepot(tile, flags);
636
637 default:
638 NOT_REACHED();
639 }
640}
641
651{
652 switch (GetTileType(tile)) {
653 case MP_WATER:
654 switch (GetWaterTileType(tile)) {
655 default: NOT_REACHED();
656 case WATER_TILE_DEPOT: case WATER_TILE_CLEAR: return true;
658
659 case WATER_TILE_COAST:
660 switch (GetTileSlope(tile)) {
661 case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE);
662 case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW);
663 case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW);
664 case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE);
665 default: return false;
666 }
667 }
668
669 case MP_RAILWAY:
670 if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
671 assert(IsPlainRail(tile));
672 switch (GetTileSlope(tile)) {
673 case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE);
674 case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW);
675 case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW);
676 case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE);
677 default: return false;
678 }
679 }
680 return false;
681
682 case MP_STATION:
683 if (IsOilRig(tile)) {
684 /* Do not draw waterborders inside of industries.
685 * Note: There is no easy way to detect the industry of an oilrig tile. */
686 TileIndex src_tile = tile + TileOffsByDir(from);
687 if ((IsTileType(src_tile, MP_STATION) && IsOilRig(src_tile)) ||
688 (IsTileType(src_tile, MP_INDUSTRY))) return true;
689
690 return IsTileOnWater(tile);
691 }
692 return (IsDock(tile) && IsTileFlat(tile)) || IsBuoy(tile);
693
694 case MP_INDUSTRY: {
695 /* Do not draw waterborders inside of industries.
696 * Note: There is no easy way to detect the industry of an oilrig tile. */
697 TileIndex src_tile = tile + TileOffsByDir(from);
698 if ((IsTileType(src_tile, MP_STATION) && IsOilRig(src_tile)) ||
699 (IsTileType(src_tile, MP_INDUSTRY) && GetIndustryIndex(src_tile) == GetIndustryIndex(tile))) return true;
700
701 return IsTileOnWater(tile);
702 }
703
704 case MP_OBJECT: return IsTileOnWater(tile);
705
707
708 case MP_VOID: return true; // consider map border as water, esp. for rivers
709
710 default: return false;
711 }
712}
713
721static void DrawWaterSprite(SpriteID base, uint offset, CanalFeature feature, TileIndex tile)
722{
723 if (base != SPR_FLAT_WATER_TILE) {
724 /* Only call offset callback if the sprite is NewGRF-provided. */
725 offset = GetCanalSpriteOffset(feature, tile, offset);
726 }
727 DrawGroundSprite(base + offset, PAL_NONE);
728}
729
736static void DrawWaterEdges(bool canal, uint offset, TileIndex tile)
737{
738 CanalFeature feature;
739 SpriteID base = 0;
740 if (canal) {
741 feature = CF_DIKES;
742 base = GetCanalSprite(CF_DIKES, tile);
743 if (base == 0) base = SPR_CANAL_DIKES_BASE;
744 } else {
745 feature = CF_RIVER_EDGE;
746 base = GetCanalSprite(CF_RIVER_EDGE, tile);
747 if (base == 0) return; // Don't draw if no sprites provided.
748 }
749
750 uint wa;
751
752 /* determine the edges around with water. */
753 wa = IsWateredTile(TileAddXY(tile, -1, 0), DIR_SW) << 0;
754 wa += IsWateredTile(TileAddXY(tile, 0, 1), DIR_NW) << 1;
755 wa += IsWateredTile(TileAddXY(tile, 1, 0), DIR_NE) << 2;
756 wa += IsWateredTile(TileAddXY(tile, 0, -1), DIR_SE) << 3;
757
758 if (!(wa & 1)) DrawWaterSprite(base, offset, feature, tile);
759 if (!(wa & 2)) DrawWaterSprite(base, offset + 1, feature, tile);
760 if (!(wa & 4)) DrawWaterSprite(base, offset + 2, feature, tile);
761 if (!(wa & 8)) DrawWaterSprite(base, offset + 3, feature, tile);
762
763 /* right corner */
764 switch (wa & 0x03) {
765 case 0: DrawWaterSprite(base, offset + 4, feature, tile); break;
766 case 3: if (!IsWateredTile(TileAddXY(tile, -1, 1), DIR_W)) DrawWaterSprite(base, offset + 8, feature, tile); break;
767 }
768
769 /* bottom corner */
770 switch (wa & 0x06) {
771 case 0: DrawWaterSprite(base, offset + 5, feature, tile); break;
772 case 6: if (!IsWateredTile(TileAddXY(tile, 1, 1), DIR_N)) DrawWaterSprite(base, offset + 9, feature, tile); break;
773 }
774
775 /* left corner */
776 switch (wa & 0x0C) {
777 case 0: DrawWaterSprite(base, offset + 6, feature, tile); break;
778 case 12: if (!IsWateredTile(TileAddXY(tile, 1, -1), DIR_E)) DrawWaterSprite(base, offset + 10, feature, tile); break;
779 }
780
781 /* upper corner */
782 switch (wa & 0x09) {
783 case 0: DrawWaterSprite(base, offset + 7, feature, tile); break;
784 case 9: if (!IsWateredTile(TileAddXY(tile, -1, -1), DIR_S)) DrawWaterSprite(base, offset + 11, feature, tile); break;
785 }
786}
787
790{
791 DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
792}
793
795static void DrawCanalWater(TileIndex tile)
796{
797 SpriteID image = SPR_FLAT_WATER_TILE;
798 if (HasBit(_water_feature[CF_WATERSLOPE].flags, CFF_HAS_FLAT_SPRITE)) {
799 /* First water slope sprite is flat water. */
800 image = GetCanalSprite(CF_WATERSLOPE, tile);
801 if (image == 0) image = SPR_FLAT_WATER_TILE;
802 }
803 DrawWaterSprite(image, 0, CF_WATERSLOPE, tile);
804
805 DrawWaterEdges(true, 0, tile);
806}
807
808#include "table/water_land.h"
809
819static void DrawWaterTileStruct(const TileInfo *ti, std::span<const DrawTileSeqStruct> seq, SpriteID base, uint offset, PaletteID palette, CanalFeature feature)
820{
821 /* Don't draw if buildings are invisible. */
822 if (IsInvisibilitySet(TO_BUILDINGS)) return;
823
824 for (const DrawTileSeqStruct &dtss : seq) {
825 uint tile_offs = offset + dtss.image.sprite;
826 if (feature < CF_END) tile_offs = GetCanalSpriteOffset(feature, ti->tile, tile_offs);
827 AddSortableSpriteToDraw(base + tile_offs, palette, *ti, dtss, IsTransparencySet(TO_BUILDINGS));
828 }
829}
830
832static void DrawWaterLock(const TileInfo *ti)
833{
834 int part = GetLockPart(ti->tile);
835 const DrawTileSprites &dts = _lock_display_data[part][GetLockDirection(ti->tile)];
836
837 /* Draw ground sprite. */
838 SpriteID image = dts.ground.sprite;
839
840 SpriteID water_base = GetCanalSprite(CF_WATERSLOPE, ti->tile);
841 if (water_base == 0) {
842 /* Use default sprites. */
843 water_base = SPR_CANALS_BASE;
844 } else if (HasBit(_water_feature[CF_WATERSLOPE].flags, CFF_HAS_FLAT_SPRITE)) {
845 /* NewGRF supplies a flat sprite as first sprite. */
846 if (image == SPR_FLAT_WATER_TILE) {
847 image = water_base;
848 } else {
849 image++;
850 }
851 }
852
853 if (image < 5) image += water_base;
854 DrawGroundSprite(image, PAL_NONE);
855
856 /* Draw structures. */
857 uint zoffs = 0;
858 SpriteID base = GetCanalSprite(CF_LOCKS, ti->tile);
859
860 if (base == 0) {
861 /* If no custom graphics, use defaults. */
862 base = SPR_LOCK_BASE;
863 uint8_t z_threshold = part == LOCK_PART_UPPER ? 8 : 0;
864 zoffs = ti->z > z_threshold ? 24 : 0;
865 }
866
867 DrawWaterTileStruct(ti, dts.GetSequence(), base, zoffs, PAL_NONE, CF_LOCKS);
868}
869
871static void DrawWaterDepot(const TileInfo *ti)
872{
873 DrawWaterClassGround(ti);
874 DrawWaterTileStruct(ti, _shipdepot_display_data[GetShipDepotAxis(ti->tile)][GetShipDepotPart(ti->tile)].seq, 0, 0, GetCompanyPalette(GetTileOwner(ti->tile)), CF_END);
875}
876
877static void DrawRiverWater(const TileInfo *ti)
878{
879 SpriteID image = SPR_FLAT_WATER_TILE;
880 uint offset = 0;
881 uint edges_offset = 0;
882
883 if (ti->tileh != SLOPE_FLAT || HasBit(_water_feature[CF_RIVER_SLOPE].flags, CFF_HAS_FLAT_SPRITE)) {
884 image = GetCanalSprite(CF_RIVER_SLOPE, ti->tile);
885 if (image == 0) {
886 switch (ti->tileh) {
887 case SLOPE_NW: image = SPR_WATER_SLOPE_Y_DOWN; break;
888 case SLOPE_SW: image = SPR_WATER_SLOPE_X_UP; break;
889 case SLOPE_SE: image = SPR_WATER_SLOPE_Y_UP; break;
890 case SLOPE_NE: image = SPR_WATER_SLOPE_X_DOWN; break;
891 default: image = SPR_FLAT_WATER_TILE; break;
892 }
893 } else {
894 /* Flag bit 0 indicates that the first sprite is flat water. */
895 offset = HasBit(_water_feature[CF_RIVER_SLOPE].flags, CFF_HAS_FLAT_SPRITE) ? 1 : 0;
896
897 switch (ti->tileh) {
898 case SLOPE_SE: edges_offset += 12; break;
899 case SLOPE_NE: offset += 1; edges_offset += 24; break;
900 case SLOPE_SW: offset += 2; edges_offset += 36; break;
901 case SLOPE_NW: offset += 3; edges_offset += 48; break;
902 default: offset = 0; break;
903 }
904
905 offset = GetCanalSpriteOffset(CF_RIVER_SLOPE, ti->tile, offset);
906 }
907 }
908
909 DrawGroundSprite(image + offset, PAL_NONE);
910
911 /* Draw river edges if available. */
912 DrawWaterEdges(false, edges_offset, ti->tile);
913}
914
915void DrawShoreTile(Slope tileh)
916{
917 /* Converts the enum Slope into an offset based on SPR_SHORE_BASE.
918 * This allows to calculate the proper sprite to display for this Slope */
919 static const uint8_t tileh_to_shoresprite[32] = {
920 0, 1, 2, 3, 4, 16, 6, 7, 8, 9, 17, 11, 12, 13, 14, 0,
921 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 10, 15, 0,
922 };
923
924 assert(!IsHalftileSlope(tileh)); // Halftile slopes need to get handled earlier.
925 assert(tileh != SLOPE_FLAT); // Shore is never flat
926
927 assert((tileh != SLOPE_EW) && (tileh != SLOPE_NS)); // No suitable sprites for current flooding behaviour
928
929 DrawGroundSprite(SPR_SHORE_BASE + tileh_to_shoresprite[tileh], PAL_NONE);
930}
931
932void DrawWaterClassGround(const TileInfo *ti)
933{
934 switch (GetWaterClass(ti->tile)) {
935 case WATER_CLASS_SEA: DrawSeaWater(ti->tile); break;
936 case WATER_CLASS_CANAL: DrawCanalWater(ti->tile); break;
937 case WATER_CLASS_RIVER: DrawRiverWater(ti); break;
938 default: NOT_REACHED();
939 }
940}
941
942static void DrawTile_Water(TileInfo *ti)
943{
944 switch (GetWaterTileType(ti->tile)) {
945 case WATER_TILE_CLEAR:
946 DrawWaterClassGround(ti);
947 /* A plain water tile can be traversed in any direction, so setting blocked pillars here would mean all bridges
948 * with edges would have no pillars above water. Instead prefer current behaviour of ships passing through. */
949 DrawBridgeMiddle(ti, {});
950 break;
951
952 case WATER_TILE_COAST: {
953 DrawShoreTile(ti->tileh);
954 DrawBridgeMiddle(ti, {});
955 break;
956 }
957
958 case WATER_TILE_LOCK:
959 DrawWaterLock(ti);
961 ? BridgePillarFlags{BridgePillarFlag::EdgeNE, BridgePillarFlag::EdgeSW}
963 break;
964
965 case WATER_TILE_DEPOT:
966 DrawWaterDepot(ti);
967 break;
968 }
969}
970
971void DrawShipDepotSprite(int x, int y, Axis axis, DepotPart part)
972{
973 const DrawTileSprites &dts = _shipdepot_display_data[axis][part];
974
975 DrawSprite(dts.ground.sprite, dts.ground.pal, x, y);
977}
978
979
980static int GetSlopePixelZ_Water(TileIndex tile, uint x, uint y, bool)
981{
982 auto [tileh, z] = GetTilePixelSlope(tile);
983
984 return z + GetPartialPixelZ(x & 0xF, y & 0xF, tileh);
985}
986
987static Foundation GetFoundation_Water(TileIndex, Slope)
988{
989 return FOUNDATION_NONE;
990}
991
992static void GetTileDesc_Water(TileIndex tile, TileDesc &td)
993{
994 switch (GetWaterTileType(tile)) {
995 case WATER_TILE_CLEAR:
996 switch (GetWaterClass(tile)) {
997 case WATER_CLASS_SEA: td.str = STR_LAI_WATER_DESCRIPTION_WATER; break;
998 case WATER_CLASS_CANAL: td.str = STR_LAI_WATER_DESCRIPTION_CANAL; break;
999 case WATER_CLASS_RIVER: td.str = STR_LAI_WATER_DESCRIPTION_RIVER; break;
1000 default: NOT_REACHED();
1001 }
1002 break;
1003 case WATER_TILE_COAST: td.str = STR_LAI_WATER_DESCRIPTION_COAST_OR_RIVERBANK; break;
1004 case WATER_TILE_LOCK : td.str = STR_LAI_WATER_DESCRIPTION_LOCK; break;
1005 case WATER_TILE_DEPOT:
1006 td.str = STR_LAI_WATER_DESCRIPTION_SHIP_DEPOT;
1007 td.build_date = Depot::GetByTile(tile)->build_date;
1008 break;
1009 default: NOT_REACHED();
1010 }
1011
1012 td.owner[0] = GetTileOwner(tile);
1013}
1014
1020static void FloodVehicle(Vehicle *v)
1021{
1022 uint victims = v->Crash(true);
1023
1024 AI::NewEvent(v->owner, new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_FLOODED, victims, v->owner));
1025 Game::NewEvent(new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_FLOODED, victims, v->owner));
1026 AddTileNewsItem(GetEncodedString(STR_NEWS_DISASTER_FLOOD_VEHICLE, victims), NewsType::Accident, v->tile);
1028 if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_12_EXPLOSION, v);
1029}
1030
1036static void FloodVehicleProc(Vehicle *v, int z)
1037{
1038 if (v->vehstatus.Test(VehState::Crashed)) return;
1039
1040 switch (v->type) {
1041 default: break;
1042
1043 case VEH_AIRCRAFT: {
1044 if (!IsAirportTile(v->tile) || GetTileMaxZ(v->tile) != 0) break;
1045 if (v->subtype == AIR_SHADOW) break;
1046
1047 /* We compare v->z_pos against delta_z + 1 because the shadow
1048 * is at delta_z and the actual aircraft at delta_z + 1. */
1049 const Station *st = Station::GetByTile(v->tile);
1050 const AirportFTAClass *airport = st->airport.GetFTA();
1051 if (v->z_pos != airport->delta_z + 1) break;
1052
1053 FloodVehicle(v);
1054 break;
1055 }
1056
1057 case VEH_TRAIN:
1058 case VEH_ROAD: {
1059 if (v->z_pos > z) break;
1060 FloodVehicle(v->First());
1061 break;
1062 }
1063 }
1064}
1065
1066static void FloodVehiclesOnTile(TileIndex tile, int z)
1067{
1068 for (Vehicle *v : VehiclesOnTile(tile)) {
1069 FloodVehicleProc(v, z);
1070 }
1071}
1072
1078static void FloodVehicles(TileIndex tile)
1079{
1080 if (IsAirportTile(tile)) {
1081 const Station *st = Station::GetByTile(tile);
1082 for (TileIndex airport_tile : st->airport) {
1083 if (st->TileBelongsToAirport(airport_tile)) FloodVehiclesOnTile(airport_tile, 0);
1084 }
1085
1086 /* No vehicle could be flooded on this airport anymore */
1087 return;
1088 }
1089
1090 if (!IsBridgeTile(tile)) {
1091 FloodVehiclesOnTile(tile, 0);
1092 return;
1093 }
1094
1095 TileIndex end = GetOtherBridgeEnd(tile);
1096 int z = GetBridgePixelHeight(tile);
1097
1098 FloodVehiclesOnTile(tile, z);
1099 FloodVehiclesOnTile(end, z);
1100}
1101
1108{
1109 /* FLOOD_ACTIVE: 'single-corner-raised'-coast, sea, sea-shipdepots, sea-buoys, sea-docks (water part), rail with flooded halftile, sea-water-industries, sea-oilrigs
1110 * FLOOD_DRYUP: coast with more than one corner raised, coast with rail-track, coast with trees
1111 * FLOOD_PASSIVE: (not used)
1112 * FLOOD_NONE: canals, rivers, everything else
1113 */
1114 switch (GetTileType(tile)) {
1115 case MP_WATER:
1116 if (IsCoast(tile)) {
1117 Slope tileh = GetTileSlope(tile);
1119 }
1120 [[fallthrough]];
1121 case MP_STATION:
1122 case MP_INDUSTRY:
1123 case MP_OBJECT:
1125
1126 case MP_RAILWAY:
1127 if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
1129 }
1130 return FLOOD_NONE;
1131
1132 case MP_TREES:
1134
1135 case MP_VOID:
1136 return FLOOD_ACTIVE;
1137
1138 default:
1139 return FLOOD_NONE;
1140 }
1141}
1142
1146static void DoFloodTile(TileIndex target)
1147{
1148 assert(!IsTileType(target, MP_WATER));
1149
1150 bool flooded = false; // Will be set to true if something is changed.
1151
1153
1154 Slope tileh = GetTileSlope(target);
1155 if (tileh != SLOPE_FLAT) {
1156 /* make coast.. */
1157 switch (GetTileType(target)) {
1158 case MP_RAILWAY: {
1159 if (!IsPlainRail(target)) break;
1160 FloodVehicles(target);
1161 flooded = FloodHalftile(target);
1162 break;
1163 }
1164
1165 case MP_TREES:
1166 if (!IsSlopeWithOneCornerRaised(tileh)) {
1168 MarkTileDirtyByTile(target);
1169 flooded = true;
1170 break;
1171 }
1172 [[fallthrough]];
1173
1174 case MP_CLEAR:
1176 MakeShore(target);
1177 MarkTileDirtyByTile(target);
1178 flooded = true;
1179 }
1180 break;
1181
1182 default:
1183 break;
1184 }
1185 } else {
1186 /* Flood vehicles */
1187 FloodVehicles(target);
1188
1189 /* flood flat tile */
1191 MakeSea(target);
1192 MarkTileDirtyByTile(target);
1193 flooded = true;
1194 }
1195 }
1196
1197 if (flooded) {
1198 /* Mark surrounding canal tiles dirty too to avoid glitches */
1200
1201 /* update signals if needed */
1203
1204 if (IsPossibleDockingTile(target)) CheckForDockingTile(target);
1205 InvalidateWaterRegion(target);
1206 }
1207
1208 cur_company.Restore();
1209}
1210
1214static void DoDryUp(TileIndex tile)
1215{
1217
1218 switch (GetTileType(tile)) {
1219 case MP_RAILWAY:
1220 assert(IsPlainRail(tile));
1221 assert(GetRailGroundType(tile) == RAIL_GROUND_WATER);
1222
1223 RailGroundType new_ground;
1224 switch (GetTrackBits(tile)) {
1225 case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
1226 case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
1227 case TRACK_BIT_LEFT: new_ground = RAIL_GROUND_FENCE_VERT1; break;
1228 case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2; break;
1229 default: NOT_REACHED();
1230 }
1231 SetRailGroundType(tile, new_ground);
1232 MarkTileDirtyByTile(tile);
1233 break;
1234
1235 case MP_TREES:
1237 MarkTileDirtyByTile(tile);
1238 break;
1239
1240 case MP_WATER:
1241 assert(IsCoast(tile));
1242
1244 MakeClear(tile, CLEAR_GRASS, 3);
1245 MarkTileDirtyByTile(tile);
1246 }
1247 break;
1248
1249 default: NOT_REACHED();
1250 }
1251
1252 cur_company.Restore();
1253}
1254
1262{
1263 if (IsTileType(tile, MP_WATER)) {
1264 AmbientSoundEffect(tile);
1265 if (IsNonFloodingWaterTile(tile)) return;
1266 }
1267
1268 switch (GetFloodingBehaviour(tile)) {
1269 case FLOOD_ACTIVE: {
1270 bool continue_flooding = false;
1271 for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
1273 /* Contrary to drying up, flooding does not consider MP_VOID tiles. */
1274 if (!IsValidTile(dest)) continue;
1275 /* do not try to flood water tiles - increases performance a lot */
1276 if (IsTileType(dest, MP_WATER)) continue;
1277
1278 /* Buoys and docks cannot be flooded, and when removed turn into flooding water. */
1279 if (IsTileType(dest, MP_STATION) && (IsBuoy(dest) || IsDock(dest))) continue;
1280
1281 /* This neighbour tile might be floodable later if the tile is cleared, so allow flooding to continue. */
1282 continue_flooding = true;
1283
1284 /* TREE_GROUND_SHORE is the sign of a previous flood. */
1285 if (IsTileType(dest, MP_TREES) && GetTreeGround(dest) == TREE_GROUND_SHORE) continue;
1286
1287 auto [slope_dest, z_dest] = GetFoundationSlope(dest);
1288 if (z_dest > 0) continue;
1289
1290 if (!_flood_from_dirs[slope_dest & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP].Test(ReverseDir(dir))) continue;
1291
1292 DoFloodTile(dest);
1293 }
1294 if (!continue_flooding && IsTileType(tile, MP_WATER)) SetNonFloodingWaterTile(tile, true);
1295 break;
1296 }
1297
1298 case FLOOD_DRYUP: {
1299 Slope slope_here = std::get<0>(GetFoundationSlope(tile)) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;
1300 for (Direction dir : _flood_from_dirs[slope_here]) {
1302 /* Contrary to flooding, drying up does consider MP_VOID tiles. */
1303 if (dest == INVALID_TILE) continue;
1304
1305 FloodingBehaviour dest_behaviour = GetFloodingBehaviour(dest);
1306 if ((dest_behaviour == FLOOD_ACTIVE) || (dest_behaviour == FLOOD_PASSIVE)) return;
1307 }
1308 DoDryUp(tile);
1309 break;
1310 }
1311
1312 default: return;
1313 }
1314}
1315
1316void ConvertGroundTilesIntoWaterTiles()
1317{
1318 for (const auto tile : Map::Iterate()) {
1319 auto [slope, z] = GetTileSlopeZ(tile);
1320 if (IsTileType(tile, MP_CLEAR) && z == 0) {
1321 /* Make both water for tiles at level 0
1322 * and make shore, as that looks much better
1323 * during the generation. */
1324 switch (slope) {
1325 case SLOPE_FLAT:
1326 MakeSea(tile);
1327 break;
1328
1329 case SLOPE_N:
1330 case SLOPE_E:
1331 case SLOPE_S:
1332 case SLOPE_W:
1333 MakeShore(tile);
1334 break;
1335
1336 default:
1337 for (Direction dir : _flood_from_dirs[slope & ~SLOPE_STEEP]) {
1338 TileIndex dest = TileAddByDir(tile, dir);
1339 Slope slope_dest = GetTileSlope(dest) & ~SLOPE_STEEP;
1340 if (slope_dest == SLOPE_FLAT || IsSlopeWithOneCornerRaised(slope_dest) || IsTileType(dest, MP_VOID)) {
1341 MakeShore(tile);
1342 break;
1343 }
1344 }
1345 break;
1346 }
1347 }
1348 }
1349}
1350
1351static TrackStatus GetTileTrackStatus_Water(TileIndex tile, TransportType mode, uint, DiagDirection)
1352{
1355
1356 TrackBits ts;
1357
1358 if (mode != TRANSPORT_WATER) return 0;
1359
1360 switch (GetWaterTileType(tile)) {
1361 case WATER_TILE_CLEAR: ts = IsTileFlat(tile) ? TRACK_BIT_ALL : TRACK_BIT_NONE; break;
1362 case WATER_TILE_COAST: ts = coast_tracks[GetTileSlope(tile) & 0xF]; break;
1364 case WATER_TILE_DEPOT: ts = AxisToTrackBits(GetShipDepotAxis(tile)); break;
1365 default: return 0;
1366 }
1367 if (TileX(tile) == 0) {
1368 /* NE border: remove tracks that connects NE tile edge */
1370 }
1371 if (TileY(tile) == 0) {
1372 /* NW border: remove tracks that connects NW tile edge */
1374 }
1376}
1377
1378static bool ClickTile_Water(TileIndex tile)
1379{
1380 if (GetWaterTileType(tile) == WATER_TILE_DEPOT) {
1382 return true;
1383 }
1384 return false;
1385}
1386
1387static void ChangeTileOwner_Water(TileIndex tile, Owner old_owner, Owner new_owner)
1388{
1389 if (!IsTileOwner(tile, old_owner)) return;
1390
1391 bool is_lock_middle = IsLock(tile) && GetLockPart(tile) == LOCK_PART_MIDDLE;
1392
1393 /* No need to dirty company windows here, we'll redraw the whole screen anyway. */
1394 if (is_lock_middle) Company::Get(old_owner)->infrastructure.water -= 3 * LOCK_DEPOT_TILE_FACTOR; // Lock has three parts.
1395 if (new_owner != INVALID_OWNER) {
1396 if (is_lock_middle) Company::Get(new_owner)->infrastructure.water += 3 * LOCK_DEPOT_TILE_FACTOR; // Lock has three parts.
1397 /* Only subtract from the old owner here if the new owner is valid,
1398 * otherwise we clear ship depots and canal water below. */
1399 if (GetWaterClass(tile) == WATER_CLASS_CANAL && !is_lock_middle) {
1400 Company::Get(old_owner)->infrastructure.water--;
1401 Company::Get(new_owner)->infrastructure.water++;
1402 }
1403 if (IsShipDepot(tile)) {
1404 Company::Get(old_owner)->infrastructure.water -= LOCK_DEPOT_TILE_FACTOR;
1405 Company::Get(new_owner)->infrastructure.water += LOCK_DEPOT_TILE_FACTOR;
1406 }
1407
1408 SetTileOwner(tile, new_owner);
1409 return;
1410 }
1411
1412 /* Remove depot */
1414
1415 /* Set owner of canals and locks ... and also canal under dock there was before.
1416 * Check if the new owner after removing depot isn't OWNER_WATER. */
1417 if (IsTileOwner(tile, old_owner)) {
1418 if (GetWaterClass(tile) == WATER_CLASS_CANAL && !is_lock_middle) Company::Get(old_owner)->infrastructure.water--;
1419 SetTileOwner(tile, OWNER_NONE);
1420 }
1421}
1422
1423static VehicleEnterTileStates VehicleEnter_Water(Vehicle *, TileIndex, int, int)
1424{
1425 return {};
1426}
1427
1428static CommandCost TerraformTile_Water(TileIndex tile, DoCommandFlags flags, int, Slope)
1429{
1430 /* Canals can't be terraformed */
1431 if (IsWaterTile(tile) && IsCanal(tile)) return CommandCost(STR_ERROR_MUST_DEMOLISH_CANAL_FIRST);
1432
1433 return Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile);
1434}
1435
1436static CommandCost CheckBuildAbove_Water(TileIndex tile, DoCommandFlags flags, Axis, int height)
1437{
1438 if (IsWater(tile) || IsCoast(tile)) return CommandCost();
1439 if (IsLock(tile)) {
1440 if (GetTileMaxZ(tile) + GetLockPartMinimalBridgeHeight(GetLockPart(tile)) <= height) return CommandCost();
1441 return CommandCost(STR_ERROR_BRIDGE_TOO_LOW_FOR_LOCK);
1442 }
1443 return Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile);
1444}
1445
1446extern const TileTypeProcs _tile_type_water_procs = {
1447 DrawTile_Water, // draw_tile_proc
1448 GetSlopePixelZ_Water, // get_slope_z_proc
1449 ClearTile_Water, // clear_tile_proc
1450 nullptr, // add_accepted_cargo_proc
1451 GetTileDesc_Water, // get_tile_desc_proc
1452 GetTileTrackStatus_Water, // get_tile_track_status_proc
1453 ClickTile_Water, // click_tile_proc
1454 nullptr, // animate_tile_proc
1455 TileLoop_Water, // tile_loop_proc
1456 ChangeTileOwner_Water, // change_tile_owner_proc
1457 nullptr, // add_produced_cargo_proc
1458 VehicleEnter_Water, // vehicle_enter_tile_proc
1459 GetFoundation_Water, // get_foundation_proc
1460 TerraformTile_Water, // terraform_tile_proc
1461 CheckBuildAbove_Water, // check_build_above_proc
1462};
Base functions for all AIs.
Base for aircraft.
@ AIR_SHADOW
shadow of the aircraft
Definition aircraft.h:31
Class for backupping variables and making sure they are restored later.
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
void DrawBridgeMiddle(const TileInfo *ti, BridgePillarFlags blocked_pillars)
Draw the middle bits of a bridge.
TileIndex GetSouthernBridgeEnd(TileIndex t)
Finds the southern end of a bridge starting at a middle tile.
TileIndex GetOtherBridgeEnd(TileIndex tile)
Starting at one bridge end finds the other bridge end.
int GetBridgeHeight(TileIndex t)
Get the height ('z') of a bridge.
bool IsBridgeTile(Tile t)
checks if there is a bridge on this tile
Definition bridge_map.h:35
int GetBridgePixelHeight(TileIndex tile)
Get the height ('z') of a bridge in pixels.
Definition bridge_map.h:84
bool IsBridgeAbove(Tile t)
checks if a bridge is set above the ground of this tile
Definition bridge_map.h:45
BridgePillarFlag
Obstructed bridge pillars information.
Definition bridge_type.h:39
static void NewEvent(CompanyID company, ScriptEvent *event)
Queue a new event for an AI.
Definition ai_core.cpp:235
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
Common return value for all commands.
bool Succeeded() const
Did this command succeed?
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.
static void NewEvent(class ScriptEvent *event)
Queue a new event for a Game Script.
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
Wrapper class to abstract away the way the tiles are stored.
Definition map_func.h:25
Iterate over all vehicles on a tile.
Map accessors for 'clear' tiles.
@ CLEAR_GRASS
0-3
Definition clear_map.h:20
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
Definition of stuff that is very close to a company, like the company struct itself.
CommandCost CheckTileOwnership(TileIndex tile)
Check whether the current owner owns the stuff on the given tile.
PaletteID GetCompanyPalette(CompanyID company)
Get the palette for recolouring with a company colour.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
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.
static constexpr Owner OWNER_NONE
The tile has no ownership.
static constexpr Owner INVALID_OWNER
An invalid owner.
static constexpr Owner OWNER_WATER
The tile/execution is done by "water".
Base for all depots (except hangars)
Functions related to depots.
void ShowDepotWindow(TileIndex tile, VehicleType type)
Opens a depot window.
bool IsValidAxis(Axis d)
Checks if an integer value is a valid Axis.
DiagDirection ReverseDiagDir(DiagDirection d)
Returns the reverse direction of the given DiagDirection.
Direction ReverseDir(Direction d)
Return the reverse of a direction.
Axis DiagDirToAxis(DiagDirection d)
Convert a DiagDirection to the axis.
DiagDirection DirToDiagDir(Direction dir)
Convert a Direction to a DiagDirection.
Direction
Defines the 8 directions on the map.
@ DIR_BEGIN
Used to iterate.
@ DIR_SW
Southwest.
@ DIR_NW
Northwest.
@ DIR_N
North.
@ DIR_SE
Southeast.
@ DIR_S
South.
@ DIR_NE
Northeast.
@ DIR_END
Used to iterate.
@ DIR_W
West.
@ DIR_E
East.
Axis
Allow incrementing of DiagDirDiff variables.
@ AXIS_X
The X axis.
DiagDirection
Enumeration for diagonal directions.
@ DIAGDIR_END
Used for iterations.
@ DIAGDIR_BEGIN
Used for iterations.
@ INVALID_DIAGDIR
Flag for an invalid DiagDirection.
static const uint LOCK_DEPOT_TILE_FACTOR
Multiplier for how many regular tiles a lock counts.
@ EXPENSES_CONSTRUCTION
Construction costs.
EffectVehicle * CreateEffectVehicleRel(const Vehicle *v, int x, int y, int z, EffectVehicleType type)
Create an effect vehicle above a particular vehicle.
Functions related to effect vehicles.
@ EV_EXPLOSION_LARGE
Various explosions.
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23)
Definition enum_type.hpp:17
Base functions for all Games.
void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub, ZoomLevel zoom)
Draw a sprite, not in a viewport.
Definition gfx.cpp:1032
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:17
uint32_t PaletteID
The number of the palette.
Definition gfx_type.h:18
static void MarkCanalsAndRiversAroundDirty(TileIndex tile)
Marks the tiles around a tile as dirty, if they are canals or rivers.
Definition water_cmd.cpp:86
void MarkTileDirtyByTile(TileIndex tile, int bridge_level_offset, int tile_height_override)
Mark a tile given by its index dirty for repaint.
Base of all industries.
Accessors for industries.
IndustryID GetIndustryIndex(Tile t)
Get the industry ID of the given tile.
uint GetPartialPixelZ(int x, int y, Slope corners)
Determines height at given coordinate of a slope.
TrackStatus GetTileTrackStatus(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
Returns information about trackdirs and signal states.
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,...
Functions related to OTTD's landscape.
Command definitions related to landscape (slopes etc.).
@ Random
Randomise borders.
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
TileIndex TileAddByDir(TileIndex tile, Direction dir)
Adds a Direction to a tile.
Definition map_func.h:598
TileIndexDiff ToTileIndexDiff(TileIndexDiffC tidc)
Return the offset between two tiles from a TileIndexDiffC struct.
Definition map_func.h:439
TileIndexDiff TileOffsByAxis(Axis axis)
Convert an Axis to a TileIndexDiff.
Definition map_func.h:554
TileIndexDiffC TileIndexDiffCByDir(Direction dir)
Returns the TileIndexDiffC offset from a Direction.
Definition map_func.h:496
TileIndexDiff TileOffsByDir(Direction dir)
Convert a Direction to a TileIndexDiff.
Definition map_func.h:583
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
int32_t TileIndexDiff
An offset value between two tiles.
Definition map_type.h:23
constexpr bool IsInsideMM(const size_t x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
CanalFeature
List of different canal 'features'.
Definition newgrf.h:26
uint GetCanalSpriteOffset(CanalFeature feature, TileIndex tile, uint cur_offset)
Get the new sprite offset for a water tile.
std::array< WaterFeature, CF_END > _water_feature
Table of canal 'feature' sprite groups.
SpriteID GetCanalSprite(CanalFeature feature, TileIndex tile)
Lookup the base sprite to use for a canal.
Handling of NewGRF canals.
@ CFF_HAS_FLAT_SPRITE
Additional flat ground sprite in the beginning.
Functions related to generic callbacks.
void AmbientSoundEffect(TileIndex tile)
Play an ambient sound effect for an empty tile.
Functions related to news.
@ Accident
An accident or disaster has occurred.
bool FloodHalftile(TileIndex t)
Called from water_cmd if a non-flat rail-tile gets flooded and should be converted to shore.
Definition rail_cmd.cpp:761
TrackBits GetTrackBits(Tile tile)
Gets the track bits of the given tile.
Definition rail_map.h:136
RailGroundType
The ground 'under' the rail.
Definition rail_map.h:484
@ RAIL_GROUND_FENCE_HORIZ1
Grass with a fence at the southern side.
Definition rail_map.h:495
@ RAIL_GROUND_FENCE_VERT1
Grass with a fence at the eastern side.
Definition rail_map.h:493
@ RAIL_GROUND_FENCE_HORIZ2
Grass with a fence at the northern side.
Definition rail_map.h:496
@ RAIL_GROUND_WATER
Grass with a fence and shore or water on the free halftile.
Definition rail_map.h:498
@ RAIL_GROUND_FENCE_VERT2
Grass with a fence at the western side.
Definition rail_map.h:494
static debug_inline bool IsPlainRail(Tile t)
Returns whether this is plain rails, with or without signals.
Definition rail_map.h:49
Pseudo random number generator.
A number of safeguards to prevent using unsafe methods.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:61
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
void UpdateSignalsInBuffer()
Update signals in buffer Called from 'outside'.
Definition signal.cpp:573
bool IsSlopeWithOneCornerRaised(Slope s)
Tests if a specific slope has exactly one corner raised.
Definition slope_func.h:88
bool IsInclinedSlope(Slope s)
Tests if a specific slope is an inclined slope.
Definition slope_func.h:228
static constexpr bool IsHalftileSlope(Slope s)
Checks for non-continuous slope on halftile foundations.
Definition slope_func.h:47
DiagDirection GetInclinedSlopeDirection(Slope s)
Returns the direction of an inclined slope.
Definition slope_func.h:239
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_HALFTILE_MASK
three bits used for halftile slopes
Definition slope_type.h:72
@ 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_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_SW
south and west corner are raised
Definition slope_type.h:56
@ SLOPE_FLAT
a flat tile
Definition slope_type.h:49
@ SLOPE_NE
north and east corner are raised
Definition slope_type.h:58
@ SLOPE_SE
south and east corner are raised
Definition slope_type.h:57
@ SLOPE_NW
north and west corner are raised
Definition slope_type.h:55
@ 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_NONE
The tile has no foundation, the slope remains unchanged.
Definition slope_type.h:94
Functions related to sound.
@ SND_12_EXPLOSION
16 == 0x10 Destruction, crashes, disasters, ...
Definition sound_type.h:63
void DrawOrigTileSeqInGUI(int x, int y, const DrawTileSprites *dts, PaletteID default_palette)
Draw TTD sprite sequence in GUI.
Definition sprite.h:121
static const SpriteID SPR_SHORE_BASE
shore tiles - action 05-0D
Definition sprites.h:226
Base classes/functions for stations.
bool IsAirportTile(Tile t)
Is this tile a station tile and an airport tile?
bool IsBuoy(Tile t)
Is tile t a buoy tile?
bool IsDockTile(Tile t)
Is tile t a dock tile?
bool IsOilRig(Tile t)
Is tile t part of an oilrig?
bool IsDockWaterPart(Tile t)
Check whether a dock tile is the tile on water.
bool IsDock(Tile t)
Is tile t a dock tile?
Definition of base types and functions in a cross-platform compatible way.
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Definition strings.cpp:90
Functions related to OTTD's strings.
Finite sTate mAchine (FTA) of an airport.
Definition airport.h:159
uint8_t delta_z
Z adjustment for helicopter pads.
Definition airport.h:197
const AirportFTAClass * GetFTA() const
Get the finite-state machine for this airport or the finite-state machine for the dummy airport in ca...
Class to backup a specific variable and restore it later.
void Restore()
Restore the variable.
static BaseStation * GetByTile(TileIndex tile)
Get the base station belonging to a specific tile.
VehicleType type
Type of vehicle.
SoundSettings sound
sound effect settings
uint32_t water
Count of company owned track bits for canals.
CompanyInfrastructure infrastructure
NOSAVE: Counts of company owned infrastructure.
bool freeform_edges
allow terraforming the tiles at the map edges
T z
Z coordinate.
TimerGameCalendar::Date build_date
Date of construction.
Definition depot_base.h:26
A tile child sprite and palette to draw for stations etc, with 3D bounding box.
Definition sprite.h:33
Ground palette sprite of a tile, together with its sprite layout.
Definition sprite.h:52
PalSpriteID ground
Palette and sprite for the ground.
Definition sprite.h:53
ConstructionSettings construction
construction of things in-game
static Industry * GetByTile(TileIndex tile)
Get the industry of the given tile.
Definition industry.h:251
Station * neutral_station
Associated neutral station.
Definition industry.h:108
Size related data of the map.
Definition map_func.h:206
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
void Add(TileIndex to_add)
Add a single tile to a tile area; enlarge if needed.
Definition tilearea.cpp:43
SpriteID sprite
The 'real' sprite.
Definition gfx_type.h:23
PaletteID pal
The palette (use PAL_NONE) if not needed)
Definition gfx_type.h:24
static Titem * Get(auto index)
Returns Titem with given index.
Tindex index
Index of this pool item.
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function()
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.
bool disaster
Play disaster and accident sounds.
Station data structure.
TileArea docking_station
Tile area the docking tiles cover.
Airport airport
Tile area the airport covers.
Tile description for the 'land area information' tool.
Definition tile_cmd.h:36
StringID str
Description of the tile.
Definition tile_cmd.h:37
TimerGameCalendar::Date build_date
Date of construction of tile contents.
Definition tile_cmd.h:41
std::array< Owner, 4 > owner
Name of the owner(s)
Definition tile_cmd.h:39
A pair-construct of a TileIndexDiff.
Definition map_type.h:31
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
Vehicle data structure.
int32_t z_pos
z coordinate.
virtual uint Crash(bool flooded=false)
Crash the (whole) vehicle chain.
Definition vehicle.cpp:291
uint8_t subtype
subtype (Filled with values from AircraftSubType/DisasterSubType/EffectVehicleType/GroundVehicleSubty...
VehStates vehstatus
Status.
Vehicle * First() const
Get the first vehicle of this vehicle chain.
TileIndex tile
Current tile index.
Owner owner
Which company owns the vehicle?
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
bool IsTileOwner(Tile tile, Owner owner)
Checks if a tile belongs to the given owner.
Definition tile_map.h:214
Owner GetTileOwner(Tile tile)
Returns the owner of a tile.
Definition tile_map.h:178
void SetTileOwner(Tile tile, Owner owner)
Sets the owner of a tile.
Definition tile_map.h:198
static debug_inline TileType GetTileType(Tile tile)
Get the tiletype of a given tile.
Definition tile_map.h:96
std::tuple< Slope, int > GetTilePixelSlope(TileIndex tile)
Return the slope of a given tile.
Definition tile_map.h:289
bool IsValidTile(Tile tile)
Checks if a tile is valid.
Definition tile_map.h:161
TropicZone GetTropicZone(Tile tile)
Get the tropic zone.
Definition tile_map.h:238
static debug_inline bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition tile_map.h:150
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
@ 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
@ MP_TREES
Tile got trees.
Definition tile_type.h:52
@ MP_STATION
A tile of a station.
Definition tile_type.h:53
@ MP_TUNNELBRIDGE
Tunnel entry/exit and bridge heads.
Definition tile_type.h:57
@ 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_RAILWAY
A railway.
Definition tile_type.h:49
@ MP_INDUSTRY
Part of an industry.
Definition tile_type.h:56
@ MP_VOID
Invisible tiles at the SW and SE border.
Definition tile_type.h:55
@ MP_OBJECT
Contains objects such as transmitters and owned land.
Definition tile_type.h:58
Definition of the game-calendar-timer.
Base of the town class.
void MakeDefaultName(T *obj)
Set the default name for a depot/waypoint.
Definition town.h:284
TrackdirBits TrackBitsToTrackdirBits(TrackBits bits)
Converts TrackBits to TrackdirBits while allowing both directions.
Definition track_func.h:319
TrackStatus CombineTrackStatus(TrackdirBits trackdirbits, TrackdirBits red_signals)
Builds a TrackStatus.
Definition track_func.h:388
TrackBits AxisToTrackBits(Axis a)
Maps an Axis to the corresponding TrackBits value.
Definition track_func.h:88
TrackBits DiagDirToDiagTrackBits(DiagDirection diagdir)
Maps a (4-way) direction to the diagonal track bits incidating with that diagdir.
Definition track_func.h:524
TrackBits TrackStatusToTrackBits(TrackStatus ts)
Returns the present-track-information of a TrackStatus.
Definition track_func.h:363
TrackBits
Allow incrementing of Track variables.
Definition track_type.h:35
@ TRACK_BIT_UPPER
Upper track.
Definition track_type.h:39
@ TRACK_BIT_LEFT
Left track.
Definition track_type.h:41
@ TRACK_BIT_Y
Y-axis track.
Definition track_type.h:38
@ TRACK_BIT_NONE
No track.
Definition track_type.h:36
@ TRACK_BIT_X
X-axis track.
Definition track_type.h:37
@ TRACK_BIT_LOWER
Lower track.
Definition track_type.h:40
@ TRACK_BIT_ALL
All possible tracks.
Definition track_type.h:50
@ TRACK_BIT_RIGHT
Right track.
Definition track_type.h:42
@ TRACKDIR_BIT_NONE
No track build.
Definition track_type.h:98
bool IsTransparencySet(TransparencyOption to)
Check if the transparency option bit is set and if we aren't in the game menu (there's never transpar...
bool IsInvisibilitySet(TransparencyOption to)
Check if the invisibility option bit is set and if we aren't in the game menu (there's never transpar...
@ TO_BUILDINGS
company buildings - depots, stations, HQ, ...
TransportType
Available types of transport.
@ TRANSPORT_WATER
Transport over water.
Map accessors for tree tiles.
TreeGround GetTreeGround(Tile t)
Returns the groundtype for tree tiles.
Definition tree_map.h:102
@ TREE_GROUND_GRASS
normal grass
Definition tree_map.h:53
@ TREE_GROUND_SHORE
shore
Definition tree_map.h:56
void SetTreeGroundDensity(Tile t, TreeGround g, uint d)
Set the density and ground type of a tile with trees.
Definition tree_map.h:144
Functions that have tunnels and bridges in common.
DiagDirection GetTunnelBridgeDirection(Tile t)
Get the direction pointing to the other end.
TransportType GetTunnelBridgeTransportType(Tile t)
Tunnel: Get the transport type of the tunnel (road or rail) Bridge: Get the transport type of the bri...
CommandCost EnsureNoVehicleOnGround(TileIndex tile)
Ensure there is no vehicle at the ground at the given position.
Definition vehicle.cpp:527
@ Crashed
Vehicle is crashed.
Functions related to vehicles.
@ VEH_ROAD
Road vehicle type.
@ VEH_AIRCRAFT
Aircraft vehicle type.
@ VEH_SHIP
Ship vehicle type.
@ VEH_TRAIN
Train vehicle type.
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
void DrawGroundSprite(SpriteID image, PaletteID pal, const SubSprite *sub, int extra_offs_x, int extra_offs_y)
Draws a ground sprite for the current tile.
Definition viewport.cpp:579
Functions related to (drawing on) viewports.
Functions related to water (management)
FloodingBehaviour
Describes the behaviour of a tile during flooding.
Definition water.h:19
@ FLOOD_NONE
The tile does not flood neighboured tiles.
Definition water.h:20
@ FLOOD_ACTIVE
The tile floods neighboured tiles.
Definition water.h:21
@ FLOOD_DRYUP
The tile drys up if it is not constantly flooded from neighboured tiles.
Definition water.h:23
@ FLOOD_PASSIVE
The tile does not actively flood neighboured tiles, but it prevents them from drying up.
Definition water.h:22
static const uint RIVER_OFFSET_DESERT_DISTANCE
Circular tile search diameter to create non-desert around a river tile.
Definition water.h:44
static uint8_t GetLockPartMinimalBridgeHeight(LockPart lock_part)
Get the minimal height required for a bridge above a lock part.
void TileLoop_Water(TileIndex tile)
Let a water tile floods its diagonal adjoining tiles called from tunnelbridge_cmd,...
static void DrawWaterDepot(const TileInfo *ti)
Draw a ship depot tile.
static void DrawWaterSprite(SpriteID base, uint offset, CanalFeature feature, TileIndex tile)
Draw a water sprite, potentially with a NewGRF-modified sprite offset.
static CommandCost DoBuildLock(TileIndex tile, DiagDirection dir, DoCommandFlags flags)
Builds a lock.
CommandCost CmdBuildLock(DoCommandFlags flags, TileIndex tile)
Builds a lock.
static CommandCost RemoveLock(TileIndex tile, DoCommandFlags flags)
Remove a lock.
static void DrawWaterLock(const TileInfo *ti)
Draw a lock tile.
static void FloodVehicle(Vehicle *v)
Handle the flooding of a vehicle.
static void FloodVehicles(TileIndex tile)
Finds a vehicle to flood.
static void DrawWaterEdges(bool canal, uint offset, TileIndex tile)
Draw canal or river edges.
static void FloodVehicleProc(Vehicle *v, int z)
Flood a vehicle if we are allowed to flood it, i.e.
static const Directions _flood_from_dirs[]
Describes from which directions a specific slope can be flooded (if the tile is floodable at all).
Definition water_cmd.cpp:51
void ClearNeighbourNonFloodingStates(TileIndex tile)
Clear non-flooding state of the tiles around a tile.
Definition water_cmd.cpp:97
static void DrawWaterTileStruct(const TileInfo *ti, std::span< const DrawTileSeqStruct > seq, SpriteID base, uint offset, PaletteID palette, CanalFeature feature)
Draw a build sprite sequence for water tiles.
static void DoDryUp(TileIndex tile)
Drys a tile up.
static void MarkTileDirtyIfCanalOrRiver(TileIndex tile)
Marks tile dirty if it is a canal or river tile.
Definition water_cmd.cpp:75
FloodingBehaviour GetFloodingBehaviour(TileIndex tile)
Returns the behaviour of a tile during flooding.
void CheckForDockingTile(TileIndex t)
Mark the supplied tile as a docking tile if it is suitable for docking.
static void DrawSeaWater(TileIndex)
Draw a plain sea water tile with no edges.
CommandCost CmdBuildShipDepot(DoCommandFlags flags, TileIndex tile, Axis axis)
Build a ship depot.
static void DrawCanalWater(TileIndex tile)
draw a canal styled water tile with dikes around
void MakeRiverAndModifyDesertZoneAround(TileIndex tile)
Make a river tile and remove desert directly around it.
static void DoFloodTile(TileIndex target)
Floods a tile.
bool IsWateredTile(TileIndex tile, Direction from)
return true if a tile is a water tile wrt.
CommandCost CmdBuildCanal(DoCommandFlags flags, TileIndex tile, TileIndex start_tile, WaterClass wc, bool diagonal)
Build a piece of canal.
Command definitions related to water tiles.
Sprites to use and how to display them for water tiles (depots/locks).
void MakeShore(Tile t)
Helper function to make a coast tile.
Definition water_map.h:383
bool HasTileWaterGround(Tile t)
Checks whether the tile has water at the ground.
Definition water_map.h:352
TileIndex GetShipDepotNorthTile(Tile t)
Get the most northern tile of a ship depot.
Definition water_map.h:291
void MakeLock(Tile t, Owner o, DiagDirection d, WaterClass wc_lower, WaterClass wc_upper, WaterClass wc_middle)
Make a water lock.
Definition water_map.h:508
DepotPart GetShipDepotPart(Tile t)
Get the part of a ship depot.
Definition water_map.h:257
bool IsTileOnWater(Tile t)
Tests if the tile was built on water.
Definition water_map.h:138
bool IsShipDepot(Tile t)
Is it a water tile with a ship depot on it?
Definition water_map.h:224
bool IsValidWaterClass(WaterClass wc)
Checks if a water class is valid.
Definition water_map.h:52
bool IsRiver(Tile t)
Is it a river water tile?
Definition water_map.h:182
DiagDirection GetLockDirection(Tile t)
Get the direction of the water lock.
Definition water_map.h:316
WaterClass
classes of water (for WATER_TILE_CLEAR water tile type).
Definition water_map.h:39
@ WATER_CLASS_SEA
Sea.
Definition water_map.h:40
@ WATER_CLASS_CANAL
Canal.
Definition water_map.h:41
@ WATER_CLASS_INVALID
Used for industry tiles on land (also for oilrig if newgrf says so).
Definition water_map.h:43
@ WATER_CLASS_RIVER
River.
Definition water_map.h:42
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
bool IsCoast(Tile t)
Is it a coast tile?
Definition water_map.h:203
void MakeRiver(Tile t, uint8_t random_bits)
Make a river tile.
Definition water_map.h:434
WaterTileType GetWaterTileType(Tile t)
Get the water tile type of a tile.
Definition water_map.h:80
void SetNonFloodingWaterTile(Tile t, bool b)
Set the non-flooding water tile state of a tile.
Definition water_map.h:526
WaterClass GetWaterClass(Tile t)
Get the water class at a tile.
Definition water_map.h:114
void MakeCanal(Tile t, Owner o, uint8_t random_bits)
Make a canal tile.
Definition water_map.h:445
TileIndex GetOtherShipDepotTile(Tile t)
Get the other tile of the ship depot.
Definition water_map.h:280
DepotPart
Sections of the water depot.
Definition water_map.h:58
@ DEPOT_PART_NORTH
Northern part of a depot.
Definition water_map.h:59
@ DEPOT_PART_SOUTH
Southern part of a depot.
Definition water_map.h:60
@ WATER_TILE_COAST
Coast.
Definition water_map.h:33
@ WATER_TILE_LOCK
Water lock.
Definition water_map.h:34
@ WATER_TILE_DEPOT
Water Depot.
Definition water_map.h:35
@ WATER_TILE_CLEAR
Plain water.
Definition water_map.h:32
bool IsNonFloodingWaterTile(Tile t)
Checks whether the tile is marked as a non-flooding water tile.
Definition water_map.h:535
void SetDockingTile(Tile t, bool b)
Set the docking tile state of a tile.
Definition water_map.h:363
LockPart
Sections of the water lock.
Definition water_map.h:65
@ LOCK_PART_UPPER
Upper part of a lock.
Definition water_map.h:68
@ LOCK_PART_MIDDLE
Middle part of a lock.
Definition water_map.h:66
bool IsWater(Tile t)
Is it a plain water tile?
Definition water_map.h:149
bool IsWaterTile(Tile t)
Is it a water tile with plain water?
Definition water_map.h:192
bool IsLock(Tile t)
Is there a lock on a given water tile?
Definition water_map.h:305
void MakeShipDepot(Tile t, Owner o, DepotID did, DepotPart part, Axis a, WaterClass original_water_class)
Make a ship depot section.
Definition water_map.h:460
void MakeSea(Tile t)
Make a sea tile.
Definition water_map.h:424
LockPart GetLockPart(Tile t)
Get the part of a lock.
Definition water_map.h:328
Axis GetShipDepotAxis(Tile t)
Get the axis of the ship depot.
Definition water_map.h:245
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.