OpenTTD Source 20241224-master-gf74b0cf984
water_regions.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 "map_func.h"
12#include "water_regions.h"
13#include "tilearea_type.h"
14#include "track_func.h"
15#include "transport_type.h"
16#include "landscape.h"
17#include "tunnelbridge_map.h"
18#include "follow_track.hpp"
19#include "ship.h"
20#include "debug.h"
21
22using TWaterRegionTraversabilityBits = uint16_t;
23constexpr TWaterRegionPatchLabel FIRST_REGION_LABEL = 1;
24
25static_assert(sizeof(TWaterRegionTraversabilityBits) * 8 == WATER_REGION_EDGE_LENGTH);
26static_assert(sizeof(TWaterRegionPatchLabel) == sizeof(uint8_t)); // Important for the hash calculation.
27
28static inline TrackBits GetWaterTracks(TileIndex tile) { return TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_WATER, 0)); }
29static inline bool IsAqueductTile(TileIndex tile) { return IsBridgeTile(tile) && GetTunnelBridgeTransportType(tile) == TRANSPORT_WATER; }
30
31static inline int GetWaterRegionX(TileIndex tile) { return TileX(tile) / WATER_REGION_EDGE_LENGTH; }
32static inline int GetWaterRegionY(TileIndex tile) { return TileY(tile) / WATER_REGION_EDGE_LENGTH; }
33
34static inline int GetWaterRegionMapSizeX() { return Map::SizeX() / WATER_REGION_EDGE_LENGTH; }
35static inline int GetWaterRegionMapSizeY() { return Map::SizeY() / WATER_REGION_EDGE_LENGTH; }
36
37static inline TWaterRegionIndex GetWaterRegionIndex(int region_x, int region_y) { return GetWaterRegionMapSizeX() * region_y + region_x; }
38static inline TWaterRegionIndex GetWaterRegionIndex(TileIndex tile) { return GetWaterRegionIndex(GetWaterRegionX(tile), GetWaterRegionY(tile)); }
39
40using TWaterRegionPatchLabelArray = std::array<TWaterRegionPatchLabel, WATER_REGION_NUMBER_OF_TILES>;
41
46 friend class WaterRegion;
47
48 std::array<TWaterRegionTraversabilityBits, DIAGDIR_END> edge_traversability_bits{};
49 std::unique_ptr<TWaterRegionPatchLabelArray> tile_patch_labels; // Tile patch labels, this may be nullptr in the following trivial cases: region is invalid, region is only land (0 patches), region is only water (1 patch)
50 bool has_cross_region_aqueducts = false;
51 TWaterRegionPatchLabel number_of_patches = 0; // 0 = no water, 1 = one single patch of water, etc...
52};
53
61{
62private:
63 WaterRegionData &data;
64 const OrthogonalTileArea tile_area;
65
72 inline int GetLocalIndex(TileIndex tile) const
73 {
74 assert(this->tile_area.Contains(tile));
75 return (TileX(tile) - TileX(this->tile_area.tile)) + WATER_REGION_EDGE_LENGTH * (TileY(tile) - TileY(this->tile_area.tile));
76 }
77
78public:
79 WaterRegion(int region_x, int region_y, WaterRegionData &water_region_data)
80 : data(water_region_data)
81 , tile_area(TileXY(region_x * WATER_REGION_EDGE_LENGTH, region_y * WATER_REGION_EDGE_LENGTH), WATER_REGION_EDGE_LENGTH, WATER_REGION_EDGE_LENGTH)
82 {}
83
84 OrthogonalTileIterator begin() const { return this->tile_area.begin(); }
85 OrthogonalTileIterator end() const { return this->tile_area.end(); }
86
94 TWaterRegionTraversabilityBits GetEdgeTraversabilityBits(DiagDirection side) const { return this->data.edge_traversability_bits[side]; }
95
100 int NumberOfPatches() const { return static_cast<int>(this->data.number_of_patches); }
101
105 bool HasCrossRegionAqueducts() const { return this->data.has_cross_region_aqueducts; }
106
112 TWaterRegionPatchLabel GetLabel(TileIndex tile) const
113 {
114 assert(this->tile_area.Contains(tile));
115 if (this->data.tile_patch_labels == nullptr) {
116 return this->NumberOfPatches() == 0 ? INVALID_WATER_REGION_PATCH : FIRST_REGION_LABEL;
117 }
118 return (*this->data.tile_patch_labels)[this->GetLocalIndex(tile)];
119 }
120
126 {
127 Debug(map, 3, "Updating water region ({},{})", GetWaterRegionX(this->tile_area.tile), GetWaterRegionY(this->tile_area.tile));
128 this->data.has_cross_region_aqueducts = false;
129
130 /* Acquire a tile patch label array if this region does not already have one */
131 if (this->data.tile_patch_labels == nullptr) {
132 this->data.tile_patch_labels = std::make_unique<TWaterRegionPatchLabelArray>();
133 }
134
135 this->data.tile_patch_labels->fill(INVALID_WATER_REGION_PATCH);
136 this->data.edge_traversability_bits.fill(0);
137
138 TWaterRegionPatchLabel current_label = FIRST_REGION_LABEL;
139 TWaterRegionPatchLabel highest_assigned_label = INVALID_WATER_REGION_PATCH;
140
141 /* Perform connected component labeling. This uses a flooding algorithm that expands until no
142 * additional tiles can be added. Only tiles inside the water region are considered. */
143 for (const TileIndex start_tile : this->tile_area) {
144 static std::vector<TileIndex> tiles_to_check;
145 tiles_to_check.clear();
146 tiles_to_check.push_back(start_tile);
147
148 bool increase_label = false;
149 while (!tiles_to_check.empty()) {
150 const TileIndex tile = tiles_to_check.back();
151 tiles_to_check.pop_back();
152
153 const TrackdirBits valid_dirs = TrackBitsToTrackdirBits(GetWaterTracks(tile));
154 if (valid_dirs == TRACKDIR_BIT_NONE) continue;
155
156 TWaterRegionPatchLabel &tile_patch = (*this->data.tile_patch_labels)[this->GetLocalIndex(tile)];
157 if (tile_patch != INVALID_WATER_REGION_PATCH) continue;
158
159 tile_patch = current_label;
160 highest_assigned_label = current_label;
161 increase_label = true;
162
163 for (const Trackdir dir : SetTrackdirBitIterator(valid_dirs)) {
164 /* By using a TrackFollower we "play by the same rules" as the actual ship pathfinder */
166 if (ft.Follow(tile, dir)) {
167 if (this->tile_area.Contains(ft.new_tile)) {
168 tiles_to_check.push_back(ft.new_tile);
169 } else if (!ft.is_bridge) {
170 assert(DistanceManhattan(ft.new_tile, tile) == 1);
171 const auto side = DiagdirBetweenTiles(tile, ft.new_tile);
172 const int local_x_or_y = DiagDirToAxis(side) == AXIS_X ? TileY(tile) - TileY(this->tile_area.tile) : TileX(tile) - TileX(this->tile_area.tile);
173 SetBit(this->data.edge_traversability_bits[side], local_x_or_y);
174 } else {
175 this->data.has_cross_region_aqueducts = true;
176 }
177 }
178 }
179 }
180
181 if (increase_label) current_label++;
182 }
183
184 this->data.number_of_patches = highest_assigned_label;
185
186 if (this->NumberOfPatches() == 0 || (this->NumberOfPatches() == 1 &&
187 std::all_of(this->data.tile_patch_labels->begin(), this->data.tile_patch_labels->end(), [](TWaterRegionPatchLabel label) { return label == FIRST_REGION_LABEL; }))) {
188 /* No need for patch storage: trivial cases */
189 this->data.tile_patch_labels.reset();
190 }
191 }
192
193 void PrintDebugInfo()
194 {
195 Debug(map, 9, "Water region {},{} labels and edge traversability = ...", GetWaterRegionX(this->tile_area.tile), GetWaterRegionY(this->tile_area.tile));
196
197 const size_t max_element_width = std::to_string(this->NumberOfPatches()).size();
198
199 std::string traversability = fmt::format("{:0{}b}", this->GetEdgeTraversabilityBits(DIAGDIR_NW), WATER_REGION_EDGE_LENGTH);
200 Debug(map, 9, " {:{}}", fmt::join(traversability, " "), max_element_width);
201 Debug(map, 9, " +{:->{}}+", "", WATER_REGION_EDGE_LENGTH * (max_element_width + 1) + 1);
202
203 for (int y = 0; y < WATER_REGION_EDGE_LENGTH; ++y) {
204 std::string line{};
205 for (int x = 0; x < WATER_REGION_EDGE_LENGTH; ++x) {
206 const auto label = this->GetLabel(TileAddXY(this->tile_area.tile, x, y));
207 const std::string label_str = label == INVALID_WATER_REGION_PATCH ? "." : std::to_string(label);
208 line = fmt::format("{:{}}", label_str, max_element_width) + " " + line;
209 }
210 Debug(map, 9, "{} | {}| {}", GB(this->GetEdgeTraversabilityBits(DIAGDIR_SW), y, 1), line, GB(this->GetEdgeTraversabilityBits(DIAGDIR_NE), y, 1));
211 }
212
213 Debug(map, 9, " +{:->{}}+", "", WATER_REGION_EDGE_LENGTH * (max_element_width + 1) + 1);
214 traversability = fmt::format("{:0{}b}", this->GetEdgeTraversabilityBits(DIAGDIR_SE), WATER_REGION_EDGE_LENGTH);
215 Debug(map, 9, " {:{}}", fmt::join(traversability, " "), max_element_width);
216 }
217};
218
219std::vector<WaterRegionData> _water_region_data;
220std::vector<bool> _is_water_region_valid;
221
222static TileIndex GetTileIndexFromLocalCoordinate(int region_x, int region_y, int local_x, int local_y)
223{
224 assert(local_x >= 0 && local_x < WATER_REGION_EDGE_LENGTH);
225 assert(local_y >= 0 && local_y < WATER_REGION_EDGE_LENGTH);
226 return TileXY(WATER_REGION_EDGE_LENGTH * region_x + local_x, WATER_REGION_EDGE_LENGTH * region_y + local_y);
227}
228
229static TileIndex GetEdgeTileCoordinate(int region_x, int region_y, DiagDirection side, int x_or_y)
230{
231 assert(x_or_y >= 0 && x_or_y < WATER_REGION_EDGE_LENGTH);
232 switch (side) {
233 case DIAGDIR_NE: return GetTileIndexFromLocalCoordinate(region_x, region_y, 0, x_or_y);
234 case DIAGDIR_SW: return GetTileIndexFromLocalCoordinate(region_x, region_y, WATER_REGION_EDGE_LENGTH - 1, x_or_y);
235 case DIAGDIR_NW: return GetTileIndexFromLocalCoordinate(region_x, region_y, x_or_y, 0);
236 case DIAGDIR_SE: return GetTileIndexFromLocalCoordinate(region_x, region_y, x_or_y, WATER_REGION_EDGE_LENGTH - 1);
237 default: NOT_REACHED();
238 }
239}
240
241static WaterRegion GetUpdatedWaterRegion(uint16_t region_x, uint16_t region_y)
242{
243 const TWaterRegionIndex index = GetWaterRegionIndex(region_x, region_y);
244 WaterRegion water_region(region_x, region_y, _water_region_data[index]);
245 if (!_is_water_region_valid[index]) {
246 water_region.ForceUpdate();
247 _is_water_region_valid[index] = true;
248 }
249 return water_region;
250}
251
252static WaterRegion GetUpdatedWaterRegion(TileIndex tile)
253{
254 return GetUpdatedWaterRegion(GetWaterRegionX(tile), GetWaterRegionY(tile));
255}
256
261static TWaterRegionIndex GetWaterRegionIndex(const WaterRegionDesc &water_region)
262{
263 return GetWaterRegionIndex(water_region.x, water_region.y);
264}
265
271{
272 return water_region_patch.label | GetWaterRegionIndex(water_region_patch) << 8;
273}
274
281{
282 return TileXY(water_region.x * WATER_REGION_EDGE_LENGTH + (WATER_REGION_EDGE_LENGTH / 2), water_region.y * WATER_REGION_EDGE_LENGTH + (WATER_REGION_EDGE_LENGTH / 2));
283}
284
290{
291 return WaterRegionDesc{ GetWaterRegionX(tile), GetWaterRegionY(tile) };
292}
293
299{
300 const WaterRegion region = GetUpdatedWaterRegion(tile);
301 return WaterRegionPatchDesc{ GetWaterRegionX(tile), GetWaterRegionY(tile), region.GetLabel(tile) };
302}
303
309{
310 if (!IsValidTile(tile)) return;
311
312 auto invalidate_region = [](TileIndex tile) {
313 const TWaterRegionIndex water_region_index = GetWaterRegionIndex(tile);
314 if (!_is_water_region_valid[water_region_index]) Debug(map, 3, "Invalidated water region ({},{})", GetWaterRegionX(tile), GetWaterRegionY(tile));
315 _is_water_region_valid[water_region_index] = false;
316 };
317
318 invalidate_region(tile);
319
320 /* When updating the water region we look into the first tile of adjacent water regions to determine edge
321 * traversability. This means that if we invalidate any region edge tiles we might also change the traversability
322 * of the adjacent region. This code ensures the adjacent regions also get invalidated in such a case. */
323 for (DiagDirection side = DIAGDIR_BEGIN; side < DIAGDIR_END; side++) {
324 const TileIndex adjacent_tile = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDiagDir(side));
325 if (adjacent_tile == INVALID_TILE) continue;
326 if (GetWaterRegionIndex(adjacent_tile) != GetWaterRegionIndex(tile)) invalidate_region(adjacent_tile);
327 }
328}
329
337static inline void VisitAdjacentWaterRegionPatchNeighbors(const WaterRegionPatchDesc &water_region_patch, DiagDirection side, TVisitWaterRegionPatchCallBack &func)
338{
339 if (water_region_patch.label == INVALID_WATER_REGION_PATCH) return;
340
341 const WaterRegion current_region = GetUpdatedWaterRegion(water_region_patch.x, water_region_patch.y);
342
343 const TileIndexDiffC offset = TileIndexDiffCByDiagDir(side);
344 const int nx = water_region_patch.x + offset.x;
345 const int ny = water_region_patch.y + offset.y;
346
347 if (nx < 0 || ny < 0 || nx >= GetWaterRegionMapSizeX() || ny >= GetWaterRegionMapSizeY()) return;
348
349 const WaterRegion neighboring_region = GetUpdatedWaterRegion(nx, ny);
350 const DiagDirection opposite_side = ReverseDiagDir(side);
351
352 /* Indicates via which local x or y coordinates (depends on the "side" parameter) we can cross over into the adjacent region. */
353 const TWaterRegionTraversabilityBits traversability_bits = current_region.GetEdgeTraversabilityBits(side)
354 & neighboring_region.GetEdgeTraversabilityBits(opposite_side);
355 if (traversability_bits == 0) return;
356
357 if (current_region.NumberOfPatches() == 1 && neighboring_region.NumberOfPatches() == 1) {
358 func(WaterRegionPatchDesc{ nx, ny, FIRST_REGION_LABEL }); // No further checks needed because we know there is just one patch for both adjacent regions
359 return;
360 }
361
362 /* Multiple water patches can be reached from the current patch. Check each edge tile individually. */
363 static std::vector<TWaterRegionPatchLabel> unique_labels; // static and vector-instead-of-map for performance reasons
364 unique_labels.clear();
365 for (int x_or_y = 0; x_or_y < WATER_REGION_EDGE_LENGTH; ++x_or_y) {
366 if (!HasBit(traversability_bits, x_or_y)) continue;
367
368 const TileIndex current_edge_tile = GetEdgeTileCoordinate(water_region_patch.x, water_region_patch.y, side, x_or_y);
369 const TWaterRegionPatchLabel current_label = current_region.GetLabel(current_edge_tile);
370 if (current_label != water_region_patch.label) continue;
371
372 const TileIndex neighbor_edge_tile = GetEdgeTileCoordinate(nx, ny, opposite_side, x_or_y);
373 const TWaterRegionPatchLabel neighbor_label = neighboring_region.GetLabel(neighbor_edge_tile);
374 assert(neighbor_label != INVALID_WATER_REGION_PATCH);
375 if (std::ranges::find(unique_labels, neighbor_label) == unique_labels.end()) unique_labels.push_back(neighbor_label);
376 }
377 for (TWaterRegionPatchLabel unique_label : unique_labels) func(WaterRegionPatchDesc{ nx, ny, unique_label });
378}
379
386void VisitWaterRegionPatchNeighbors(const WaterRegionPatchDesc &water_region_patch, TVisitWaterRegionPatchCallBack &callback)
387{
388 if (water_region_patch.label == INVALID_WATER_REGION_PATCH) return;
389
390 const WaterRegion current_region = GetUpdatedWaterRegion(water_region_patch.x, water_region_patch.y);
391
392 /* Visit adjacent water region patches in each cardinal direction */
393 for (DiagDirection side = DIAGDIR_BEGIN; side < DIAGDIR_END; side++) VisitAdjacentWaterRegionPatchNeighbors(water_region_patch, side, callback);
394
395 /* Visit neigboring water patches accessible via cross-region aqueducts */
396 if (current_region.HasCrossRegionAqueducts()) {
397 for (const TileIndex tile : current_region) {
398 if (GetWaterRegionPatchInfo(tile) == water_region_patch && IsAqueductTile(tile)) {
399 const TileIndex other_end_tile = GetOtherBridgeEnd(tile);
400 if (GetWaterRegionIndex(tile) != GetWaterRegionIndex(other_end_tile)) callback(GetWaterRegionPatchInfo(other_end_tile));
401 }
402 }
403 }
404}
405
410{
411 const int number_of_regions = GetWaterRegionMapSizeX() * GetWaterRegionMapSizeY();
412
413 _water_region_data.clear();
414 _water_region_data.resize(number_of_regions);
415
416 _is_water_region_valid.clear();
417 _is_water_region_valid.resize(number_of_regions, false);
418
419 Debug(map, 2, "Allocating {} x {} water regions", GetWaterRegionMapSizeX(), GetWaterRegionMapSizeY());
420 assert(_is_water_region_valid.size() == _water_region_data.size());
421}
422
423void PrintWaterRegionDebugInfo(TileIndex tile)
424{
425 GetUpdatedWaterRegion(tile).PrintDebugInfo();
426}
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
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.
TileIndex GetOtherBridgeEnd(TileIndex tile)
Starting at one bridge end finds the other bridge end.
bool IsBridgeTile(Tile t)
checks if there is a bridge on this tile
Definition bridge_map.h:35
Iterator to iterate over a tile area (rectangle) of the map.
The data stored for each water region.
Represents a square section of the map of a fixed size.
TWaterRegionPatchLabel GetLabel(TileIndex tile) const
Returns the patch label that was assigned to the tile.
int NumberOfPatches() const
bool HasCrossRegionAqueducts() const
int GetLocalIndex(TileIndex tile) const
Returns the local index of the tile within the region.
void ForceUpdate()
Performs the connected component labeling and other data gathering.
TWaterRegionTraversabilityBits GetEdgeTraversabilityBits(DiagDirection side) const
Returns a set of bits indicating whether an edge tile on a particular side is traversable or not.
Functions related to debugging.
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
Definition debug.h:37
DiagDirection ReverseDiagDir(DiagDirection d)
Returns the reverse direction of the given DiagDirection.
Axis DiagDirToAxis(DiagDirection d)
Convert a DiagDirection to the axis.
@ AXIS_X
The X 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.
Template function for track followers.
TrackStatus GetTileTrackStatus(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
Returns information about trackdirs and signal states.
Functions related to OTTD's landscape.
uint DistanceManhattan(TileIndex t0, TileIndex t1)
Gets the Manhattan distance between the two given tiles.
Definition map.cpp:146
Functions related to maps.
DiagDirection DiagdirBetweenTiles(TileIndex tile_from, TileIndex tile_to)
Determines the DiagDirection to get from one tile to another.
Definition map_func.h:620
TileIndex TileAddXY(TileIndex tile, int x, int y)
Adds a given offset to a tile.
Definition map_func.h:467
TileIndex AddTileIndexDiffCWrap(TileIndex tile, TileIndexDiffC diff)
Add a TileIndexDiffC to a TileIndex and returns the new one.
Definition map_func.h:512
static debug_inline TileIndex TileXY(uint x, uint y)
Returns the TileIndex of a coordinate.
Definition map_func.h:373
TileIndexDiffC TileIndexDiffCByDiagDir(DiagDirection dir)
Returns the TileIndexDiffC offset from a DiagDirection.
Definition map_func.h:480
static debug_inline uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition map_func.h:425
static debug_inline uint TileX(TileIndex tile)
Get the X component of a tile.
Definition map_func.h:415
Base for ships.
Definition of base types and functions in a cross-platform compatible way.
Track follower helper template class (can serve pathfinders and vehicle controllers).
bool Follow(TileIndex old_tile, Trackdir old_td)
main follower routine.
bool is_bridge
last turn passed bridge ramp
TileIndex new_tile
the new tile (the vehicle has entered)
static uint SizeY()
Get the size of the map along the Y.
Definition map_func.h:279
static debug_inline uint SizeX()
Get the size of the map along the X.
Definition map_func.h:270
Represents the covered area of e.g.
OrthogonalTileIterator end() const
Returns an iterator to the end of the tile area.
Definition tilearea.cpp:162
bool Contains(TileIndex tile) const
Does this tile area contain a tile?
Definition tilearea.cpp:104
TileIndex tile
The base tile of the area.
OrthogonalTileIterator begin() const
Returns an iterator to the beginning of the tile area.
Definition tilearea.cpp:153
Iterable ensemble of each set bit in a value.
A pair-construct of a TileIndexDiff.
Definition map_type.h:31
int16_t x
The x value of the coordinate.
Definition map_type.h:32
int16_t y
The y value of the coordinate.
Definition map_type.h:33
Describes a single square water region.
int x
The X coordinate of the water region, i.e. X=2 is the 3rd water region along the X-axis.
int y
The Y coordinate of the water region, i.e. Y=2 is the 3rd water region along the Y-axis.
Describes a single interconnected patch of water within a particular water region.
TWaterRegionPatchLabel label
Unique label identifying the patch within the region.
int y
The Y coordinate of the water region, i.e. Y=2 is the 3rd water region along the Y-axis.
int x
The X coordinate of the water region, i.e. X=2 is the 3rd water region along the X-axis.
bool IsValidTile(Tile tile)
Checks if a tile is valid.
Definition tile_map.h:161
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:95
Type for storing the 'area' of something uses on the map.
Different conversion functions from one kind of track to another.
TrackdirBits TrackBitsToTrackdirBits(TrackBits bits)
Converts TrackBits to TrackdirBits while allowing both directions.
Definition track_func.h:319
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
Trackdir
Enumeration for tracks and directions.
Definition track_type.h:67
TrackdirBits
Allow incrementing of Trackdir variables.
Definition track_type.h:98
@ TRACKDIR_BIT_NONE
No track build.
Definition track_type.h:99
Base types related to transport.
@ TRANSPORT_WATER
Transport over water.
Functions that have tunnels and bridges in common.
TransportType GetTunnelBridgeTransportType(Tile t)
Tunnel: Get the transport type of the tunnel (road or rail) Bridge: Get the transport type of the bri...
void AllocateWaterRegions()
Allocates the appropriate amount of water regions for the current map size.
static void VisitAdjacentWaterRegionPatchNeighbors(const WaterRegionPatchDesc &water_region_patch, DiagDirection side, TVisitWaterRegionPatchCallBack &func)
Calls the provided callback function for all water region patches accessible from one particular side...
WaterRegionDesc GetWaterRegionInfo(TileIndex tile)
Returns basic water region information for the provided tile.
WaterRegionPatchDesc GetWaterRegionPatchInfo(TileIndex tile)
Returns basic water region patch information for the provided tile.
TileIndex GetWaterRegionCenterTile(const WaterRegionDesc &water_region)
Returns the center tile of a particular water region.
void InvalidateWaterRegion(TileIndex tile)
Marks the water region that tile is part of as invalid.
void VisitWaterRegionPatchNeighbors(const WaterRegionPatchDesc &water_region_patch, TVisitWaterRegionPatchCallBack &callback)
Calls the provided callback function on all accessible water region patches in each cardinal directio...
int CalculateWaterRegionPatchHash(const WaterRegionPatchDesc &water_region_patch)
Calculates a number that uniquely identifies the provided water region patch.
Handles dividing the water in the map into regions to assist pathfinding.