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