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