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