00001
00002
00003
00004
00005
00006
00007
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 "../../infrastructure_func.h"
00026 #include "../pathfinder_func.h"
00027 #include "../pathfinder_type.h"
00028 #include "../follow_track.hpp"
00029 #include "aystar.h"
00030
00031 enum {
00032 NPF_HASH_BITS = 12,
00033
00034 NPF_HASH_SIZE = 1 << NPF_HASH_BITS,
00035 NPF_HASH_HALFBITS = NPF_HASH_BITS / 2,
00036 NPF_HASH_HALFMASK = (1 << NPF_HASH_HALFBITS) - 1
00037 };
00038
00039
00040 struct NPFFindStationOrTileData {
00041 TileIndex dest_coords;
00042 StationID station_index;
00043 bool reserve_path;
00044 StationType station_type;
00045 bool not_articulated;
00046 const Vehicle *v;
00047 };
00048
00049
00050 enum {
00051 NPF_TYPE = 0,
00052 NPF_SUB_TYPE,
00053 NPF_OWNER,
00054 NPF_RAILTYPES,
00055 };
00056
00057
00058 enum {
00059 NPF_TRACKDIR_CHOICE = 0,
00060 NPF_NODE_FLAGS,
00061 };
00062
00063
00064 enum NPFNodeFlag {
00065 NPF_FLAG_SEEN_SIGNAL,
00066 NPF_FLAG_2ND_SIGNAL,
00067 NPF_FLAG_3RD_SIGNAL,
00068 NPF_FLAG_REVERSE,
00069 NPF_FLAG_LAST_SIGNAL_RED,
00070 NPF_FLAG_LAST_SIGNAL_BLOCK,
00071 NPF_FLAG_IGNORE_START_TILE,
00072 NPF_FLAG_TARGET_RESERVED,
00073 NPF_FLAG_IGNORE_RESERVED,
00074 };
00075
00076
00077 struct NPFFoundTargetData {
00078 uint best_bird_dist;
00079 uint best_path_dist;
00080 Trackdir best_trackdir;
00081 AyStarNode node;
00082 bool res_okay;
00083 };
00084
00085 static AyStar _npf_aystar;
00086
00087
00088
00089
00090 #define NPF_STRAIGHT_LENGTH (uint)(NPF_TILE_LENGTH * STRAIGHT_TRACK_LENGTH)
00091 static const uint _trackdir_length[TRACKDIR_END] = {
00092 NPF_TILE_LENGTH, NPF_TILE_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH,
00093 0, 0,
00094 NPF_TILE_LENGTH, NPF_TILE_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH
00095 };
00096
00100 static inline bool NPFGetFlag(const AyStarNode *node, NPFNodeFlag flag)
00101 {
00102 return HasBit(node->user_data[NPF_NODE_FLAGS], flag);
00103 }
00104
00108 static inline void NPFSetFlag(AyStarNode *node, NPFNodeFlag flag, bool value)
00109 {
00110 SB(node->user_data[NPF_NODE_FLAGS], flag, 1, value);
00111 }
00112
00119 static uint NPFDistanceTrack(TileIndex t0, TileIndex t1)
00120 {
00121 const uint dx = Delta(TileX(t0), TileX(t1));
00122 const uint dy = Delta(TileY(t0), TileY(t1));
00123
00124 const uint straightTracks = 2 * min(dx, dy);
00125
00126
00127
00128
00129 const uint diagTracks = dx + dy - straightTracks;
00130
00131
00132
00133 return diagTracks * NPF_TILE_LENGTH + straightTracks * NPF_TILE_LENGTH * STRAIGHT_TRACK_LENGTH;
00134 }
00135
00136
00137 #if 0
00138 static uint NTPHash(uint key1, uint key2)
00139 {
00140
00141 return PATHFIND_HASH_TILE(key1);
00142 }
00143 #endif
00144
00152 static uint NPFHash(uint key1, uint key2)
00153 {
00154
00155 uint part1 = TileX(key1) & NPF_HASH_HALFMASK;
00156 uint part2 = TileY(key1) & NPF_HASH_HALFMASK;
00157
00158 assert(IsValidTrackdir((Trackdir)key2));
00159 assert(IsValidTile(key1));
00160 return ((part1 << NPF_HASH_HALFBITS | part2) + (NPF_HASH_SIZE * key2 / TRACKDIR_END)) % NPF_HASH_SIZE;
00161 }
00162
00163 static int32 NPFCalcZero(AyStar *as, AyStarNode *current, OpenListNode *parent)
00164 {
00165 return 0;
00166 }
00167
00168
00169
00170
00171 static int32 NPFCalcStationOrTileHeuristic(AyStar *as, AyStarNode *current, OpenListNode *parent)
00172 {
00173 NPFFindStationOrTileData *fstd = (NPFFindStationOrTileData*)as->user_target;
00174 NPFFoundTargetData *ftd = (NPFFoundTargetData*)as->user_path;
00175 TileIndex from = current->tile;
00176 TileIndex to = fstd->dest_coords;
00177 uint dist;
00178
00179
00180 if (as->user_data[NPF_TYPE] != TRANSPORT_WATER && fstd->station_index != INVALID_STATION)
00181 to = CalcClosestStationTile(fstd->station_index, from, fstd->station_type);
00182
00183 if (as->user_data[NPF_TYPE] == TRANSPORT_ROAD) {
00184
00185 dist = DistanceManhattan(from, to) * NPF_TILE_LENGTH;
00186 } else {
00187
00188 dist = NPFDistanceTrack(from, to);
00189 }
00190
00191 DEBUG(npf, 4, "Calculating H for: (%d, %d). Result: %d", TileX(current->tile), TileY(current->tile), dist);
00192
00193 if (dist < ftd->best_bird_dist) {
00194 ftd->best_bird_dist = dist;
00195 ftd->best_trackdir = (Trackdir)current->user_data[NPF_TRACKDIR_CHOICE];
00196 }
00197 return dist;
00198 }
00199
00200
00201
00202
00203
00204 static void NPFFillTrackdirChoice(AyStarNode *current, OpenListNode *parent)
00205 {
00206 if (parent->path.parent == NULL) {
00207 Trackdir trackdir = current->direction;
00208
00209
00210 current->user_data[NPF_TRACKDIR_CHOICE] = trackdir;
00211 DEBUG(npf, 6, "Saving trackdir: 0x%X", trackdir);
00212 } else {
00213
00214 current->user_data[NPF_TRACKDIR_CHOICE] = parent->path.node.user_data[NPF_TRACKDIR_CHOICE];
00215 }
00216 }
00217
00218
00219
00220
00221 static uint NPFTunnelCost(AyStarNode *current)
00222 {
00223 DiagDirection exitdir = TrackdirToExitdir(current->direction);
00224 TileIndex tile = current->tile;
00225 if (GetTunnelBridgeDirection(tile) == ReverseDiagDir(exitdir)) {
00226
00227
00228 return NPF_TILE_LENGTH * (GetTunnelBridgeLength(current->tile, GetOtherTunnelEnd(current->tile)) + 1);
00229
00230 } else {
00231
00232
00233 return NPF_TILE_LENGTH;
00234 }
00235 }
00236
00237 static inline uint NPFBridgeCost(AyStarNode *current)
00238 {
00239 return NPF_TILE_LENGTH * GetTunnelBridgeLength(current->tile, GetOtherBridgeEnd(current->tile));
00240 }
00241
00242 static uint NPFSlopeCost(AyStarNode *current)
00243 {
00244 TileIndex next = current->tile + TileOffsByDiagDir(TrackdirToExitdir(current->direction));
00245
00246
00247 int x1 = TileX(current->tile) * TILE_SIZE + TILE_SIZE / 2;
00248 int y1 = TileY(current->tile) * TILE_SIZE + TILE_SIZE / 2;
00249 int x2 = TileX(next) * TILE_SIZE + TILE_SIZE / 2;
00250 int y2 = TileY(next) * TILE_SIZE + TILE_SIZE / 2;
00251
00252 int dx4 = (x2 - x1) / 4;
00253 int dy4 = (y2 - y1) / 4;
00254
00255
00256
00257
00258 int z1 = GetSlopeZ(x1 + dx4, y1 + dy4);
00259 int z2 = GetSlopeZ(x2 - dx4, y2 - dy4);
00260
00261 if (z2 - z1 > 1) {
00262
00263 return _settings_game.pf.npf.npf_rail_slope_penalty;
00264 }
00265 return 0;
00266
00267
00268
00269 }
00270
00271 static uint NPFReservedTrackCost(AyStarNode *current)
00272 {
00273 TileIndex tile = current->tile;
00274 TrackBits track = TrackToTrackBits(TrackdirToTrack(current->direction));
00275 TrackBits res = GetReservedTrackbits(tile);
00276
00277 if (NPFGetFlag(current, NPF_FLAG_3RD_SIGNAL) || NPFGetFlag(current, NPF_FLAG_LAST_SIGNAL_BLOCK) || ((res & track) == TRACK_BIT_NONE && !TracksOverlap(res | track))) return 0;
00278
00279 if (IsTileType(tile, MP_TUNNELBRIDGE)) {
00280 DiagDirection exitdir = TrackdirToExitdir(current->direction);
00281 if (GetTunnelBridgeDirection(tile) == ReverseDiagDir(exitdir)) {
00282 return _settings_game.pf.npf.npf_rail_pbs_cross_penalty * (GetTunnelBridgeLength(tile, GetOtherTunnelBridgeEnd(tile)) + 1);
00283 }
00284 }
00285 return _settings_game.pf.npf.npf_rail_pbs_cross_penalty;
00286 }
00287
00292 static void NPFMarkTile(TileIndex tile)
00293 {
00294 #ifndef NO_DEBUG_MESSAGES
00295 if (_debug_npf_level < 1 || _networking) return;
00296 switch (GetTileType(tile)) {
00297 case MP_RAILWAY:
00298
00299 if (!IsRailDepot(tile)) {
00300 SetRailGroundType(tile, RAIL_GROUND_BARREN);
00301 MarkTileDirtyByTile(tile);
00302 }
00303 break;
00304
00305 case MP_ROAD:
00306 if (!IsRoadDepot(tile)) {
00307 SetRoadside(tile, ROADSIDE_BARREN);
00308 MarkTileDirtyByTile(tile);
00309 }
00310 break;
00311
00312 default:
00313 break;
00314 }
00315 #endif
00316 }
00317
00318 static int32 NPFWaterPathCost(AyStar *as, AyStarNode *current, OpenListNode *parent)
00319 {
00320
00321 int32 cost = 0;
00322 Trackdir trackdir = current->direction;
00323
00324 cost = _trackdir_length[trackdir];
00325
00326 if (IsBuoyTile(current->tile) && IsDiagonalTrackdir(trackdir))
00327 cost += _settings_game.pf.npf.npf_buoy_penalty;
00328
00329 if (current->direction != NextTrackdir((Trackdir)parent->path.node.direction))
00330 cost += _settings_game.pf.npf.npf_water_curve_penalty;
00331
00332
00333
00334 return cost;
00335 }
00336
00337
00338 static int32 NPFRoadPathCost(AyStar *as, AyStarNode *current, OpenListNode *parent)
00339 {
00340 TileIndex tile = current->tile;
00341 int32 cost = 0;
00342
00343
00344 switch (GetTileType(tile)) {
00345 case MP_TUNNELBRIDGE:
00346 cost = IsTunnel(tile) ? NPFTunnelCost(current) : NPFBridgeCost(current);
00347 break;
00348
00349 case MP_ROAD:
00350 cost = NPF_TILE_LENGTH;
00351
00352 if (IsLevelCrossing(tile)) cost += _settings_game.pf.npf.npf_crossing_penalty;
00353 break;
00354
00355 case MP_STATION: {
00356 cost = NPF_TILE_LENGTH;
00357 const RoadStop *rs = RoadStop::GetByTile(tile, GetRoadStopType(tile));
00358 if (IsDriveThroughStopTile(tile)) {
00359
00360 cost += _settings_game.pf.npf.npf_road_drive_through_penalty;
00361 DiagDirection dir = TrackdirToExitdir(current->direction);
00362 if (!RoadStop::IsDriveThroughRoadStopContinuation(tile, tile - TileOffsByDiagDir(dir))) {
00363
00364
00365 const RoadStop::Entry *entry = rs->GetEntry(dir);
00366 cost += entry->GetOccupied() * _settings_game.pf.npf.npf_road_dt_occupied_penalty / entry->GetLength();
00367 }
00368 } else {
00369
00370 cost += _settings_game.pf.npf.npf_road_bay_occupied_penalty * (!rs->IsFreeBay(0) + !rs->IsFreeBay(1)) / 2;
00371 }
00372 } break;
00373
00374 default:
00375 break;
00376 }
00377
00378
00379
00380
00381 cost += NPFSlopeCost(current);
00382
00383
00384
00385 if (!IsDiagonalTrackdir(current->direction))
00386 cost += _settings_game.pf.npf.npf_road_curve_penalty;
00387
00388 NPFMarkTile(tile);
00389 DEBUG(npf, 4, "Calculating G for: (%d, %d). Result: %d", TileX(current->tile), TileY(current->tile), cost);
00390 return cost;
00391 }
00392
00393
00394
00395 static int32 NPFRailPathCost(AyStar *as, AyStarNode *current, OpenListNode *parent)
00396 {
00397 TileIndex tile = current->tile;
00398 Trackdir trackdir = current->direction;
00399 int32 cost = 0;
00400
00401 OpenListNode new_node;
00402
00403
00404 switch (GetTileType(tile)) {
00405 case MP_TUNNELBRIDGE:
00406 cost = IsTunnel(tile) ? NPFTunnelCost(current) : NPFBridgeCost(current);
00407 break;
00408
00409 case MP_RAILWAY:
00410 cost = _trackdir_length[trackdir];
00411 break;
00412
00413 case MP_ROAD:
00414 cost = NPF_TILE_LENGTH;
00415 break;
00416
00417 case MP_STATION:
00418
00419
00420
00421
00422
00423
00424 cost = NPF_TILE_LENGTH + _settings_game.pf.npf.npf_rail_station_penalty;
00425
00426 if (IsRailWaypoint(tile)) {
00427 NPFFindStationOrTileData *fstd = (NPFFindStationOrTileData*)as->user_target;
00428 if (fstd->v->current_order.IsType(OT_GOTO_WAYPOINT) && GetStationIndex(tile) == fstd->v->current_order.GetDestination()) {
00429
00430
00431
00432 const Train *train = Train::From(fstd->v);
00433 CFollowTrackRail ft(train);
00434 TileIndex t = tile;
00435 Trackdir td = trackdir;
00436 while (ft.Follow(t, td)) {
00437 assert(t != ft.m_new_tile);
00438 t = ft.m_new_tile;
00439 if (KillFirstBit(ft.m_new_td_bits) != TRACKDIR_BIT_NONE) {
00440
00441
00442
00443 td = INVALID_TRACKDIR;
00444 break;
00445 }
00446 td = RemoveFirstTrackdir(&ft.m_new_td_bits);
00447
00448 if (IsSafeWaitingPosition(train, t, td, true, _settings_game.pf.forbid_90_deg)) break;
00449 }
00450 if (td == INVALID_TRACKDIR ||
00451 !IsSafeWaitingPosition(train, t, td, true, _settings_game.pf.forbid_90_deg) ||
00452 !IsWaitingPositionFree(train, t, td, _settings_game.pf.forbid_90_deg)) {
00453 cost += _settings_game.pf.npf.npf_rail_lastred_penalty;
00454 }
00455 }
00456 }
00457 break;
00458
00459 default:
00460 break;
00461 }
00462
00463
00464
00465
00466 if (IsTileType(tile, MP_RAILWAY)) {
00467 if (HasSignalOnTrackdir(tile, trackdir)) {
00468 SignalType sigtype = GetSignalType(tile, TrackdirToTrack(trackdir));
00469
00470 if (GetSignalStateByTrackdir(tile, trackdir) == SIGNAL_STATE_RED) {
00471
00472 if (!NPFGetFlag(current, NPF_FLAG_SEEN_SIGNAL)) {
00473
00474
00475
00476
00477 if (!IsPbsSignal(sigtype)) {
00478 if (sigtype == SIGTYPE_EXIT || sigtype == SIGTYPE_COMBO) {
00479
00480 cost += _settings_game.pf.npf.npf_rail_firstred_exit_penalty;
00481 } else {
00482 cost += _settings_game.pf.npf.npf_rail_firstred_penalty;
00483 }
00484 }
00485 }
00486
00487 NPFSetFlag(current, NPF_FLAG_LAST_SIGNAL_RED, true);
00488 } else {
00489
00490 NPFSetFlag(current, NPF_FLAG_LAST_SIGNAL_RED, false);
00491 }
00492 if (NPFGetFlag(current, NPF_FLAG_SEEN_SIGNAL)) {
00493 if (NPFGetFlag(current, NPF_FLAG_2ND_SIGNAL)) {
00494 NPFSetFlag(current, NPF_FLAG_3RD_SIGNAL, true);
00495 } else {
00496 NPFSetFlag(current, NPF_FLAG_2ND_SIGNAL, true);
00497 }
00498 } else {
00499 NPFSetFlag(current, NPF_FLAG_SEEN_SIGNAL, true);
00500 }
00501 NPFSetFlag(current, NPF_FLAG_LAST_SIGNAL_BLOCK, !IsPbsSignal(sigtype));
00502 }
00503
00504 if (HasPbsSignalOnTrackdir(tile, ReverseTrackdir(trackdir)) && !NPFGetFlag(current, NPF_FLAG_3RD_SIGNAL)) {
00505 cost += _settings_game.pf.npf.npf_rail_pbs_signal_back_penalty;
00506 }
00507 }
00508
00509
00510
00511
00512
00513 new_node.path.node = *current;
00514 if (as->EndNodeCheck(as, &new_node) == AYSTAR_FOUND_END_NODE && NPFGetFlag(current, NPF_FLAG_LAST_SIGNAL_RED))
00515 cost += _settings_game.pf.npf.npf_rail_lastred_penalty;
00516
00517
00518 cost += NPFSlopeCost(current);
00519
00520
00521 if (current->direction != NextTrackdir((Trackdir)parent->path.node.direction))
00522 cost += _settings_game.pf.npf.npf_rail_curve_penalty;
00523
00524
00525
00526
00527 if (IsRailDepotTile(tile) && as->EndNodeCheck(as, &new_node) != AYSTAR_FOUND_END_NODE) {
00528
00529
00530
00531 cost += _settings_game.pf.npf.npf_rail_depot_reverse_penalty;
00532 }
00533
00534
00535 cost += NPFReservedTrackCost(current);
00536
00537 NPFMarkTile(tile);
00538 DEBUG(npf, 4, "Calculating G for: (%d, %d). Result: %d", TileX(current->tile), TileY(current->tile), cost);
00539 return cost;
00540 }
00541
00542
00543 static int32 NPFFindDepot(AyStar *as, OpenListNode *current)
00544 {
00545
00546
00547 return IsDepotTypeTile(current->path.node.tile, (TransportType)as->user_data[NPF_TYPE]) ?
00548 AYSTAR_FOUND_END_NODE : AYSTAR_DONE;
00549 }
00550
00552 static int32 NPFFindSafeTile(AyStar *as, OpenListNode *current)
00553 {
00554 const Train *v = Train::From(((NPFFindStationOrTileData *)as->user_target)->v);
00555
00556 return
00557 IsSafeWaitingPosition(v, current->path.node.tile, current->path.node.direction, true, _settings_game.pf.forbid_90_deg) &&
00558 IsWaitingPositionFree(v, current->path.node.tile, current->path.node.direction, _settings_game.pf.forbid_90_deg) ?
00559 AYSTAR_FOUND_END_NODE : AYSTAR_DONE;
00560 }
00561
00562
00563 static int32 NPFFindStationOrTile(AyStar *as, OpenListNode *current)
00564 {
00565 NPFFindStationOrTileData *fstd = (NPFFindStationOrTileData*)as->user_target;
00566 AyStarNode *node = ¤t->path.node;
00567 TileIndex tile = node->tile;
00568
00569 if (fstd->station_index == INVALID_STATION && tile == fstd->dest_coords) return AYSTAR_FOUND_END_NODE;
00570
00571 if (IsTileType(tile, MP_STATION) && GetStationIndex(tile) == fstd->station_index) {
00572 if (fstd->v->type == VEH_TRAIN) return AYSTAR_FOUND_END_NODE;
00573
00574 assert(fstd->v->type == VEH_ROAD);
00575
00576 if (GetStationType(tile) == fstd->station_type && (fstd->not_articulated || IsDriveThroughStopTile(tile))) return AYSTAR_FOUND_END_NODE;
00577 }
00578 return AYSTAR_DONE;
00579 }
00580
00588 static const PathNode *FindSafePosition(PathNode *path, const Train *v)
00589 {
00590
00591 PathNode *sig = path;
00592
00593 for (; path->parent != NULL; path = path->parent) {
00594 if (IsSafeWaitingPosition(v, path->node.tile, path->node.direction, true, _settings_game.pf.forbid_90_deg)) {
00595 sig = path;
00596 }
00597 }
00598
00599 return sig;
00600 }
00601
00605 static void ClearPathReservation(const PathNode *start, const PathNode *end)
00606 {
00607 bool first_run = true;
00608 for (; start != end; start = start->parent) {
00609 if (IsRailStationTile(start->node.tile) && first_run) {
00610 SetRailStationPlatformReservation(start->node.tile, TrackdirToExitdir(start->node.direction), false);
00611 } else {
00612 UnreserveRailTrack(start->node.tile, TrackdirToTrack(start->node.direction));
00613 }
00614 first_run = false;
00615 }
00616 }
00617
00624 static void NPFSaveTargetData(AyStar *as, OpenListNode *current)
00625 {
00626 NPFFoundTargetData *ftd = (NPFFoundTargetData*)as->user_path;
00627 ftd->best_trackdir = (Trackdir)current->path.node.user_data[NPF_TRACKDIR_CHOICE];
00628 ftd->best_path_dist = current->g;
00629 ftd->best_bird_dist = 0;
00630 ftd->node = current->path.node;
00631 ftd->res_okay = false;
00632
00633 if (as->user_target != NULL && ((NPFFindStationOrTileData*)as->user_target)->reserve_path && as->user_data[NPF_TYPE] == TRANSPORT_RAIL) {
00634
00635 const Train *v = Train::From(((NPFFindStationOrTileData *)as->user_target)->v);
00636
00637 const PathNode *target = FindSafePosition(¤t->path, v);
00638 ftd->node = target->node;
00639
00640
00641 if (IsRailStationTile(target->node.tile)) {
00642 DiagDirection dir = TrackdirToExitdir(target->node.direction);
00643 uint len = Station::GetByTile(target->node.tile)->GetPlatformLength(target->node.tile, dir);
00644 TileIndex end_tile = TILE_ADD(target->node.tile, (len - 1) * TileOffsByDiagDir(dir));
00645
00646
00647 ftd->node.tile = end_tile;
00648 if (!IsWaitingPositionFree(v, end_tile, target->node.direction, _settings_game.pf.forbid_90_deg)) return;
00649 SetRailStationPlatformReservation(target->node.tile, dir, true);
00650 SetRailStationReservation(target->node.tile, false);
00651 } else {
00652 if (!IsWaitingPositionFree(v, target->node.tile, target->node.direction, _settings_game.pf.forbid_90_deg)) return;
00653 }
00654
00655 for (const PathNode *cur = target; cur->parent != NULL; cur = cur->parent) {
00656 if (!TryReserveRailTrack(cur->node.tile, TrackdirToTrack(cur->node.direction))) {
00657
00658 ClearPathReservation(target, cur);
00659 return;
00660 }
00661 }
00662
00663 ftd->res_okay = true;
00664 }
00665 }
00666
00676 static bool CanEnterTileOwnerCheck(Owner owner, TileIndex tile, DiagDirection enterdir)
00677 {
00678 switch (GetTileType(tile)) {
00679 case MP_RAILWAY:
00680 return IsInfraTileUsageAllowed(tile, owner, VEH_TRAIN);
00681
00682 case MP_ROAD:
00683
00684 if (IsLevelCrossing(tile) &&
00685 DiagDirToAxis(enterdir) != GetCrossingRoadAxis(tile)) {
00686 return IsInfraTileUsageAllowed(tile, owner, VEH_TRAIN);
00687 } else if (IsRoadDepot(tile)) {
00688 return IsInfraTileUsageAllowed(tile, owner, VEH_ROAD);
00689 }
00690 break;
00691
00692 case MP_STATION:
00693 if (HasStationRail(tile)) {
00694 return IsInfraTileUsageAllowed(tile, owner, VEH_TRAIN);
00695 } else if (IsStandardRoadStopTile(tile)) {
00696 return IsInfraTileUsageAllowed(tile, owner, VEH_ROAD);
00697 }
00698 break;
00699
00700 case MP_TUNNELBRIDGE:
00701 if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) {
00702 return IsInfraTileUsageAllowed(tile, owner, VEH_TRAIN);
00703 }
00704 break;
00705
00706 default:
00707 break;
00708 }
00709
00710 return true;
00711 }
00712
00713
00717 static DiagDirection GetDepotDirection(TileIndex tile, TransportType type)
00718 {
00719 assert(IsDepotTypeTile(tile, type));
00720
00721 switch (type) {
00722 case TRANSPORT_RAIL: return GetRailDepotDirection(tile);
00723 case TRANSPORT_ROAD: return GetRoadDepotDirection(tile);
00724 case TRANSPORT_WATER: return GetShipDepotDirection(tile);
00725 default: return INVALID_DIAGDIR;
00726 }
00727 }
00728
00730 static DiagDirection GetSingleTramBit(TileIndex tile)
00731 {
00732 if (IsNormalRoadTile(tile)) {
00733 RoadBits rb = GetRoadBits(tile, ROADTYPE_TRAM);
00734 switch (rb) {
00735 case ROAD_NW: return DIAGDIR_NW;
00736 case ROAD_SW: return DIAGDIR_SW;
00737 case ROAD_SE: return DIAGDIR_SE;
00738 case ROAD_NE: return DIAGDIR_NE;
00739 default: break;
00740 }
00741 }
00742 return INVALID_DIAGDIR;
00743 }
00744
00755 static DiagDirection GetTileSingleEntry(TileIndex tile, TransportType type, uint subtype)
00756 {
00757 if (type != TRANSPORT_WATER && IsDepotTypeTile(tile, type)) return GetDepotDirection(tile, type);
00758
00759 if (type == TRANSPORT_ROAD) {
00760 if (IsStandardRoadStopTile(tile)) return GetRoadStopDir(tile);
00761 if (HasBit(subtype, ROADTYPE_TRAM)) return GetSingleTramBit(tile);
00762 }
00763
00764 return INVALID_DIAGDIR;
00765 }
00766
00776 static inline bool ForceReverse(TileIndex tile, DiagDirection dir, TransportType type, uint subtype)
00777 {
00778 DiagDirection single_entry = GetTileSingleEntry(tile, type, subtype);
00779 return single_entry != INVALID_DIAGDIR && single_entry != dir;
00780 }
00781
00793 static bool CanEnterTile(TileIndex tile, DiagDirection dir, TransportType type, uint subtype, RailTypes railtypes, Owner owner)
00794 {
00795
00796 if (IsTileType(tile, MP_TUNNELBRIDGE) && GetTunnelBridgeDirection(tile) != dir) return false;
00797
00798
00799 if (!CanEnterTileOwnerCheck(owner, tile, dir)) return false;
00800
00801
00802 if (type == TRANSPORT_RAIL) {
00803 RailType rail_type = GetTileRailType(tile);
00804 if (!HasBit(railtypes, rail_type)) return false;
00805 }
00806
00807
00808 DiagDirection single_entry = GetTileSingleEntry(tile, type, subtype);
00809 if (single_entry != INVALID_DIAGDIR && single_entry != ReverseDiagDir(dir)) return false;
00810
00811 return true;
00812 }
00813
00825 static TrackdirBits GetDriveableTrackdirBits(TileIndex dst_tile, Trackdir src_trackdir, TransportType type, uint subtype)
00826 {
00827 TrackdirBits trackdirbits = TrackStatusToTrackdirBits(GetTileTrackStatus(dst_tile, type, subtype));
00828
00829 if (trackdirbits == 0 && type == TRANSPORT_ROAD && HasBit(subtype, ROADTYPE_TRAM)) {
00830
00831
00832 switch (GetSingleTramBit(dst_tile)) {
00833 case DIAGDIR_NE:
00834 case DIAGDIR_SW:
00835 trackdirbits = TRACKDIR_BIT_X_NE | TRACKDIR_BIT_X_SW;
00836 break;
00837
00838 case DIAGDIR_NW:
00839 case DIAGDIR_SE:
00840 trackdirbits = TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_Y_SE;
00841 break;
00842
00843 default: break;
00844 }
00845 }
00846
00847 DEBUG(npf, 4, "Next node: (%d, %d) [%d], possible trackdirs: 0x%X", TileX(dst_tile), TileY(dst_tile), dst_tile, trackdirbits);
00848
00849
00850 trackdirbits &= TrackdirReachesTrackdirs(src_trackdir);
00851
00852
00853 if (_settings_game.pf.forbid_90_deg && (type == TRANSPORT_RAIL || type == TRANSPORT_WATER)) trackdirbits &= ~TrackdirCrossesTrackdirs(src_trackdir);
00854
00855 DEBUG(npf, 6, "After filtering: (%d, %d), possible trackdirs: 0x%X", TileX(dst_tile), TileY(dst_tile), trackdirbits);
00856
00857 return trackdirbits;
00858 }
00859
00860
00861
00862
00863
00864
00865
00866
00867 static void NPFFollowTrack(AyStar *aystar, OpenListNode *current)
00868 {
00869
00870 Trackdir src_trackdir = current->path.node.direction;
00871 TileIndex src_tile = current->path.node.tile;
00872 DiagDirection src_exitdir = TrackdirToExitdir(src_trackdir);
00873
00874
00875
00876
00877 bool ignore_src_tile = (current->path.parent == NULL && NPFGetFlag(¤t->path.node, NPF_FLAG_IGNORE_START_TILE));
00878
00879
00880 TransportType type = (TransportType)aystar->user_data[NPF_TYPE];
00881 uint subtype = aystar->user_data[NPF_SUB_TYPE];
00882
00883
00884 aystar->num_neighbours = 0;
00885 DEBUG(npf, 4, "Expanding: (%d, %d, %d) [%d]", TileX(src_tile), TileY(src_tile), src_trackdir, src_tile);
00886
00887
00888 TileIndex dst_tile;
00889 TrackdirBits trackdirbits;
00890
00891
00892 if (ignore_src_tile) {
00893
00894 dst_tile = src_tile + TileOffsByDiagDir(src_exitdir);
00895 trackdirbits = GetDriveableTrackdirBits(dst_tile, src_trackdir, type, subtype);
00896 } else if (IsTileType(src_tile, MP_TUNNELBRIDGE) && GetTunnelBridgeDirection(src_tile) == src_exitdir) {
00897
00898 dst_tile = GetOtherTunnelBridgeEnd(src_tile);
00899 trackdirbits = TrackdirToTrackdirBits(src_trackdir);
00900 } else if (ForceReverse(src_tile, src_exitdir, type, subtype)) {
00901
00902 dst_tile = src_tile;
00903 src_trackdir = ReverseTrackdir(src_trackdir);
00904 trackdirbits = TrackdirToTrackdirBits(src_trackdir);
00905 } else {
00906
00907 dst_tile = AddTileIndexDiffCWrap(src_tile, TileIndexDiffCByDiagDir(src_exitdir));
00908
00909 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;
00910
00911 if (dst_tile == INVALID_TILE) {
00912
00913 if (type != TRANSPORT_ROAD || HasBit(subtype, ROADTYPE_TRAM)) return;
00914
00915 dst_tile = src_tile;
00916 src_trackdir = ReverseTrackdir(src_trackdir);
00917 }
00918
00919 trackdirbits = GetDriveableTrackdirBits(dst_tile, src_trackdir, type, subtype);
00920
00921 if (trackdirbits == 0) {
00922
00923 if (type != TRANSPORT_ROAD || HasBit(subtype, ROADTYPE_TRAM)) return;
00924
00925 dst_tile = src_tile;
00926 src_trackdir = ReverseTrackdir(src_trackdir);
00927
00928 trackdirbits = GetDriveableTrackdirBits(dst_tile, src_trackdir, type, subtype);
00929 }
00930 }
00931
00932 if (NPFGetFlag(¤t->path.node, NPF_FLAG_IGNORE_RESERVED)) {
00933
00934 TrackBits reserved = GetReservedTrackbits(dst_tile);
00935 trackdirbits &= ~TrackBitsToTrackdirBits(reserved);
00936
00937 uint bits = TrackdirBitsToTrackBits(trackdirbits);
00938 int i;
00939 FOR_EACH_SET_BIT(i, bits) {
00940 if (TracksOverlap(reserved | TrackToTrackBits((Track)i))) trackdirbits &= ~TrackToTrackdirBits((Track)i);
00941 }
00942 }
00943
00944
00945 uint i = 0;
00946 while (trackdirbits != 0) {
00947 Trackdir dst_trackdir = RemoveFirstTrackdir(&trackdirbits);
00948 DEBUG(npf, 5, "Expanded into trackdir: %d, remaining trackdirs: 0x%X", dst_trackdir, trackdirbits);
00949
00950
00951 if (IsTileType(dst_tile, MP_RAILWAY) && GetRailTileType(dst_tile) == RAIL_TILE_SIGNALS) {
00952 if (HasSignalOnTrackdir(dst_tile, ReverseTrackdir(dst_trackdir)) && !HasSignalOnTrackdir(dst_tile, dst_trackdir) && IsOnewaySignal(dst_tile, TrackdirToTrack(dst_trackdir)))
00953
00954 break;
00955 }
00956 {
00957
00958 AyStarNode *neighbour = &aystar->neighbours[i];
00959 neighbour->tile = dst_tile;
00960 neighbour->direction = dst_trackdir;
00961
00962 neighbour->user_data[NPF_NODE_FLAGS] = current->path.node.user_data[NPF_NODE_FLAGS];
00963 NPFFillTrackdirChoice(neighbour, current);
00964 }
00965 i++;
00966 }
00967 aystar->num_neighbours = i;
00968 }
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980 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)
00981 {
00982 int r;
00983 NPFFoundTargetData result;
00984
00985
00986 _npf_aystar.CalculateH = heuristic_proc;
00987 _npf_aystar.EndNodeCheck = target_proc;
00988 _npf_aystar.FoundEndNode = NPFSaveTargetData;
00989 _npf_aystar.GetNeighbours = NPFFollowTrack;
00990 switch (type) {
00991 default: NOT_REACHED();
00992 case TRANSPORT_RAIL: _npf_aystar.CalculateG = NPFRailPathCost; break;
00993 case TRANSPORT_ROAD: _npf_aystar.CalculateG = NPFRoadPathCost; break;
00994 case TRANSPORT_WATER: _npf_aystar.CalculateG = NPFWaterPathCost; break;
00995 }
00996
00997
00998 start1->user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR;
00999 start1->user_data[NPF_NODE_FLAGS] = 0;
01000 NPFSetFlag(start1, NPF_FLAG_IGNORE_START_TILE, ignore_start_tile1);
01001 _npf_aystar.addstart(&_npf_aystar, start1, 0);
01002 if (start2) {
01003 start2->user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR;
01004 start2->user_data[NPF_NODE_FLAGS] = 0;
01005 NPFSetFlag(start2, NPF_FLAG_IGNORE_START_TILE, ignore_start_tile2);
01006 NPFSetFlag(start2, NPF_FLAG_REVERSE, true);
01007 _npf_aystar.addstart(&_npf_aystar, start2, reverse_penalty);
01008 }
01009
01010
01011 result.best_bird_dist = UINT_MAX;
01012 result.best_path_dist = UINT_MAX;
01013 result.best_trackdir = INVALID_TRACKDIR;
01014 result.node.tile = INVALID_TILE;
01015 result.res_okay = false;
01016 _npf_aystar.user_path = &result;
01017
01018
01019 _npf_aystar.user_target = target;
01020
01021
01022 _npf_aystar.user_data[NPF_TYPE] = type;
01023 _npf_aystar.user_data[NPF_SUB_TYPE] = sub_type;
01024 _npf_aystar.user_data[NPF_OWNER] = owner;
01025 _npf_aystar.user_data[NPF_RAILTYPES] = railtypes;
01026
01027
01028 r = AyStarMain_Main(&_npf_aystar);
01029 assert(r != AYSTAR_STILL_BUSY);
01030
01031 if (result.best_bird_dist != 0) {
01032 if (target != NULL) {
01033 DEBUG(npf, 1, "Could not find route to tile 0x%X from 0x%X.", target->dest_coords, start1->tile);
01034 } else {
01035
01036 DEBUG(npf, 1, "Could not find route to a depot from tile 0x%X.", start1->tile);
01037 }
01038
01039 }
01040 return result;
01041 }
01042
01043
01044
01045
01046 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)
01047 {
01048 AyStarNode start1;
01049 AyStarNode start2;
01050
01051 start1.tile = tile1;
01052 start2.tile = tile2;
01053
01054
01055 start1.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR;
01056 start1.direction = trackdir1;
01057 start2.direction = trackdir2;
01058 start2.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR;
01059
01060 return NPFRouteInternal(&start1, ignore_start_tile1, (IsValidTile(tile2) ? &start2 : NULL), ignore_start_tile2, target, NPFFindStationOrTile, NPFCalcStationOrTileHeuristic, type, sub_type, owner, railtypes, 0);
01061 }
01062
01063
01064
01065
01066 static NPFFoundTargetData NPFRouteToStationOrTile(TileIndex tile, Trackdir trackdir, bool ignore_start_tile, NPFFindStationOrTileData *target, TransportType type, uint sub_type, Owner owner, RailTypes railtypes)
01067 {
01068 return NPFRouteToStationOrTileTwoWay(tile, trackdir, ignore_start_tile, INVALID_TILE, INVALID_TRACKDIR, false, target, type, sub_type, owner, railtypes);
01069 }
01070
01071
01072
01073
01074
01075
01076
01077
01078 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)
01079 {
01080 AyStarNode start1;
01081 AyStarNode start2;
01082
01083 start1.tile = tile1;
01084 start2.tile = tile2;
01085
01086
01087 start1.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR;
01088 start1.direction = trackdir1;
01089 start2.direction = trackdir2;
01090 start2.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR;
01091
01092
01093
01094 return NPFRouteInternal(&start1, ignore_start_tile1, (IsValidTile(tile2) ? &start2 : NULL), ignore_start_tile2, NULL, NPFFindDepot, NPFCalcZero, type, sub_type, owner, railtypes, reverse_penalty);
01095 }
01096
01097 void InitializeNPF()
01098 {
01099 static bool first_init = true;
01100 if (first_init) {
01101 first_init = false;
01102 init_AyStar(&_npf_aystar, NPFHash, NPF_HASH_SIZE);
01103 } else {
01104 AyStarMain_Clear(&_npf_aystar);
01105 }
01106 _npf_aystar.loops_per_tick = 0;
01107 _npf_aystar.max_path_cost = 0;
01108
01109
01110
01111 _npf_aystar.max_search_nodes = _settings_game.pf.npf.npf_max_search_nodes;
01112 }
01113
01114 static void NPFFillWithOrderData(NPFFindStationOrTileData *fstd, const Vehicle *v, bool reserve_path = false)
01115 {
01116
01117
01118
01119
01120
01121
01122 if (v->type != VEH_SHIP && (v->current_order.IsType(OT_GOTO_STATION) || v->current_order.IsType(OT_GOTO_WAYPOINT))) {
01123 assert(v->type == VEH_TRAIN || v->type == VEH_ROAD);
01124 fstd->station_index = v->current_order.GetDestination();
01125 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);
01126 fstd->not_articulated = v->type == VEH_ROAD && !RoadVehicle::From(v)->HasArticulatedPart();
01127
01128 fstd->dest_coords = CalcClosestStationTile(fstd->station_index, v->tile, fstd->station_type);
01129 } else {
01130 fstd->dest_coords = v->dest_tile;
01131 fstd->station_index = INVALID_STATION;
01132 }
01133 fstd->reserve_path = reserve_path;
01134 fstd->v = v;
01135 }
01136
01137
01138
01139 FindDepotData NPFRoadVehicleFindNearestDepot(const RoadVehicle *v, int max_penalty)
01140 {
01141 Trackdir trackdir = v->GetVehicleTrackdir();
01142
01143 NPFFoundTargetData ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, false, v->tile, ReverseTrackdir(trackdir), false, TRANSPORT_ROAD, v->compatible_roadtypes, v->owner, INVALID_RAILTYPES, 0);
01144
01145 if (ftd.best_bird_dist != 0) return FindDepotData();
01146
01147
01148
01149
01150
01151
01152 return FindDepotData(ftd.node.tile, ftd.best_path_dist);
01153 }
01154
01155 Trackdir NPFRoadVehicleChooseTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, TrackdirBits trackdirs)
01156 {
01157 NPFFindStationOrTileData fstd;
01158
01159 NPFFillWithOrderData(&fstd, v);
01160 Trackdir trackdir = DiagDirToDiagTrackdir(enterdir);
01161
01162 NPFFoundTargetData ftd = NPFRouteToStationOrTile(tile - TileOffsByDiagDir(enterdir), trackdir, true, &fstd, TRANSPORT_ROAD, v->compatible_roadtypes, v->owner, INVALID_RAILTYPES);
01163 if (ftd.best_trackdir == INVALID_TRACKDIR) {
01164
01165
01166
01167 return (Trackdir)FindFirstBit2x64(trackdirs);
01168 }
01169
01170
01171
01172
01173
01174 return ftd.best_trackdir;
01175 }
01176
01177
01178
01179 Track NPFShipChooseTrack(const Ship *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks)
01180 {
01181 NPFFindStationOrTileData fstd;
01182 Trackdir trackdir = v->GetVehicleTrackdir();
01183 assert(trackdir != INVALID_TRACKDIR);
01184
01185 NPFFillWithOrderData(&fstd, v);
01186
01187 NPFFoundTargetData ftd = NPFRouteToStationOrTile(tile - TileOffsByDiagDir(enterdir), trackdir, true, &fstd, TRANSPORT_WATER, 0, v->owner, INVALID_RAILTYPES);
01188
01189
01190
01191
01192
01193 if (ftd.best_trackdir == 0xff) return INVALID_TRACK;
01194 return TrackdirToTrack(ftd.best_trackdir);
01195 }
01196
01197
01198
01199 FindDepotData NPFTrainFindNearestDepot(const Train *v, int max_penalty)
01200 {
01201 const Train *last = v->Last();
01202 Trackdir trackdir = v->GetVehicleTrackdir();
01203 Trackdir trackdir_rev = ReverseTrackdir(last->GetVehicleTrackdir());
01204
01205 assert(trackdir != INVALID_TRACKDIR);
01206 NPFFoundTargetData ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, false, last->tile, trackdir_rev, false, TRANSPORT_RAIL, 0, v->owner, v->compatible_railtypes, NPF_INFINITE_PENALTY);
01207 if (ftd.best_bird_dist != 0) return FindDepotData();
01208
01209
01210
01211
01212
01213
01214 return FindDepotData(ftd.node.tile, ftd.best_path_dist, NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE));
01215 }
01216
01217 bool NPFTrainFindNearestSafeTile(const Train *v, TileIndex tile, Trackdir trackdir, bool override_railtype)
01218 {
01219 assert(v->type == VEH_TRAIN);
01220
01221 NPFFindStationOrTileData fstd;
01222 fstd.v = v;
01223 fstd.reserve_path = true;
01224
01225 AyStarNode start1;
01226 start1.tile = tile;
01227
01228
01229 start1.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR;
01230 start1.direction = trackdir;
01231 NPFSetFlag(&start1, NPF_FLAG_IGNORE_RESERVED, true);
01232
01233 RailTypes railtypes = v->compatible_railtypes;
01234 if (override_railtype) railtypes |= GetRailTypeInfo(v->railtype)->compatible_railtypes;
01235
01236
01237
01238 return NPFRouteInternal(&start1, true, NULL, false, &fstd, NPFFindSafeTile, NPFCalcZero, TRANSPORT_RAIL, 0, v->owner, railtypes, 0).res_okay;
01239 }
01240
01241 bool NPFTrainCheckReverse(const Train *v)
01242 {
01243 NPFFindStationOrTileData fstd;
01244 NPFFoundTargetData ftd;
01245 const Train *last = v->Last();
01246
01247 NPFFillWithOrderData(&fstd, v);
01248
01249 Trackdir trackdir = v->GetVehicleTrackdir();
01250 Trackdir trackdir_rev = ReverseTrackdir(last->GetVehicleTrackdir());
01251 assert(trackdir != INVALID_TRACKDIR);
01252 assert(trackdir_rev != INVALID_TRACKDIR);
01253
01254 ftd = NPFRouteToStationOrTileTwoWay(v->tile, trackdir, false, last->tile, trackdir_rev, false, &fstd, TRANSPORT_RAIL, 0, v->owner, v->compatible_railtypes);
01255
01256 return ftd.best_bird_dist != 0 && NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE);
01257 }
01258
01259 Track NPFTrainChooseTrack(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool *path_not_found, bool reserve_track, struct PBSTileInfo *target)
01260 {
01261 NPFFindStationOrTileData fstd;
01262 NPFFillWithOrderData(&fstd, v, reserve_track);
01263
01264 PBSTileInfo origin = FollowTrainReservation(v);
01265 assert(IsValidTrackdir(origin.trackdir));
01266
01267 NPFFoundTargetData ftd = NPFRouteToStationOrTile(origin.tile, origin.trackdir, true, &fstd, TRANSPORT_RAIL, 0, v->owner, v->compatible_railtypes);
01268
01269 if (target != NULL) {
01270 target->tile = ftd.node.tile;
01271 target->trackdir = (Trackdir)ftd.node.direction;
01272 target->okay = ftd.res_okay;
01273 }
01274
01275 if (ftd.best_trackdir == INVALID_TRACKDIR) {
01276
01277
01278
01279 if (path_not_found) *path_not_found = false;
01280 return FindFirstTrack(tracks);
01281 }
01282
01283
01284
01285
01286
01287 if (path_not_found != NULL) *path_not_found = (ftd.best_bird_dist != 0);
01288
01289 return TrackdirToTrack(ftd.best_trackdir);
01290 }