Tracerestrict: Import "Long Reserve" feature.

https://github.com/KeldorKatarn/OpenTTD_PatchPack

Minor code de-duplications.
pull/6/merge
patch-import 9 years ago committed by Jonathan G Rennison
parent b5b06351ac
commit 82cab7f31c

@ -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

@ -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;
}

@ -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<TraceRestrictItem>
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;

@ -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;
}

@ -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<NWidgetCore>(TR_WIDGET_VALUE_DROPDOWN)->widget_data =
GetTraceRestrictValue(item) ? STR_TRACE_RESTRICT_LONG_RESERVE_CANCEL : STR_TRACE_RESTRICT_LONG_RESERVE;
break;
default:
break;
}

@ -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};
@ -2334,12 +2336,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;
@ -2518,8 +2522,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;
@ -2527,7 +2560,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));
@ -2548,10 +2582,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);
@ -2559,11 +2594,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.
@ -2607,28 +2649,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)) {
@ -2649,26 +2691,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;
}
@ -2719,7 +2774,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);
}
@ -2735,7 +2790,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;
}
@ -2893,7 +2948,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) {
@ -2901,10 +2962,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. */
@ -3365,27 +3429,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);
}
}

Loading…
Cancel
Save