diff --git a/src/lang/english.txt b/src/lang/english.txt index 28bec42f8d..1092128108 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -2417,6 +2417,8 @@ STR_TRACE_RESTRICT_PF_ALLOW :Allow STR_TRACE_RESTRICT_PF_ALLOW_LONG :Allow (cancel previous Deny) STR_TRACE_RESTRICT_RESERVE_THROUGH :Reserve through STR_TRACE_RESTRICT_RESERVE_THROUGH_CANCEL :Cancel reserve through +STR_TRACE_RESTRICT_LONG_RESERVE :Long reserve +STR_TRACE_RESTRICT_LONG_RESERVE_CANCEL :Cancel long reserve STR_TRACE_RESTRICT_PF_PENALTY :Penalty STR_TRACE_RESTRICT_PF_VALUE_SMALL :small STR_TRACE_RESTRICT_PF_VALUE_MEDIUM :medium diff --git a/src/pbs.cpp b/src/pbs.cpp index a54c04a521..8bc6c4ee62 100644 --- a/src/pbs.cpp +++ b/src/pbs.cpp @@ -393,7 +393,7 @@ Train *GetTrainForReservation(TileIndex tile, Track track) * This is called to retrieve the previous signal, as required * This is not run all the time as it is somewhat expensive and most restrictions will not test for the previous signal */ -static TileIndex IsSafeWaitingPositionTraceRestrictPreviousSignalCallback(const Train *v, const void *) +TileIndex VehiclePosTraceRestrictPreviousSignalCallback(const Train *v, const void *) { // scan forwards from vehicle position, for the case that train is waiting at/approaching PBS signal @@ -470,7 +470,7 @@ bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bo const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(ft.m_new_tile, TrackdirToTrack(td)); if (prog && prog->actions_used_flags & TRPAUF_RESERVE_THROUGH) { TraceRestrictProgramResult out; - prog->Execute(v, TraceRestrictProgramInput(tile, trackdir, &IsSafeWaitingPositionTraceRestrictPreviousSignalCallback, NULL), out); + prog->Execute(v, TraceRestrictProgramInput(tile, trackdir, &VehiclePosTraceRestrictPreviousSignalCallback, NULL), out); if (out.flags & TRPRF_RESERVE_THROUGH) { return false; } diff --git a/src/tracerestrict.cpp b/src/tracerestrict.cpp index 9100f1a8ae..8aaf480e76 100644 --- a/src/tracerestrict.cpp +++ b/src/tracerestrict.cpp @@ -390,6 +390,14 @@ void TraceRestrictProgram::Execute(const Train* v, const TraceRestrictProgramInp } break; + case TRIT_LONG_RESERVE: + if (GetTraceRestrictValue(item)) { + out.flags &= ~TRPRF_LONG_RESERVE; + } else { + out.flags |= TRPRF_LONG_RESERVE; + } + break; + default: NOT_REACHED(); } @@ -492,6 +500,10 @@ CommandCost TraceRestrictProgram::Validate(const std::vector actions_used_flags |= TRPAUF_RESERVE_THROUGH; break; + case TRIT_LONG_RESERVE: + actions_used_flags |= TRPAUF_LONG_RESERVE; + break; + default: return_cmd_error(STR_TRACE_RESTRICT_ERROR_VALIDATE_UNKNOWN_INSTRUCTION); } @@ -544,6 +556,7 @@ void SetTraceRestrictValueDefault(TraceRestrictItem &item, TraceRestrictValueTyp case TRVT_SPEED: case TRVT_TILE_INDEX: case TRVT_RESERVE_THROUGH: + case TRVT_LONG_RESERVE: SetTraceRestrictValue(item, 0); SetTraceRestrictAuxField(item, 0); break; diff --git a/src/tracerestrict.h b/src/tracerestrict.h index 50324acfe6..c62f21fe33 100644 --- a/src/tracerestrict.h +++ b/src/tracerestrict.h @@ -98,6 +98,7 @@ enum TraceRestrictItemType { TRIT_PF_DENY = 1, ///< Pathfinder deny/allow TRIT_PF_PENALTY = 2, ///< Add to pathfinder penalty TRIT_RESERVE_THROUGH = 3, ///< Reserve through PBS signal + TRIT_LONG_RESERVE = 4, ///< Long reserve PBS signal TRIT_COND_BEGIN = 8, ///< Start of conditional item types, note that this has the same value as TRIT_COND_ENDIF TRIT_COND_ENDIF = 8, ///< This is an endif block or an else block @@ -195,6 +196,7 @@ enum TraceRestrictPathfinderPenaltyPresetIndex { enum TraceRestrictProgramResultFlags { TRPRF_DENY = 1 << 0, ///< Pathfinder deny is set TRPRF_RESERVE_THROUGH = 1 << 1, ///< Reserve through is set + TRPRF_LONG_RESERVE = 1 << 2, ///< Long reserve is set }; DECLARE_ENUM_AS_BIT_SET(TraceRestrictProgramResultFlags) @@ -204,6 +206,7 @@ DECLARE_ENUM_AS_BIT_SET(TraceRestrictProgramResultFlags) enum TraceRestrictProgramActionsUsedFlags { TRPAUF_PF = 1 << 0, ///< Pathfinder deny or penalty are present TRPAUF_RESERVE_THROUGH = 1 << 1, ///< Reserve through action is present + TRPAUF_LONG_RESERVE = 1 << 2, ///< Long reserve action is present }; DECLARE_ENUM_AS_BIT_SET(TraceRestrictProgramActionsUsedFlags) @@ -407,6 +410,7 @@ enum TraceRestrictValueType { TRVT_TILE_INDEX = 8, ///< takes a TileIndex in the next item slot TRVT_PF_PENALTY = 9, ///< takes a pathfinder penalty value or preset index, as per the auxiliary field as type: TraceRestrictPathfinderPenaltyAuxField TRVT_RESERVE_THROUGH = 10,///< takes a value 0 = reserve through, 1 = cancel previous reserve through + TRVT_LONG_RESERVE = 11,///< takes a value 0 = long reserve, 1 = cancel previous long reserve }; /** @@ -480,6 +484,8 @@ static inline TraceRestrictTypePropertySet GetTraceRestrictTypeProperties(TraceR out.value_type = TRVT_DENY; } else if (GetTraceRestrictType(item) == TRIT_RESERVE_THROUGH) { out.value_type = TRVT_RESERVE_THROUGH; + } else if (GetTraceRestrictType(item) == TRIT_LONG_RESERVE) { + out.value_type = TRVT_LONG_RESERVE; } else { out.value_type = TRVT_NONE; } diff --git a/src/tracerestrict_gui.cpp b/src/tracerestrict_gui.cpp index 6fe002c4b9..d0a0471853 100644 --- a/src/tracerestrict_gui.cpp +++ b/src/tracerestrict_gui.cpp @@ -120,6 +120,7 @@ static const StringID _program_insert_str[] = { STR_TRACE_RESTRICT_PF_DENY, STR_TRACE_RESTRICT_PF_PENALTY, STR_TRACE_RESTRICT_RESERVE_THROUGH, + STR_TRACE_RESTRICT_LONG_RESERVE, INVALID_STRING_ID }; static const uint32 _program_insert_else_hide_mask = 8; ///< disable bitmask for else @@ -133,6 +134,7 @@ static const uint _program_insert_val[] = { TRIT_PF_DENY, // deny TRIT_PF_PENALTY, // penalty TRIT_RESERVE_THROUGH, // reserve through + TRIT_LONG_RESERVE, // long reserve }; /** insert drop down list strings and values */ @@ -170,6 +172,21 @@ static const TraceRestrictDropDownListSet _reserve_through_value = { _reserve_through_value_str, _reserve_through_value_val, }; +static const StringID _long_reserve_value_str[] = { + STR_TRACE_RESTRICT_LONG_RESERVE, + STR_TRACE_RESTRICT_LONG_RESERVE_CANCEL, + INVALID_STRING_ID +}; +static const uint _long_reserve_value_val[] = { + 0, + 1, +}; + +/** value drop down list for long reserve types strings and values */ +static const TraceRestrictDropDownListSet _long_reserve_value = { + _long_reserve_value_str, _long_reserve_value_val, +}; + static const StringID _direction_value_str[] = { STR_TRACE_RESTRICT_DIRECTION_FRONT, STR_TRACE_RESTRICT_DIRECTION_BACK, @@ -229,12 +246,14 @@ static const TraceRestrictDropDownListSet *GetTypeDropDownListSet(TraceRestrictI STR_TRACE_RESTRICT_PF_DENY, STR_TRACE_RESTRICT_PF_PENALTY, STR_TRACE_RESTRICT_RESERVE_THROUGH, + STR_TRACE_RESTRICT_LONG_RESERVE, INVALID_STRING_ID, }; static const uint val_action[] = { TRIT_PF_DENY, TRIT_PF_PENALTY, TRIT_RESERVE_THROUGH, + TRIT_LONG_RESERVE, }; static const TraceRestrictDropDownListSet set_action = { str_action, val_action, @@ -665,6 +684,10 @@ static void DrawInstructionString(const TraceRestrictProgram *prog, TraceRestric instruction_string = GetTraceRestrictValue(item) ? STR_TRACE_RESTRICT_RESERVE_THROUGH_CANCEL : STR_TRACE_RESTRICT_RESERVE_THROUGH; break; + case TRIT_LONG_RESERVE: + instruction_string = GetTraceRestrictValue(item) ? STR_TRACE_RESTRICT_LONG_RESERVE_CANCEL : STR_TRACE_RESTRICT_LONG_RESERVE; + break; + default: NOT_REACHED(); break; @@ -870,6 +893,10 @@ public: this->ShowDropDownListWithValue(&_reserve_through_value, GetTraceRestrictValue(item), false, TR_WIDGET_VALUE_DROPDOWN, 0, 0, 0); break; + case TRVT_LONG_RESERVE: + this->ShowDropDownListWithValue(&_long_reserve_value, GetTraceRestrictValue(item), false, TR_WIDGET_VALUE_DROPDOWN, 0, 0, 0); + break; + default: break; } @@ -1615,6 +1642,13 @@ private: GetTraceRestrictValue(item) ? STR_TRACE_RESTRICT_RESERVE_THROUGH_CANCEL : STR_TRACE_RESTRICT_RESERVE_THROUGH; break; + case TRVT_LONG_RESERVE: + right_sel->SetDisplayedPlane(DPR_VALUE_DROPDOWN); + this->EnableWidget(TR_WIDGET_VALUE_DROPDOWN); + this->GetWidget(TR_WIDGET_VALUE_DROPDOWN)->widget_data = + GetTraceRestrictValue(item) ? STR_TRACE_RESTRICT_LONG_RESERVE_CANCEL : STR_TRACE_RESTRICT_LONG_RESERVE; + break; + default: break; } diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index ac2fca925a..3f89d4f2e9 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -35,18 +35,20 @@ #include "order_backup.h" #include "zoom_func.h" #include "newgrf_debug.h" +#include "tracerestrict.h" #include "table/strings.h" #include "table/train_cmd.h" #include "safeguards.h" -static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool force_res, bool *got_reservation, bool mark_stuck); +static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool force_res, bool *p_got_reservation, bool mark_stuck); static bool TrainCheckIfLineEnds(Train *v, bool reverse = true); bool TrainController(Train *v, Vehicle *nomove, bool reverse = true); // Also used in vehicle_sl.cpp. static TileIndex TrainApproachingCrossingTile(const Train *v); static void CheckIfTrainNeedsService(Train *v); static void CheckNextTrainTile(Train *v); +TileIndex VehiclePosTraceRestrictPreviousSignalCallback(const Train *v, const void *); static const byte _vehicle_initial_x_fract[4] = {10, 8, 4, 8}; static const byte _vehicle_initial_y_fract[4] = { 8, 4, 8, 10}; @@ -2336,12 +2338,14 @@ static Track DoTrainPathfind(const Train *v, TileIndex tile, DiagDirection enter /** * Extend a train path as far as possible. Stops on encountering a safe tile, * another reservation or a track choice. + * @param v The train. + * @param origin The tile from which the reservation have to be extended + * @param new_tracks [out] Tracks to choose from when encountering a choice + * @param enterdir [out] The direction from which the choice tile is to be entered * @return INVALID_TILE indicates that the reservation failed. */ -static PBSTileInfo ExtendTrainReservation(const Train *v, TrackBits *new_tracks, DiagDirection *enterdir) +static PBSTileInfo ExtendTrainReservation(const Train *v, const PBSTileInfo &origin, TrackBits *new_tracks, DiagDirection *enterdir) { - PBSTileInfo origin = FollowTrainReservation(v); - CFollowTrackRail ft(v); TileIndex tile = origin.tile; @@ -2520,8 +2524,37 @@ public: } }; -/* choose a track */ -static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool force_res, bool *got_reservation, bool mark_stuck) +static bool HasLongReservePbsSignalOnTrackdir(Train* v, TileIndex tile, Trackdir trackdir) +{ + if (HasPbsSignalOnTrackdir(tile, trackdir)) { + if (IsRestrictedSignal(tile)) { + const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(tile, TrackdirToTrack(trackdir)); + if (prog && prog->actions_used_flags & TRPAUF_LONG_RESERVE) { + TraceRestrictProgramResult out; + prog->Execute(v, TraceRestrictProgramInput(tile, trackdir, &VehiclePosTraceRestrictPreviousSignalCallback, nullptr), out); + if (out.flags & TRPRF_LONG_RESERVE) { + return true; + } + } + } + } + + return false; +} + +/** + * Choose a track and reserve if necessary + * + * @param v The vehicle + * @param tile The tile from which to start + * @param enterdir + * @param tracks + * @param force_res Force a reservation to be made + * @param p_got_reservation [out] If the train has a reservation + * @param mark_stuck The train has to be marked as stuck when needed + * @return The track the train should take. + */ +static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool force_res, bool *p_got_reservation, bool mark_stuck) { Track best_track = INVALID_TRACK; bool do_track_reservation = _settings_game.pf.reserve_paths || force_res; @@ -2529,7 +2562,8 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, assert((tracks & ~TRACK_BIT_MASK) == 0); - if (got_reservation != NULL) *got_reservation = false; + bool got_reservation = false; + if (p_got_reservation != NULL) *p_got_reservation = got_reservation; /* Don't use tracks here as the setting to forbid 90 deg turns might have been switched between reservation and now. */ TrackBits res_tracks = (TrackBits)(GetReservedTrackbits(tile) & DiagdirReachesTracks(enterdir)); @@ -2550,10 +2584,11 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, best_track = track; } + PBSTileInfo origin = FollowTrainReservation(v); PBSTileInfo res_dest(tile, INVALID_TRACKDIR, false); DiagDirection dest_enterdir = enterdir; if (do_track_reservation) { - res_dest = ExtendTrainReservation(v, &tracks, &dest_enterdir); + res_dest = ExtendTrainReservation(v, origin, &tracks, &dest_enterdir); if (res_dest.tile == INVALID_TILE) { /* Reservation failed? */ if (mark_stuck) MarkTrainAsStuck(v); @@ -2561,11 +2596,18 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, return FindFirstTrack(tracks); } if (res_dest.okay) { - /* Got a valid reservation that ends at a safe target, quick exit. */ - if (got_reservation != NULL) *got_reservation = true; - if (changed_signal) MarkTileDirtyByTile(tile); - TryReserveRailTrack(v->tile, TrackdirToTrack(v->GetVehicleTrackdir())); - return best_track; + CFollowTrackRail ft(v); + if (ft.Follow(res_dest.tile, res_dest.trackdir)) { + Trackdir new_td = FindFirstTrackdir(ft.m_new_td_bits); + + if (!HasLongReservePbsSignalOnTrackdir(v, ft.m_new_tile, new_td)) { + /* Got a valid reservation that ends at a safe target, quick exit. */ + if (p_got_reservation != NULL) *p_got_reservation = true; + if (changed_signal) MarkTileDirtyByTile(tile); + TryReserveRailTrack(v->tile, TrackdirToTrack(v->GetVehicleTrackdir())); + return best_track; + } + } } /* Check if the train needs service here, so it has a chance to always find a depot. @@ -2609,28 +2651,28 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, /* A path was found, but could not be reserved. */ if (res_dest.tile != INVALID_TILE && !res_dest.okay) { if (mark_stuck) MarkTrainAsStuck(v); - FreeTrainTrackReservation(v); + FreeTrainTrackReservation(v, origin.tile, origin.trackdir); return best_track; } /* No possible reservation target found, we are probably lost. */ if (res_dest.tile == INVALID_TILE) { /* Try to find any safe destination. */ - PBSTileInfo origin = FollowTrainReservation(v); - if (TryReserveSafeTrack(v, origin.tile, origin.trackdir, false)) { + PBSTileInfo path_end = FollowTrainReservation(v); + if (TryReserveSafeTrack(v, path_end.tile, path_end.trackdir, false)) { TrackBits res = GetReservedTrackbits(tile) & DiagdirReachesTracks(enterdir); best_track = FindFirstTrack(res); TryReserveRailTrack(v->tile, TrackdirToTrack(v->GetVehicleTrackdir())); - if (got_reservation != NULL) *got_reservation = true; + if (p_got_reservation != NULL) *p_got_reservation = true; if (changed_signal) MarkTileDirtyByTile(tile); } else { - FreeTrainTrackReservation(v); + FreeTrainTrackReservation(v, origin.tile, origin.trackdir); if (mark_stuck) MarkTrainAsStuck(v); } return best_track; } - if (got_reservation != NULL) *got_reservation = true; + got_reservation = true; /* Reservation target found and free, check if it is safe. */ while (!IsSafeWaitingPosition(v, res_dest.tile, res_dest.trackdir, true, _settings_game.pf.forbid_90_deg)) { @@ -2651,26 +2693,39 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, res_dest = cur_dest; if (res_dest.okay) continue; /* Path found, but could not be reserved. */ - FreeTrainTrackReservation(v); + FreeTrainTrackReservation(v, origin.tile, origin.trackdir); if (mark_stuck) MarkTrainAsStuck(v); - if (got_reservation != NULL) *got_reservation = false; + got_reservation = false; changed_signal = false; break; } } /* No order or no safe position found, try any position. */ if (!TryReserveSafeTrack(v, res_dest.tile, res_dest.trackdir, true)) { - FreeTrainTrackReservation(v); + FreeTrainTrackReservation(v, origin.tile, origin.trackdir); if (mark_stuck) MarkTrainAsStuck(v); - if (got_reservation != NULL) *got_reservation = false; + got_reservation = false; changed_signal = false; } break; } + if (got_reservation) { + CFollowTrackRail ft(v); + if (ft.Follow(res_dest.tile, res_dest.trackdir)) { + Trackdir new_td = FindFirstTrackdir(ft.m_new_td_bits); + + if (HasLongReservePbsSignalOnTrackdir(v, ft.m_new_tile, new_td)) { + // We reserved up to a LR signal, reserve past it as well. recursion + ChooseTrainTrack(v, ft.m_new_tile, ft.m_exitdir, TrackdirBitsToTrackBits(ft.m_new_td_bits), force_res, NULL, mark_stuck); + } + } + } + TryReserveRailTrack(v->tile, TrackdirToTrack(v->GetVehicleTrackdir())); if (changed_signal) MarkTileDirtyByTile(tile); + if (p_got_reservation != NULL) *p_got_reservation = got_reservation; return best_track; } @@ -2721,7 +2776,7 @@ bool TryPathReserve(Train *v, bool mark_as_stuck, bool first_tile_okay) } /* If we are in a depot, tentatively reserve the depot. */ - if (v->track == TRACK_BIT_DEPOT) { + if (v->track == TRACK_BIT_DEPOT && v->tile == origin.tile) { SetDepotReservation(v->tile, true); if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(v->tile); } @@ -2737,7 +2792,7 @@ bool TryPathReserve(Train *v, bool mark_as_stuck, bool first_tile_okay) if (!res_made) { /* Free the depot reservation as well. */ - if (v->track == TRACK_BIT_DEPOT) SetDepotReservation(v->tile, false); + if (v->track == TRACK_BIT_DEPOT && v->tile == origin.tile) SetDepotReservation(v->tile, false); return false; } @@ -2895,7 +2950,13 @@ static inline void AffectSpeedByZChange(Train *v, int old_z) } } -static bool TrainMovedChangeSignals(TileIndex tile, DiagDirection dir) +enum TrainMovedChangeSignalEnum { + CHANGED_NOTHING, ///< No special signals were changed + CHANGED_NORMAL_TO_PBS_BLOCK, ///< A PBS block with a non-PBS signal facing us + CHANGED_LR_PBS ///< A long reserve PBS signal +}; + +static TrainMovedChangeSignalEnum TrainMovedChangeSignal(Train* v, TileIndex tile, DiagDirection dir) { if (IsTileType(tile, MP_RAILWAY) && GetRailTileType(tile) == RAIL_TILE_SIGNALS) { @@ -2903,10 +2964,13 @@ static bool TrainMovedChangeSignals(TileIndex tile, DiagDirection dir) Trackdir trackdir = FindFirstTrackdir(tracks); if (UpdateSignalsOnSegment(tile, TrackdirToExitdir(trackdir), GetTileOwner(tile)) == SIGSEG_PBS && HasSignalOnTrackdir(tile, trackdir)) { /* A PBS block with a non-PBS signal facing us? */ - if (!IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) return true; + if (!IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) return CHANGED_NORMAL_TO_PBS_BLOCK; + + if (HasLongReservePbsSignalOnTrackdir(v, tile, trackdir)) return CHANGED_LR_PBS; } } - return false; + + return CHANGED_NOTHING; } /** Tries to reserve track under whole train consist. */ @@ -3367,27 +3431,51 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) if (update_signals_crossing) { if (v->IsFrontEngine()) { - if (TrainMovedChangeSignals(gp.new_tile, enterdir)) { - /* We are entering a block with PBS signals right now, but - * not through a PBS signal. This means we don't have a - * reservation right now. As a conventional signal will only - * ever be green if no other train is in the block, getting - * a path should always be possible. If the player built - * such a strange network that it is not possible, the train - * will be marked as stuck and the player has to deal with - * the problem. */ - if ((!HasReservedTracks(gp.new_tile, v->track) && - !TryReserveRailTrack(gp.new_tile, FindFirstTrack(v->track))) || - !TryPathReserve(v)) { - MarkTrainAsStuck(v); - } + switch (TrainMovedChangeSignal(v, gp.new_tile, enterdir)) { + case CHANGED_NORMAL_TO_PBS_BLOCK: + /* We are entering a block with PBS signals right now, but + * not through a PBS signal. This means we don't have a + * reservation right now. As a conventional signal will only + * ever be green if no other train is in the block, getting + * a path should always be possible. If the player built + * such a strange network that it is not possible, the train + * will be marked as stuck and the player has to deal with + * the problem. */ + if ((!HasReservedTracks(gp.new_tile, v->track) && + !TryReserveRailTrack(gp.new_tile, FindFirstTrack(v->track))) || + !TryPathReserve(v)) { + MarkTrainAsStuck(v); + } + + break; + + case CHANGED_LR_PBS: + { + /* We went past a long reserve PBS signal. Try to extend the + * reservation if reserving failed at another LR signal. */ + PBSTileInfo origin = FollowTrainReservation(v); + CFollowTrackRail ft(v); + + if (ft.Follow(origin.tile, origin.trackdir)) { + Trackdir new_td = FindFirstTrackdir(ft.m_new_td_bits); + + if (HasLongReservePbsSignalOnTrackdir(v, ft.m_new_tile, new_td)) { + ChooseTrainTrack(v, ft.m_new_tile, ft.m_exitdir, TrackdirBitsToTrackBits(ft.m_new_td_bits), true, NULL, false); + } + } + + break; + } + + default: + break; } } /* Signals can only change when the first * (above) or the last vehicle moves. */ if (v->Next() == NULL) { - TrainMovedChangeSignals(gp.old_tile, ReverseDiagDir(enterdir)); + TrainMovedChangeSignal(v, gp.old_tile, ReverseDiagDir(enterdir)); if (IsLevelCrossingTile(gp.old_tile)) UpdateLevelCrossing(gp.old_tile); } }