OpenTTD Source 20260208-master-g43af8e94d0
yapf_ship.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#include "../../stdafx.h"
11#include "../../ship.h"
12#include "../../vehicle_func.h"
13
14#include "yapf.hpp"
15#include "yapf_node_ship.hpp"
16#include "yapf_ship_regions.h"
17#include "../water_regions.h"
18
19#include "../../safeguards.h"
20
21constexpr int NUMBER_OR_WATER_REGIONS_LOOKAHEAD = 4;
22constexpr int MAX_SHIP_PF_NODES = (NUMBER_OR_WATER_REGIONS_LOOKAHEAD + 1) * WATER_REGION_NUMBER_OF_TILES * 4; // 4 possible exit dirs per tile.
23
24constexpr int SHIP_LOST_PATH_LENGTH = 8; // The length of the (aimless) path assigned when a ship is lost.
25
26template <class Types>
28public:
29 typedef typename Types::Tpf Tpf;
30 typedef typename Types::TrackFollower TrackFollower;
31 typedef typename Types::NodeList::Item Node;
32 typedef typename Node::Key Key;
33
34protected:
35 TileIndex dest_tile;
36 TrackdirBits dest_trackdirs;
37 StationID dest_station;
38
39 bool has_intermediate_dest = false;
40 TileIndex intermediate_dest_tile;
41 WaterRegionPatchDesc intermediate_dest_region_patch;
42
43public:
44 void SetDestination(const Ship *v)
45 {
46 if (v->current_order.IsType(OT_GOTO_STATION)) {
47 this->dest_station = v->current_order.GetDestination().ToStationID();
48 this->dest_tile = CalcClosestStationTile(this->dest_station, v->tile, StationType::Dock);
49 this->dest_trackdirs = INVALID_TRACKDIR_BIT;
50 } else {
51 this->dest_station = StationID::Invalid();
52 this->dest_tile = v->dest_tile == INVALID_TILE ? TileIndex{} : v->dest_tile;
53 this->dest_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(this->dest_tile, TRANSPORT_WATER, 0));
54 }
55 }
56
57 void SetIntermediateDestination(const WaterRegionPatchDesc &water_region_patch)
58 {
59 this->has_intermediate_dest = true;
60 this->intermediate_dest_tile = GetWaterRegionCenterTile(water_region_patch);
61 this->intermediate_dest_region_patch = water_region_patch;
62 }
63
64protected:
66 inline Tpf& Yapf()
67 {
68 return *static_cast<Tpf*>(this);
69 }
70
71public:
73 inline bool PfDetectDestination(Node &n)
74 {
75 return this->PfDetectDestinationTile(n.GetTile(), n.GetTrackdir());
76 }
77
78 inline bool PfDetectDestinationTile(TileIndex tile, Trackdir trackdir)
79 {
80 if (this->has_intermediate_dest) {
81 /* GetWaterRegionInfo is much faster than GetWaterRegionPatchInfo so we try that first. */
82 if (GetWaterRegionInfo(tile) != this->intermediate_dest_region_patch) return false;
83 return GetWaterRegionPatchInfo(tile) == this->intermediate_dest_region_patch;
84 }
85
86 if (this->dest_station != StationID::Invalid()) return IsDockingTile(tile) && IsShipDestinationTile(tile, this->dest_station);
87
88 return tile == this->dest_tile && ((this->dest_trackdirs & TrackdirToTrackdirBits(trackdir)) != TRACKDIR_BIT_NONE);
89 }
90
95 inline bool PfCalcEstimate(Node &n)
96 {
97 const TileIndex destination_tile = this->has_intermediate_dest ? this->intermediate_dest_tile : this->dest_tile;
98
99 if (this->PfDetectDestination(n)) {
100 n.estimate = n.cost;
101 return true;
102 }
103
104 n.estimate = n.cost + OctileDistanceCost(n.GetTile(), n.GetTrackdir(), destination_tile);
105 assert(n.estimate >= n.parent->estimate);
106 return true;
107 }
108};
109
111template <class Types>
113public:
114 typedef typename Types::Tpf Tpf;
115 typedef typename Types::TrackFollower TrackFollower;
116 typedef typename Types::NodeList::Item Node;
117 typedef typename Node::Key Key;
118
119protected:
121 inline Tpf &Yapf()
122 {
123 return *static_cast<Tpf*>(this);
124 }
125
126 std::vector<WaterRegionDesc> water_region_corridor;
127
128public:
134 inline void PfFollowNode(Node &old_node)
135 {
136 TrackFollower follower{Yapf().GetVehicle()};
137 if (follower.Follow(old_node.key.tile, old_node.key.td)) {
138 if (this->water_region_corridor.empty()
139 || std::ranges::find(this->water_region_corridor, GetWaterRegionInfo(follower.new_tile)) != this->water_region_corridor.end()) {
140 Yapf().AddMultipleNodes(&old_node, follower);
141 }
142 }
143 }
144
146 inline void RestrictSearch(const std::vector<WaterRegionPatchDesc> &path)
147 {
148 this->water_region_corridor.clear();
149 for (const WaterRegionPatchDesc &path_entry : path) this->water_region_corridor.push_back(path_entry);
150 }
151
153 inline char TransportTypeChar() const
154 {
155 return 'w';
156 }
157
160 {
161 const int strip_amount = RandomRange(CountBits(trackdirs));
162 for (int s = 0; s < strip_amount; ++s) RemoveFirstTrackdir(&trackdirs);
163 return FindFirstTrackdir(trackdirs);
164 }
165
167 static std::pair<TileIndex, Trackdir> GetRandomFollowUpTileTrackdir(const Ship *v, TileIndex tile, Trackdir dir)
168 {
169 TrackFollower follower{v};
170 if (follower.Follow(tile, dir)) {
171 TrackdirBits dirs = follower.new_td_bits;
172 const TrackdirBits dirs_without_90_degree = dirs & ~TrackdirCrossesTrackdirs(dir);
173 if (dirs_without_90_degree != TRACKDIR_BIT_NONE) dirs = dirs_without_90_degree;
174 return { follower.new_tile, GetRandomTrackdir(dirs) };
175 }
176 return { follower.new_tile, INVALID_TRACKDIR };
177 }
178
180 static Trackdir CreateRandomPath(const Ship *v, ShipPathCache &path_cache, int path_length)
181 {
182 std::pair<TileIndex, Trackdir> tile_dir = { v->tile, v->GetVehicleTrackdir()};
183 for (int i = 0; i < path_length; ++i) {
184 tile_dir = GetRandomFollowUpTileTrackdir(v, tile_dir.first, tile_dir.second);
185 if (tile_dir.second == INVALID_TRACKDIR) break;
186 path_cache.push_back(tile_dir.second);
187 }
188
189 if (path_cache.empty()) return INVALID_TRACKDIR;
190
191 /* Reverse the path so we can take from the end. */
192 std::reverse(std::begin(path_cache), std::end(path_cache));
193
194 const Trackdir result = path_cache.back().trackdir;
195 path_cache.pop_back();
196 return result;
197 }
198
199 static Trackdir ChooseShipTrack(const Ship *v, TileIndex tile, TrackdirBits forward_dirs, TrackdirBits reverse_dirs,
200 bool &path_found, ShipPathCache &path_cache, Trackdir &best_origin_dir)
201 {
202 const std::vector<WaterRegionPatchDesc> high_level_path = YapfShipFindWaterRegionPath(v, tile, NUMBER_OR_WATER_REGIONS_LOOKAHEAD + 1);
203 if (high_level_path.empty()) {
204 path_found = false;
205 /* Make the ship move around aimlessly. This prevents repeated pathfinder calls and clearly indicates that the ship is lost. */
206 return CreateRandomPath(v, path_cache, SHIP_LOST_PATH_LENGTH);
207 }
208
209 /* Try one time without restricting the search area, which generally results in better and more natural looking paths.
210 * However the pathfinder can hit the node limit in certain situations such as long aqueducts or maze-like terrain.
211 * If that happens we run the pathfinder again, but restricted only to the regions provided by the region pathfinder. */
212 for (int attempt = 0; attempt < 2; ++attempt) {
213 Tpf pf(MAX_SHIP_PF_NODES);
214
215 /* Set origin and destination nodes */
216 pf.SetOrigin(v->tile, forward_dirs | reverse_dirs);
217 pf.SetDestination(v);
218 const bool is_intermediate_destination = static_cast<int>(high_level_path.size()) >= NUMBER_OR_WATER_REGIONS_LOOKAHEAD + 1;
219 if (is_intermediate_destination) pf.SetIntermediateDestination(high_level_path.back());
220
221 /* Restrict the search area to prevent the low level pathfinder from expanding too many nodes. This can happen
222 * when the terrain is very "maze-like" or when the high level path "teleports" via a very long aqueduct. */
223 if (attempt > 0) pf.RestrictSearch(high_level_path);
224
225 /* Find best path. */
226 path_found = pf.FindPath(v);
227 Node *node = pf.GetBestNode();
228 if (attempt == 0 && !path_found) continue; // Try again with restricted search area.
229
230 /* Make the ship move around aimlessly. This prevents repeated pathfinder calls and clearly indicates that the ship is lost. */
231 if (!path_found) return CreateRandomPath(v, path_cache, SHIP_LOST_PATH_LENGTH);
232
233 /* Return only the path within the current water region if an intermediate destination was returned. If not, cache the entire path
234 * to the final destination tile. The low-level pathfinder might actually prefer a different docking tile in a nearby region. Without
235 * caching the full path the ship can get stuck in a loop. */
236 const WaterRegionPatchDesc end_water_patch = GetWaterRegionPatchInfo(node->GetTile());
237 assert(GetWaterRegionPatchInfo(tile) == high_level_path.front());
238 const WaterRegionPatchDesc start_water_patch = high_level_path.front();
239 while (node->parent) {
240 const WaterRegionPatchDesc node_water_patch = GetWaterRegionPatchInfo(node->GetTile());
241
242 const bool node_water_patch_on_high_level_path = std::ranges::find(high_level_path, node_water_patch) != high_level_path.end();
243 const bool add_full_path = !is_intermediate_destination && node_water_patch != end_water_patch;
244
245 /* The cached path must always lead to a region patch that's on the high level path.
246 * This is what can happen when that's not the case https://github.com/OpenTTD/OpenTTD/issues/12176. */
247 if (add_full_path || !node_water_patch_on_high_level_path || node_water_patch == start_water_patch) {
248 path_cache.push_back(node->GetTrackdir());
249 } else {
250 path_cache.clear();
251 }
252 node = node->parent;
253 }
254 assert(node->GetTile() == v->tile);
255
256 /* Return INVALID_TRACKDIR to trigger a ship reversal if that is the best option. */
257 best_origin_dir = node->GetTrackdir();
258 if ((TrackdirToTrackdirBits(best_origin_dir) & forward_dirs) == TRACKDIR_BIT_NONE) {
259 path_cache.clear();
260 return INVALID_TRACKDIR;
261 }
262
263 /* A empty path means we are already at the destination. The pathfinder shouldn't have been called at all.
264 * Return a random reachable trackdir to hopefully nudge the ship out of this strange situation. */
265 if (path_cache.empty()) return CreateRandomPath(v, path_cache, 1);
266
267 /* Take out the last trackdir as the result. */
268 const Trackdir result = path_cache.back().trackdir;
269 path_cache.pop_back();
270
271 /* Clear path cache when in final water region patch. This is to allow ships to spread over different docking tiles dynamically. */
272 if (start_water_patch == end_water_patch) path_cache.clear();
273
274 return result;
275 }
276
277 NOT_REACHED();
278 }
279
287 static bool CheckShipReverse(const Ship *v, Trackdir *trackdir)
288 {
289 bool path_found = false;
290 ShipPathCache dummy_cache;
291 Trackdir best_origin_dir = INVALID_TRACKDIR;
292
293 if (trackdir == nullptr) {
294 /* The normal case, typically called when ships leave a dock. */
295 const Trackdir reverse_dir = ReverseTrackdir(v->GetVehicleTrackdir());
296 const TrackdirBits forward_dirs = TrackdirToTrackdirBits(v->GetVehicleTrackdir());
297 const TrackdirBits reverse_dirs = TrackdirToTrackdirBits(reverse_dir);
298 (void)ChooseShipTrack(v, v->tile, forward_dirs, reverse_dirs, path_found, dummy_cache, best_origin_dir);
299 return path_found && best_origin_dir == reverse_dir;
300 } else {
301 /* This gets called when a ship suddenly can't move forward, e.g. due to terraforming. */
304 (void)ChooseShipTrack(v, v->tile, TRACKDIR_BIT_NONE, reverse_dirs, path_found, dummy_cache, best_origin_dir);
305 *trackdir = path_found && best_origin_dir != INVALID_TRACKDIR ? best_origin_dir : GetRandomTrackdir(reverse_dirs);
306 return true;
307 }
308 }
309};
310
312template <class Types>
314public:
315 typedef typename Types::Tpf Tpf;
316 typedef typename Types::TrackFollower TrackFollower;
317 typedef typename Types::NodeList::Item Node;
318 typedef typename Node::Key Key;
319
322 {
323 return *static_cast<Tpf*>(this);
324 }
325
326public:
327 inline int CurveCost(Trackdir td1, Trackdir td2)
328 {
329 assert(IsValidTrackdir(td1));
330 assert(IsValidTrackdir(td2));
331
332 if (HasTrackdir(TrackdirCrossesTrackdirs(td1), td2)) {
333 /* 90-deg curve penalty. */
334 return Yapf().PfGetSettings().ship_curve90_penalty;
335 } else if (td2 != NextTrackdir(td1)) {
336 /* 45-deg curve penalty. */
337 return Yapf().PfGetSettings().ship_curve45_penalty;
338 }
339 return 0;
340 }
341
348 inline static bool IsPreferredShipDirection(TileIndex tile, Trackdir td)
349 {
350 const bool odd_x = TileX(tile) & 1;
351 const bool odd_y = TileY(tile) & 1;
352 if (td == TRACKDIR_X_NE) return odd_y;
353 if (td == TRACKDIR_X_SW) return !odd_y;
354 if (td == TRACKDIR_Y_NW) return odd_x;
355 if (td == TRACKDIR_Y_SE) return !odd_x;
357 }
358
364 inline bool PfCalcCost(Node &n, const TrackFollower *follower)
365 {
366 /* Base tile cost depending on distance. */
368 /* Additional penalty for curves. */
369 c += this->CurveCost(n.parent->GetTrackdir(), n.GetTrackdir());
370
371 if (IsDockingTile(n.GetTile())) {
372 /* Check docking tile for occupancy. */
373 uint count = std::ranges::count_if(VehiclesOnTile(n.GetTile()), [](const Vehicle *v) {
374 /* Ignore other vehicles (aircraft) and ships inside depot. */
375 return v->type == VEH_SHIP && !v->vehstatus.Test(VehState::Hidden);
376 });
377 c += count * 3 * YAPF_TILE_LENGTH;
378 }
379
380 /* Encourage separation between ships traveling in different directions. */
381 if (!IsPreferredShipDirection(n.GetTile(), n.GetTrackdir())) c += YAPF_TILE_LENGTH;
382
383 /* Skipped tile cost for aqueducts. */
384 c += YAPF_TILE_LENGTH * follower->tiles_skipped;
385
386 /* Ocean/canal speed penalty. */
387 const ShipVehicleInfo *svi = ShipVehInfo(Yapf().GetVehicle()->engine_type);
388 uint8_t speed_frac = (GetEffectiveWaterClass(n.GetTile()) == WaterClass::Sea) ? svi->ocean_speed_frac : svi->canal_speed_frac;
389 if (speed_frac > 0) c += YAPF_TILE_LENGTH * (1 + follower->tiles_skipped) * speed_frac / (256 - speed_frac);
390
391 /* Lock penalty. */
392 if (IsTileType(n.GetTile(), TileType::Water) && IsLock(n.GetTile()) && GetLockPart(n.GetTile()) == LockPart::Middle) {
393 const uint canal_speed = svi->ApplyWaterClassSpeedFrac(svi->max_speed, false);
394 /* Cost is proportional to the vehicle's speed as the vehicle stops in the lock. */
395 c += (TILE_HEIGHT * YAPF_TILE_LENGTH * canal_speed) / 128;
396 }
397
398 /* Apply it. */
399 n.cost = n.parent->cost + c;
400 return true;
401 }
402};
403
408template <class Tpf_>
411 typedef Tpf_ Tpf;
412 typedef CFollowTrackWater TrackFollower;
413 typedef CShipNodeList NodeList;
414 typedef Ship VehicleType;
415
423};
424
425struct CYapfShip : CYapfT<CYapfShip_TypesT<CYapfShip>> {
426 explicit CYapfShip(int max_nodes) { this->max_search_nodes = max_nodes; }
427};
428
430Track YapfShipChooseTrack(const Ship *v, TileIndex tile, bool &path_found, ShipPathCache &path_cache)
431{
432 Trackdir best_origin_dir = INVALID_TRACKDIR;
434 const Trackdir td_ret = CYapfShip::ChooseShipTrack(v, tile, origin_dirs, TRACKDIR_BIT_NONE, path_found, path_cache, best_origin_dir);
435 return (td_ret != INVALID_TRACKDIR) ? TrackdirToTrack(td_ret) : INVALID_TRACK;
436}
437
438bool YapfShipCheckReverse(const Ship *v, Trackdir *trackdir)
439{
440 return CYapfShip::CheckShipReverse(v, trackdir);
441}
constexpr uint CountBits(T value)
Counts the number of set bits in a variable.
constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
CYapfBaseT - A-star type path finder base class.
Definition yapf_base.hpp:48
int max_search_nodes
maximum number of nodes we are allowed to visit before we give up
Definition yapf_base.hpp:63
Cost Provider module of YAPF for ships.
Node::Key Key
key to hash tables.
static bool IsPreferredShipDirection(TileIndex tile, Trackdir td)
Whether the provided direction is a preferred direction for a given tile.
Types::NodeList::Item Node
this will be our node type.
bool PfCalcCost(Node &n, const TrackFollower *follower)
Called by YAPF to calculate the cost from the origin to the given node.
Tpf & Yapf()
to access inherited path finder
Types::Tpf Tpf
the pathfinder class (derived from THIS class).
Types::Tpf Tpf
the pathfinder class (derived from THIS class).
Definition yapf_ship.cpp:29
bool PfCalcEstimate(Node &n)
Called by YAPF to calculate cost estimate.
Definition yapf_ship.cpp:95
Types::NodeList::Item Node
this will be our node type.
Definition yapf_ship.cpp:31
bool PfDetectDestination(Node &n)
Called by YAPF to detect if node ends in the desired destination.
Definition yapf_ship.cpp:73
Node::Key Key
key to hash tables.
Definition yapf_ship.cpp:32
Tpf & Yapf()
To access inherited path finder.
Definition yapf_ship.cpp:66
Node Follower module of YAPF for ships.
static std::pair< TileIndex, Trackdir > GetRandomFollowUpTileTrackdir(const Ship *v, TileIndex tile, Trackdir dir)
Returns a random tile/trackdir that can be reached from the current tile/trackdir,...
char TransportTypeChar() const
Return debug report character to identify the transportation type.
void PfFollowNode(Node &old_node)
Called by YAPF to move from the given node to the next tile.
static Trackdir GetRandomTrackdir(TrackdirBits trackdirs)
Returns a random trackdir out of a set of trackdirs.
Node::Key Key
key to hash tables.
static Trackdir CreateRandomPath(const Ship *v, ShipPathCache &path_cache, int path_length)
Creates a random path, avoids 90 degree turns.
Types::NodeList::Item Node
this will be our node type.
Types::Tpf Tpf
the pathfinder class (derived from THIS class).
void RestrictSearch(const std::vector< WaterRegionPatchDesc > &path)
Restricts the search by creating corridor or water regions through which the ship is allowed to trave...
static bool CheckShipReverse(const Ship *v, Trackdir *trackdir)
Check whether a ship should reverse to reach its destination.
Tpf & Yapf()
to access inherited path finder
YAPF origin provider base class - used when origin is one tile / multiple trackdirs.
CYapfSegmentCostCacheNoneT - the formal only yapf cost cache provider that implements PfNodeCacheFetc...
YAPF template that uses Ttypes template argument to determine all YAPF components (base classes) from...
Iterate over all vehicles on a tile.
DiagDirection ReverseDiagDir(DiagDirection d)
Returns the reverse direction of the given DiagDirection.
DiagDirection
Enumeration for diagonal directions.
TrackStatus GetTileTrackStatus(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
Returns information about trackdirs and signal states.
static uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition map_func.h:427
static uint TileX(TileIndex tile)
Get the X component of a tile.
Definition map_func.h:417
TileIndex CalcClosestStationTile(StationID station, TileIndex tile, StationType station_type)
Calculates the tile of given station that is closest to a given tile for this we assume the station i...
static const int YAPF_TILE_CORNER_LENGTH
Length (penalty) of a corner with YAPF.
static const int YAPF_TILE_LENGTH
Length (penalty) of one tile with YAPF.
uint32_t RandomRange(uint32_t limit, const std::source_location location=std::source_location::current())
Pick a random number between 0 and limit - 1, inclusive.
A number of safeguards to prevent using unsafe methods.
Base for ships.
bool IsShipDestinationTile(TileIndex tile, StationID station)
Test if a tile is a docking tile for the given station.
Definition ship_cmd.cpp:617
WaterClass GetEffectiveWaterClass(TileIndex tile)
Determine the effective WaterClass for a ship travelling on a tile.
Definition ship_cmd.cpp:53
static Track ChooseShipTrack(Ship *v, TileIndex tile, TrackBits tracks)
Runs the pathfinder to choose a track to continue along.
Definition ship_cmd.cpp:465
@ Dock
Ship port.
Definition of base types and functions in a cross-platform compatible way.
Config struct of YAPF for ships.
CYapfShip_TypesT< Tpf_ > Types
Shortcut for this struct type.
CYapfDestinationTileWaterT< Types > PfDestination
Destination/distance provider.
CYapfSegmentCostCacheNoneT< Types > PfCache
Segment cost cache provider.
CYapfOriginTileT< Types > PfOrigin
Origin provider.
Tpf_ Tpf
Pathfinder type.
CFollowTrackWater TrackFollower
Track follower helper class.
CYapfFollowShipT< Types > PfFollow
Node follower.
CYapfCostShipT< Types > PfCost
Cost provider.
CYapfBaseT< Types > PfBase
Pathfinder components (modules).
DestinationID GetDestination() const
Gets the destination of this order.
Definition order_base.h:99
bool IsType(OrderType type) const
Check whether this order is of the given type.
Definition order_base.h:66
Information about a ship vehicle.
Definition engine_type.h:99
uint8_t ocean_speed_frac
Fraction of maximum speed for ocean tiles.
uint ApplyWaterClassSpeedFrac(uint raw_speed, bool is_ocean) const
Apply ocean/canal speed fraction to a velocity.
uint16_t max_speed
Maximum speed (1 unit = 1/3.2 mph = 0.5 km-ish/h).
uint8_t canal_speed_frac
Fraction of maximum speed for canal/river tiles.
All ships have this type.
Definition ship.h:32
TrackBits state
The "track" the ship is following.
Definition ship.h:34
Trackdir GetVehicleTrackdir() const override
Returns the Trackdir on which the vehicle is currently located.
Definition ship_cmd.cpp:287
Vehicle data structure.
Direction direction
facing
Vehicle * first
NOSAVE: pointer to the first vehicle in the chain.
Order current_order
The current order (+ status, like: loading).
TileIndex tile
Current tile index.
TileIndex dest_tile
Heading for this tile.
Describes a single interconnected patch of water within a particular water region.
static bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition tile_map.h:150
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > > TileIndex
The index/ID of a Tile.
Definition tile_type.h:92
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:100
static constexpr uint TILE_HEIGHT
Height of a height level in world coordinate AND in pixels in ZOOM_BASE.
Definition tile_type.h:18
@ Water
Water tile.
Definition tile_type.h:55
Trackdir RemoveFirstTrackdir(TrackdirBits *trackdirs)
Removes first Trackdir from TrackdirBits and returns it.
Definition track_func.h:156
Track TrackdirToTrack(Trackdir trackdir)
Returns the Track that a given Trackdir represents.
Definition track_func.h:262
DiagDirection VehicleExitDir(Direction direction, TrackBits track)
Determine the side in which the vehicle will leave the tile.
Definition track_func.h:714
TrackdirBits TrackStatusToTrackdirBits(TrackStatus ts)
Returns the present-trackdir-information of a TrackStatus.
Definition track_func.h:352
Trackdir NextTrackdir(Trackdir trackdir)
Maps a trackdir to the trackdir that you will end up on if you go straight ahead.
Definition track_func.h:403
Trackdir ReverseTrackdir(Trackdir trackdir)
Maps a trackdir to the reverse trackdir.
Definition track_func.h:247
bool IsValidTrackdir(Trackdir trackdir)
Checks if a Trackdir is valid for non-road vehicles.
Definition track_func.h:52
Trackdir FindFirstTrackdir(TrackdirBits trackdirs)
Returns first Trackdir from TrackdirBits or INVALID_TRACKDIR.
Definition track_func.h:211
TrackdirBits TrackdirCrossesTrackdirs(Trackdir trackdir)
Maps a trackdir to all trackdirs that make 90 deg turns with it.
Definition track_func.h:606
TrackdirBits DiagdirReachesTrackdirs(DiagDirection diagdir)
Returns all trackdirs that can be reached when entering a tile from a given (diagonal) direction.
Definition track_func.h:555
bool IsDiagonalTrackdir(Trackdir trackdir)
Checks if a given Trackdir is diagonal.
Definition track_func.h:631
bool HasTrackdir(TrackdirBits trackdirs, Trackdir trackdir)
Checks whether a TrackdirBits has a given Trackdir.
Definition track_func.h:340
TrackdirBits TrackdirToTrackdirBits(Trackdir trackdir)
Maps a Trackdir to the corresponding TrackdirBits value.
Definition track_func.h:111
Trackdir
Enumeration for tracks and directions.
Definition track_type.h:66
@ TRACKDIR_X_NE
X-axis and direction to north-east.
Definition track_type.h:68
@ INVALID_TRACKDIR
Flag for an invalid trackdir.
Definition track_type.h:85
@ TRACKDIR_Y_SE
Y-axis and direction to south-east.
Definition track_type.h:69
@ TRACKDIR_X_SW
X-axis and direction to south-west.
Definition track_type.h:76
@ TRACKDIR_Y_NW
Y-axis and direction to north-west.
Definition track_type.h:77
TrackdirBits
Allow incrementing of Trackdir variables.
Definition track_type.h:97
@ TRACKDIR_BIT_LEFT_S
Track left, direction south.
Definition track_type.h:103
@ TRACKDIR_BIT_LOWER_E
Track lower, direction east.
Definition track_type.h:102
@ TRACKDIR_BIT_NONE
No track build.
Definition track_type.h:98
@ TRACKDIR_BIT_RIGHT_N
Track right, direction north.
Definition track_type.h:111
@ TRACKDIR_BIT_UPPER_W
Track upper, direction west.
Definition track_type.h:108
@ INVALID_TRACKDIR_BIT
Flag for an invalid trackdirbit value.
Definition track_type.h:113
Track
These are used to specify a single track.
Definition track_type.h:19
@ INVALID_TRACK
Flag for an invalid track.
Definition track_type.h:28
@ TRANSPORT_WATER
Transport over water.
Functions related to vehicles.
@ Sea
Sea.
Definition water_map.h:40
bool IsDockingTile(Tile t)
Checks whether the tile is marked as a dockling tile.
Definition water_map.h:373
@ Middle
Middle part of a lock.
Definition water_map.h:66
bool IsLock(Tile t)
Is there a lock on a given water tile?
Definition water_map.h:305
LockPart GetLockPart(Tile t)
Get the part of a lock.
Definition water_map.h:328
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.
Handles dividing the water in the map into regions to assist pathfinding.
Base includes/functions for YAPF.
int OctileDistanceCost(TileIndex start_tile, Trackdir start_td, TileIndex destination_tile)
Calculates the octile distance cost between a starting tile / trackdir and a destination tile.
Node tailored for ship pathfinding.
bool YapfShipCheckReverse(const Ship *v, Trackdir *trackdir)
Returns true if it is better to reverse the ship before leaving depot using YAPF.
Track YapfShipChooseTrack(const Ship *v, TileIndex tile, bool &path_found, ShipPathCache &path_cache)
Ship controller helper - path finder invoker.
std::vector< WaterRegionPatchDesc > YapfShipFindWaterRegionPath(const Ship *v, TileIndex start_tile, int max_returned_path_length)
Finds a path at the water region level.
Implementation of YAPF for water regions, which are used for finding intermediate ship destinations.