Add reserve through action to trace restrict programs.
This only changes the behaviour of PBS reservations which would otherwise terminate at a PBS signal. If the signal restriction sets the reserve through state, the reservation continues through the signal, and the signal is set to green.
This commit is contained in:
@@ -2413,6 +2413,8 @@ STR_TRACE_RESTRICT_END :End
|
||||
STR_TRACE_RESTRICT_PF_DENY :Deny
|
||||
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_PF_PENALTY :Penalty
|
||||
STR_TRACE_RESTRICT_PF_VALUE_SMALL :small
|
||||
STR_TRACE_RESTRICT_PF_VALUE_MEDIUM :medium
|
||||
|
@@ -97,7 +97,7 @@ private:
|
||||
m_res_fail_td = td;
|
||||
}
|
||||
} else {
|
||||
if (!TryReserveRailTrack(tile, TrackdirToTrack(td))) {
|
||||
if (!TryReserveRailTrackdir(tile, td)) {
|
||||
/* Tile couldn't be reserved, undo. */
|
||||
m_res_fail_tile = tile;
|
||||
m_res_fail_td = td;
|
||||
|
75
src/pbs.cpp
75
src/pbs.cpp
@@ -14,6 +14,7 @@
|
||||
#include "vehicle_func.h"
|
||||
#include "newgrf_station.h"
|
||||
#include "pathfinder/follow_track.hpp"
|
||||
#include "tracerestrict.h"
|
||||
|
||||
#include "safeguards.h"
|
||||
|
||||
@@ -71,6 +72,24 @@ void SetRailStationPlatformReservation(TileIndex start, DiagDirection dir, bool
|
||||
} while (IsCompatibleTrainStationTile(tile, start));
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to reserve a specific track on a tile
|
||||
* This also sets PBS signals to green if reserving through the facing track direction
|
||||
* @param tile the tile
|
||||
* @param t the track
|
||||
* @param trigger_stations whether to call station randomisation trigger
|
||||
* @return \c true if reservation was successful, i.e. the track was
|
||||
* free and didn't cross any other reserved tracks.
|
||||
*/
|
||||
bool TryReserveRailTrackdir(TileIndex tile, Trackdir td, bool trigger_stations)
|
||||
{
|
||||
bool success = TryReserveRailTrack(tile, TrackdirToTrack(td), trigger_stations);
|
||||
if (success && HasPbsSignalOnTrackdir(tile, td)) {
|
||||
SetSignalStateByTrackdir(tile, td, SIGNAL_STATE_GREEN);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to reserve a specific track on a tile
|
||||
* @param tile the tile
|
||||
@@ -370,6 +389,46 @@ Train *GetTrainForReservation(TileIndex tile, Track track)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 *)
|
||||
{
|
||||
// scan forwards from vehicle position, for the case that train is waiting at/approaching PBS signal
|
||||
|
||||
TileIndex tile = v->tile;
|
||||
Trackdir trackdir = v->GetVehicleTrackdir();
|
||||
|
||||
CFollowTrackRail ft(v);
|
||||
|
||||
for (;;) {
|
||||
if (IsTileType(tile, MP_RAILWAY) && HasSignalOnTrackdir(tile, trackdir)) {
|
||||
if (HasPbsSignalOnTrackdir(tile, trackdir)) {
|
||||
// found PBS signal
|
||||
return tile;
|
||||
} else {
|
||||
// wrong type of signal
|
||||
return INVALID_TILE;
|
||||
}
|
||||
}
|
||||
|
||||
// advance to next tile
|
||||
if (!ft.Follow(tile, trackdir)) {
|
||||
// ran out of track
|
||||
return INVALID_TILE;
|
||||
}
|
||||
|
||||
if (KillFirstBit(ft.m_new_td_bits) != TRACKDIR_BIT_NONE) {
|
||||
// reached a junction tile
|
||||
return INVALID_TILE;
|
||||
}
|
||||
|
||||
tile = ft.m_new_tile;
|
||||
trackdir = FindFirstTrackdir(ft.m_new_td_bits);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether a certain track on a tile is a safe position to end a path.
|
||||
*
|
||||
@@ -405,8 +464,20 @@ bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bo
|
||||
|
||||
if (ft.m_new_td_bits != TRACKDIR_BIT_NONE && KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE) {
|
||||
Trackdir td = FindFirstTrackdir(ft.m_new_td_bits);
|
||||
/* PBS signal on next trackdir? Safe position. */
|
||||
if (HasPbsSignalOnTrackdir(ft.m_new_tile, td)) return true;
|
||||
/* PBS signal on next trackdir? Conditionally safe position. */
|
||||
if (HasPbsSignalOnTrackdir(ft.m_new_tile, td)) {
|
||||
if (IsRestrictedSignal(ft.m_new_tile)) {
|
||||
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(ft.m_new_tile, TrackdirToTrack(td));
|
||||
if (prog) {
|
||||
TraceRestrictProgramResult out;
|
||||
prog->Execute(v, TraceRestrictProgramInput(tile, trackdir, &IsSafeWaitingPositionTraceRestrictPreviousSignalCallback, nullptr), out);
|
||||
if (out.flags & TRPRF_RESERVE_THROUGH) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/* One-way PBS signal against us? Safe if end-of-line is allowed. */
|
||||
if (IsTileType(ft.m_new_tile, MP_RAILWAY) && HasSignalOnTrackdir(ft.m_new_tile, ReverseTrackdir(td)) &&
|
||||
GetSignalType(ft.m_new_tile, TrackdirToTrack(td)) == SIGTYPE_PBS_ONEWAY) {
|
||||
|
@@ -22,6 +22,7 @@ TrackBits GetReservedTrackbits(TileIndex t);
|
||||
void SetRailStationPlatformReservation(TileIndex start, DiagDirection dir, bool b);
|
||||
|
||||
bool TryReserveRailTrack(TileIndex tile, Track t, bool trigger_stations = true);
|
||||
bool TryReserveRailTrackdir(TileIndex tile, Trackdir td, bool trigger_stations = true);
|
||||
void UnreserveRailTrack(TileIndex tile, Track t);
|
||||
|
||||
/** This struct contains information about the end of a reserved path. */
|
||||
|
@@ -382,6 +382,14 @@ void TraceRestrictProgram::Execute(const Train* v, const TraceRestrictProgramInp
|
||||
}
|
||||
break;
|
||||
|
||||
case TRIT_RESERVE_THROUGH:
|
||||
if (GetTraceRestrictValue(item)) {
|
||||
out.flags &= ~TRPRF_RESERVE_THROUGH;
|
||||
} else {
|
||||
out.flags |= TRPRF_RESERVE_THROUGH;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
}
|
||||
@@ -502,6 +510,7 @@ void SetTraceRestrictValueDefault(TraceRestrictItem &item, TraceRestrictValueTyp
|
||||
case TRVT_DENY:
|
||||
case TRVT_SPEED:
|
||||
case TRVT_TILE_INDEX:
|
||||
case TRVT_RESERVE_THROUGH:
|
||||
SetTraceRestrictValue(item, 0);
|
||||
SetTraceRestrictAuxField(item, 0);
|
||||
break;
|
||||
|
@@ -97,6 +97,7 @@ enum TraceRestrictItemType {
|
||||
TRIT_NULL = 0, ///< Null-type, not in programs and not valid for execution, mainly used with TraceRestrictNullTypeSpecialValue for start/end
|
||||
TRIT_PF_DENY = 1, ///< Pathfinder deny/allow
|
||||
TRIT_PF_PENALTY = 2, ///< Add to pathfinder penalty
|
||||
TRIT_RESERVE_THROUGH = 3, ///< Reserve through PBS signal
|
||||
|
||||
TRIT_COND_BEGIN = 8, ///< Start of conditional item types, note that this has the save value as TRIT_COND_ENDIF
|
||||
TRIT_COND_ENDIF = 8, ///< This is an endif block or an else block
|
||||
@@ -192,6 +193,7 @@ enum TraceRestrictPathfinderPenaltyPresetIndex {
|
||||
*/
|
||||
enum TraceRestrictProgramResultFlags {
|
||||
TRPRF_DENY = 1 << 0, ///< Pathfinder deny is set
|
||||
TRPRF_RESERVE_THROUGH = 1 << 1, ///< Reserve through is set
|
||||
};
|
||||
DECLARE_ENUM_AS_BIT_SET(TraceRestrictProgramResultFlags)
|
||||
|
||||
@@ -392,6 +394,7 @@ enum TraceRestrictValueType {
|
||||
TRVT_DIRECTION = 7, ///< takes a TraceRestrictDirectionTypeSpecialValue
|
||||
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
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -463,6 +466,8 @@ static inline TraceRestrictTypePropertySet GetTraceRestrictTypeProperties(TraceR
|
||||
out.value_type = TRVT_PF_PENALTY;
|
||||
} else if (GetTraceRestrictType(item) == TRIT_PF_DENY) {
|
||||
out.value_type = TRVT_DENY;
|
||||
} else if (GetTraceRestrictType(item) == TRIT_RESERVE_THROUGH) {
|
||||
out.value_type = TRVT_RESERVE_THROUGH;
|
||||
} else {
|
||||
out.value_type = TRVT_NONE;
|
||||
}
|
||||
|
@@ -119,6 +119,7 @@ static const StringID _program_insert_str[] = {
|
||||
STR_TRACE_RESTRICT_CONDITIONAL_ELSE,
|
||||
STR_TRACE_RESTRICT_PF_DENY,
|
||||
STR_TRACE_RESTRICT_PF_PENALTY,
|
||||
STR_TRACE_RESTRICT_RESERVE_THROUGH,
|
||||
INVALID_STRING_ID
|
||||
};
|
||||
static const uint32 _program_insert_else_hide_mask = 8; ///< disable bitmask for else
|
||||
@@ -131,6 +132,7 @@ static const uint _program_insert_val[] = {
|
||||
TRIT_COND_ENDIF | (TRCF_ELSE << 16), // else block
|
||||
TRIT_PF_DENY, // deny
|
||||
TRIT_PF_PENALTY, // penalty
|
||||
TRIT_RESERVE_THROUGH, // reserve through
|
||||
};
|
||||
|
||||
/** insert drop down list strings and values */
|
||||
@@ -153,6 +155,21 @@ static const TraceRestrictDropDownListSet _deny_value = {
|
||||
_deny_value_str, _deny_value_val,
|
||||
};
|
||||
|
||||
static const StringID _reserve_through_value_str[] = {
|
||||
STR_TRACE_RESTRICT_RESERVE_THROUGH,
|
||||
STR_TRACE_RESTRICT_RESERVE_THROUGH_CANCEL,
|
||||
INVALID_STRING_ID
|
||||
};
|
||||
static const uint _reserve_through_value_val[] = {
|
||||
0,
|
||||
1,
|
||||
};
|
||||
|
||||
/** value drop down list for deny types strings and values */
|
||||
static const TraceRestrictDropDownListSet _reserve_through_value = {
|
||||
_reserve_through_value_str, _reserve_through_value_val,
|
||||
};
|
||||
|
||||
static const StringID _direction_value_str[] = {
|
||||
STR_TRACE_RESTRICT_DIRECTION_FRONT,
|
||||
STR_TRACE_RESTRICT_DIRECTION_BACK,
|
||||
@@ -211,11 +228,13 @@ static const TraceRestrictDropDownListSet *GetTypeDropDownListSet(TraceRestrictI
|
||||
static const StringID str_action[] = {
|
||||
STR_TRACE_RESTRICT_PF_DENY,
|
||||
STR_TRACE_RESTRICT_PF_PENALTY,
|
||||
STR_TRACE_RESTRICT_RESERVE_THROUGH,
|
||||
INVALID_STRING_ID,
|
||||
};
|
||||
static const uint val_action[] = {
|
||||
TRIT_PF_DENY,
|
||||
TRIT_PF_PENALTY,
|
||||
TRIT_RESERVE_THROUGH,
|
||||
};
|
||||
static const TraceRestrictDropDownListSet set_action = {
|
||||
str_action, val_action,
|
||||
@@ -642,6 +661,10 @@ static void DrawInstructionString(const TraceRestrictProgram *prog, TraceRestric
|
||||
}
|
||||
break;
|
||||
|
||||
case TRIT_RESERVE_THROUGH:
|
||||
instruction_string = GetTraceRestrictValue(item) ? STR_TRACE_RESTRICT_RESERVE_THROUGH_CANCEL : STR_TRACE_RESTRICT_RESERVE_THROUGH;
|
||||
break;
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
break;
|
||||
@@ -843,6 +866,10 @@ public:
|
||||
this->ShowDropDownListWithValue(&_pf_penalty_dropdown, GetPathfinderPenaltyDropdownIndex(item), false, TR_WIDGET_VALUE_DROPDOWN, 0, 0, 0);
|
||||
break;
|
||||
|
||||
case TRVT_RESERVE_THROUGH:
|
||||
this->ShowDropDownListWithValue(&_reserve_through_value, GetTraceRestrictValue(item), false, TR_WIDGET_VALUE_DROPDOWN, 0, 0, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1581,6 +1608,13 @@ private:
|
||||
}
|
||||
break;
|
||||
|
||||
case TRVT_RESERVE_THROUGH:
|
||||
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_RESERVE_THROUGH_CANCEL : STR_TRACE_RESTRICT_RESERVE_THROUGH;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@@ -2386,7 +2386,7 @@ static PBSTileInfo ExtendTrainReservation(const Train *v, TrackBits *new_tracks,
|
||||
return PBSTileInfo(tile, cur_td, true);
|
||||
}
|
||||
|
||||
if (!TryReserveRailTrack(tile, TrackdirToTrack(cur_td))) break;
|
||||
if (!TryReserveRailTrackdir(tile, cur_td)) break;
|
||||
}
|
||||
|
||||
if (ft.m_err == CFollowTrackRail::EC_OWNER || ft.m_err == CFollowTrackRail::EC_NO_WAY) {
|
||||
|
Reference in New Issue
Block a user