From a25ac7a1610e5ce7fcee29ef8d1016d42f917fb6 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sat, 20 Feb 2016 20:12:10 +0000 Subject: [PATCH] Enable signals on bridges/tunnels to work with PBS. --- src/pathfinder/follow_track.hpp | 4 +-- src/pathfinder/npf/npf.cpp | 4 +++ src/pathfinder/yapf/yapf_costrail.hpp | 4 +++ src/pbs.cpp | 10 +++++++- src/rail_map.h | 12 +++++++-- src/train_cmd.cpp | 37 +++++++++++++++++++++++---- src/tunnelbridge_cmd.cpp | 3 ++- 7 files changed, 63 insertions(+), 11 deletions(-) diff --git a/src/pathfinder/follow_track.hpp b/src/pathfinder/follow_track.hpp index 76f33407fb..9f19b029c0 100644 --- a/src/pathfinder/follow_track.hpp +++ b/src/pathfinder/follow_track.hpp @@ -358,7 +358,7 @@ protected: if (IsTunnel(m_new_tile)) { if (!m_is_tunnel) { DiagDirection tunnel_enterdir = GetTunnelBridgeDirection(m_new_tile); - if (tunnel_enterdir != m_exitdir || IsTunnelBridgeExit(m_new_tile)) { + if (tunnel_enterdir != m_exitdir) { m_err = EC_NO_WAY; return false; } @@ -366,7 +366,7 @@ protected: } else { // IsBridge(m_new_tile) if (!m_is_bridge) { DiagDirection ramp_enderdir = GetTunnelBridgeDirection(m_new_tile); - if (ramp_enderdir != m_exitdir || IsTunnelBridgeExit(m_new_tile)) { + if (ramp_enderdir != m_exitdir) { m_err = EC_NO_WAY; return false; } diff --git a/src/pathfinder/npf/npf.cpp b/src/pathfinder/npf/npf.cpp index bb705e5f4a..496a9fdc53 100644 --- a/src/pathfinder/npf/npf.cpp +++ b/src/pathfinder/npf/npf.cpp @@ -936,6 +936,10 @@ static void NPFFollowTrack(AyStar *aystar, OpenListNode *current) break; } } + if (IsTileType(dst_tile, MP_TUNNELBRIDGE) && IsTunnelBridgeExit(dst_tile) && DiagDirToDiagTrackdir(GetTunnelBridgeDirection(dst_tile)) == dst_trackdir) { + /* Entering a signalled bridge/tunnel from the wrong side, equivalent to encountering a one-way signal from the wrong side */ + break; + } { /* We've found ourselves a neighbour :-) */ AyStarNode *neighbour = &aystar->neighbours[i]; diff --git a/src/pathfinder/yapf/yapf_costrail.hpp b/src/pathfinder/yapf/yapf_costrail.hpp index 64cf963800..15da32d9f7 100644 --- a/src/pathfinder/yapf/yapf_costrail.hpp +++ b/src/pathfinder/yapf/yapf_costrail.hpp @@ -244,6 +244,10 @@ public: } } } + if (IsTileType(tile, MP_TUNNELBRIDGE) && IsTunnelBridgeExit(tile) && DiagDirToDiagTrackdir(GetTunnelBridgeDirection(tile)) == trackdir) { + /* Entering a signalled bridge/tunnel from the wrong side, equivalent to encountering a one-way signal from the wrong side */ + n.m_segment->m_end_segment_reason |= ESRB_DEAD_END; + } return cost; } diff --git a/src/pbs.cpp b/src/pbs.cpp index 133293909f..2ca4422cc8 100644 --- a/src/pbs.cpp +++ b/src/pbs.cpp @@ -246,6 +246,7 @@ static PBSTileInfo FollowReservation(Owner o, RailTypes rts, TileIndex tile, Tra if (IsRailDepotTile(tile)) break; /* Non-pbs signal? Reservation can't continue. */ if (IsTileType(tile, MP_RAILWAY) && HasSignalOnTrackdir(tile, trackdir) && !IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) break; + if (IsTileType(tile, MP_TUNNELBRIDGE) && HasWormholeSignals(tile)) break; } return PBSTileInfo(tile, trackdir, false); @@ -314,7 +315,7 @@ PBSTileInfo FollowTrainReservation(const Train *v, Vehicle **train_on_res) if (ftoti.best != NULL) *train_on_res = ftoti.best->First(); } } - if (*train_on_res == NULL && IsTileType(ftoti.res.tile, MP_TUNNELBRIDGE)) { + if (*train_on_res == NULL && IsTileType(ftoti.res.tile, MP_TUNNELBRIDGE) && !HasWormholeSignals(ftoti.res.tile)) { /* The target tile is a bridge/tunnel, also check the other end tile. */ FindVehicleOnPos(GetOtherTunnelBridgeEnd(ftoti.res.tile), &ftoti, FindTrainOnTrackEnum); if (ftoti.best != NULL) *train_on_res = ftoti.best->First(); @@ -389,6 +390,12 @@ bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bo if (HasSignalOnTrackdir(tile, trackdir) && !IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) return true; } + if (IsTileType(tile, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) { + if (IsTunnelBridgeEntrance(tile)) { + return true; + } + } + /* Check next tile. For performance reasons, we check for 90 degree turns ourself. */ CFollowTrackRail ft(v, GetRailTypeInfo(v->railtype)->compatible_railtypes); @@ -437,6 +444,7 @@ bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bo /* Not reserved and depot or not a pbs signal -> free. */ if (IsRailDepotTile(tile)) return true; if (IsTileType(tile, MP_RAILWAY) && HasSignalOnTrackdir(tile, trackdir) && !IsPbsSignal(GetSignalType(tile, track))) return true; + if (IsTileType(tile, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL && IsTunnelBridgeEntrance(tile)) return true; /* Check the next tile, if it's a PBS signal, it has to be free as well. */ CFollowTrackRail ft(v, GetRailTypeInfo(v->railtype)->compatible_railtypes); diff --git a/src/rail_map.h b/src/rail_map.h index 2431a79202..d2befc4686 100644 --- a/src/rail_map.h +++ b/src/rail_map.h @@ -18,6 +18,7 @@ #include "track_func.h" #include "tile_map.h" #include "signal_type.h" +#include "tunnelbridge_map.h" /** Different types of Rail-related tiles */ @@ -475,8 +476,15 @@ static inline bool HasPbsSignalOnTrackdir(TileIndex tile, Trackdir td) */ static inline bool HasOnewaySignalBlockingTrackdir(TileIndex tile, Trackdir td) { - return IsTileType(tile, MP_RAILWAY) && HasSignalOnTrackdir(tile, ReverseTrackdir(td)) && - !HasSignalOnTrackdir(tile, td) && IsOnewaySignal(tile, TrackdirToTrack(td)); + if (IsTileType(tile, MP_RAILWAY) && HasSignalOnTrackdir(tile, ReverseTrackdir(td)) && + !HasSignalOnTrackdir(tile, td) && IsOnewaySignal(tile, TrackdirToTrack(td))) { + return true; + } + if (IsTileType(tile, MP_TUNNELBRIDGE) && IsTunnelBridgeExit(tile) && + DiagDirToDiagTrackdir(GetTunnelBridgeDirection(tile)) == td) { + return true; + } + return false; } diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 345bff3ff7..78b19e8e3a 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -2260,7 +2260,13 @@ static void ClearPathReservation(const Train *v, TileIndex tile, Trackdir track_ TileIndex end = GetOtherTunnelBridgeEnd(tile); bool free = TunnelBridgeIsFree(tile, end, v).Succeeded(); - if (free) { + if (HasWormholeSignals(tile)) { + SetTunnelBridgeReservation(tile, false); + HandleLastTunnelBridgeSignals(tile, end, dir, free); + if (_settings_client.gui.show_track_reservation) { + MarkTileDirtyByTile(tile); + } + } else if (free) { /* Free the reservation only if no other train is on the tiles. */ SetTunnelBridgeReservation(tile, false); SetTunnelBridgeReservation(end, false); @@ -2274,7 +2280,12 @@ static void ClearPathReservation(const Train *v, TileIndex tile, Trackdir track_ } } } - if (HasWormholeSignals(tile)) HandleLastTunnelBridgeSignals(tile, end, dir, free); + } else if (GetTunnelBridgeDirection(tile) == dir && HasWormholeSignals(tile)) { + /* cancelling reservation of entry ramp, due to reverse */ + SetTunnelBridgeReservation(tile, false); + if (_settings_client.gui.show_track_reservation) { + MarkTileDirtyByTile(tile); + } } } else if (IsRailStationTile(tile)) { TileIndex new_tile = TileAddByDiagDir(tile, dir); @@ -2955,6 +2966,12 @@ static bool TrainMovedChangeSignals(TileIndex tile, DiagDirection dir) if (!IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) return true; } } + if (IsTileType(tile, MP_TUNNELBRIDGE) && IsTunnelBridgeExit(tile) && GetTunnelBridgeDirection(tile) == ReverseDiagDir(dir)) { + if (UpdateSignalsOnSegment(tile, dir, GetTileOwner(tile)) == SIGSEG_PBS) { + return true; + } + } + return false; } @@ -3192,6 +3209,15 @@ static bool IsToCloseBehindTrain(Vehicle *v, TileIndex tile, bool check_endtile) return false; } +static bool CheckTrainStayInWormHolePathReserve(Train *t, TileIndex tile) +{ + TileIndex veh_orig = t->tile; + t->tile = tile; + bool ok = TryPathReserve(t); + t->tile = veh_orig; + return ok; +} + /** Simulate signals in tunnel - bridge. */ static bool CheckTrainStayInWormHole(Train *t, TileIndex tile) { @@ -3204,7 +3230,7 @@ static bool CheckTrainStayInWormHole(Train *t, TileIndex tile) return true; } SigSegState seg_state = _settings_game.pf.reserve_paths ? SIGSEG_PBS : UpdateSignalsOnSegment(tile, INVALID_DIAGDIR, t->owner); - if (seg_state == SIGSEG_FULL || (seg_state == SIGSEG_PBS && !TryPathReserve(t))) { + if (seg_state == SIGSEG_FULL || (seg_state == SIGSEG_PBS && !CheckTrainStayInWormHolePathReserve(t, tile))) { t->vehstatus |= VS_TRAIN_SLOWING; t->cur_speed = 0; return true; @@ -3493,7 +3519,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) } else { /* Handle signal simulation on tunnel/bridge. */ TileIndex old_tile = TileVirtXY(v->x_pos, v->y_pos); - if (old_tile != gp.new_tile && HasWormholeSignals(v->tile) && (v->IsFrontEngine() || v->Next() == NULL)){ + if (old_tile != gp.new_tile && HasWormholeSignals(v->tile) && (v->IsFrontEngine() || v->Next() == NULL)) { if (old_tile == v->tile) { if (v->IsFrontEngine() && v->force_proceed == 0 && IsTunnelBridgeExit(v->tile)) goto invalid_rail; /* Entered wormhole set counters. */ @@ -3532,6 +3558,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) v->x_pos = gp.x; v->y_pos = gp.y; UpdateSignalsOnSegment(old_tile, INVALID_DIAGDIR, v->owner); + SetTunnelBridgeReservation(old_tile, false); } } if (distance == 0) v->load_unload_ticks++; @@ -3553,7 +3580,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) if (IsTileType(gp.new_tile, MP_TUNNELBRIDGE) && HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) { /* Perform look-ahead on tunnel exit. */ if (v->IsFrontEngine()) { - TryReserveRailTrack(gp.new_tile, DiagDirToDiagTrack(GetTunnelBridgeDirection(gp.new_tile))); + if (!HasWormholeSignals(gp.new_tile)) TryReserveRailTrack(gp.new_tile, DiagDirToDiagTrack(GetTunnelBridgeDirection(gp.new_tile))); CheckNextTrainTile(v); } /* Prevent v->UpdateInclination() being called with wrong parameters. diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp index 4dec3f80e0..22350db906 100644 --- a/src/tunnelbridge_cmd.cpp +++ b/src/tunnelbridge_cmd.cpp @@ -1598,7 +1598,8 @@ void DrawBridgeMiddle(const TileInfo *ti) } } - if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && !IsInvisibilitySet(TO_BRIDGES) && HasTunnelBridgeReservation(rampnorth)) { + if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && !IsInvisibilitySet(TO_BRIDGES) && HasTunnelBridgeReservation(rampnorth) + && !HasWormholeSignals(rampnorth)) { if (rti->UsesOverlay()) { SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY); AddSortableSpriteToDraw(overlay + RTO_X + axis, PALETTE_CRASH, ti->x, ti->y, 16, 16, 0, bridge_z, IsTransparencySet(TO_BRIDGES));