npf.cpp

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