diff --git a/src/npf.cpp b/src/npf.cpp index d5f431b..ea4222a 100644 --- a/src/npf.cpp +++ b/src/npf.cpp @@ -409,7 +409,7 @@ static int32 NPFRailPathCost(AyStar* as, AyStarNode* current, OpenListNode* pare } } - if (HasPbsSignalOnTrackdir(tile, ReverseTrackdir(trackdir)) && !NPFGetFlag(current, NPF_FLAG_3RD_SIGNAL)) { + if (HasPbsSignalOnTrackdir(tile, ReverseTrackdir(trackdir)) && !HasApproachSignalOnTrack(tile, TrackdirToTrack(trackdir)) && !NPFGetFlag(current, NPF_FLAG_3RD_SIGNAL)) { cost += _settings_game.pf.npf.npf_rail_pbs_signal_back_penalty; } } diff --git a/src/pbs.cpp b/src/pbs.cpp index bf3913b..83b516b 100644 --- a/src/pbs.cpp +++ b/src/pbs.cpp @@ -175,7 +175,7 @@ bool TryReserveRailTrack(TileIndex tile, Track t) /** Follow a reservation starting from a specific tile to the end. */ -static PBSTileInfo FollowReservation(Owner o, RailTypes rts, TileIndex tile, Trackdir trackdir, bool ignore_oneway = false) +static PBSTileInfo FollowReservation(Owner o, RailTypes rts, TileIndex tile, Trackdir trackdir, bool ignore_oneway = false, bool break_on_pbs_signal = false) { /* Do not disallow 90 deg turns as the setting might have changed between reserving and now. */ CFollowTrackRail ft(o, rts); @@ -198,7 +198,10 @@ static PBSTileInfo FollowReservation(Owner o, RailTypes rts, TileIndex tile, Tra /* Depot tile? Can't continue. */ 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_RAILWAY) && HasSignalOnTrackdir(tile, trackdir)) { + SignalType type = GetSignalType(tile, TrackdirToTrack(trackdir)); + if ((break_on_pbs_signal && type != SIGTYPE_PBS_PRE) || !IsPbsSignal(type)) break; + } } return PBSTileInfo(tile, trackdir, false); @@ -313,7 +316,8 @@ bool IsSafeWaitingPosition(const Vehicle *v, TileIndex tile, Trackdir trackdir, if (ft.m_new_td_bits != TRACKDIR_BIT_NONE && KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE) { /* PBS signal on next trackdir? Safe position. */ - if (HasPbsSignalOnTrackdir(ft.m_new_tile, FindFirstTrackdir(ft.m_new_td_bits))) return true; + Trackdir td = FindFirstTrackdir(ft.m_new_td_bits); + if (HasPbsSignalOnTrackdir(ft.m_new_tile, td) && GetSignalType(ft.m_new_tile, TrackdirToTrack(td)) != SIGTYPE_PBS_PRE) return true; } return false; @@ -351,3 +355,10 @@ bool IsWaitingPositionFree(const Vehicle *v, TileIndex tile, Trackdir trackdir, return !HasReservedTracks(ft.m_new_tile, TrackdirBitsToTrackBits(ft.m_new_td_bits)); } + +PBSTileInfo FindFirstPbsSignal(const Vehicle *v, TileIndex tile, Trackdir trackdir) +{ + PBSTileInfo info = FollowReservation(v->owner, GetRailTypeInfo(v->u.rail.railtype)->compatible_railtypes, tile, trackdir, false, true); + info.okay = IsTileType(info.tile, MP_RAILWAY) && HasPbsSignalOnTrackdir(info.tile, info.trackdir) && GetSignalType(info.tile, TrackdirToTrack(info.trackdir)) != SIGTYPE_PBS_PRE; + return info; +} diff --git a/src/pbs.h b/src/pbs.h index d01123e..54bbdd1 100644 --- a/src/pbs.h +++ b/src/pbs.h @@ -33,6 +33,8 @@ bool IsWaitingPositionFree(const Vehicle *v, TileIndex tile, Trackdir trackdir, Vehicle *GetTrainForReservation(TileIndex tile, Track track); +PBSTileInfo FindFirstPbsSignal(const Vehicle *v, TileIndex tile, Trackdir trackdir); + /** * Check whether some of tracks is reserved on a tile. * diff --git a/src/rail_map.h b/src/rail_map.h index 0937da7..427be28 100644 --- a/src/rail_map.h +++ b/src/rail_map.h @@ -340,7 +340,7 @@ static inline TrackBits GetRailDepotReservation(TileIndex t) static inline bool IsPbsSignal(SignalType s) { - return s == SIGTYPE_PBS || s == SIGTYPE_PBS_ONEWAY; + return s > SIGTYPE_LAST_NOPBS; } static inline SignalType GetSignalType(TileIndex t, Track track) @@ -371,7 +371,13 @@ static inline bool IsPresignalExit(TileIndex t, Track track) /** One-way signals can't be passed the 'wrong' way. */ static inline bool IsOnewaySignal(TileIndex t, Track track) { - return GetSignalType(t, track) != SIGTYPE_PBS; + SignalType s = GetSignalType(t, track); + return s <= SIGTYPE_LAST_NOPBS || s == SIGTYPE_PBS_ONEWAY; +} + +static inline bool IsApproachSignal(SignalType s) +{ + return s == SIGTYPE_PBS_PRE || s == SIGTYPE_PBS_COMBO; } static inline void CycleSignalSide(TileIndex t, Track track) @@ -549,6 +555,13 @@ static inline bool HasOnewaySignalBlockingTrackdir(TileIndex tile, Trackdir td) IsOnewaySignal(tile, TrackdirToTrack(td)); } +static inline bool HasApproachSignalOnTrack(TileIndex tile, Track track) +{ + return + HasSignalOnTrack(tile, track) && + GetSignalType(tile, track) == SIGTYPE_PBS_PRE; +} + /** * Return the rail type of tile, or INVALID_RAILTYPE if this is no rail tile. diff --git a/src/signal_type.h b/src/signal_type.h index 0bcd107..e496fce 100644 --- a/src/signal_type.h +++ b/src/signal_type.h @@ -20,7 +20,9 @@ enum SignalType { SIGTYPE_COMBO = 3, ///< presignal inter-block SIGTYPE_PBS = 4, ///< normal pbs signal SIGTYPE_PBS_ONEWAY = 5, ///< no-entry signal - SIGTYPE_LAST = SIGTYPE_PBS_ONEWAY, + SIGTYPE_PBS_PRE = 6, ///< approach signal + SIGTYPE_PBS_COMBO = 7, ///< combined normal and approach signal + SIGTYPE_LAST = SIGTYPE_PBS_COMBO, SIGTYPE_LAST_NOPBS = SIGTYPE_COMBO }; diff --git a/src/train.h b/src/train.h index 27e2329..8f3d997 100644 --- a/src/train.h +++ b/src/train.h @@ -274,7 +274,7 @@ void UpdateTrainAcceleration(Vehicle* v); void CheckTrainsLengths(); void FreeTrainTrackReservation(const Vehicle *v, TileIndex origin = INVALID_TILE, Trackdir orig_td = INVALID_TRACKDIR); -bool TryPathReserve(Vehicle *v, bool mark_as_stuck = false, bool first_tile_okay = false); +bool TryPathReserve(Vehicle *v, bool mark_as_stuck = false, bool first_tile_okay = false, bool always_extend = false); /** * This class 'wraps' Vehicle; you do not actually instantiate this class. diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 37334c0..039b2ad 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -2377,10 +2377,11 @@ static void CheckNextTrainTile(Vehicle *v) CFollowTrackRail ft(v); if (!ft.Follow(v->tile, td)) return; - if (!HasReservedTracks(ft.m_new_tile, TrackdirBitsToTrackBits(ft.m_new_td_bits))) { - /* Next tile is not reserved. */ - if (KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE) { - if (HasPbsSignalOnTrackdir(ft.m_new_tile, FindFirstTrackdir(ft.m_new_td_bits))) { + if (KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE) { + /* Tile is not a choice tile and can have signals. */ + Trackdir td = FindFirstTrackdir(ft.m_new_td_bits); + if (IsTileType(ft.m_new_tile, MP_RAILWAY) && HasSignalOnTrackdir(ft.m_new_tile, td)) { + if (!HasReservedTracks(ft.m_new_tile, TrackdirBitsToTrackBits(ft.m_new_td_bits)) && HasPbsSignalOnTrackdir(ft.m_new_tile, FindFirstTrackdir(ft.m_new_td_bits))) { /* If the next tile is a PBS signal, try to make a reservation. */ TrackBits tracks = TrackdirBitsToTrackBits(ft.m_new_td_bits); if (_settings_game.pf.pathfinder_for_trains != VPF_NTP && _settings_game.pf.forbid_90_deg) { @@ -2388,6 +2389,13 @@ static void CheckNextTrainTile(Vehicle *v) } ChooseTrainTrack(v, ft.m_new_tile, ft.m_exitdir, tracks, false, NULL, false); } + if (IsApproachSignal(GetSignalType(ft.m_new_tile, TrackdirToTrack(td))) && GetSignalStateByTrackdir(ft.m_new_tile, td) != SIGNAL_STATE_GREEN) { + TryPathReserve(v, false, false, true); + PBSTileInfo info = FindFirstPbsSignal(v, v->tile, GetVehicleTrackdir(v)); + if (info.okay && GetSignalStateByTrackdir(info.tile, info.trackdir) == SIGNAL_STATE_GREEN) { + SetSignalStateByTrackdir(ft.m_new_tile, td, SIGNAL_STATE_GREEN); + } + } } } } @@ -3028,7 +3036,7 @@ static Track ChooseTrainTrack(Vehicle* v, TileIndex tile, DiagDirection enterdir * @param v The vehicle * @return True if a path could be reserved */ -bool TryPathReserve(Vehicle *v, bool mark_as_stuck, bool first_tile_okay) +bool TryPathReserve(Vehicle *v, bool mark_as_stuck, bool first_tile_okay, bool always_extend) { assert(v->type == VEH_TRAIN && IsFrontEngine(v)); @@ -3063,7 +3071,7 @@ bool TryPathReserve(Vehicle *v, bool mark_as_stuck, bool first_tile_okay) Vehicle *other_train = NULL; PBSTileInfo origin = FollowTrainReservation(v, &other_train); /* If we have a reserved path and the path ends at a safe tile, we are finished already. */ - if (origin.okay && (v->tile != origin.tile || first_tile_okay)) { + if (!always_extend && origin.okay && (v->tile != origin.tile || first_tile_okay)) { /* Can't be stuck then. */ if (HasBit(v->u.rail.flags, VRF_TRAIN_STUCK)) InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); ClrBit(v->u.rail.flags, VRF_TRAIN_STUCK); @@ -3657,11 +3665,12 @@ static void TrainController(Vehicle *v, Vehicle *nomove, bool update_image) if (prev == NULL) { /* Currently the locomotive is active. Determine which one of the * available tracks to choose */ - chosen_track = TrackToTrackBits(ChooseTrainTrack(v, gp.new_tile, enterdir, bits, false, NULL, true)); + Track new_track = ChooseTrainTrack(v, gp.new_tile, enterdir, bits, false, NULL, true); + chosen_track = TrackToTrackBits(new_track); assert(chosen_track & (bits | GetReservedTrackbits(gp.new_tile))); /* Check if it's a red signal and that force proceed is not clicked. */ - if (red_signals & chosen_track && v->u.rail.force_proceed == 0) { + if (!(IsTileType(gp.new_tile, MP_RAILWAY) && HasApproachSignalOnTrack(gp.new_tile, new_track)) && red_signals & chosen_track && v->u.rail.force_proceed == 0) { /* In front of a red signal */ Trackdir i = FindFirstTrackdir(trackdirbits); @@ -4182,7 +4191,7 @@ static bool TrainCheckIfLineEnds(Vehicle *v) } /* approaching red signal */ - if ((trackdirbits & red_signals) != 0) return TrainApproachingLineEnd(v, true); + if ((trackdirbits & red_signals) != 0 && !HasApproachSignalOnTrack(tile, FindFirstTrack(bits))) return TrainApproachingLineEnd(v, true); /* approaching a rail/road crossing? then make it red */ if (IsLevelCrossingTile(tile)) MaybeBarCrossingWithSound(tile); diff --git a/src/yapf/yapf_costrail.hpp b/src/yapf/yapf_costrail.hpp index edcb7c7..3aaf5b8 100644 --- a/src/yapf/yapf_costrail.hpp +++ b/src/yapf/yapf_costrail.hpp @@ -224,7 +224,7 @@ public: n.m_segment->m_last_signal_td = trackdir; } - if (has_signal_against && IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) { + if (has_signal_against && IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir))) && !HasApproachSignalOnTrack(tile, TrackdirToTrack(trackdir))) { cost += n.m_num_signals_passed < Yapf().PfGetSettings().rail_look_ahead_max_signals ? Yapf().PfGetSettings().rail_pbs_signal_back_penalty : 0; } }