OpenTTD Source  20241108-master-g80f628063a
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 "map_func.h"
14 #include "tilearea_type.h"
15 #include "track_func.h"
16 #include "transport_type.h"
17 #include "landscape.h"
18 #include "tunnelbridge_map.h"
19 #include "follow_track.hpp"
20 #include "ship.h"
21 #include "debug.h"
22 
23 using TWaterRegionTraversabilityBits = uint16_t;
24 constexpr TWaterRegionPatchLabel FIRST_REGION_LABEL = 1;
25 
26 static_assert(sizeof(TWaterRegionTraversabilityBits) * 8 == WATER_REGION_EDGE_LENGTH);
27 static_assert(sizeof(TWaterRegionPatchLabel) == sizeof(uint8_t)); // Important for the hash calculation.
28 
29 static inline TrackBits GetWaterTracks(TileIndex tile) { return TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_WATER, 0)); }
30 static inline bool IsAqueductTile(TileIndex tile) { return IsBridgeTile(tile) && GetTunnelBridgeTransportType(tile) == TRANSPORT_WATER; }
31 
32 static inline int GetWaterRegionX(TileIndex tile) { return TileX(tile) / WATER_REGION_EDGE_LENGTH; }
33 static inline int GetWaterRegionY(TileIndex tile) { return TileY(tile) / WATER_REGION_EDGE_LENGTH; }
34 
35 static inline int GetWaterRegionMapSizeX() { return Map::SizeX() / WATER_REGION_EDGE_LENGTH; }
36 static inline int GetWaterRegionMapSizeY() { return Map::SizeY() / WATER_REGION_EDGE_LENGTH; }
37 
38 static inline TWaterRegionIndex GetWaterRegionIndex(int region_x, int region_y) { return GetWaterRegionMapSizeX() * region_y + region_x; }
39 static inline TWaterRegionIndex GetWaterRegionIndex(TileIndex tile) { return GetWaterRegionIndex(GetWaterRegionX(tile), GetWaterRegionY(tile)); }
40 
41 using TWaterRegionPatchLabelArray = std::array<TWaterRegionPatchLabel, WATER_REGION_NUMBER_OF_TILES>;
42 
47  friend class WaterRegion;
48 
49  std::array<TWaterRegionTraversabilityBits, DIAGDIR_END> edge_traversability_bits{};
50  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)
51  bool has_cross_region_aqueducts = false;
52  TWaterRegionPatchLabel number_of_patches = 0; // 0 = no water, 1 = one single patch of water, etc...
53 };
54 
62 {
63 private:
64  WaterRegionData &data;
65  const OrthogonalTileArea tile_area;
66 
73  inline int GetLocalIndex(TileIndex tile) const
74  {
75  assert(this->tile_area.Contains(tile));
76  return (TileX(tile) - TileX(this->tile_area.tile)) + WATER_REGION_EDGE_LENGTH * (TileY(tile) - TileY(this->tile_area.tile));
77  }
78 
79 public:
80  WaterRegion(int region_x, int region_y, WaterRegionData &water_region_data)
81  : data(water_region_data)
82  , tile_area(TileXY(region_x * WATER_REGION_EDGE_LENGTH, region_y * WATER_REGION_EDGE_LENGTH), WATER_REGION_EDGE_LENGTH, WATER_REGION_EDGE_LENGTH)
83  {}
84 
85  OrthogonalTileIterator begin() const { return this->tile_area.begin(); }
86  OrthogonalTileIterator end() const { return this->tile_area.end(); }
87 
95  TWaterRegionTraversabilityBits GetEdgeTraversabilityBits(DiagDirection side) const { return this->data.edge_traversability_bits[side]; }
96 
101  int NumberOfPatches() const { return static_cast<int>(this->data.number_of_patches); }
102 
106  bool HasCrossRegionAqueducts() const { return this->data.has_cross_region_aqueducts; }
107 
113  TWaterRegionPatchLabel GetLabel(TileIndex tile) const
114  {
115  assert(this->tile_area.Contains(tile));
116  if (this->data.tile_patch_labels == nullptr) {
117  return this->NumberOfPatches() == 0 ? INVALID_WATER_REGION_PATCH : FIRST_REGION_LABEL;
118  }
119  return (*this->data.tile_patch_labels)[this->GetLocalIndex(tile)];
120  }
121 
126  void ForceUpdate()
127  {
128  Debug(map, 3, "Updating water region ({},{})", GetWaterRegionX(this->tile_area.tile), GetWaterRegionY(this->tile_area.tile));
129  this->data.has_cross_region_aqueducts = false;
130 
131  /* Acquire a tile patch label array if this region does not already have one */
132  if (this->data.tile_patch_labels == nullptr) {
133  this->data.tile_patch_labels = std::make_unique<TWaterRegionPatchLabelArray>();
134  }
135 
136  this->data.tile_patch_labels->fill(INVALID_WATER_REGION_PATCH);
137  this->data.edge_traversability_bits.fill(0);
138 
139  TWaterRegionPatchLabel current_label = FIRST_REGION_LABEL;
140  TWaterRegionPatchLabel highest_assigned_label = INVALID_WATER_REGION_PATCH;
141 
142  /* Perform connected component labeling. This uses a flooding algorithm that expands until no
143  * additional tiles can be added. Only tiles inside the water region are considered. */
144  for (const TileIndex start_tile : this->tile_area) {
145  static std::vector<TileIndex> tiles_to_check;
146  tiles_to_check.clear();
147  tiles_to_check.push_back(start_tile);
148 
149  bool increase_label = false;
150  while (!tiles_to_check.empty()) {
151  const TileIndex tile = tiles_to_check.back();
152  tiles_to_check.pop_back();
153 
154  const TrackdirBits valid_dirs = TrackBitsToTrackdirBits(GetWaterTracks(tile));
155  if (valid_dirs == TRACKDIR_BIT_NONE) continue;
156 
157  TWaterRegionPatchLabel &tile_patch = (*this->data.tile_patch_labels)[this->GetLocalIndex(tile)];
158  if (tile_patch != INVALID_WATER_REGION_PATCH) continue;
159 
160  tile_patch = current_label;
161  highest_assigned_label = current_label;
162  increase_label = true;
163 
164  for (const Trackdir dir : SetTrackdirBitIterator(valid_dirs)) {
165  /* By using a TrackFollower we "play by the same rules" as the actual ship pathfinder */
167  if (ft.Follow(tile, dir)) {
168  if (this->tile_area.Contains(ft.new_tile)) {
169  tiles_to_check.push_back(ft.new_tile);
170  } else if (!ft.is_bridge) {
171  assert(DistanceManhattan(ft.new_tile, tile) == 1);
172  const auto side = DiagdirBetweenTiles(tile, ft.new_tile);
173  const int local_x_or_y = DiagDirToAxis(side) == AXIS_X ? TileY(tile) - TileY(this->tile_area.tile) : TileX(tile) - TileX(this->tile_area.tile);
174  SetBit(this->data.edge_traversability_bits[side], local_x_or_y);
175  } else {
176  this->data.has_cross_region_aqueducts = true;
177  }
178  }
179  }
180  }
181 
182  if (increase_label) current_label++;
183  }
184 
185  this->data.number_of_patches = highest_assigned_label;
186 
187  if (this->NumberOfPatches() == 0 || (this->NumberOfPatches() == 1 &&
188  std::all_of(this->data.tile_patch_labels->begin(), this->data.tile_patch_labels->end(), [](TWaterRegionPatchLabel label) { return label == FIRST_REGION_LABEL; }))) {
189  /* No need for patch storage: trivial cases */
190  this->data.tile_patch_labels.reset();
191  }
192  }
193 
194  void PrintDebugInfo()
195  {
196  Debug(map, 9, "Water region {},{} labels and edge traversability = ...", GetWaterRegionX(this->tile_area.tile), GetWaterRegionY(this->tile_area.tile));
197 
198  const size_t max_element_width = std::to_string(this->NumberOfPatches()).size();
199 
200  std::string traversability = fmt::format("{:0{}b}", this->GetEdgeTraversabilityBits(DIAGDIR_NW), WATER_REGION_EDGE_LENGTH);
201  Debug(map, 9, " {:{}}", fmt::join(traversability, " "), max_element_width);
202  Debug(map, 9, " +{:->{}}+", "", WATER_REGION_EDGE_LENGTH * (max_element_width + 1) + 1);
203 
204  for (int y = 0; y < WATER_REGION_EDGE_LENGTH; ++y) {
205  std::string line{};
206  for (int x = 0; x < WATER_REGION_EDGE_LENGTH; ++x) {
207  const auto label = this->GetLabel(TileAddXY(this->tile_area.tile, x, y));
208  const std::string label_str = label == INVALID_WATER_REGION_PATCH ? "." : std::to_string(label);
209  line = fmt::format("{:{}}", label_str, max_element_width) + " " + line;
210  }
211  Debug(map, 9, "{} | {}| {}", GB(this->GetEdgeTraversabilityBits(DIAGDIR_SW), y, 1), line, GB(this->GetEdgeTraversabilityBits(DIAGDIR_NE), y, 1));
212  }
213 
214  Debug(map, 9, " +{:->{}}+", "", WATER_REGION_EDGE_LENGTH * (max_element_width + 1) + 1);
215  traversability = fmt::format("{:0{}b}", this->GetEdgeTraversabilityBits(DIAGDIR_SE), WATER_REGION_EDGE_LENGTH);
216  Debug(map, 9, " {:{}}", fmt::join(traversability, " "), max_element_width);
217  }
218 };
219 
220 std::vector<WaterRegionData> _water_region_data;
221 std::vector<bool> _is_water_region_valid;
222 
223 static TileIndex GetTileIndexFromLocalCoordinate(int region_x, int region_y, int local_x, int local_y)
224 {
225  assert(local_x >= 0 && local_x < WATER_REGION_EDGE_LENGTH);
226  assert(local_y >= 0 && local_y < WATER_REGION_EDGE_LENGTH);
227  return TileXY(WATER_REGION_EDGE_LENGTH * region_x + local_x, WATER_REGION_EDGE_LENGTH * region_y + local_y);
228 }
229 
230 static TileIndex GetEdgeTileCoordinate(int region_x, int region_y, DiagDirection side, int x_or_y)
231 {
232  assert(x_or_y >= 0 && x_or_y < WATER_REGION_EDGE_LENGTH);
233  switch (side) {
234  case DIAGDIR_NE: return GetTileIndexFromLocalCoordinate(region_x, region_y, 0, x_or_y);
235  case DIAGDIR_SW: return GetTileIndexFromLocalCoordinate(region_x, region_y, WATER_REGION_EDGE_LENGTH - 1, x_or_y);
236  case DIAGDIR_NW: return GetTileIndexFromLocalCoordinate(region_x, region_y, x_or_y, 0);
237  case DIAGDIR_SE: return GetTileIndexFromLocalCoordinate(region_x, region_y, x_or_y, WATER_REGION_EDGE_LENGTH - 1);
238  default: NOT_REACHED();
239  }
240 }
241 
242 static WaterRegion GetUpdatedWaterRegion(uint16_t region_x, uint16_t region_y)
243 {
244  const TWaterRegionIndex index = GetWaterRegionIndex(region_x, region_y);
245  WaterRegion water_region(region_x, region_y, _water_region_data[index]);
246  if (!_is_water_region_valid[index]) {
247  water_region.ForceUpdate();
248  _is_water_region_valid[index] = true;
249  }
250  return water_region;
251 }
252 
253 static WaterRegion GetUpdatedWaterRegion(TileIndex tile)
254 {
255  return GetUpdatedWaterRegion(GetWaterRegionX(tile), GetWaterRegionY(tile));
256 }
257 
262 static TWaterRegionIndex GetWaterRegionIndex(const WaterRegionDesc &water_region)
263 {
264  return GetWaterRegionIndex(water_region.x, water_region.y);
265 }
266 
272 {
273  return water_region_patch.label | GetWaterRegionIndex(water_region_patch) << 8;
274 }
275 
282 {
283  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));
284 }
285 
291 {
292  return WaterRegionDesc{ GetWaterRegionX(tile), GetWaterRegionY(tile) };
293 }
294 
300 {
301  const WaterRegion region = GetUpdatedWaterRegion(tile);
302  return WaterRegionPatchDesc{ GetWaterRegionX(tile), GetWaterRegionY(tile), region.GetLabel(tile) };
303 }
304 
310 {
311  if (!IsValidTile(tile)) return;
312 
313  auto invalidate_region = [](TileIndex tile) {
314  const TWaterRegionIndex water_region_index = GetWaterRegionIndex(tile);
315  if (!_is_water_region_valid[water_region_index]) Debug(map, 3, "Invalidated water region ({},{})", GetWaterRegionX(tile), GetWaterRegionY(tile));
316  _is_water_region_valid[water_region_index] = false;
317  };
318 
319  invalidate_region(tile);
320 
321  /* When updating the water region we look into the first tile of adjacent water regions to determine edge
322  * traversability. This means that if we invalidate any region edge tiles we might also change the traversability
323  * of the adjacent region. This code ensures the adjacent regions also get invalidated in such a case. */
324  for (DiagDirection side = DIAGDIR_BEGIN; side < DIAGDIR_END; side++) {
325  const TileIndex adjacent_tile = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDiagDir(side));
326  if (adjacent_tile == INVALID_TILE) continue;
327  if (GetWaterRegionIndex(adjacent_tile) != GetWaterRegionIndex(tile)) invalidate_region(adjacent_tile);
328  }
329 }
330 
338 static inline void VisitAdjacentWaterRegionPatchNeighbors(const WaterRegionPatchDesc &water_region_patch, DiagDirection side, TVisitWaterRegionPatchCallBack &func)
339 {
340  if (water_region_patch.label == INVALID_WATER_REGION_PATCH) return;
341 
342  const WaterRegion current_region = GetUpdatedWaterRegion(water_region_patch.x, water_region_patch.y);
343 
344  const TileIndexDiffC offset = TileIndexDiffCByDiagDir(side);
345  const int nx = water_region_patch.x + offset.x;
346  const int ny = water_region_patch.y + offset.y;
347 
348  if (nx < 0 || ny < 0 || nx >= GetWaterRegionMapSizeX() || ny >= GetWaterRegionMapSizeY()) return;
349 
350  const WaterRegion neighboring_region = GetUpdatedWaterRegion(nx, ny);
351  const DiagDirection opposite_side = ReverseDiagDir(side);
352 
353  /* Indicates via which local x or y coordinates (depends on the "side" parameter) we can cross over into the adjacent region. */
354  const TWaterRegionTraversabilityBits traversability_bits = current_region.GetEdgeTraversabilityBits(side)
355  & neighboring_region.GetEdgeTraversabilityBits(opposite_side);
356  if (traversability_bits == 0) return;
357 
358  if (current_region.NumberOfPatches() == 1 && neighboring_region.NumberOfPatches() == 1) {
359  func(WaterRegionPatchDesc{ nx, ny, FIRST_REGION_LABEL }); // No further checks needed because we know there is just one patch for both adjacent regions
360  return;
361  }
362 
363  /* Multiple water patches can be reached from the current patch. Check each edge tile individually. */
364  static std::vector<TWaterRegionPatchLabel> unique_labels; // static and vector-instead-of-map for performance reasons
365  unique_labels.clear();
366  for (int x_or_y = 0; x_or_y < WATER_REGION_EDGE_LENGTH; ++x_or_y) {
367  if (!HasBit(traversability_bits, x_or_y)) continue;
368 
369  const TileIndex current_edge_tile = GetEdgeTileCoordinate(water_region_patch.x, water_region_patch.y, side, x_or_y);
370  const TWaterRegionPatchLabel current_label = current_region.GetLabel(current_edge_tile);
371  if (current_label != water_region_patch.label) continue;
372 
373  const TileIndex neighbor_edge_tile = GetEdgeTileCoordinate(nx, ny, opposite_side, x_or_y);
374  const TWaterRegionPatchLabel neighbor_label = neighboring_region.GetLabel(neighbor_edge_tile);
375  assert(neighbor_label != INVALID_WATER_REGION_PATCH);
376  if (std::find(unique_labels.begin(), unique_labels.end(), neighbor_label) == unique_labels.end()) unique_labels.push_back(neighbor_label);
377  }
378  for (TWaterRegionPatchLabel unique_label : unique_labels) func(WaterRegionPatchDesc{ nx, ny, unique_label });
379 }
380 
387 void VisitWaterRegionPatchNeighbors(const WaterRegionPatchDesc &water_region_patch, TVisitWaterRegionPatchCallBack &callback)
388 {
389  if (water_region_patch.label == INVALID_WATER_REGION_PATCH) return;
390 
391  const WaterRegion current_region = GetUpdatedWaterRegion(water_region_patch.x, water_region_patch.y);
392 
393  /* Visit adjacent water region patches in each cardinal direction */
394  for (DiagDirection side = DIAGDIR_BEGIN; side < DIAGDIR_END; side++) VisitAdjacentWaterRegionPatchNeighbors(water_region_patch, side, callback);
395 
396  /* Visit neigboring water patches accessible via cross-region aqueducts */
397  if (current_region.HasCrossRegionAqueducts()) {
398  for (const TileIndex tile : current_region) {
399  if (GetWaterRegionPatchInfo(tile) == water_region_patch && IsAqueductTile(tile)) {
400  const TileIndex other_end_tile = GetOtherBridgeEnd(tile);
401  if (GetWaterRegionIndex(tile) != GetWaterRegionIndex(other_end_tile)) callback(GetWaterRegionPatchInfo(other_end_tile));
402  }
403  }
404  }
405 }
406 
411 {
412  const int number_of_regions = GetWaterRegionMapSizeX() * GetWaterRegionMapSizeY();
413 
414  _water_region_data.clear();
415  _water_region_data.resize(number_of_regions);
416 
417  _is_water_region_valid.clear();
418  _is_water_region_valid.resize(number_of_regions, false);
419 
420  Debug(map, 2, "Allocating {} x {} water regions", GetWaterRegionMapSizeX(), GetWaterRegionMapSizeY());
421  assert(_is_water_region_valid.size() == _water_region_data.size());
422 }
423 
424 void PrintWaterRegionDebugInfo(TileIndex tile)
425 {
426  GetUpdatedWaterRegion(tile).PrintDebugInfo();
427 }
constexpr debug_inline 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.
constexpr static debug_inline 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.
Definition: bridge_map.cpp:59
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.
Definition: landscape.cpp:554
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.
Definition: tilearea_type.h:18
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.
Definition: tilearea_type.h:19
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.
Definition: water_regions.h:41
int x
The X coordinate of the water region, i.e. X=2 is the 3rd water region along the X-axis.
Definition: water_regions.h:42
int y
The Y coordinate of the water region, i.e. Y=2 is the 3rd water region along the Y-axis.
Definition: water_regions.h:43
Describes a single interconnected patch of water within a particular water region.
Definition: water_regions.h:27
TWaterRegionPatchLabel label
Unique label identifying the patch within the region.
Definition: water_regions.h:30
int y
The Y coordinate of the water region, i.e. Y=2 is the 3rd water region along the Y-axis.
Definition: water_regions.h:29
int x
The X coordinate of the water region, i.e. X=2 is the 3rd water region along the X-axis.
Definition: water_regions.h:28
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 TWaterRegionIndex GetWaterRegionIndex(const WaterRegionDesc &water_region)
Returns the index of the water region.
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.