# npf.cpp

Go to the documentation of this file.

    00001 /* $Id: npf.cpp 18535 2009-12-19 15:30:24Z rubidium $ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * 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.
    00006  * 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.
    00007  * 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/>.
    00008  */
    00009
    00012 #include "../../stdafx.h"
    00013 #include "../../debug.h"
    00014 #include "../../landscape.h"
    00015 #include "../../depot_base.h"
    00016 #include "../../network/network.h"
    00017 #include "../../tunnelbridge_map.h"
    00018 #include "../../functions.h"
    00019 #include "../../tunnelbridge.h"
    00020 #include "../../pbs.h"
    00021 #include "../../roadveh.h"
    00022 #include "../../ship.h"
    00023 #include "../../train.h"
    00024 #include "../../roadstop_base.h"
    00025 #include "../pathfinder_func.h"
    00026 #include "../pathfinder_type.h"
    00027 #include "../follow_track.hpp"
    00028 #include "aystar.h"
    00029
    00030 enum {
    00031   NPF_HASH_BITS = 12,
    00032   /* Do no change below values */
    00033   NPF_HASH_SIZE = 1 << NPF_HASH_BITS,
    00034   NPF_HASH_HALFBITS = NPF_HASH_BITS / 2,
    00035   NPF_HASH_HALFMASK = (1 << NPF_HASH_HALFBITS) - 1
    00036 };
    00037
    00038 /* Meant to be stored in AyStar.targetdata */
    00039 struct NPFFindStationOrTileData {
    00040   TileIndex dest_coords;
    00041   StationID station_index;
    00042   bool reserve_path;
    00043   StationType station_type;
    00044   bool not_articulated;
    00045   const Vehicle *v;
    00046 };
    00047
    00048 /* Indices into AyStar.userdata[] */
    00049 enum {
    00050   NPF_TYPE = 0,
    00051   NPF_SUB_TYPE,
    00052   NPF_OWNER,
    00053   NPF_RAILTYPES,
    00054 };
    00055
    00056 /* Indices into AyStarNode.userdata[] */
    00057 enum {
    00058   NPF_TRACKDIR_CHOICE = 0,
    00059   NPF_NODE_FLAGS,
    00060 };
    00061
    00062 /* Flags for AyStarNode.userdata[NPF_NODE_FLAGS]. Use NPFSetFlag() and NPFGetFlag() to use them. */
    00063 enum NPFNodeFlag {
    00064   NPF_FLAG_SEEN_SIGNAL,
    00065   NPF_FLAG_2ND_SIGNAL,
    00066   NPF_FLAG_3RD_SIGNAL,
    00067   NPF_FLAG_REVERSE,
    00068   NPF_FLAG_LAST_SIGNAL_RED,
    00069   NPF_FLAG_LAST_SIGNAL_BLOCK,
    00070   NPF_FLAG_IGNORE_START_TILE,
    00071   NPF_FLAG_TARGET_RESERVED,
    00072   NPF_FLAG_IGNORE_RESERVED,
    00073 };
    00074
    00075 /* Meant to be stored in AyStar.userpath */
    00076 struct NPFFoundTargetData {
    00077   uint best_bird_dist;
    00078   uint best_path_dist;
    00079   Trackdir best_trackdir;
    00080   AyStarNode node;
    00081   bool res_okay;
    00082 };
    00083
    00084 static AyStar _npf_aystar;
    00085
    00086 /* The cost of each trackdir. A diagonal piece is the full NPF_TILE_LENGTH,
    00087  * the shorter piece is sqrt(2)/2*NPF_TILE_LENGTH =~ 0.7071
    00088  */
    00089 #define NPF_STRAIGHT_LENGTH (uint)(NPF_TILE_LENGTH * STRAIGHT_TRACK_LENGTH)
    00090 static const uint _trackdir_length[TRACKDIR_END] = {
    00091   NPF_TILE_LENGTH, NPF_TILE_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH,
    00092   0, 0,
    00093   NPF_TILE_LENGTH, NPF_TILE_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH
    00094 };
    00095
    00099 static inline bool NPFGetFlag(const AyStarNode *node, NPFNodeFlag flag)
    00100 {
    00101   return HasBit(node->user_data[NPF_NODE_FLAGS], flag);
    00102 }
    00103
    00107 static inline void NPFSetFlag(AyStarNode *node, NPFNodeFlag flag, bool value)
    00108 {
    00109   SB(node->user_data[NPF_NODE_FLAGS], flag, 1, value);
    00110 }
    00111
    00118 static uint NPFDistanceTrack(TileIndex t0, TileIndex t1)
    00119 {
    00120   const uint dx = Delta(TileX(t0), TileX(t1));
    00121   const uint dy = Delta(TileY(t0), TileY(t1));
    00122
    00123   const uint straightTracks = 2 * min(dx, dy); // The number of straight (not full length) tracks
    00124   /* OPTIMISATION:
    00125    * Original: diagTracks = max(dx, dy) - min(dx,dy);
    00126    * Proof:
    00127    * (dx+dy) - straightTracks  == (min + max) - straightTracks = min + max - 2 * min = max - min */
    00128   const uint diagTracks = dx + dy - straightTracks; // The number of diagonal (full tile length) tracks.
    00129
    00130   /* Don't factor out NPF_TILE_LENGTH below, this will round values and lose
    00131    * precision */
    00132   return diagTracks * NPF_TILE_LENGTH + straightTracks * NPF_TILE_LENGTH * STRAIGHT_TRACK_LENGTH;
    00133 }
    00134
    00135
    00136 #if 0
    00137 static uint NTPHash(uint key1, uint key2)
    00138 {
    00139   /* This function uses the old hash, which is fixed on 10 bits (1024 buckets) */
    00140   return PATHFIND_HASH_TILE(key1);
    00141 }
    00142 #endif
    00143
    00151 static uint NPFHash(uint key1, uint key2)
    00152 {
    00153   /* TODO: think of a better hash? */
    00154   uint part1 = TileX(key1) & NPF_HASH_HALFMASK;
    00155   uint part2 = TileY(key1) & NPF_HASH_HALFMASK;
    00156
    00157   assert(IsValidTrackdir((Trackdir)key2));
    00158   assert(IsValidTile(key1));
    00159   return ((part1 << NPF_HASH_HALFBITS | part2) + (NPF_HASH_SIZE * key2 / TRACKDIR_END)) % NPF_HASH_SIZE;
    00160 }
    00161
    00162 static int32 NPFCalcZero(AyStar *as, AyStarNode *current, OpenListNode *parent)
    00163 {
    00164   return 0;
    00165 }
    00166
    00167 /* Calcs the heuristic to the target station or tile. For train stations, it
    00168  * takes into account the direction of approach.
    00169  */
    00170 static int32 NPFCalcStationOrTileHeuristic(AyStar *as, AyStarNode *current, OpenListNode *parent)
    00171 {
    00172   NPFFindStationOrTileData *fstd = (NPFFindStationOrTileData*)as->user_target;
    00173   NPFFoundTargetData *ftd = (NPFFoundTargetData*)as->user_path;
    00174   TileIndex from = current->tile;
    00175   TileIndex to = fstd->dest_coords;
    00176   uint dist;
    00177
    00178   /* for train-stations, we are going to aim for the closest station tile */
    00179   if (as->user_data[NPF_TYPE] != TRANSPORT_WATER && fstd->station_index != INVALID_STATION)
    00180     to = CalcClosestStationTile(fstd->station_index, from, fstd->station_type);
    00181
    00182   if (as->user_data[NPF_TYPE] == TRANSPORT_ROAD) {
    00183     /* Since roads only have diagonal pieces, we use manhattan distance here */
    00184     dist = DistanceManhattan(from, to) * NPF_TILE_LENGTH;
    00185   } else {
    00186     /* Ships and trains can also go diagonal, so the minimum distance is shorter */
    00187     dist = NPFDistanceTrack(from, to);
    00188   }
    00189
    00190   DEBUG(npf, 4, "Calculating H for: (%d, %d). Result: %d", TileX(current->tile), TileY(current->tile), dist);
    00191
    00192   if (dist < ftd->best_bird_dist) {
    00193     ftd->best_bird_dist = dist;
    00194     ftd->best_trackdir = (Trackdir)current->user_data[NPF_TRACKDIR_CHOICE];
    00195   }
    00196   return dist;
    00197 }
    00198
    00199
    00200 /* Fills AyStarNode.user_data[NPF_TRACKDIRCHOICE] with the chosen direction to
    00201  * get here, either getting it from the current choice or from the parent's
    00202  * choice */
    00203 static void NPFFillTrackdirChoice(AyStarNode *current, OpenListNode *parent)
    00204 {
    00205   if (parent->path.parent == NULL) {
    00206     Trackdir trackdir = current->direction;
    00207     /* This is a first order decision, so we'd better save the
    00208      * direction we chose */
    00209     current->user_data[NPF_TRACKDIR_CHOICE] = trackdir;
    00210     DEBUG(npf, 6, "Saving trackdir: 0x%X", trackdir);
    00211   } else {
    00212     /* We've already made the decision, so just save our parent's decision */
    00213     current->user_data[NPF_TRACKDIR_CHOICE] = parent->path.node.user_data[NPF_TRACKDIR_CHOICE];
    00214   }
    00215 }
    00216
    00217 /* Will return the cost of the tunnel. If it is an entry, it will return the
    00218  * cost of that tile. If the tile is an exit, it will return the tunnel length
    00219  * including the exit tile. Requires that this is a Tunnel tile */
    00220 static uint NPFTunnelCost(AyStarNode *current)
    00221 {
    00222   DiagDirection exitdir = TrackdirToExitdir(current->direction);
    00223   TileIndex tile = current->tile;
    00224   if (GetTunnelBridgeDirection(tile) == ReverseDiagDir(exitdir)) {
    00225     /* We just popped out if this tunnel, since were
    00226      * facing the tunnel exit */
    00227     return NPF_TILE_LENGTH * (GetTunnelBridgeLength(current->tile, GetOtherTunnelEnd(current->tile)) + 1);
    00228     /* @todo: Penalty for tunnels? */
    00229   } else {
    00230     /* We are entering the tunnel, the enter tile is just a
    00231      * straight track */
    00232     return NPF_TILE_LENGTH;
    00233   }
    00234 }
    00235
    00236 static inline uint NPFBridgeCost(AyStarNode *current)
    00237 {
    00238   return NPF_TILE_LENGTH * GetTunnelBridgeLength(current->tile, GetOtherBridgeEnd(current->tile));
    00239 }
    00240
    00241 static uint NPFSlopeCost(AyStarNode *current)
    00242 {
    00243   TileIndex next = current->tile + TileOffsByDiagDir(TrackdirToExitdir(current->direction));
    00244
    00245   /* Get center of tiles */
    00246   int x1 = TileX(current->tile) * TILE_SIZE + TILE_SIZE / 2;
    00247   int y1 = TileY(current->tile) * TILE_SIZE + TILE_SIZE / 2;
    00248   int x2 = TileX(next) * TILE_SIZE + TILE_SIZE / 2;
    00249   int y2 = TileY(next) * TILE_SIZE + TILE_SIZE / 2;
    00250
    00251   int dx4 = (x2 - x1) / 4;
    00252   int dy4 = (y2 - y1) / 4;
    00253
    00254   /* Get the height on both sides of the tile edge.
    00255    * Avoid testing the height on the tile-center. This will fail for halftile-foundations.
    00256    */
    00257   int z1 = GetSlopeZ(x1 + dx4, y1 + dy4);
    00258   int z2 = GetSlopeZ(x2 - dx4, y2 - dy4);
    00259
    00260   if (z2 - z1 > 1) {
    00261     /* Slope up */
    00262     return _settings_game.pf.npf.npf_rail_slope_penalty;
    00263   }
    00264   return 0;
    00265   /* Should we give a bonus for slope down? Probably not, we
    00266    * could just substract that bonus from the penalty, because
    00267    * there is only one level of steepness... */
    00268 }
    00269
    00270 static uint NPFReservedTrackCost(AyStarNode *current)
    00271 {
    00272   TileIndex tile = current->tile;
    00273   TrackBits track = TrackToTrackBits(TrackdirToTrack(current->direction));
    00274   TrackBits res = GetReservedTrackbits(tile);
    00275
    00276   if (NPFGetFlag(current, NPF_FLAG_3RD_SIGNAL) || NPFGetFlag(current, NPF_FLAG_LAST_SIGNAL_BLOCK) || ((res & track) == TRACK_BIT_NONE && !TracksOverlap(res | track))) return 0;
    00277
    00278   if (IsTileType(tile, MP_TUNNELBRIDGE)) {
    00279     DiagDirection exitdir = TrackdirToExitdir(current->direction);
    00280     if (GetTunnelBridgeDirection(tile) == ReverseDiagDir(exitdir)) {
    00281       return  _settings_game.pf.npf.npf_rail_pbs_cross_penalty * (GetTunnelBridgeLength(tile, GetOtherTunnelBridgeEnd(tile)) + 1);
    00282     }
    00283   }
    00284   return  _settings_game.pf.npf.npf_rail_pbs_cross_penalty;
    00285 }
    00286
    00291 static void NPFMarkTile(TileIndex tile)
    00292 {
    00293 #ifndef NO_DEBUG_MESSAGES
    00294   if (_debug_npf_level < 1 || _networking) return;
    00295   switch (GetTileType(tile)) {
    00296     case MP_RAILWAY:
    00297       /* DEBUG: mark visited tiles by mowing the grass under them ;-) */
    00298       if (!IsRailDepot(tile)) {
    00299         SetRailGroundType(tile, RAIL_GROUND_BARREN);
    00300         MarkTileDirtyByTile(tile);
    00301       }
    00302       break;
    00303
    00304     case MP_ROAD:
    00305       if (!IsRoadDepot(tile)) {
    00306         SetRoadside(tile, ROADSIDE_BARREN);
    00307         MarkTileDirtyByTile(tile);
    00308       }
    00309       break;
    00310
    00311     default:
    00312       break;
    00313   }
    00314 #endif
    00315 }
    00316
    00317 static int32 NPFWaterPathCost(AyStar *as, AyStarNode *current, OpenListNode *parent)
    00318 {
    00319   /* TileIndex tile = current->tile; */
    00320   int32 cost = 0;
    00321   Trackdir trackdir = current->direction;
    00322
    00323   cost = _trackdir_length[trackdir]; // Should be different for diagonal tracks
    00324
    00325   if (IsBuoyTile(current->tile) && IsDiagonalTrackdir(trackdir))
    00326     cost += _settings_game.pf.npf.npf_buoy_penalty; // A small penalty for going over buoys
    00327
    00328   if (current->direction != NextTrackdir((Trackdir)parent->path.node.direction))
    00329     cost += _settings_game.pf.npf.npf_water_curve_penalty;
    00330
    00331   /* @todo More penalties? */
    00332
    00333   return cost;
    00334 }
    00335
    00336 /* Determine the cost of this node, for road tracks */
    00337 static int32 NPFRoadPathCost(AyStar *as, AyStarNode *current, OpenListNode *parent)
    00338 {
    00339   TileIndex tile = current->tile;
    00340   int32 cost = 0;
    00341
    00342   /* Determine base length */
    00343   switch (GetTileType(tile)) {
    00344     case MP_TUNNELBRIDGE:
    00345       cost = IsTunnel(tile) ? NPFTunnelCost(current) : NPFBridgeCost(current);
    00346       break;
    00347
    00348     case MP_ROAD:
    00349       cost = NPF_TILE_LENGTH;
    00350       /* Increase the cost for level crossings */
    00351       if (IsLevelCrossing(tile)) cost += _settings_game.pf.npf.npf_crossing_penalty;
    00352       break;
    00353
    00354     case MP_STATION: {
    00355       cost = NPF_TILE_LENGTH;
    00356       const RoadStop *rs = RoadStop::GetByTile(tile, GetRoadStopType(tile));
    00357       if (IsDriveThroughStopTile(tile)) {
    00358         /* Increase the cost for drive-through road stops */
    00359         cost += _settings_game.pf.npf.npf_road_drive_through_penalty;
    00360         DiagDirection dir = TrackdirToExitdir(current->direction);
    00361         if (!RoadStop::IsDriveThroughRoadStopContinuation(tile, tile - TileOffsByDiagDir(dir))) {
    00362           /* When we're the first road stop in a 'queue' of them we increase
    00363            * cost based on the fill percentage of the whole queue. */
    00364           const RoadStop::Entry *entry = rs->GetEntry(dir);
    00365           cost += entry->GetOccupied() * _settings_game.pf.npf.npf_road_dt_occupied_penalty / entry->GetLength();
    00366         }
    00367       } else {
    00368         /* Increase cost for filled road stops */
    00369         cost += _settings_game.pf.npf.npf_road_bay_occupied_penalty * (!rs->IsFreeBay(0) + !rs->IsFreeBay(1)) / 2;
    00370       }
    00371     } break;
    00372
    00373     default:
    00374       break;
    00375   }
    00376
    00377   /* Determine extra costs */
    00378
    00379   /* Check for slope */
    00380   cost += NPFSlopeCost(current);
    00381
    00382   /* Check for turns. Road vehicles only really drive diagonal, turns are
    00383    * represented by non-diagonal tracks */
    00384   if (!IsDiagonalTrackdir(current->direction))
    00385     cost += _settings_game.pf.npf.npf_road_curve_penalty;
    00386
    00387   NPFMarkTile(tile);
    00388   DEBUG(npf, 4, "Calculating G for: (%d, %d). Result: %d", TileX(current->tile), TileY(current->tile), cost);
    00389   return cost;
    00390 }
    00391
    00392
    00393 /* Determine the cost of this node, for railway tracks */
    00394 static int32 NPFRailPathCost(AyStar *as, AyStarNode *current, OpenListNode *parent)
    00395 {
    00396   TileIndex tile = current->tile;
    00397   Trackdir trackdir = current->direction;
    00398   int32 cost = 0;
    00399   /* HACK: We create a OpenListNode manually, so we can call EndNodeCheck */
    00400   OpenListNode new_node;
    00401
    00402   /* Determine base length */
    00403   switch (GetTileType(tile)) {
    00404     case MP_TUNNELBRIDGE:
    00405       cost = IsTunnel(tile) ? NPFTunnelCost(current) : NPFBridgeCost(current);
    00406       break;
    00407
    00408     case MP_RAILWAY:
    00409       cost = _trackdir_length[trackdir]; // Should be different for diagonal tracks
    00410       break;
    00411
    00412     case MP_ROAD: // Railway crossing
    00413       cost = NPF_TILE_LENGTH;
    00414       break;
    00415
    00416     case MP_STATION:
    00417       /* We give a station tile a penalty. Logically we would only want to give
    00418        * station tiles that are not our destination this penalty. This would
    00419        * discourage trains to drive through busy stations. But, we can just
    00420        * give any station tile a penalty, because every possible route will get
    00421        * this penalty exactly once, on its end tile (if it's a station) and it
    00422        * will therefore not make a difference. */
    00423       cost = NPF_TILE_LENGTH + _settings_game.pf.npf.npf_rail_station_penalty;
    00424
    00425       if (IsRailWaypoint(tile)) {
    00426         NPFFindStationOrTileData *fstd = (NPFFindStationOrTileData*)as->user_target;
    00427         if (fstd->v->current_order.IsType(OT_GOTO_WAYPOINT) && GetStationIndex(tile) == fstd->v->current_order.GetDestination()) {
    00428           /* This waypoint is our destination; maybe this isn't an unreserved
    00429            * one, so check that and if so see that as the last signal being
    00430            * red. This way waypoints near stations should work better. */
    00431           const Train *train = Train::From(fstd->v);
    00432           CFollowTrackRail ft(train);
    00433           TileIndex t = tile;
    00434           Trackdir td = trackdir;
    00435           while (ft.Follow(t, td)) {
    00436             assert(t != ft.m_new_tile);
    00437             t = ft.m_new_tile;
    00438             if (KillFirstBit(ft.m_new_td_bits) != TRACKDIR_BIT_NONE) {
    00439               /* We encountered a junction; it's going to be too complex to
    00440                * handle this perfectly, so just bail out. There is no simple
    00441                * free path, so try the other possibilities. */
    00442               td = INVALID_TRACKDIR;
    00443               break;
    00444             }
    00445             td = RemoveFirstTrackdir(&ft.m_new_td_bits);
    00446             /* If this is a safe waiting position we're done searching for it */
    00447             if (IsSafeWaitingPosition(train, t, td, true, _settings_game.pf.forbid_90_deg)) break;
    00448           }
    00449           if (td == INVALID_TRACKDIR ||
    00450               !IsSafeWaitingPosition(train, t, td, true, _settings_game.pf.forbid_90_deg) ||
    00451               !IsWaitingPositionFree(train, t, td, _settings_game.pf.forbid_90_deg)) {
    00452             cost += _settings_game.pf.npf.npf_rail_lastred_penalty;
    00453           }
    00454         }
    00455       }
    00456       break;
    00457
    00458     default:
    00459       break;
    00460   }
    00461
    00462   /* Determine extra costs */
    00463
    00464   /* Check for signals */
    00465   if (IsTileType(tile, MP_RAILWAY)) {
    00466     if (HasSignalOnTrackdir(tile, trackdir)) {
    00467       SignalType sigtype = GetSignalType(tile, TrackdirToTrack(trackdir));
    00468       /* Ordinary track with signals */
    00469       if (GetSignalStateByTrackdir(tile, trackdir) == SIGNAL_STATE_RED) {
    00470         /* Signal facing us is red */
    00471         if (!NPFGetFlag(current, NPF_FLAG_SEEN_SIGNAL)) {
    00472           /* Penalize the first signal we
    00473            * encounter, if it is red */
    00474
    00475           /* Is this a presignal exit or combo? */
    00476           if (!IsPbsSignal(sigtype)) {
    00477             if (sigtype == SIGTYPE_EXIT || sigtype == SIGTYPE_COMBO) {
    00478               /* Penalise exit and combo signals differently (heavier) */
    00479               cost += _settings_game.pf.npf.npf_rail_firstred_exit_penalty;
    00480             } else {
    00481               cost += _settings_game.pf.npf.npf_rail_firstred_penalty;
    00482             }
    00483           }
    00484         }
    00485         /* Record the state of this signal */
    00486         NPFSetFlag(current, NPF_FLAG_LAST_SIGNAL_RED, true);
    00487       } else {
    00488         /* Record the state of this signal */
    00489         NPFSetFlag(current, NPF_FLAG_LAST_SIGNAL_RED, false);
    00490       }
    00491       if (NPFGetFlag(current, NPF_FLAG_SEEN_SIGNAL)) {
    00492         if (NPFGetFlag(current, NPF_FLAG_2ND_SIGNAL)) {
    00493           NPFSetFlag(current, NPF_FLAG_3RD_SIGNAL, true);
    00494         } else {
    00495           NPFSetFlag(current, NPF_FLAG_2ND_SIGNAL, true);
    00496         }
    00497       } else {
    00498         NPFSetFlag(current, NPF_FLAG_SEEN_SIGNAL, true);
    00499       }
    00500       NPFSetFlag(current, NPF_FLAG_LAST_SIGNAL_BLOCK, !IsPbsSignal(sigtype));
    00501     }
    00502
    00503     if (HasPbsSignalOnTrackdir(tile, ReverseTrackdir(trackdir)) && !NPFGetFlag(current, NPF_FLAG_3RD_SIGNAL)) {
    00504       cost += _settings_game.pf.npf.npf_rail_pbs_signal_back_penalty;
    00505     }
    00506   }
    00507
    00508   /* Penalise the tile if it is a target tile and the last signal was
    00509    * red */
    00510   /* HACK: We create a new_node here so we can call EndNodeCheck. Ugly as hell
    00511    * of course... */
    00512   new_node.path.node = *current;
    00513   if (as->EndNodeCheck(as, &new_node) == AYSTAR_FOUND_END_NODE && NPFGetFlag(current, NPF_FLAG_LAST_SIGNAL_RED))
    00514     cost += _settings_game.pf.npf.npf_rail_lastred_penalty;
    00515
    00516   /* Check for slope */
    00517   cost += NPFSlopeCost(current);
    00518
    00519   /* Check for turns */
    00520   if (current->direction != NextTrackdir((Trackdir)parent->path.node.direction))
    00521     cost += _settings_game.pf.npf.npf_rail_curve_penalty;
    00522   /* TODO, with realistic acceleration, also the amount of straight track between
    00523    *      curves should be taken into account, as this affects the speed limit. */
    00524
    00525   /* Check for reverse in depot */
    00526   if (IsRailDepotTile(tile) && as->EndNodeCheck(as, &new_node) != AYSTAR_FOUND_END_NODE) {
    00527     /* Penalise any depot tile that is not the last tile in the path. This
    00528      * _should_ penalise every occurence of reversing in a depot (and only
    00529      * that) */
    00530     cost += _settings_game.pf.npf.npf_rail_depot_reverse_penalty;
    00531   }
    00532
    00533   /* Check for occupied track */
    00534   cost += NPFReservedTrackCost(current);
    00535
    00536   NPFMarkTile(tile);
    00537   DEBUG(npf, 4, "Calculating G for: (%d, %d). Result: %d", TileX(current->tile), TileY(current->tile), cost);
    00538   return cost;
    00539 }
    00540
    00541 /* Will find any depot */
    00542 static int32 NPFFindDepot(AyStar *as, OpenListNode *current)
    00543 {
    00544   /* It's not worth caching the result with NPF_FLAG_IS_TARGET here as below,
    00545    * since checking the cache not that much faster than the actual check */
    00546   return IsDepotTypeTile(current->path.node.tile, (TransportType)as->user_data[NPF_TYPE]) ?
    00547     AYSTAR_FOUND_END_NODE : AYSTAR_DONE;
    00548 }
    00549
    00551 static int32 NPFFindSafeTile(AyStar *as, OpenListNode *current)
    00552 {
    00553   const Train *v = Train::From(((NPFFindStationOrTileData *)as->user_target)->v);
    00554
    00555   return
    00556     IsSafeWaitingPosition(v, current->path.node.tile, current->path.node.direction, true, _settings_game.pf.forbid_90_deg) &&
    00557     IsWaitingPositionFree(v, current->path.node.tile, current->path.node.direction, _settings_game.pf.forbid_90_deg) ?
    00558       AYSTAR_FOUND_END_NODE : AYSTAR_DONE;
    00559 }
    00560
    00561 /* Will find a station identified using the NPFFindStationOrTileData */
    00562 static int32 NPFFindStationOrTile(AyStar *as, OpenListNode *current)
    00563 {
    00564   NPFFindStationOrTileData *fstd = (NPFFindStationOrTileData*)as->user_target;
    00565   AyStarNode *node = &current->path.node;
    00566   TileIndex tile = node->tile;
    00567
    00568   if (fstd->station_index == INVALID_STATION && tile == fstd->dest_coords) return AYSTAR_FOUND_END_NODE;
    00569
    00570   if (IsTileType(tile, MP_STATION) && GetStationIndex(tile) == fstd->station_index) {
    00571     if (fstd->v->type == VEH_TRAIN) return AYSTAR_FOUND_END_NODE;
    00572
    00573     assert(fstd->v->type == VEH_ROAD);
    00574     /* Only if it is a valid station *and* we can stop there */
    00575     if (GetStationType(tile) == fstd->station_type && (fstd->not_articulated || IsDriveThroughStopTile(tile))) return AYSTAR_FOUND_END_NODE;
    00576   }
    00577   return AYSTAR_DONE;
    00578 }
    00579
    00587 static const PathNode *FindSafePosition(PathNode *path, const Train *v)
    00588 {
    00589   /* If there is no signal, reserve the whole path. */
    00590   PathNode *sig = path;
    00591
    00592   for (; path->parent != NULL; path = path->parent) {
    00593     if (IsSafeWaitingPosition(v, path->node.tile, path->node.direction, true, _settings_game.pf.forbid_90_deg)) {
    00594       sig = path;
    00595     }
    00596   }
    00597
    00598   return sig;
    00599 }
    00600
    00604 static void ClearPathReservation(const PathNode *start, const PathNode *end)
    00605 {
    00606   bool first_run = true;
    00607   for (; start != end; start = start->parent) {
    00608     if (IsRailStationTile(start->node.tile) && first_run) {
    00609       SetRailStationPlatformReservation(start->node.tile, TrackdirToExitdir(start->node.direction), false);
    00610     } else {
    00611       UnreserveRailTrack(start->node.tile, TrackdirToTrack(start->node.direction));
    00612     }
    00613     first_run = false;
    00614   }
    00615 }
    00616
    00623 static void NPFSaveTargetData(AyStar *as, OpenListNode *current)
    00624 {
    00625   NPFFoundTargetData *ftd = (NPFFoundTargetData*)as->user_path;
    00626   ftd->best_trackdir = (Trackdir)current->path.node.user_data[NPF_TRACKDIR_CHOICE];
    00627   ftd->best_path_dist = current->g;
    00628   ftd->best_bird_dist = 0;
    00629   ftd->node = current->path.node;
    00630   ftd->res_okay = false;
    00631
    00632   if (as->user_target != NULL && ((NPFFindStationOrTileData*)as->user_target)->reserve_path && as->user_data[NPF_TYPE] == TRANSPORT_RAIL) {
    00633     /* Path reservation is requested. */
    00634     const Train *v = Train::From(((NPFFindStationOrTileData *)as->user_target)->v);
    00635
    00636     const PathNode *target = FindSafePosition(&current->path, v);
    00637     ftd->node = target->node;
    00638
    00639     /* If the target is a station skip to platform end. */
    00640     if (IsRailStationTile(target->node.tile)) {
    00641       DiagDirection dir = TrackdirToExitdir(target->node.direction);
    00642       uint len = Station::GetByTile(target->node.tile)->GetPlatformLength(target->node.tile, dir);
    00643       TileIndex end_tile = TILE_ADD(target->node.tile, (len - 1) * TileOffsByDiagDir(dir));
    00644
    00645       /* Update only end tile, trackdir of a station stays the same. */
    00646       ftd->node.tile = end_tile;
    00647       if (!IsWaitingPositionFree(v, end_tile, target->node.direction, _settings_game.pf.forbid_90_deg)) return;
    00648       SetRailStationPlatformReservation(target->node.tile, dir, true);
    00649       SetRailStationReservation(target->node.tile, false);
    00650     } else {
    00651       if (!IsWaitingPositionFree(v, target->node.tile, target->node.direction, _settings_game.pf.forbid_90_deg)) return;
    00652     }
    00653
    00654     for (const PathNode *cur = target; cur->parent != NULL; cur = cur->parent) {
    00655       if (!TryReserveRailTrack(cur->node.tile, TrackdirToTrack(cur->node.direction))) {
    00656         /* Reservation failed, undo. */
    00657         ClearPathReservation(target, cur);
    00658         return;
    00659       }
    00660     }
    00661
    00662     ftd->res_okay = true;
    00663   }
    00664 }
    00665
    00675 static bool CanEnterTileOwnerCheck(Owner owner, TileIndex tile, DiagDirection enterdir)
    00676 {
    00677   if (IsTileType(tile, MP_RAILWAY) || // Rail tile (also rail depot)
    00678       HasStationTileRail(tile) ||     // Rail station tile/waypoint
    00679       IsRoadDepotTile(tile) ||        // Road depot tile
    00680       IsStandardRoadStopTile(tile)) { // Road station tile (but not drive-through stops)
    00681     return IsTileOwner(tile, owner);  // You need to own these tiles entirely to use them
    00682   }
    00683
    00684   switch (GetTileType(tile)) {
    00685     case MP_ROAD:
    00686       /* rail-road crossing : are we looking at the railway part? */
    00687       if (IsLevelCrossing(tile) &&
    00688           DiagDirToAxis(enterdir) != GetCrossingRoadAxis(tile)) {
    00689         return IsTileOwner(tile, owner); // Railway needs owner check, while the street is public
    00690       }
    00691       break;
    00692
    00693     case MP_TUNNELBRIDGE:
    00694       if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) {
    00695         return IsTileOwner(tile, owner);
    00696       }
    00697       break;
    00698
    00699     default:
    00700       break;
    00701   }
    00702
    00703   return true; // no need to check
    00704 }
    00705
    00706
    00710 static DiagDirection GetDepotDirection(TileIndex tile, TransportType type)
    00711 {
    00712   assert(IsDepotTypeTile(tile, type));
    00713
    00714   switch (type) {
    00715     case TRANSPORT_RAIL:  return GetRailDepotDirection(tile);
    00716     case TRANSPORT_ROAD:  return GetRoadDepotDirection(tile);
    00717     case TRANSPORT_WATER: return GetShipDepotDirection(tile);
    00718     default: return INVALID_DIAGDIR; // Not reached
    00719   }
    00720 }
    00721
    00723 static DiagDirection GetSingleTramBit(TileIndex tile)
    00724 {
    00725   if (IsNormalRoadTile(tile)) {
    00726     RoadBits rb = GetRoadBits(tile, ROADTYPE_TRAM);
    00727     switch (rb) {
    00728       case ROAD_NW: return DIAGDIR_NW;
    00729       case ROAD_SW: return DIAGDIR_SW;
    00730       case ROAD_SE: return DIAGDIR_SE;
    00731       case ROAD_NE: return DIAGDIR_NE;
    00732       default: break;
    00733     }
    00734   }
    00735   return INVALID_DIAGDIR;
    00736 }
    00737
    00748 static DiagDirection GetTileSingleEntry(TileIndex tile, TransportType type, uint subtype)
    00749 {
    00750   if (type != TRANSPORT_WATER && IsDepotTypeTile(tile, type)) return GetDepotDirection(tile, type);
    00751
    00752   if (type == TRANSPORT_ROAD) {
    00753     if (IsStandardRoadStopTile(tile)) return GetRoadStopDir(tile);
    00754     if (HasBit(subtype, ROADTYPE_TRAM)) return GetSingleTramBit(tile);
    00755   }
    00756
    00757   return INVALID_DIAGDIR;
    00758 }
    00759
    00769 static inline bool ForceReverse(TileIndex tile, DiagDirection dir, TransportType type, uint subtype)
    00770 {
    00771   DiagDirection single_entry = GetTileSingleEntry(tile, type, subtype);
    00772   return single_entry != INVALID_DIAGDIR && single_entry != dir;
    00773 }
    00774
    00786 static bool CanEnterTile(TileIndex tile, DiagDirection dir, TransportType type, uint subtype, RailTypes railtypes, Owner owner)
    00787 {
    00788   /* Check tunnel entries and bridge ramps */
    00789   if (IsTileType(tile, MP_TUNNELBRIDGE) && GetTunnelBridgeDirection(tile) != dir) return false;
    00790
    00791   /* Test ownership */
    00792   if (!CanEnterTileOwnerCheck(owner, tile, dir)) return false;
    00793
    00794   /* check correct rail type (mono, maglev, etc) */
    00795   if (type == TRANSPORT_RAIL) {
    00796     RailType rail_type = GetTileRailType(tile);
    00797     if (!HasBit(railtypes, rail_type)) return false;
    00798   }
    00799
    00800   /* Depots, standard roadstops and single tram bits can only be entered from one direction */
    00801   DiagDirection single_entry = GetTileSingleEntry(tile, type, subtype);
    00802   if (single_entry != INVALID_DIAGDIR && single_entry != ReverseDiagDir(dir)) return false;
    00803
    00804   return true;
    00805 }
    00806
    00818 static TrackdirBits GetDriveableTrackdirBits(TileIndex dst_tile, Trackdir src_trackdir, TransportType type, uint subtype)
    00819 {
    00820   TrackdirBits trackdirbits = TrackStatusToTrackdirBits(GetTileTrackStatus(dst_tile, type, subtype));
    00821
    00822   if (trackdirbits == 0 && type == TRANSPORT_ROAD && HasBit(subtype, ROADTYPE_TRAM)) {
    00823     /* GetTileTrackStatus() returns 0 for single tram bits.
    00824      * As we cannot change it there (easily) without breaking something, change it here */
    00825     switch (GetSingleTramBit(dst_tile)) {
    00826       case DIAGDIR_NE:
    00827       case DIAGDIR_SW:
    00828         trackdirbits = TRACKDIR_BIT_X_NE | TRACKDIR_BIT_X_SW;
    00829         break;
    00830
    00831       case DIAGDIR_NW:
    00832       case DIAGDIR_SE:
    00833         trackdirbits = TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_Y_SE;
    00834         break;
    00835
    00836       default: break;
    00837     }
    00838   }
    00839
    00840   DEBUG(npf, 4, "Next node: (%d, %d) [%d], possible trackdirs: 0x%X", TileX(dst_tile), TileY(dst_tile), dst_tile, trackdirbits);
    00841
    00842   /* Select only trackdirs we can reach from our current trackdir */
    00843   trackdirbits &= TrackdirReachesTrackdirs(src_trackdir);
    00844
    00845   /* Filter out trackdirs that would make 90 deg turns for trains */
    00846   if (_settings_game.pf.forbid_90_deg && (type == TRANSPORT_RAIL || type == TRANSPORT_WATER)) trackdirbits &= ~TrackdirCrossesTrackdirs(src_trackdir);
    00847
    00848   DEBUG(npf, 6, "After filtering: (%d, %d), possible trackdirs: 0x%X", TileX(dst_tile), TileY(dst_tile), trackdirbits);
    00849
    00850   return trackdirbits;
    00851 }
    00852
    00853
    00854 /* Will just follow the results of GetTileTrackStatus concerning where we can
    00855  * go and where not. Uses AyStar.user_data[NPF_TYPE] as the transport type and
    00856  * an argument to GetTileTrackStatus. Will skip tunnels, meaning that the
    00857  * entry and exit are neighbours. Will fill
    00858  * AyStarNode.user_data[NPF_TRACKDIR_CHOICE] with an appropriate value, and
    00859  * copy AyStarNode.user_data[NPF_NODE_FLAGS] from the parent */
    00860 static void NPFFollowTrack(AyStar *aystar, OpenListNode *current)
    00861 {
    00862   /* We leave src_tile on track src_trackdir in direction src_exitdir */
    00863   Trackdir src_trackdir = current->path.node.direction;
    00864   TileIndex src_tile = current->path.node.tile;
    00865   DiagDirection src_exitdir = TrackdirToExitdir(src_trackdir);
    00866
    00867   /* Is src_tile valid, and can be used?
    00868    * When choosing track on a junction src_tile is the tile neighboured to the junction wrt. exitdir.
    00869    * But we must not check the validity of this move, as src_tile is totally unrelated to the move, if a roadvehicle reversed on a junction. */
    00870   bool ignore_src_tile = (current->path.parent == NULL && NPFGetFlag(&current->path.node, NPF_FLAG_IGNORE_START_TILE));
    00871
    00872   /* Information about the vehicle: TransportType (road/rail/water) and SubType (compatible rail/road types) */
    00873   TransportType type = (TransportType)aystar->user_data[NPF_TYPE];
    00874   uint subtype = aystar->user_data[NPF_SUB_TYPE];
    00875
    00876   /* Initialize to 0, so we can jump out (return) somewhere an have no neighbours */
    00877   aystar->num_neighbours = 0;
    00878   DEBUG(npf, 4, "Expanding: (%d, %d, %d) [%d]", TileX(src_tile), TileY(src_tile), src_trackdir, src_tile);
    00879
    00880   /* We want to determine the tile we arrive, and which choices we have there */
    00881   TileIndex dst_tile;
    00882   TrackdirBits trackdirbits;
    00883
    00884   /* Find dest tile */
    00885   if (ignore_src_tile) {
    00886     /* Do not perform any checks that involve src_tile */
    00887     dst_tile = src_tile + TileOffsByDiagDir(src_exitdir);
    00888     trackdirbits = GetDriveableTrackdirBits(dst_tile, src_trackdir, type, subtype);
    00889   } else if (IsTileType(src_tile, MP_TUNNELBRIDGE) && GetTunnelBridgeDirection(src_tile) == src_exitdir) {
    00890     /* We drive through the wormhole and arrive on the other side */
    00891     dst_tile = GetOtherTunnelBridgeEnd(src_tile);
    00892     trackdirbits = TrackdirToTrackdirBits(src_trackdir);
    00893   } else if (ForceReverse(src_tile, src_exitdir, type, subtype)) {
    00894     /* We can only reverse on this tile */
    00895     dst_tile = src_tile;
    00896     src_trackdir = ReverseTrackdir(src_trackdir);
    00897     trackdirbits = TrackdirToTrackdirBits(src_trackdir);
    00898   } else {
    00899     /* We leave src_tile in src_exitdir and reach dst_tile */
    00900     dst_tile = AddTileIndexDiffCWrap(src_tile, TileIndexDiffCByDiagDir(src_exitdir));
    00901
    00902     if (dst_tile != INVALID_TILE && !CanEnterTile(dst_tile, src_exitdir, type, subtype, (RailTypes)aystar->user_data[NPF_RAILTYPES], (Owner)aystar->user_data[NPF_OWNER])) dst_tile = INVALID_TILE;
    00903
    00904     if (dst_tile == INVALID_TILE) {
    00905       /* We cannot enter the next tile. Road vehicles can reverse, others reach dead end */
    00906       if (type != TRANSPORT_ROAD || HasBit(subtype, ROADTYPE_TRAM)) return;
    00907
    00908       dst_tile = src_tile;
    00909       src_trackdir = ReverseTrackdir(src_trackdir);
    00910     }
    00911
    00912     trackdirbits = GetDriveableTrackdirBits(dst_tile, src_trackdir, type, subtype);
    00913
    00914     if (trackdirbits == 0) {
    00915       /* We cannot enter the next tile. Road vehicles can reverse, others reach dead end */
    00916       if (type != TRANSPORT_ROAD || HasBit(subtype, ROADTYPE_TRAM)) return;
    00917
    00918       dst_tile = src_tile;
    00919       src_trackdir = ReverseTrackdir(src_trackdir);
    00920
    00921       trackdirbits = GetDriveableTrackdirBits(dst_tile, src_trackdir, type, subtype);
    00922     }
    00923   }
    00924
    00925   if (NPFGetFlag(&current->path.node, NPF_FLAG_IGNORE_RESERVED)) {
    00926     /* Mask out any reserved tracks. */
    00927     TrackBits reserved = GetReservedTrackbits(dst_tile);
    00928     trackdirbits &= ~TrackBitsToTrackdirBits(reserved);
    00929
    00930     uint bits = TrackdirBitsToTrackBits(trackdirbits);
    00931     int i;
    00932     FOR_EACH_SET_BIT(i, bits) {
    00933       if (TracksOverlap(reserved | TrackToTrackBits((Track)i))) trackdirbits &= ~TrackToTrackdirBits((Track)i);
    00934     }
    00935   }
    00936
    00937   /* Enumerate possible track */
    00938   uint i = 0;
    00939   while (trackdirbits != 0) {
    00940     Trackdir dst_trackdir = RemoveFirstTrackdir(&trackdirbits);
    00941     DEBUG(npf, 5, "Expanded into trackdir: %d, remaining trackdirs: 0x%X", dst_trackdir, trackdirbits);
    00942
    00943     /* Tile with signals? */
    00944     if (IsTileType(dst_tile, MP_RAILWAY) && GetRailTileType(dst_tile) == RAIL_TILE_SIGNALS) {
    00945       if (HasSignalOnTrackdir(dst_tile, ReverseTrackdir(dst_trackdir)) && !HasSignalOnTrackdir(dst_tile, dst_trackdir) && IsOnewaySignal(dst_tile, TrackdirToTrack(dst_trackdir)))
    00946         /* If there's a one-way signal not pointing towards us, stop going in this direction. */
    00947         break;
    00948     }
    00949     {
    00950       /* We've found ourselves a neighbour :-) */
    00951       AyStarNode *neighbour = &aystar->neighbours[i];
    00952       neighbour->tile = dst_tile;
    00953       neighbour->direction = dst_trackdir;
    00954       /* Save user data */
    00955       neighbour->user_data[NPF_NODE_FLAGS] = current->path.node.user_data[NPF_NODE_FLAGS];
    00956       NPFFillTrackdirChoice(neighbour, current);
    00957     }
    00958     i++;
    00959   }
    00960   aystar->num_neighbours = i;
    00961 }
    00962
    00963 /*
    00964  * Plan a route to the specified target (which is checked by target_proc),
    00965  * from start1 and if not NULL, from start2 as well. The type of transport we
    00966  * are checking is in type. reverse_penalty is applied to all routes that
    00967  * originate from the second start node.
    00968  * When we are looking for one specific target (optionally multiple tiles), we
    00969  * should use a good heuristic to perform aystar search. When we search for
    00970  * multiple targets that are spread around, we should perform a breadth first
    00971  * search by specifiying CalcZero as our heuristic.
    00972  */
    00973 static NPFFoundTargetData NPFRouteInternal(AyStarNode *start1, bool ignore_start_tile1, AyStarNode *start2, bool ignore_start_tile2, NPFFindStationOrTileData *target, AyStar_EndNodeCheck target_proc, AyStar_CalculateH heuristic_proc, TransportType type, uint sub_type, Owner owner, RailTypes railtypes, uint reverse_penalty)
    00974 {
    00975   int r;
    00976   NPFFoundTargetData result;
    00977
    00978   /* Initialize procs */
    00979   _npf_aystar.CalculateH = heuristic_proc;
    00980   _npf_aystar.EndNodeCheck = target_proc;
    00981   _npf_aystar.FoundEndNode = NPFSaveTargetData;
    00982   _npf_aystar.GetNeighbours = NPFFollowTrack;
    00983   switch (type) {
    00984     default: NOT_REACHED();
    00985     case TRANSPORT_RAIL:  _npf_aystar.CalculateG = NPFRailPathCost;  break;
    00986     case TRANSPORT_ROAD:  _npf_aystar.CalculateG = NPFRoadPathCost;  break;
    00987     case TRANSPORT_WATER: _npf_aystar.CalculateG = NPFWaterPathCost; break;
    00988   }
    00989
    00990   /* Initialize Start Node(s) */
    00991   start1->user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR;
    00992   start1->user_data[NPF_NODE_FLAGS] = 0;
    00993   NPFSetFlag(start1, NPF_FLAG_IGNORE_START_TILE, ignore_start_tile1);
    00994   _npf_aystar.addstart(&_npf_aystar, start1, 0);
    00995   if (start2) {
    00996     start2->user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR;
    00997     start2->user_data[NPF_NODE_FLAGS] = 0;
    00998     NPFSetFlag(start2, NPF_FLAG_IGNORE_START_TILE, ignore_start_tile2);
    00999     NPFSetFlag(start2, NPF_FLAG_REVERSE, true);
    01000     _npf_aystar.addstart(&_npf_aystar, start2, reverse_penalty);
    01001   }
    01002
    01003   /* Initialize result */
    01004   result.best_bird_dist = UINT_MAX;
    01005   result.best_path_dist = UINT_MAX;
    01006   result.best_trackdir  = INVALID_TRACKDIR;
    01007   result.node.tile      = INVALID_TILE;
    01008   result.res_okay       = false;
    01009   _npf_aystar.user_path = &result;
    01010
    01011   /* Initialize target */
    01012   _npf_aystar.user_target = target;
    01013
    01014   /* Initialize user_data */
    01015   _npf_aystar.user_data[NPF_TYPE] = type;
    01016   _npf_aystar.user_data[NPF_SUB_TYPE] = sub_type;
    01017   _npf_aystar.user_data[NPF_OWNER] = owner;
    01018   _npf_aystar.user_data[NPF_RAILTYPES] = railtypes;
    01019
    01020   /* GO! */
    01021   r = AyStarMain_Main(&_npf_aystar);
    01022   assert(r != AYSTAR_STILL_BUSY);
    01023
    01024   if (result.best_bird_dist != 0) {
    01025     if (target != NULL) {
    01026       DEBUG(npf, 1, "Could not find route to tile 0x%X from 0x%X.", target->dest_coords, start1->tile);
    01027     } else {
    01028       /* Assumption: target == NULL, so we are looking for a depot */
    01029       DEBUG(npf, 1, "Could not find route to a depot from tile 0x%X.", start1->tile);
    01030     }
    01031
    01032   }
    01033   return result;
    01034 }
    01035
    01036 /* Will search as below, but with two start nodes, the second being the
    01037  * reverse. Look at the NPF_FLAG_REVERSE flag in the result node to see which
    01038  * direction was taken (NPFGetFlag(result.node, NPF_FLAG_REVERSE)) */
    01039 static NPFFoundTargetData NPFRouteToStationOrTileTwoWay(TileIndex tile1, Trackdir trackdir1, bool ignore_start_tile1, TileIndex tile2, Trackdir trackdir2, bool ignore_start_tile2, NPFFindStationOrTileData *target, TransportType type, uint sub_type, Owner owner, RailTypes railtypes)
    01040 {
    01041   AyStarNode start1;
    01042   AyStarNode start2;
    01043
    01044   start1.tile = tile1;
    01045   start2.tile = tile2;
    01046   /* We set this in case the target is also the start tile, we will just
    01047    * return a not found then */
    01048   start1.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR;
    01049   start1.direction = trackdir1;
    01050   start2.direction = trackdir2;
    01051   start2.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR;
    01052
    01053   return NPFRouteInternal(&start1, ignore_start_tile1, (IsValidTile(tile2) ? &start2 : NULL), ignore_start_tile2, target, NPFFindStationOrTile, NPFCalcStationOrTileHeuristic, type, sub_type, owner, railtypes, 0);
    01054 }
    01055
    01056 /* Will search from the given tile and direction, for a route to the given
    01057  * station for the given transport type. See the declaration of
    01058  * NPFFoundTargetData above for the meaning of the result. */
    01059 static NPFFoundTargetData NPFRouteToStationOrTile(TileIndex tile, Trackdir trackdir, bool ignore_start_tile, NPFFindStationOrTileData *target, TransportType type, uint sub_type, Owner owner, RailTypes railtypes)
    01060 {
    01061   return NPFRouteToStationOrTileTwoWay(tile, trackdir, ignore_start_tile, INVALID_TILE, INVALID_TRACKDIR, false, target, type, sub_type, owner, railtypes);
    01062 }
    01063
    01064 /* Search using breadth first. Good for little track choice and inaccurate
    01065  * heuristic, such as railway/road with two start nodes, the second being the reverse. Call
    01066  * NPFGetFlag(result.node, NPF_FLAG_REVERSE) to see from which node the path
    01067  * orginated. All pathfs from the second node will have the given
    01068  * reverse_penalty applied (NPF_TILE_LENGTH is the equivalent of one full
    01069  * tile).
    01070  */
    01071 static NPFFoundTargetData NPFRouteToDepotBreadthFirstTwoWay(TileIndex tile1, Trackdir trackdir1, bool ignore_start_tile1, TileIndex tile2, Trackdir trackdir2, bool ignore_start_tile2, TransportType type, uint sub_type, Owner owner, RailTypes railtypes, uint reverse_penalty)
    01072 {
    01073   AyStarNode start1;
    01074   AyStarNode start2;
    01075
    01076   start1.tile = tile1;
    01077   start2.tile = tile2;
    01078   /* We set this in case the target is also the start tile, we will just
    01079    * return a not found then */
    01080   start1.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR;
    01081   start1.direction = trackdir1;
    01082   start2.direction = trackdir2;
    01083   start2.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR;
    01084
    01085   /* perform a breadth first search. Target is NULL,
    01086    * since we are just looking for any depot...*/
    01087   return NPFRouteInternal(&start1, ignore_start_tile1, (IsValidTile(tile2) ? &start2 : NULL), ignore_start_tile2, NULL, NPFFindDepot, NPFCalcZero, type, sub_type, owner, railtypes, reverse_penalty);
    01088 }
    01089
    01090 void InitializeNPF()
    01091 {
    01092   static bool first_init = true;
    01093   if (first_init) {
    01094     first_init = false;
    01095     init_AyStar(&_npf_aystar, NPFHash, NPF_HASH_SIZE);
    01096   } else {
    01097     AyStarMain_Clear(&_npf_aystar);
    01098   }
    01099   _npf_aystar.loops_per_tick = 0;
    01100   _npf_aystar.max_path_cost = 0;
    01101   //_npf_aystar.max_search_nodes = 0;
    01102   /* We will limit the number of nodes for now, until we have a better
    01103    * solution to really fix performance */
    01104   _npf_aystar.max_search_nodes = _settings_game.pf.npf.npf_max_search_nodes;
    01105 }
    01106
    01107 static void NPFFillWithOrderData(NPFFindStationOrTileData *fstd, const Vehicle *v, bool reserve_path = false)
    01108 {
    01109   /* Ships don't really reach their stations, but the tile in front. So don't
    01110    * save the station id for ships. For roadvehs we don't store it either,
    01111    * because multistop depends on vehicles actually reaching the exact
    01112    * dest_tile, not just any stop of that station.
    01113    * So only for train orders to stations we fill fstd->station_index, for all
    01114    * others only dest_coords */
    01115   if (v->type != VEH_SHIP && (v->current_order.IsType(OT_GOTO_STATION) || v->current_order.IsType(OT_GOTO_WAYPOINT))) {
    01116     assert(v->type == VEH_TRAIN || v->type == VEH_ROAD);
    01117     fstd->station_index = v->current_order.GetDestination();
    01118     fstd->station_type = (v->type == VEH_TRAIN) ? (v->current_order.IsType(OT_GOTO_STATION) ? STATION_RAIL : STATION_WAYPOINT) : (RoadVehicle::From(v)->IsBus() ? STATION_BUS : STATION_TRUCK);
    01119     fstd->not_articulated = v->type == VEH_ROAD && !RoadVehicle::From(v)->HasArticulatedPart();
    01120     /* Let's take the closest tile of the station as our target for vehicles */
    01121     fstd->dest_coords = CalcClosestStationTile(fstd->station_index, v->tile, fstd->station_type);
    01122   } else {
    01123     fstd->dest_coords = v->dest_tile;
    01124     fstd->station_index = INVALID_STATION;
    01125   }
    01126   fstd->reserve_path = reserve_path;
    01127   fstd->v = v;
    01128 }
    01129
    01130 /*** Road vehicles ***/
    01131
    01132 FindDepotData NPFRoadVehicleFindNearestDepot(const RoadVehicle *v, int max_penalty)
    01133 {
    01134   Trackdir trackdir = v->GetVehicleTrackdir();
    01135
    01136   NPFFoundTargetData ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, false, v->tile, ReverseTrackdir(trackdir), false, TRANSPORT_ROAD, v->compatible_roadtypes, v->owner, INVALID_RAILTYPES, 0);
    01137
    01138   if (ftd.best_bird_dist != 0) return FindDepotData();
    01139
    01140   /* Found target */
    01141   /* Our caller expects a number of tiles, so we just approximate that
    01142    * number by this. It might not be completely what we want, but it will
    01143    * work for now :-) We can possibly change this when the old pathfinder
    01144    * is removed. */
    01145   return FindDepotData(ftd.node.tile, ftd.best_path_dist);
    01146 }
    01147
    01148 Trackdir NPFRoadVehicleChooseTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, TrackdirBits trackdirs)
    01149 {
    01150   NPFFindStationOrTileData fstd;
    01151
    01152   NPFFillWithOrderData(&fstd, v);
    01153   Trackdir trackdir = DiagDirToDiagTrackdir(enterdir);
    01154
    01155   NPFFoundTargetData ftd = NPFRouteToStationOrTile(tile - TileOffsByDiagDir(enterdir), trackdir, true, &fstd, TRANSPORT_ROAD, v->compatible_roadtypes, v->owner, INVALID_RAILTYPES);
    01156   if (ftd.best_trackdir == INVALID_TRACKDIR) {
    01157     /* We are already at our target. Just do something
    01158      * @todo: maybe display error?
    01159      * @todo: go straight ahead if possible? */
    01160     return (Trackdir)FindFirstBit2x64(trackdirs);
    01161   }
    01162
    01163   /* If ftd.best_bird_dist is 0, we found our target and ftd.best_trackdir contains
    01164    * the direction we need to take to get there, if ftd.best_bird_dist is not 0,
    01165    * we did not find our target, but ftd.best_trackdir contains the direction leading
    01166    * to the tile closest to our target. */
    01167   return ftd.best_trackdir;
    01168 }
    01169
    01170 /*** Ships ***/
    01171
    01172 Track NPFShipChooseTrack(const Ship *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks)
    01173 {
    01174   NPFFindStationOrTileData fstd;
    01175   Trackdir trackdir = v->GetVehicleTrackdir();
    01176   assert(trackdir != INVALID_TRACKDIR); // Check that we are not in a depot
    01177
    01178   NPFFillWithOrderData(&fstd, v);
    01179
    01180   NPFFoundTargetData ftd = NPFRouteToStationOrTile(tile - TileOffsByDiagDir(enterdir), trackdir, true, &fstd, TRANSPORT_WATER, 0, v->owner, INVALID_RAILTYPES);
    01181
    01182   /* If ftd.best_bird_dist is 0, we found our target and ftd.best_trackdir contains
    01183    * the direction we need to take to get there, if ftd.best_bird_dist is not 0,
    01184    * we did not find our target, but ftd.best_trackdir contains the direction leading
    01185    * to the tile closest to our target. */
    01186   if (ftd.best_trackdir == 0xff) return INVALID_TRACK;
    01187   return TrackdirToTrack(ftd.best_trackdir);
    01188 }
    01189
    01190 /*** Trains ***/
    01191
    01192 FindDepotData NPFTrainFindNearestDepot(const Train *v, int max_penalty)
    01193 {
    01194   const Train *last = v->Last();
    01195   Trackdir trackdir = v->GetVehicleTrackdir();
    01196   Trackdir trackdir_rev = ReverseTrackdir(last->GetVehicleTrackdir());
    01197
    01198   assert(trackdir != INVALID_TRACKDIR);
    01199   NPFFoundTargetData ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, false, last->tile, trackdir_rev, false, TRANSPORT_RAIL, 0, v->owner, v->compatible_railtypes, NPF_INFINITE_PENALTY);
    01200   if (ftd.best_bird_dist != 0) return FindDepotData();
    01201
    01202   /* Found target */
    01203   /* Our caller expects a number of tiles, so we just approximate that
    01204    * number by this. It might not be completely what we want, but it will
    01205    * work for now :-) We can possibly change this when the old pathfinder
    01206    * is removed. */
    01207   return FindDepotData(ftd.node.tile, ftd.best_path_dist, NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE));
    01208 }
    01209
    01210 bool NPFTrainFindNearestSafeTile(const Train *v, TileIndex tile, Trackdir trackdir, bool override_railtype)
    01211 {
    01212   assert(v->type == VEH_TRAIN);
    01213
    01214   NPFFindStationOrTileData fstd;
    01215   fstd.v = v;
    01216   fstd.reserve_path = true;
    01217
    01218   AyStarNode start1;
    01219   start1.tile = tile;
    01220   /* We set this in case the target is also the start tile, we will just
    01221    * return a not found then */
    01222   start1.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR;
    01223   start1.direction = trackdir;
    01224   NPFSetFlag(&start1, NPF_FLAG_IGNORE_RESERVED, true);
    01225
    01226   RailTypes railtypes = v->compatible_railtypes;
    01227   if (override_railtype) railtypes |= GetRailTypeInfo(v->railtype)->compatible_railtypes;
    01228
    01229   /* perform a breadth first search. Target is NULL,
    01230    * since we are just looking for any safe tile...*/
    01231   return NPFRouteInternal(&start1, true, NULL, false, &fstd, NPFFindSafeTile, NPFCalcZero, TRANSPORT_RAIL, 0, v->owner, railtypes, 0).res_okay;
    01232 }
    01233
    01234 bool NPFTrainCheckReverse(const Train *v)
    01235 {
    01236   NPFFindStationOrTileData fstd;
    01237   NPFFoundTargetData ftd;
    01238   const Train *last = v->Last();
    01239
    01240   NPFFillWithOrderData(&fstd, v);
    01241
    01242   Trackdir trackdir = v->GetVehicleTrackdir();
    01243   Trackdir trackdir_rev = ReverseTrackdir(last->GetVehicleTrackdir());
    01244   assert(trackdir != INVALID_TRACKDIR);
    01245   assert(trackdir_rev != INVALID_TRACKDIR);
    01246
    01247   ftd = NPFRouteToStationOrTileTwoWay(v->tile, trackdir, false, last->tile, trackdir_rev, false, &fstd, TRANSPORT_RAIL, 0, v->owner, v->compatible_railtypes);
    01248   /* If we didn't find anything, just keep on going straight ahead, otherwise take the reverse flag */
    01249   return ftd.best_bird_dist != 0 && NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE);
    01250 }
    01251
    01252 Track NPFTrainChooseTrack(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool *path_not_found, bool reserve_track, struct PBSTileInfo *target)
    01253 {
    01254   NPFFindStationOrTileData fstd;
    01255   NPFFillWithOrderData(&fstd, v, reserve_track);
    01256
    01257   PBSTileInfo origin = FollowTrainReservation(v);
    01258   assert(IsValidTrackdir(origin.trackdir));
    01259
    01260   NPFFoundTargetData ftd = NPFRouteToStationOrTile(origin.tile, origin.trackdir, true, &fstd, TRANSPORT_RAIL, 0, v->owner, v->compatible_railtypes);
    01261
    01262   if (target != NULL) {
    01263     target->tile = ftd.node.tile;
    01264     target->trackdir = (Trackdir)ftd.node.direction;
    01265     target->okay = ftd.res_okay;
    01266   }
    01267
    01268   if (ftd.best_trackdir == INVALID_TRACKDIR) {
    01269     /* We are already at our target. Just do something
    01270      * @todo maybe display error?
    01271      * @todo: go straight ahead if possible? */
    01272     if (path_not_found) *path_not_found = false;
    01273     return FindFirstTrack(tracks);
    01274   }
    01275
    01276   /* If ftd.best_bird_dist is 0, we found our target and ftd.best_trackdir contains
    01277    * the direction we need to take to get there, if ftd.best_bird_dist is not 0,
    01278    * we did not find our target, but ftd.best_trackdir contains the direction leading
    01279    * to the tile closest to our target. */
    01280   if (path_not_found != NULL) *path_not_found = (ftd.best_bird_dist != 0);
    01281   /* Discard enterdir information, making it a normal track */
    01282   return TrackdirToTrack(ftd.best_trackdir);
    01283 }