static void TPFModeShip(TrackPathFinder *tpf, TileIndex tile, DiagDirection direction) { if (IsTileType(tile, MP_TUNNELBRIDGE)) { /* wrong track type */ if (GetTunnelBridgeTransportType(tile) != TRANSPORT_WATER) return; DiagDirection dir = GetTunnelBridgeDirection(tile); /* entering tunnel / bridge? */ if (dir == direction) { TileIndex endtile = GetOtherTunnelBridgeEnd(tile); tpf->rd.cur_length += GetTunnelBridgeLength(tile, endtile) + 1; tile = endtile; } else { /* leaving tunnel / bridge? */ if (ReverseDiagDir(dir) != direction) return; } } /* This addition will sometimes overflow by a single tile. * The use of TILE_MASK here makes sure that we still point at a valid * tile, and then this tile will be in the sentinel row/col, so GetTileTrackStatus will fail. */ tile = TILE_MASK(tile + TileOffsByDiagDir(direction)); if (++tpf->rd.cur_length > 50) return; TrackBits bits = TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_WATER, 0)) & DiagdirReachesTracks(direction); if (bits == TRACK_BIT_NONE) return; assert(TileX(tile) != MapMaxX() && TileY(tile) != MapMaxY()); bool only_one_track = true; do { Track track = RemoveFirstTrack(&bits); if (bits != TRACK_BIT_NONE) only_one_track = false; RememberData rd = tpf->rd; /* Change direction 4 times only */ if (!only_one_track && track != tpf->rd.last_choosen_track) { if (++tpf->rd.depth > 4) { tpf->rd = rd; return; } tpf->rd.last_choosen_track = track; } tpf->the_dir = TrackEnterdirToTrackdir(track, direction); if (!ShipTrackFollower(tile, tpf, tpf->rd.cur_length)) { TPFModeShip(tpf, tile, TrackdirToExitdir(tpf->the_dir)); } tpf->rd = rd; } while (bits != TRACK_BIT_NONE); }
/* Will return the cost of the tunnel. If it is an entry, it will return the * cost of that tile. If the tile is an exit, it will return the tunnel length * including the exit tile. Requires that this is a Tunnel tile */ static uint NPFTunnelCost(AyStarNode *current) { DiagDirection exitdir = TrackdirToExitdir(current->direction); TileIndex tile = current->tile; if (GetTunnelBridgeDirection(tile) == ReverseDiagDir(exitdir)) { /* We just popped out if this tunnel, since were * facing the tunnel exit */ return NPF_TILE_LENGTH * (GetTunnelBridgeLength(current->tile, GetOtherTunnelEnd(current->tile)) + 1); /* @todo: Penalty for tunnels? */ } else { /* We are entering the tunnel, the enter tile is just a * straight track */ return NPF_TILE_LENGTH; } }
static uint NPFReservedTrackCost(AyStarNode *current) { TileIndex tile = current->tile; TrackBits track = TrackToTrackBits(TrackdirToTrack(current->direction)); TrackBits res = GetReservedTrackbits(tile); if (NPFGetFlag(current, NPF_FLAG_3RD_SIGNAL) || NPFGetFlag(current, NPF_FLAG_LAST_SIGNAL_BLOCK) || ((res & track) == TRACK_BIT_NONE && !TracksOverlap(res | track))) return 0; if (IsTileType(tile, MP_TUNNELBRIDGE)) { DiagDirection exitdir = TrackdirToExitdir(current->direction); if (GetTunnelBridgeDirection(tile) == ReverseDiagDir(exitdir)) { return _settings_game.pf.npf.npf_rail_pbs_cross_penalty * (GetTunnelBridgeLength(tile, GetOtherTunnelBridgeEnd(tile)) + 1); } } return _settings_game.pf.npf.npf_rail_pbs_cross_penalty; }
static inline uint NPFBridgeCost(AyStarNode *current) { return NPF_TILE_LENGTH * GetTunnelBridgeLength(current->tile, GetOtherBridgeEnd(current->tile)); }