Allow placing routing restrictions on tunnel/bridge entrance/exit signals
No reserve through support
This commit is contained in:
@@ -1735,6 +1735,7 @@
|
||||
<ul>
|
||||
<li>m2 bit 15: for bridge entrances only: storage for visual red/green state of signals starting from 15 is allocated outside the map array</li>
|
||||
<li>m2 bits 14..4: for bridge entrances only: for signals 0..10 on bridge, signal is visually red if corresponding bit in 4..14 is set</li>
|
||||
<li>m3 bit 6: the entrance and/or exit signals on this tile are restricted (tracerestrict patch)</li>
|
||||
<li>m3 bits 5..3: entrance signal aspect (only valid if signal is present and not red, and multi-aspect signalling is in effect)</li>
|
||||
<li>m3 bits 2..0: exit signal aspect (only valid if signal is present and not red, and multi-aspect signalling is in effect)</li>
|
||||
<li>m6 bit 7: set = exit signal shows green, clear = exit signal shows red</li>
|
||||
|
@@ -287,7 +287,7 @@ the array so you can quickly see what is used and what is not.
|
||||
<td class="caption">tunnel entrance</td>
|
||||
<td class="bits" rowspan=3><span class="free">OOO</span> <span class="used" title="Owner">XXXXX</span></td>
|
||||
<td class="bits"><span class="patch-pool" title="Tunnel index on pool (or overflow sentinel)">PPPP PPPP PPPP PPPP</span></td>
|
||||
<td class="bits" rowspan=4><span class="rearrange" title="Owner of tram (road only; a rearrangement can free some of these bits)">XXXX</span> <span class="free">OOOO</span><br /><span class="free">OO</span> <span class="patch" title="Entrance/exit signal aspects (rail only)">PPPPPP</span></td>
|
||||
<td class="bits" rowspan=4><span class="rearrange" title="Owner of tram (road only; a rearrangement can free some of these bits)">XXXX</span> <span class="free">OOOO</span><br /><span class="free">O</span><span class="patch" title="Routing restrictions present on entrance/exit signal(s)">P</span> <span class="patch" title="Entrance/exit signal aspects (rail only)">PPPPPP</span></td>
|
||||
<td class="bits"><span class="free">OO</span><span class="used" title="Road type">XX XXXX</span></td>
|
||||
<td class="bits"><span class="used" title="Bridge or tunnel bit">O</span><span class="patch" title="Signal simulation mode (rail only)">PP</span><span class="rearrange" title="PBS reservation (rail; a rearrangement can free some of these bits)">X</span> <span class="used" title="Transport type">XX</span> <span class="used" title="Direction of the tunnel/bridge">XX</span></td>
|
||||
<td class="bits"><span class="patch" title="PBS mode, exit signal state">PP</span><span class="free">OO OO</span><span class="patch" title="Semaphore/light mode, entrance signal state">PP</span></td>
|
||||
|
@@ -572,6 +572,7 @@ void DumpMapStats(char *b, const char *last)
|
||||
if (IsTunnelBridgeWithSignalSimulation(t)) {
|
||||
bucket |= TBB_SIGNALLED;
|
||||
if (IsTunnelBridgeSignalSimulationBidirectional(t)) bucket |= TBB_SIGNALLED_BIDI;
|
||||
if (IsTunnelBridgeRestrictedSignal(t)) restricted_signals++;
|
||||
}
|
||||
if (GetTunnelBridgeTransportType(t) == TRANSPORT_ROAD) {
|
||||
if (HasTileRoadType(t, RTT_ROAD)) bucket |= TBB_ROAD;
|
||||
|
@@ -176,6 +176,13 @@ private:
|
||||
IsRestrictedSignal(tile);
|
||||
}
|
||||
|
||||
// returns true if ExecuteTunnelBridgeTraceRestrict should be called
|
||||
inline bool ShouldCheckTunnelBridgeTraceRestrict(Node& n, TileIndex tile)
|
||||
{
|
||||
return n.m_num_signals_passed < m_sig_look_ahead_costs.size() &&
|
||||
IsTunnelBridgeRestrictedSignal(tile);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -312,6 +319,22 @@ private:
|
||||
return false;
|
||||
}
|
||||
|
||||
// returns true if dead end bit has been set
|
||||
inline bool ExecuteTunnelBridgeTraceRestrict(Node& n, TileIndex tile, Trackdir trackdir, int& cost, TraceRestrictProgramResult &out)
|
||||
{
|
||||
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(tile, TrackdirToTrack(trackdir));
|
||||
TraceRestrictProgramActionsUsedFlags flags_to_check = TRPAUF_PF;
|
||||
if (prog && prog->actions_used_flags & flags_to_check) {
|
||||
prog->Execute(Yapf().GetVehicle(), TraceRestrictProgramInput(tile, trackdir, &TraceRestrictPreviousSignalCallback, &n), out);
|
||||
if (out.flags & TRPRF_DENY) {
|
||||
n.m_segment->m_end_segment_reason |= ESRB_DEAD_END;
|
||||
return true;
|
||||
}
|
||||
cost += out.penalty;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
int SignalCost(Node &n, TileIndex tile, Trackdir trackdir)
|
||||
{
|
||||
@@ -417,17 +440,27 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
if (IsTileType(tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExitOnly(tile) && TrackdirEntersTunnelBridge(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;
|
||||
}
|
||||
if (IsTileType(tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExit(tile) && IsTunnelBridgeEffectivelyPBS(tile) && TrackdirExitsTunnelBridge(tile, trackdir)) {
|
||||
/* Exiting a PBS signalled tunnel/bridge, record the last non-reserve through signal */
|
||||
n.m_last_non_reserve_through_signal_tile = tile;
|
||||
n.m_last_non_reserve_through_signal_td = trackdir;
|
||||
}
|
||||
if (n.flags_u.flags_s.m_reverse_pending && IsTileType(tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationEntrance(tile)) {
|
||||
n.m_segment->m_end_segment_reason |= ESRB_SAFE_TILE;
|
||||
if (IsTunnelBridgeWithSignalSimulation(tile)) {
|
||||
const bool entering = TrackdirEntersTunnelBridge(tile, trackdir);
|
||||
const bool exiting = TrackdirExitsTunnelBridge(tile, trackdir);
|
||||
if (IsTunnelBridgeSignalSimulationExitOnly(tile) && entering) {
|
||||
/* 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;
|
||||
}
|
||||
if (IsTunnelBridgeSignalSimulationExit(tile) && IsTunnelBridgeEffectivelyPBS(tile) && exiting) {
|
||||
/* Exiting a PBS signalled tunnel/bridge, record the last non-reserve through signal */
|
||||
n.m_last_non_reserve_through_signal_tile = tile;
|
||||
n.m_last_non_reserve_through_signal_td = trackdir;
|
||||
}
|
||||
if (ShouldCheckTunnelBridgeTraceRestrict(n, tile)) {
|
||||
TraceRestrictProgramResult out;
|
||||
if (ExecuteTunnelBridgeTraceRestrict(n, tile, trackdir, cost, out)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (n.flags_u.flags_s.m_reverse_pending && entering && IsTunnelBridgeSignalSimulationEntrance(tile)) {
|
||||
n.m_segment->m_end_segment_reason |= ESRB_SAFE_TILE;
|
||||
}
|
||||
}
|
||||
return cost;
|
||||
}
|
||||
|
85
src/pbs.cpp
85
src/pbs.cpp
@@ -353,6 +353,39 @@ static int LookaheadTileHeightForChunnel(int length, int offset)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint16 ApplyTunnelBridgeLookaheadSignalSpeedRestriction(TileIndex tile, Trackdir trackdir, const Train *v,
|
||||
uint16 initial_speed_restriction, TrainReservationLookAhead *lookahead, int offset, int16 z)
|
||||
{
|
||||
uint16 speed_restriction = initial_speed_restriction;
|
||||
|
||||
if (v != nullptr && IsTunnelBridgeRestrictedSignal(tile)) {
|
||||
if (trackdir == INVALID_TRACKDIR) {
|
||||
trackdir = GetTunnelBridgeExitTrackdir(tile);
|
||||
}
|
||||
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(tile, TrackdirToTrack(trackdir));
|
||||
if (prog && prog->actions_used_flags & TRPAUF_SPEED_RESTRICTION) {
|
||||
TraceRestrictProgramResult out;
|
||||
TraceRestrictProgramInput input(tile, trackdir, nullptr, nullptr);
|
||||
prog->Execute(v, input, out);
|
||||
if (out.flags & TRPRF_SPEED_RESTRICTION_SET) {
|
||||
int duration;
|
||||
if (TrackdirEntersTunnelBridge(tile, trackdir)) {
|
||||
duration = 4 + (IsDiagonalTrackdir(trackdir) ? 16 : 8);
|
||||
} else {
|
||||
duration = 4;
|
||||
}
|
||||
lookahead->AddSpeedRestriction(out.speed_restriction, offset, duration, z);
|
||||
if (out.speed_restriction != 0 && (speed_restriction == 0 || out.speed_restriction < speed_restriction)) {
|
||||
/* lower of the speed restrictions before or after the signal */
|
||||
speed_restriction = out.speed_restriction;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return speed_restriction;
|
||||
}
|
||||
|
||||
/** Follow a reservation starting from a specific tile to the end. */
|
||||
static PBSTileInfo FollowReservation(Owner o, RailTypes rts, TileIndex tile, Trackdir trackdir, FollowReservationFlags flags, const Train *v, TrainReservationLookAhead *lookahead)
|
||||
{
|
||||
@@ -525,8 +558,10 @@ static PBSTileInfo FollowReservation(Owner o, RailTypes rts, TileIndex tile, Tra
|
||||
const int spacing = GetTunnelBridgeSignalSimulationSpacing(tile);
|
||||
const int signals = length / spacing;
|
||||
|
||||
uint16 speed_restriction = ApplyTunnelBridgeLookaheadSignalSpeedRestriction(tile, trackdir, v, lookahead->speed_restriction, lookahead, 0, z);
|
||||
|
||||
uint16 signal_speed = GetRailTypeInfo(rt)->max_speed;
|
||||
if (signal_speed == 0 || (lookahead->speed_restriction != 0 && lookahead->speed_restriction < signal_speed)) signal_speed = lookahead->speed_restriction;
|
||||
if (signal_speed == 0 || (speed_restriction != 0 && speed_restriction < signal_speed)) signal_speed = speed_restriction;
|
||||
if (signal_speed == 0 || (bridge_speed != 0 && bridge_speed < signal_speed)) signal_speed = bridge_speed;
|
||||
|
||||
/* Entrance signal */
|
||||
@@ -548,7 +583,16 @@ static PBSTileInfo FollowReservation(Owner o, RailTypes rts, TileIndex tile, Tra
|
||||
}
|
||||
|
||||
/* Exit signal */
|
||||
const int end_offset = start_offset + (TILE_SIZE * length) /* + ((DiagDirToDiagTrackBits(GetTunnelBridgeDirection(end)) & GetTunnelBridgeTrackBits(end)) ? 16 : 8)*/;
|
||||
const int end_offset = start_offset + (TILE_SIZE * length);
|
||||
|
||||
uint16 exit_speed_restriction = ApplyTunnelBridgeLookaheadSignalSpeedRestriction(end, INVALID_TRACKDIR, v, lookahead->speed_restriction, lookahead, end_offset, z);
|
||||
if (exit_speed_restriction != speed_restriction) {
|
||||
speed_restriction = exit_speed_restriction;
|
||||
signal_speed = GetRailTypeInfo(rt)->max_speed;
|
||||
if (signal_speed == 0 || (speed_restriction != 0 && speed_restriction < signal_speed)) signal_speed = speed_restriction;
|
||||
if (signal_speed == 0 || (bridge_speed != 0 && bridge_speed < signal_speed)) signal_speed = bridge_speed;
|
||||
}
|
||||
|
||||
lookahead->AddSignal(signal_speed, end_offset, z);
|
||||
|
||||
lookahead->SetNextExtendPositionIfUnset();
|
||||
@@ -580,7 +624,7 @@ static PBSTileInfo FollowReservation(Owner o, RailTypes rts, TileIndex tile, Tra
|
||||
lookahead->AddReverse(z);
|
||||
}
|
||||
if (out.flags & TRPRF_SPEED_RESTRICTION_SET) {
|
||||
lookahead->AddSpeedRestriction(out.speed_restriction, z);
|
||||
lookahead->AddSpeedRestriction(out.speed_restriction, 0, 0, z);
|
||||
if (out.speed_restriction != 0 && (speed_restriction == 0 || out.speed_restriction < speed_restriction)) {
|
||||
/* lower of the speed restrictions before or after the signal */
|
||||
speed_restriction = out.speed_restriction;
|
||||
@@ -869,12 +913,14 @@ void TryCreateLookAheadForTrainInTunnelBridge(Train *t)
|
||||
if (IsTunnel(t->tile) && Tunnel::GetByTile(t->tile)->is_chunnel) SetBit(t->lookahead->flags, TRLF_CHUNNEL);
|
||||
|
||||
if (IsTunnelBridgeSignalSimulationEntrance(t->tile)) {
|
||||
uint16 bridge_speed = IsBridge(t->tile) ? GetBridgeSpec(GetBridgeType(t->tile))->speed : 0;
|
||||
const int length = GetTunnelBridgeLength(t->tile, GetOtherTunnelBridgeEnd(t->tile));
|
||||
const uint16 bridge_speed = IsBridge(t->tile) ? GetBridgeSpec(GetBridgeType(t->tile))->speed : 0;
|
||||
const TileIndex end = GetOtherTunnelBridgeEnd(t->tile);
|
||||
const int length = GetTunnelBridgeLength(t->tile, end);
|
||||
const int spacing = GetTunnelBridgeSignalSimulationSpacing(t->tile);
|
||||
const int signals = length / spacing;
|
||||
|
||||
uint16 signal_speed = GetRailTypeInfo(GetRailTypeByTrack(t->tile, TrackdirToTrack(t->lookahead->reservation_end_trackdir)))->max_speed;
|
||||
const RailType rt = GetRailTypeByTrack(t->tile, TrackdirToTrack(t->lookahead->reservation_end_trackdir));
|
||||
uint16 signal_speed = GetRailTypeInfo(rt)->max_speed;
|
||||
if (signal_speed == 0 || (t->speed_restriction != 0 && t->speed_restriction < signal_speed)) signal_speed = t->speed_restriction;
|
||||
if (signal_speed == 0 || (bridge_speed != 0 && bridge_speed < signal_speed)) signal_speed = bridge_speed;
|
||||
|
||||
@@ -889,6 +935,14 @@ void TryCreateLookAheadForTrainInTunnelBridge(Train *t)
|
||||
|
||||
/* Exit signal */
|
||||
const int end_offset = TILE_SIZE * length;
|
||||
|
||||
uint16 exit_speed_restriction = ApplyTunnelBridgeLookaheadSignalSpeedRestriction(end, INVALID_TRACKDIR, t, t->speed_restriction, t->lookahead.get(), end_offset, z);
|
||||
if (exit_speed_restriction != t->speed_restriction) {
|
||||
signal_speed = GetRailTypeInfo(rt)->max_speed;
|
||||
if (signal_speed == 0 || (exit_speed_restriction != 0 && exit_speed_restriction < signal_speed)) signal_speed = exit_speed_restriction;
|
||||
if (signal_speed == 0 || (bridge_speed != 0 && bridge_speed < signal_speed)) signal_speed = bridge_speed;
|
||||
}
|
||||
|
||||
t->lookahead->AddSignal(signal_speed, end_offset, z);
|
||||
|
||||
t->lookahead->SetNextExtendPositionIfUnset();
|
||||
@@ -1157,10 +1211,8 @@ bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bo
|
||||
if (HasSignalOnTrackdir(tile, trackdir) && !IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) return true;
|
||||
}
|
||||
|
||||
if (IsRailTunnelBridgeTile(tile) && IsTrackAcrossTunnelBridge(tile, TrackdirToTrack(trackdir))) {
|
||||
if (IsTunnelBridgeSignalSimulationEntrance(tile)) {
|
||||
return true;
|
||||
}
|
||||
if (IsTunnelBridgeSignalSimulationEntranceTile(tile) && IsTrackAcrossTunnelBridge(tile, TrackdirToTrack(trackdir))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Check next tile. For performance reasons, we check for 90 degree turns ourself. */
|
||||
@@ -1229,8 +1281,8 @@ 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;
|
||||
|
||||
auto pbs_res_end_wait_test = [v, restricted_signal_info](TileIndex t, Trackdir td) -> bool {
|
||||
if (IsRestrictedSignal(t)) {
|
||||
auto pbs_res_end_wait_test = [v, restricted_signal_info](TileIndex t, Trackdir td, bool tunnel_bridge) -> bool {
|
||||
if (tunnel_bridge ? IsTunnelBridgeRestrictedSignal(t) : IsRestrictedSignal(t)) {
|
||||
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(t, TrackdirToTrack(td));
|
||||
if (restricted_signal_info && prog) {
|
||||
restricted_signal_info->tile = t;
|
||||
@@ -1250,11 +1302,12 @@ bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bo
|
||||
};
|
||||
|
||||
if (IsTileType(tile, MP_RAILWAY) && HasSignalOnTrackdir(tile, trackdir) && !IsPbsSignal(GetSignalType(tile, track))) {
|
||||
return pbs_res_end_wait_test(tile, trackdir);
|
||||
return pbs_res_end_wait_test(tile, trackdir, false);
|
||||
}
|
||||
|
||||
if (IsTunnelBridgeSignalSimulationEntranceTile(tile) && IsTrackAcrossTunnelBridge(tile, TrackdirToTrack(trackdir))) {
|
||||
if (IsTunnelBridgeSignalSimulationBidirectional(tile)) {
|
||||
bool free = pbs_res_end_wait_test(tile, trackdir, true);
|
||||
if (free && IsTunnelBridgeSignalSimulationBidirectional(tile)) {
|
||||
TileIndex other_end = GetOtherTunnelBridgeEnd(tile);
|
||||
if (HasAcrossTunnelBridgeReservation(other_end) && GetTunnelBridgeExitSignalState(other_end) == SIGNAL_STATE_RED) return false;
|
||||
Direction dir = DiagDirToDir(GetTunnelBridgeDirection(other_end));
|
||||
@@ -1267,7 +1320,7 @@ bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bo
|
||||
return nullptr;
|
||||
})) return false;
|
||||
}
|
||||
return true;
|
||||
return free;
|
||||
}
|
||||
|
||||
/* Check the next tile, if it's a PBS signal, it has to be free as well. */
|
||||
@@ -1285,7 +1338,7 @@ bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bo
|
||||
Trackdir td = FindFirstTrackdir(ft.m_new_td_bits);
|
||||
/* PBS signal on next trackdir? */
|
||||
if (HasPbsSignalOnTrackdir(ft.m_new_tile, td)) {
|
||||
return pbs_res_end_wait_test(ft.m_new_tile, td);
|
||||
return pbs_res_end_wait_test(ft.m_new_tile, td, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -114,10 +114,10 @@ struct TrainReservationLookAhead {
|
||||
this->items.push_back({ end + offset, end + offset + duration, z_pos, speed, TRLIT_TRACK_SPEED });
|
||||
}
|
||||
|
||||
void AddSpeedRestriction(uint16 speed, int16 z_pos)
|
||||
void AddSpeedRestriction(uint16 speed, int offset, int duration, int16 z_pos)
|
||||
{
|
||||
int end = this->RealEndPosition();
|
||||
this->items.push_back({ end, end, z_pos, speed, TRLIT_SPEED_RESTRICTION });
|
||||
this->items.push_back({ end + offset, end + offset + duration, z_pos, speed, TRLIT_SPEED_RESTRICTION });
|
||||
this->speed_restriction = speed;
|
||||
}
|
||||
|
||||
|
@@ -2110,6 +2110,7 @@ CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1
|
||||
}
|
||||
}
|
||||
if (flags & DC_EXEC) {
|
||||
Track end_track = FindFirstTrack(GetAcrossTunnelBridgeTrackBits(end));
|
||||
Company *c = Company::Get(GetTileOwner(tile));
|
||||
c->infrastructure.signal -= GetTunnelBridgeSignalSimulationSignalCount(tile, end);
|
||||
ClearBridgeTunnelSignalSimulation(end, tile);
|
||||
@@ -2118,7 +2119,9 @@ CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1
|
||||
AddSideToSignalBuffer(tile, INVALID_DIAGDIR, GetTileOwner(tile));
|
||||
AddSideToSignalBuffer(end, INVALID_DIAGDIR, GetTileOwner(tile));
|
||||
YapfNotifyTrackLayoutChange(tile, track);
|
||||
YapfNotifyTrackLayoutChange(end, track);
|
||||
YapfNotifyTrackLayoutChange(end, end_track);
|
||||
TraceRestrictNotifySignalRemoval(tile, track);
|
||||
TraceRestrictNotifySignalRemoval(end, end_track);
|
||||
DirtyCompanyInfrastructureWindows(GetTileOwner(tile));
|
||||
for (Train *v : re_reserve_trains) {
|
||||
ReReserveTrainPath(v);
|
||||
|
@@ -248,6 +248,9 @@ static void GenericPlaceSignals(TileIndex tile)
|
||||
if (IsPlainRailTile(tile) && HasTrack(tile, track) && HasSignalOnTrack(tile, track)) {
|
||||
ShowTraceRestrictProgramWindow(tile, track);
|
||||
}
|
||||
if (IsTunnelBridgeWithSignalSimulation(tile) && HasTrack(GetAcrossTunnelBridgeTrackBits(tile), track)) {
|
||||
ShowTraceRestrictProgramWindow(tile, track);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -3971,6 +3971,14 @@ bool AfterLoadGame()
|
||||
}
|
||||
}
|
||||
|
||||
if (SlXvIsFeatureMissing(XSLFI_TRACE_RESTRICT_TUNBRIDGE)) {
|
||||
for (TileIndex t = 0; t < map_size; t++) {
|
||||
if (IsTileType(t, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL && IsTunnelBridgeWithSignalSimulation(t)) {
|
||||
SetTunnelBridgeRestrictedSignal(t, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InitializeRoadGUI();
|
||||
|
||||
/* This needs to be done after conversion. */
|
||||
|
@@ -80,6 +80,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
|
||||
{ XSLFI_TRACE_RESTRICT_BRKCND, XSCF_NULL, 2, 2, "tracerestrict_braking_cond",nullptr, nullptr, nullptr },
|
||||
{ XSLFI_TRACE_RESTRICT_CTGRYCND,XSCF_NULL, 1, 1, "tracerestrict_ctgry_cond", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_TRACE_RESTRICT_PENCTRL, XSCF_NULL, 1, 1, "tracerestrict_pfpenctrl", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_TRACE_RESTRICT_TUNBRIDGE,XSCF_NULL, 1, 1, "tracerestrict_sigtunbridge",nullptr, nullptr, nullptr },
|
||||
{ XSLFI_PROG_SIGS, XSCF_NULL, 2, 2, "programmable_signals", nullptr, nullptr, "SPRG" },
|
||||
{ XSLFI_ADJACENT_CROSSINGS, XSCF_NULL, 1, 1, "adjacent_crossings", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_SAFER_CROSSINGS, XSCF_NULL, 1, 1, "safer_crossings", nullptr, nullptr, nullptr },
|
||||
|
@@ -34,6 +34,7 @@ enum SlXvFeatureIndex {
|
||||
XSLFI_TRACE_RESTRICT_BRKCND, ///< Trace restrict: realistic braking related conditionals
|
||||
XSLFI_TRACE_RESTRICT_CTGRYCND, ///< Trace restrict: category conditionals
|
||||
XSLFI_TRACE_RESTRICT_PENCTRL, ///< Trace restrict: PF penalty control
|
||||
XSLFI_TRACE_RESTRICT_TUNBRIDGE, ///< Trace restrict: restricted signalled tunnel/bridge support
|
||||
XSLFI_PROG_SIGS, ///< programmable pre-signals patch
|
||||
XSLFI_ADJACENT_CROSSINGS, ///< Adjacent level crossings closure patch
|
||||
XSLFI_SAFER_CROSSINGS, ///< Safer level crossings
|
||||
|
@@ -1124,7 +1124,18 @@ void TraceRestrictSetIsSignalRestrictedBit(TileIndex t)
|
||||
TraceRestrictMapping::iterator upper_bound = _tracerestrictprogram_mapping.lower_bound(MakeTraceRestrictRefId(t + 1, static_cast<Track>(0)));
|
||||
|
||||
// If iterators are the same, there are no mappings for this tile
|
||||
SetRestrictedSignal(t, lower_bound != upper_bound);
|
||||
switch (GetTileType(t)) {
|
||||
case MP_RAILWAY:
|
||||
SetRestrictedSignal(t, lower_bound != upper_bound);
|
||||
break;
|
||||
|
||||
case MP_TUNNELBRIDGE:
|
||||
SetTunnelBridgeRestrictedSignal(t, lower_bound != upper_bound);
|
||||
break;
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1251,11 +1262,27 @@ void TraceRestrictDoCommandP(TileIndex tile, Track track, TraceRestrictDoCommand
|
||||
static CommandCost TraceRestrictCheckTileIsUsable(TileIndex tile, Track track)
|
||||
{
|
||||
// Check that there actually is a signal here
|
||||
if (!IsPlainRailTile(tile) || !HasTrack(tile, track)) {
|
||||
return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
|
||||
}
|
||||
if (!HasSignalOnTrack(tile, track)) {
|
||||
return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS);
|
||||
switch (GetTileType(tile)) {
|
||||
case MP_RAILWAY:
|
||||
if (!IsPlainRailTile(tile) || !HasTrack(tile, track)) {
|
||||
return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
|
||||
}
|
||||
if (!HasSignalOnTrack(tile, track)) {
|
||||
return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS);
|
||||
}
|
||||
break;
|
||||
|
||||
case MP_TUNNELBRIDGE:
|
||||
if (!IsRailTunnelBridgeTile(tile) || !HasBit(GetTunnelBridgeTrackBits(tile), track)) {
|
||||
return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
|
||||
}
|
||||
if (!IsTunnelBridgeWithSignalSimulation(tile) || !IsTrackAcrossTunnelBridge(tile, track)) {
|
||||
return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
|
||||
}
|
||||
|
||||
// Check tile ownership, do this afterwards to avoid tripping up on house/industry tiles
|
||||
|
@@ -875,12 +875,24 @@ TraceRestrictProgram *GetTraceRestrictProgram(TraceRestrictRefId ref, bool creat
|
||||
|
||||
void TraceRestrictNotifySignalRemoval(TileIndex tile, Track track);
|
||||
|
||||
static inline bool IsRestrictedSignalTile(TileIndex t)
|
||||
{
|
||||
switch (GetTileType(t)) {
|
||||
case MP_RAILWAY:
|
||||
return IsRestrictedSignal(t);
|
||||
case MP_TUNNELBRIDGE:
|
||||
return IsTunnelBridgeRestrictedSignal(t);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the existing signal program for the tile identified by @p t and @p track, or nullptr
|
||||
*/
|
||||
static inline const TraceRestrictProgram *GetExistingTraceRestrictProgram(TileIndex t, Track track)
|
||||
{
|
||||
if (IsRestrictedSignal(t)) {
|
||||
if (IsRestrictedSignalTile(t)) {
|
||||
return GetTraceRestrictProgram(MakeTraceRestrictRefId(t, track), false);
|
||||
} else {
|
||||
return nullptr;
|
||||
|
@@ -2093,7 +2093,7 @@ public:
|
||||
*/
|
||||
void OnPlaceObjectSignal(Point pt, TileIndex source_tile, int widget, int error_message)
|
||||
{
|
||||
if (!IsPlainRailTile(source_tile)) {
|
||||
if (!IsPlainRailTile(source_tile) && !IsRailTunnelBridgeTile(source_tile)) {
|
||||
ShowErrorMessage(error_message, STR_ERROR_THERE_IS_NO_RAILROAD_TRACK, WL_INFO);
|
||||
return;
|
||||
}
|
||||
@@ -2112,14 +2112,26 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
if (!HasTrack(source_tile, source_track)) {
|
||||
ShowErrorMessage(error_message, STR_ERROR_THERE_IS_NO_RAILROAD_TRACK, WL_INFO);
|
||||
return;
|
||||
}
|
||||
if (IsTileType(source_tile, MP_RAILWAY)) {
|
||||
if (!HasTrack(source_tile, source_track)) {
|
||||
ShowErrorMessage(error_message, STR_ERROR_THERE_IS_NO_RAILROAD_TRACK, WL_INFO);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!HasSignalOnTrack(source_tile, source_track)) {
|
||||
ShowErrorMessage(error_message, STR_ERROR_THERE_ARE_NO_SIGNALS, WL_INFO);
|
||||
return;
|
||||
if (!HasSignalOnTrack(source_tile, source_track)) {
|
||||
ShowErrorMessage(error_message, STR_ERROR_THERE_ARE_NO_SIGNALS, WL_INFO);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (!HasTrack(GetTunnelBridgeTrackBits(source_tile), source_track)) {
|
||||
ShowErrorMessage(error_message, STR_ERROR_THERE_IS_NO_RAILROAD_TRACK, WL_INFO);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsTunnelBridgeWithSignalSimulation(source_tile) || !HasTrack(GetAcrossTunnelBridgeTrackBits(source_tile), source_track)) {
|
||||
ShowErrorMessage(error_message, STR_ERROR_THERE_ARE_NO_SIGNALS, WL_INFO);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (widget) {
|
||||
|
@@ -4001,11 +4001,12 @@ static bool HasLongReservePbsSignalOnTrackdir(Train* v, TileIndex tile, Trackdir
|
||||
return false;
|
||||
}
|
||||
|
||||
static TileIndex CheckLongReservePbsTunnelBridgeOnTrackdir(Train* v, TileIndex tile, Trackdir trackdir)
|
||||
static TileIndex CheckLongReservePbsTunnelBridgeOnTrackdir(Train* v, TileIndex tile, Trackdir trackdir, bool restricted_only = false)
|
||||
{
|
||||
if (_settings_game.vehicle.train_braking_model == TBM_REALISTIC && IsTunnelBridgeSignalSimulationEntranceTile(tile) && TrackdirEntersTunnelBridge(tile, trackdir)) {
|
||||
|
||||
TileIndex end = GetOtherTunnelBridgeEnd(tile);
|
||||
if (restricted_only && !IsTunnelBridgeRestrictedSignal(end)) return INVALID_TILE;
|
||||
int raw_free_tiles;
|
||||
if (v->lookahead != nullptr && v->lookahead->reservation_end_tile == tile && v->lookahead->reservation_end_trackdir == trackdir) { // TODO fix loop case
|
||||
if (HasBit(v->lookahead->flags, TRLF_TB_EXIT_FREE)) {
|
||||
@@ -4033,7 +4034,7 @@ static void TryLongReserveChooseTrainTrack(Train *v, TileIndex tile, Trackdir td
|
||||
const bool long_enough = IsReservationLookAheadLongEnough(v, lookahead_state);
|
||||
|
||||
// We reserved up to a unoccupied signalled tunnel/bridge, reserve past it as well. recursion
|
||||
TileIndex exit_tile = long_enough ? INVALID_TILE : CheckLongReservePbsTunnelBridgeOnTrackdir(v, tile, td);
|
||||
TileIndex exit_tile = CheckLongReservePbsTunnelBridgeOnTrackdir(v, tile, td, long_enough);
|
||||
if (exit_tile != INVALID_TILE) {
|
||||
CFollowTrackRail ft(v);
|
||||
Trackdir exit_td = GetTunnelBridgeExitTrackdir(exit_tile);
|
||||
@@ -4042,6 +4043,23 @@ static void TryLongReserveChooseTrainTrack(Train *v, TileIndex tile, Trackdir td
|
||||
if ((ft.m_new_td_bits & TrackBitsToTrackdirBits(reserved_bits)) == TRACKDIR_BIT_NONE) {
|
||||
/* next tile is not reserved */
|
||||
|
||||
bool long_reserve = !long_enough;
|
||||
if (IsTunnelBridgeRestrictedSignal(exit_tile)) {
|
||||
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(exit_tile, TrackdirToTrack(exit_td));
|
||||
if (prog && prog->actions_used_flags & (TRPAUF_WAIT_AT_PBS | TRPAUF_SLOT_ACQUIRE | TRPAUF_SLOT_ACQUIRE_ON_RES | TRPAUF_LONG_RESERVE)) {
|
||||
TraceRestrictProgramResult out;
|
||||
if (long_reserve) out.flags |= TRPRF_LONG_RESERVE;
|
||||
TraceRestrictProgramInput input(exit_tile, exit_td, nullptr, nullptr);
|
||||
input.permitted_slot_operations = TRPISP_ACQUIRE | TRPISP_ACQUIRE_ON_RES;
|
||||
prog->Execute(v, input, out);
|
||||
if (out.flags & TRPRF_WAIT_AT_PBS) {
|
||||
return;
|
||||
}
|
||||
long_reserve = (out.flags & TRPRF_LONG_RESERVE);
|
||||
}
|
||||
}
|
||||
if (!long_reserve) return;
|
||||
|
||||
SignalState exit_state = GetTunnelBridgeExitSignalState(exit_tile);
|
||||
|
||||
/* reserve exit to make contiguous reservation */
|
||||
@@ -4051,10 +4069,6 @@ static void TryLongReserveChooseTrainTrack(Train *v, TileIndex tile, Trackdir td
|
||||
SetTunnelReservation(exit_tile, true);
|
||||
}
|
||||
SetTunnelBridgeExitSignalState(exit_tile, SIGNAL_STATE_GREEN);
|
||||
if (_extra_aspects > 0) {
|
||||
SetTunnelBridgeExitSignalAspect(exit_tile, 0);
|
||||
UpdateAspectDeferred(exit_tile, GetTunnelBridgeExitTrackdir(exit_tile));
|
||||
}
|
||||
|
||||
ChooseTrainTrack(v, ft.m_new_tile, ft.m_exitdir, TrackdirBitsToTrackBits(ft.m_new_td_bits), CTTF_NO_LOOKAHEAD_VALIDATE | (force_res ? CTTF_FORCE_RES : CTTF_NONE), nullptr, lookahead_state);
|
||||
|
||||
@@ -4067,6 +4081,10 @@ static void TryLongReserveChooseTrainTrack(Train *v, TileIndex tile, Trackdir td
|
||||
}
|
||||
SetTunnelBridgeExitSignalState(exit_tile, exit_state);
|
||||
} else {
|
||||
if (_extra_aspects > 0) {
|
||||
SetTunnelBridgeExitSignalAspect(exit_tile, 0);
|
||||
UpdateAspectDeferred(exit_tile, GetTunnelBridgeExitTrackdir(exit_tile));
|
||||
}
|
||||
MarkTileDirtyByTile(exit_tile, VMDF_NOT_MAP_MODE);
|
||||
}
|
||||
}
|
||||
@@ -4995,6 +5013,23 @@ static bool CheckTrainStayInWormHolePathReserve(Train *t, TileIndex tile)
|
||||
}
|
||||
}
|
||||
|
||||
auto try_exit_reservation = [&]() -> bool {
|
||||
if (IsTunnelBridgeRestrictedSignal(tile)) {
|
||||
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(tile, TrackdirToTrack(td));
|
||||
if (prog && prog->actions_used_flags & (TRPAUF_WAIT_AT_PBS | TRPAUF_SLOT_ACQUIRE | TRPAUF_SLOT_ACQUIRE_ON_RES)) {
|
||||
TraceRestrictProgramResult out;
|
||||
TraceRestrictProgramInput input(tile, td, nullptr, nullptr);
|
||||
input.permitted_slot_operations = TRPISP_ACQUIRE | TRPISP_ACQUIRE_ON_RES;
|
||||
prog->Execute(t, input, out);
|
||||
if (out.flags & TRPRF_WAIT_AT_PBS) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TryPathReserve(t);
|
||||
};
|
||||
|
||||
if (_settings_game.vehicle.train_braking_model == TBM_REALISTIC) {
|
||||
if (unlikely(t->lookahead == nullptr)) {
|
||||
FillTrainReservationLookAhead(t);
|
||||
@@ -5004,10 +5039,6 @@ static bool CheckTrainStayInWormHolePathReserve(Train *t, TileIndex tile)
|
||||
if (t->lookahead->reservation_end_tile == t->tile && t->lookahead->reservation_end_position - t->lookahead->current_position <= (int)TILE_SIZE && !HasBit(t->lookahead->flags, TRLF_TB_EXIT_FREE)) return false;
|
||||
SignalState exit_state = GetTunnelBridgeExitSignalState(tile);
|
||||
SetTunnelBridgeExitSignalState(tile, SIGNAL_STATE_GREEN);
|
||||
if (_extra_aspects > 0) {
|
||||
SetTunnelBridgeExitSignalAspect(tile, 0);
|
||||
UpdateAspectDeferred(tile, GetTunnelBridgeExitTrackdir(tile));
|
||||
}
|
||||
|
||||
/* Get tile margin before changing vehicle direction */
|
||||
const int tile_margin = GetTileMarginInFrontOfTrain(t);
|
||||
@@ -5018,7 +5049,7 @@ static bool CheckTrainStayInWormHolePathReserve(Train *t, TileIndex tile)
|
||||
t->tile = tile;
|
||||
t->track = TRACK_BIT_WORMHOLE;
|
||||
t->direction = TrackdirToDirection(td);
|
||||
bool ok = TryPathReserve(t);
|
||||
bool ok = try_exit_reservation();
|
||||
if (!ok && (t->lookahead->reservation_end_position >= t->lookahead->current_position && t->lookahead->reservation_end_position > t->lookahead->current_position + tile_margin)) {
|
||||
/* Reservation was made previously and was valid then.
|
||||
* To avoid unexpected braking due to stopping short of the lookahead end,
|
||||
@@ -5026,6 +5057,10 @@ static bool CheckTrainStayInWormHolePathReserve(Train *t, TileIndex tile)
|
||||
ok = true;
|
||||
}
|
||||
if (ok) {
|
||||
if (_extra_aspects > 0) {
|
||||
SetTunnelBridgeExitSignalAspect(tile, 0);
|
||||
UpdateAspectDeferred(tile, GetTunnelBridgeExitTrackdir(tile));
|
||||
}
|
||||
mark_dirty = true;
|
||||
if (t->lookahead->reservation_end_tile == veh_orig_tile && t->lookahead->reservation_end_position - t->lookahead->current_position <= (int)TILE_SIZE) {
|
||||
/* Less than a tile of lookahead, advance tile */
|
||||
@@ -5057,7 +5092,7 @@ static bool CheckTrainStayInWormHolePathReserve(Train *t, TileIndex tile)
|
||||
t->tile = tile;
|
||||
t->track = TRACK_BIT_WORMHOLE;
|
||||
t->direction = TrackdirToDirection(td);
|
||||
bool ok = TryPathReserve(t);
|
||||
bool ok = try_exit_reservation();
|
||||
t->tile = veh_orig_tile;
|
||||
t->track = veh_orig_track;
|
||||
t->direction = veh_orig_direction;
|
||||
@@ -5170,6 +5205,21 @@ void DecrementPendingSpeedRestrictions(Train *v)
|
||||
}
|
||||
}
|
||||
|
||||
void HandleTraceRestrictSpeedRestrictionAction(const TraceRestrictProgramResult &out, Train *v, Trackdir signal_td)
|
||||
{
|
||||
if (out.flags & TRPRF_SPEED_RESTRICTION_SET) {
|
||||
SetBit(v->flags, VRF_PENDING_SPEED_RESTRICTION);
|
||||
auto range = pending_speed_restriction_change_map.equal_range(v->index);
|
||||
for (auto it = range.first; it != range.second; ++it) {
|
||||
if ((uint16) (out.speed_restriction + 0xFFFF) < (uint16) (it->second.new_speed + 0xFFFF)) it->second.new_speed = out.speed_restriction;
|
||||
}
|
||||
uint16 flags = 0;
|
||||
if (IsDiagonalTrack(TrackdirToTrack(signal_td))) SetBit(flags, PSRCF_DIAGONAL);
|
||||
pending_speed_restriction_change_map.insert({ v->index, { (uint16) (v->gcache.cached_total_length + (HasBit(flags, PSRCF_DIAGONAL) ? 8 : 4)), out.speed_restriction, v->speed_restriction, flags } });
|
||||
if ((uint16) (out.speed_restriction + 0xFFFF) < (uint16) (v->speed_restriction + 0xFFFF)) v->speed_restriction = out.speed_restriction;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Move a vehicle chain one movement stop forwards.
|
||||
* @param v First vehicle to move.
|
||||
@@ -5366,17 +5416,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
||||
v->reverse_distance = v->gcache.cached_total_length + (IsDiagonalTrack(TrackdirToTrack(dir)) ? 16 : 8);
|
||||
SetWindowDirty(WC_VEHICLE_VIEW, v->index);
|
||||
}
|
||||
if (out.flags & TRPRF_SPEED_RESTRICTION_SET) {
|
||||
SetBit(v->flags, VRF_PENDING_SPEED_RESTRICTION);
|
||||
auto range = pending_speed_restriction_change_map.equal_range(v->index);
|
||||
for (auto it = range.first; it != range.second; ++it) {
|
||||
if ((uint16) (out.speed_restriction + 0xFFFF) < (uint16) (it->second.new_speed + 0xFFFF)) it->second.new_speed = out.speed_restriction;
|
||||
}
|
||||
uint16 flags = 0;
|
||||
if (IsDiagonalTrack(TrackdirToTrack(dir))) SetBit(flags, PSRCF_DIAGONAL);
|
||||
pending_speed_restriction_change_map.insert({ v->index, { (uint16) (v->gcache.cached_total_length + (HasBit(flags, PSRCF_DIAGONAL) ? 8 : 4)), out.speed_restriction, v->speed_restriction, flags } });
|
||||
if ((uint16) (out.speed_restriction + 0xFFFF) < (uint16) (v->speed_restriction + 0xFFFF)) v->speed_restriction = out.speed_restriction;
|
||||
}
|
||||
HandleTraceRestrictSpeedRestrictionAction(out, v, dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5519,6 +5559,31 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
||||
/* Entered wormhole set counters. */
|
||||
v->wait_counter = (TILE_SIZE * simulated_wormhole_signals) - TILE_SIZE;
|
||||
v->tunnel_bridge_signal_num = 0;
|
||||
|
||||
if (v->IsFrontEngine() && IsTunnelBridgeSignalSimulationEntrance(old_tile) && IsTunnelBridgeRestrictedSignal(old_tile)) {
|
||||
const Trackdir trackdir = GetTunnelBridgeEntranceTrackdir(old_tile);
|
||||
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(old_tile, TrackdirToTrack(trackdir));
|
||||
if (prog && prog->actions_used_flags & (TRPAUF_SLOT_ACQUIRE | TRPAUF_SLOT_RELEASE_FRONT | TRPAUF_SPEED_RESTRICTION | TRPAUF_CHANGE_COUNTER)) {
|
||||
TraceRestrictProgramResult out;
|
||||
TraceRestrictProgramInput input(old_tile, trackdir, nullptr, nullptr);
|
||||
input.permitted_slot_operations = TRPISP_ACQUIRE | TRPISP_RELEASE_FRONT | TRPISP_CHANGE_COUNTER;
|
||||
prog->Execute(v, input, out);
|
||||
HandleTraceRestrictSpeedRestrictionAction(out, v, trackdir);
|
||||
}
|
||||
}
|
||||
|
||||
if (v->Next() == nullptr && IsTunnelBridgeSignalSimulationEntrance(old_tile) && IsTunnelBridgeRestrictedSignal(old_tile)) {
|
||||
const Trackdir trackdir = GetTunnelBridgeEntranceTrackdir(old_tile);
|
||||
const Track track = TrackdirToTrack(trackdir);
|
||||
|
||||
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(old_tile, track);
|
||||
if (prog && prog->actions_used_flags & TRPAUF_SLOT_RELEASE_BACK) {
|
||||
TraceRestrictProgramResult out;
|
||||
TraceRestrictProgramInput input(old_tile, trackdir, nullptr, nullptr);
|
||||
input.permitted_slot_operations = TRPISP_RELEASE_BACK;
|
||||
prog->Execute(first, input, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint distance = v->wait_counter;
|
||||
@@ -5534,6 +5599,17 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
||||
return false;
|
||||
}
|
||||
leaving = true;
|
||||
if (IsTunnelBridgeRestrictedSignal(gp.new_tile) && IsTunnelBridgeSignalSimulationExit(gp.new_tile)) {
|
||||
const Trackdir trackdir = GetTunnelBridgeExitTrackdir(gp.new_tile);
|
||||
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(gp.new_tile, TrackdirToTrack(trackdir));
|
||||
if (prog && prog->actions_used_flags & (TRPAUF_SLOT_ACQUIRE | TRPAUF_SLOT_RELEASE_FRONT | TRPAUF_SPEED_RESTRICTION | TRPAUF_CHANGE_COUNTER)) {
|
||||
TraceRestrictProgramResult out;
|
||||
TraceRestrictProgramInput input(gp.new_tile, trackdir, nullptr, nullptr);
|
||||
input.permitted_slot_operations = TRPISP_ACQUIRE | TRPISP_RELEASE_FRONT | TRPISP_CHANGE_COUNTER;
|
||||
prog->Execute(v, input, out);
|
||||
HandleTraceRestrictSpeedRestrictionAction(out, v, trackdir);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (IsTooCloseBehindTrain(v, gp.new_tile, v->wait_counter, distance == 0)) {
|
||||
if (distance == 0) v->wait_counter = 0;
|
||||
@@ -5765,6 +5841,22 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IsTileType(gp.old_tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExit(gp.old_tile) && IsTunnelBridgeRestrictedSignal(gp.old_tile)) {
|
||||
const TrackdirBits rev_tracks = TrackBitsToTrackdirBits(GetTunnelBridgeTrackBits(gp.old_tile)) & DiagdirReachesTrackdirs(ReverseDiagDir(enterdir));
|
||||
const Trackdir rev_trackdir = FindFirstTrackdir(rev_tracks);
|
||||
const Track track = TrackdirToTrack(rev_trackdir);
|
||||
|
||||
if (TrackdirEntersTunnelBridge(gp.old_tile, rev_trackdir)) {
|
||||
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(gp.old_tile, track);
|
||||
if (prog && prog->actions_used_flags & TRPAUF_SLOT_RELEASE_BACK) {
|
||||
TraceRestrictProgramResult out;
|
||||
TraceRestrictProgramInput input(gp.old_tile, ReverseTrackdir(rev_trackdir), nullptr, nullptr);
|
||||
input.permitted_slot_operations = TRPISP_RELEASE_BACK;
|
||||
prog->Execute(first, input, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -48,6 +48,7 @@
|
||||
#include "object_map.h"
|
||||
#include "newgrf_station.h"
|
||||
#include "station_func.h"
|
||||
#include "tracerestrict.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
#include "table/bridge_land.h"
|
||||
@@ -1275,6 +1276,8 @@ static CommandCost DoClearTunnel(TileIndex tile, DoCommandFlag flags)
|
||||
c->infrastructure.rail[GetRailType(tile)] -= len * TUNNELBRIDGE_TRACKBIT_FACTOR;
|
||||
if (IsTunnelBridgeWithSignalSimulation(tile)) { // handle tunnel/bridge signals.
|
||||
c->infrastructure.signal -= GetTunnelBridgeSignalSimulationSignalCount(tile, endtile);
|
||||
TraceRestrictNotifySignalRemoval(tile, track);
|
||||
TraceRestrictNotifySignalRemoval(endtile, track);
|
||||
}
|
||||
DirtyCompanyInfrastructureWindows(owner);
|
||||
}
|
||||
@@ -1410,6 +1413,10 @@ static CommandCost DoClearBridge(TileIndex tile, DoCommandFlag flags)
|
||||
/* Update company infrastructure counts. */
|
||||
if (rail) {
|
||||
SubtractRailTunnelBridgeInfrastructure(tile, endtile);
|
||||
if (IsTunnelBridgeWithSignalSimulation(tile)) {
|
||||
TraceRestrictNotifySignalRemoval(tile, FindFirstTrack(GetAcrossTunnelBridgeTrackBits(tile)));
|
||||
TraceRestrictNotifySignalRemoval(endtile, FindFirstTrack(GetAcrossTunnelBridgeTrackBits(endtile)));
|
||||
}
|
||||
} else if (GetTunnelBridgeTransportType(tile) == TRANSPORT_ROAD) {
|
||||
SubtractRoadTunnelBridgeInfrastructure(tile, endtile);
|
||||
if (RoadLayoutChangeNotificationEnabled(false)) {
|
||||
@@ -1747,7 +1754,9 @@ static void DrawTunnelBridgeRampSingleSignal(const TileInfo *ti, bool is_green,
|
||||
aspect = 1;
|
||||
}
|
||||
}
|
||||
PalSpriteID sprite = GetCustomSignalSprite(rti, ti->tile, type, variant, aspect).sprite;
|
||||
bool show_restricted = IsTunnelBridgeRestrictedSignal(ti->tile);
|
||||
const CustomSignalSpriteResult result = GetCustomSignalSprite(rti, ti->tile, type, variant, aspect, false, show_restricted);
|
||||
PalSpriteID sprite = result.sprite;
|
||||
bool is_custom_sprite = (sprite.sprite != 0);
|
||||
|
||||
if (is_custom_sprite) {
|
||||
@@ -1762,7 +1771,26 @@ static void DrawTunnelBridgeRampSingleSignal(const TileInfo *ti, bool is_green,
|
||||
}
|
||||
}
|
||||
|
||||
AddSortableSpriteToDraw(sprite.sprite, sprite.pal, x, y, 1, 1, TILE_HEIGHT, z, false, 0, 0, BB_Z_SEPARATOR);
|
||||
if (is_custom_sprite && show_restricted && _settings_client.gui.show_restricted_signal_default && !result.restricted_valid && variant == SIG_ELECTRIC) {
|
||||
/* Use duplicate sprite block, instead of GRF-specified signals */
|
||||
sprite = { (type == SIGTYPE_NORMAL && variant == SIG_ELECTRIC) ? SPR_DUP_ORIGINAL_SIGNALS_BASE : SPR_DUP_SIGNALS_BASE - 16, PAL_NONE };
|
||||
sprite.sprite += type * 16 + variant * 64 + position * 2 + is_green + (IsSignalSpritePBS(type) ? 64 : 0);
|
||||
is_custom_sprite = false;
|
||||
}
|
||||
|
||||
if (!is_custom_sprite && show_restricted && variant == SIG_ELECTRIC) {
|
||||
if (type == SIGTYPE_PBS || type == SIGTYPE_PBS_ONEWAY) {
|
||||
static const SubSprite lower_part = { -50, -10, 50, 50 };
|
||||
static const SubSprite upper_part = { -50, -50, 50, -11 };
|
||||
|
||||
AddSortableSpriteToDraw(sprite.sprite, SPR_TRACERESTRICT_BASE, x, y, 1, 1, TILE_HEIGHT, z, false, 0, 0, BB_Z_SEPARATOR, &lower_part);
|
||||
AddSortableSpriteToDraw(sprite.sprite, PAL_NONE, x, y, 1, 1, TILE_HEIGHT, z, false, 0, 0, BB_Z_SEPARATOR, &upper_part);
|
||||
} else {
|
||||
AddSortableSpriteToDraw(sprite.sprite, SPR_TRACERESTRICT_BASE + (type == SIGTYPE_NO_ENTRY ? 0 : 1), x, y, 1, 1, TILE_HEIGHT, z, false, 0, 0, BB_Z_SEPARATOR);
|
||||
}
|
||||
} else {
|
||||
AddSortableSpriteToDraw(sprite.sprite, sprite.pal, x, y, 1, 1, TILE_HEIGHT, z, false, 0, 0, BB_Z_SEPARATOR);
|
||||
}
|
||||
}
|
||||
|
||||
/* Draws a signal on tunnel / bridge entrance tile. */
|
||||
@@ -2120,14 +2148,14 @@ static void DrawTile_TunnelBridge(TileInfo *ti, DrawTileProcParams params)
|
||||
image = (SignalOffsets)(image ^ 1);
|
||||
}
|
||||
if (IsTunnelBridgeSignalSimulationEntrance(ti->tile)) {
|
||||
DrawSingleSignal(ti->tile, rti, t, GetTunnelBridgeEntranceSignalState(ti->tile), image, position, SIGTYPE_NORMAL, variant, false, false);
|
||||
DrawSingleSignal(ti->tile, rti, t, GetTunnelBridgeEntranceSignalState(ti->tile), image, position, SIGTYPE_NORMAL, variant, IsTunnelBridgeRestrictedSignal(ti->tile), false);
|
||||
}
|
||||
if (IsTunnelBridgeSignalSimulationExit(ti->tile)) {
|
||||
SignalType type = SIGTYPE_NORMAL;
|
||||
if (IsTunnelBridgePBS(ti->tile)) {
|
||||
type = IsTunnelBridgeSignalSimulationEntrance(ti->tile) ? SIGTYPE_PBS : SIGTYPE_PBS_ONEWAY;
|
||||
}
|
||||
DrawSingleSignal(ti->tile, rti, t, GetTunnelBridgeExitSignalState(ti->tile), (SignalOffsets)(image ^ 1), position ^ 1, type, variant, false, true);
|
||||
DrawSingleSignal(ti->tile, rti, t, GetTunnelBridgeExitSignalState(ti->tile), (SignalOffsets)(image ^ 1), position ^ 1, type, variant, IsTunnelBridgeRestrictedSignal(ti->tile), true);
|
||||
}
|
||||
};
|
||||
switch (t) {
|
||||
@@ -2524,6 +2552,10 @@ static void GetTileDesc_TunnelBridge(TileIndex tile, TileDesc *td)
|
||||
} else { // IsBridge(tile)
|
||||
td->str = (tt == TRANSPORT_WATER) ? STR_LAI_BRIDGE_DESCRIPTION_AQUEDUCT : IsTunnelBridgeWithSignalSimulation(tile) ? STR_LAI_BRIDGE_DESCRIPTION_RAILROAD_SIGNAL : GetBridgeSpec(GetBridgeType(tile))->transport_name[tt];
|
||||
}
|
||||
if (IsTunnelBridgeWithSignalSimulation(tile) && IsTunnelBridgeRestrictedSignal(tile)) {
|
||||
SetDParamX(td->dparam, 0, td->str);
|
||||
td->str = STR_LAI_RAIL_DESCRIPTION_RESTRICTED_SIGNAL;
|
||||
}
|
||||
td->owner[0] = GetTileOwner(tile);
|
||||
|
||||
if (tt == TRANSPORT_ROAD) {
|
||||
@@ -2718,6 +2750,24 @@ static void TileLoop_TunnelBridge(TileIndex tile)
|
||||
|
||||
static bool ClickTile_TunnelBridge(TileIndex tile)
|
||||
{
|
||||
if (_ctrl_pressed && IsTunnelBridgeWithSignalSimulation(tile)) {
|
||||
TrackBits trackbits = TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0));
|
||||
|
||||
if (trackbits & TRACK_BIT_VERT) { // N-S direction
|
||||
trackbits = (_tile_fract_coords.x <= _tile_fract_coords.y) ? TRACK_BIT_RIGHT : TRACK_BIT_LEFT;
|
||||
}
|
||||
|
||||
if (trackbits & TRACK_BIT_HORZ) { // E-W direction
|
||||
trackbits = (_tile_fract_coords.x + _tile_fract_coords.y <= 15) ? TRACK_BIT_UPPER : TRACK_BIT_LOWER;
|
||||
}
|
||||
|
||||
Track track = FindFirstTrack(trackbits);
|
||||
if (HasTrack(GetAcrossTunnelBridgeTrackBits(tile), track)) {
|
||||
ShowTraceRestrictProgramWindow(tile, track);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Show vehicles found in tunnel. */
|
||||
if (IsTunnelTile(tile)) {
|
||||
int count = 0;
|
||||
|
@@ -561,6 +561,26 @@ static inline void SetTunnelBridgeSignalSimulationSpacing(TileIndex t, uint spac
|
||||
SB(_me[t].m8, 12, 4, spacing - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Does tunnel/bridge signal tile have "one or more trace restrict mappings present" bit set
|
||||
* @param tile the tile to check
|
||||
*/
|
||||
static inline bool IsTunnelBridgeRestrictedSignal(TileIndex tile)
|
||||
{
|
||||
assert_tile(IsTunnelBridgeWithSignalSimulation(tile), tile);
|
||||
return (bool) GB(_m[tile].m3, 6, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set tunnel/bridge signal tile "one or more trace restrict mappings present" bit
|
||||
* @param tile the tile to set
|
||||
*/
|
||||
static inline void SetTunnelBridgeRestrictedSignal(TileIndex tile, bool is_restricted)
|
||||
{
|
||||
assert_tile(IsTunnelBridgeWithSignalSimulation(tile), tile);
|
||||
SB(_m[tile].m3, 6, 1, is_restricted);
|
||||
}
|
||||
|
||||
static inline Trackdir GetTunnelBridgeExitTrackdir(TileIndex t, DiagDirection tunnel_bridge_dir)
|
||||
{
|
||||
return TrackEnterdirToTrackdir((Track)FIND_FIRST_BIT(GetAcrossTunnelBridgeTrackBits(t)), ReverseDiagDir(tunnel_bridge_dir));
|
||||
|
@@ -253,6 +253,9 @@ SpriteID TileZoneCheckTraceRestrictEvaluation(TileIndex tile, Owner owner)
|
||||
if (IsTileType(tile, MP_RAILWAY) && HasSignals(tile) && IsRestrictedSignal(tile)) {
|
||||
return SPR_ZONING_INNER_HIGHLIGHT_RED;
|
||||
}
|
||||
if (IsTunnelBridgeWithSignalSimulation(tile)) {
|
||||
return SPR_ZONING_INNER_HIGHLIGHT_RED;
|
||||
}
|
||||
if (unlikely(HasBit(_misc_debug_flags, MDF_ZONING_RS_WATER_FLOOD_STATE)) && IsNonFloodingWaterTile(tile)) {
|
||||
return SPR_ZONING_INNER_HIGHLIGHT_YELLOW;
|
||||
}
|
||||
|
Reference in New Issue
Block a user