diff --git a/docs/newgrf-additions-nml.html b/docs/newgrf-additions-nml.html
index 30587cd468..4a5fe65638 100644
--- a/docs/newgrf-additions-nml.html
+++ b/docs/newgrf-additions-nml.html
@@ -516,13 +516,20 @@ item (FEAT_GLOBALVARS) {
style_opposite_side | 0 or 1 |
Set whether signals should be drawn on the opposite side of the track for the most recently defined style (defined using the define_style property).
diff --git a/docs/newgrf-additions.html b/docs/newgrf-additions.html
index f83c473d63..fc36f3b8e2 100644
--- a/docs/newgrf-additions.html
+++ b/docs/newgrf-additions.html
@@ -483,7 +483,8 @@
This is indicated by the feature name: action0_signals_style, version 1
Set custom signal style train look-ahead to single signal only mode (mappable property: signals_style_lookahead_single_signal_only)
This applies to the most recent custom signal style defined using the signals_define_style property.
- This property only makes a difference when the "limit train lookahead to signal aspect" game setting is enabled.
+ This property only makes a difference when the "limit train lookahead to signal aspect" game setting is enabled, or when using a different signal
+ type which uses signals_style_combined_normal_shunt.
This is similar to signals_style_lookahead_extra_aspects with a value of 0, except the lookahead always ends at the
next signal, even if that signal type sets signals_style_no_aspect_increase.
If enabled, this property overrides signals_style_lookahead_extra_aspects.
@@ -492,6 +493,13 @@
The Action 0 Id field is not used, the value is ignored.
This is indicated by the feature name: action0_signals_style, version 1
+ Set custom signal style combined normal aspect and shunt signal mode (mappable property: signals_style_combined_normal_shunt)
+ This applies to the most recent custom signal style defined using the signals_define_style property.
+ When enabled and displaying a shunt aspect, the signal state in the lowest byte of variable 0x18 (SS: signal state) will have the value: 0xFF.
+ The property length is 1 byte. 0 is disabled (default). 1 is enabled.
+ The Action 0 Id field is not used, the value is ignored.
+
+ This is indicated by the feature name: action0_signals_style, version 1
Set custom signal style signal drawn on opposite side (mappable property: signals_style_opposite_side)
This applies to the most recent custom signal style defined using the signals_define_style property.
When enabled, signals using this style are drawn on the opposite side of the track.
diff --git a/src/infrastructure.cpp b/src/infrastructure.cpp
index f29c74880a..e5c410cdf3 100644
--- a/src/infrastructure.cpp
+++ b/src/infrastructure.cpp
@@ -356,7 +356,7 @@ void UpdateAllBlockSignals(Owner owner)
}
if (_extra_aspects > 0 && IsTunnelBridgeSignalSimulationEntrance(tile) && GetTunnelBridgeEntranceSignalState(tile) == SIGNAL_STATE_GREEN) {
SetTunnelBridgeEntranceSignalAspect(tile, 0);
- UpdateAspectDeferred(tile, GetTunnelBridgeEntranceTrackdir(tile));
+ UpdateAspectDeferred(tile, GetTunnelBridgeEntranceTrackdir(tile), false);
}
}
} while (++tile != MapSize());
diff --git a/src/newgrf.cpp b/src/newgrf.cpp
index 28e6586b76..4ecec5daed 100644
--- a/src/newgrf.cpp
+++ b/src/newgrf.cpp
@@ -4289,6 +4289,15 @@ static ChangeInfoResult SignalsChangeInfo(uint id, int numinfo, int prop, const
break;
}
+ case A0RPI_SIGNALS_STYLE_COMBINED_NORMAL_SHUNT: {
+ if (MappedPropertyLengthMismatch(buf, 1, mapping_entry)) break;
+ uint8 value = buf->ReadByte();
+ if (_cur.grffile->current_new_signal_style != nullptr) {
+ SB(_cur.grffile->current_new_signal_style->style_flags, NSSF_COMBINED_NORMAL_SHUNT, 1, (value != 0 ? 1 : 0));
+ }
+ break;
+ }
+
default:
ret = HandleAction0PropertyDefault(buf, prop);
break;
diff --git a/src/newgrf_extension.cpp b/src/newgrf_extension.cpp
index f8e807f199..98fe2efda0 100644
--- a/src/newgrf_extension.cpp
+++ b/src/newgrf_extension.cpp
@@ -101,6 +101,7 @@ extern const GRFPropertyMapDefinition _grf_action0_remappable_properties[] = {
GRFPropertyMapDefinition(GSF_SIGNALS, A0RPI_SIGNALS_STYLE_SEMAPHORE_ENABLED, "signals_style_semaphore_enabled"),
GRFPropertyMapDefinition(GSF_SIGNALS, A0RPI_SIGNALS_STYLE_ELECTRIC_ENABLED, "signals_style_electric_enabled"),
GRFPropertyMapDefinition(GSF_SIGNALS, A0RPI_SIGNALS_STYLE_OPPOSITE_SIDE, "signals_style_opposite_side"),
+ GRFPropertyMapDefinition(GSF_SIGNALS, A0RPI_SIGNALS_STYLE_COMBINED_NORMAL_SHUNT, "signals_style_combined_normal_shunt"),
GRFPropertyMapDefinition(GSF_OBJECTS, A0RPI_OBJECT_USE_LAND_GROUND, "object_use_land_ground"),
GRFPropertyMapDefinition(GSF_OBJECTS, A0RPI_OBJECT_EDGE_FOUNDATION_MODE, "object_edge_foundation_mode"),
GRFPropertyMapDefinition(GSF_OBJECTS, A0RPI_OBJECT_FLOOD_RESISTANT, "object_flood_resistant"),
diff --git a/src/newgrf_extension.h b/src/newgrf_extension.h
index 19448d4f17..2531201494 100644
--- a/src/newgrf_extension.h
+++ b/src/newgrf_extension.h
@@ -45,6 +45,7 @@ enum Action0RemapPropertyIds {
A0RPI_SIGNALS_STYLE_SEMAPHORE_ENABLED,
A0RPI_SIGNALS_STYLE_ELECTRIC_ENABLED,
A0RPI_SIGNALS_STYLE_OPPOSITE_SIDE,
+ A0RPI_SIGNALS_STYLE_COMBINED_NORMAL_SHUNT,
A0RPI_OBJECT_USE_LAND_GROUND,
A0RPI_OBJECT_EDGE_FOUNDATION_MODE,
A0RPI_OBJECT_FLOOD_RESISTANT,
diff --git a/src/newgrf_newsignals.h b/src/newgrf_newsignals.h
index 21391cc661..25dca6e416 100644
--- a/src/newgrf_newsignals.h
+++ b/src/newgrf_newsignals.h
@@ -33,6 +33,7 @@ enum NewSignalStyleFlags {
NSSF_LOOKAHEAD_ASPECTS_SET = 2,
NSSF_OPPOSITE_SIDE = 3,
NSSF_LOOKAHEAD_SINGLE_SIGNAL = 4,
+ NSSF_COMBINED_NORMAL_SHUNT = 5,
};
struct NewSignalStyle {
diff --git a/src/newgrf_railtype.cpp b/src/newgrf_railtype.cpp
index 350f93566e..cbd5d4aff6 100644
--- a/src/newgrf_railtype.cpp
+++ b/src/newgrf_railtype.cpp
@@ -15,6 +15,7 @@
#include "date_func.h"
#include "depot_base.h"
#include "town.h"
+#include "signal_func.h"
#include "safeguards.h"
@@ -117,10 +118,16 @@ SpriteID GetCustomRailSprite(const RailtypeInfo *rti, TileIndex tile, RailTypeSp
return group->GetResult();
}
-inline uint8 RemapAspect(uint8 aspect, uint8 extra_aspects)
+inline uint8 RemapAspect(uint8 aspect, uint8 extra_aspects, uint8 style)
{
if (likely(extra_aspects == 0 || _extra_aspects == 0)) return std::min(aspect, 1);
if (aspect == 0) return 0;
+ if (style != 0 && HasBit(_signal_style_masks.combined_normal_shunt, style)) {
+ if (aspect == 1) {
+ return 0xFF;
+ }
+ aspect--;
+ }
if (aspect >= extra_aspects + 1) return 1;
return aspect + 1;
}
@@ -132,7 +139,7 @@ static PalSpriteID GetRailTypeCustomSignalSprite(const RailtypeInfo *rti, TileIn
if (type == SIGTYPE_NO_ENTRY && !HasBit(rti->ctrl_flags, RTCF_NOENTRYSIG)) return { 0, PAL_NONE };
uint32 param1 = (context == CSSC_GUI) ? 0x10 : 0x00;
- uint32 param2 = (type << 16) | (var << 8) | RemapAspect(aspect, rti->signal_extra_aspects);
+ uint32 param2 = (type << 16) | (var << 8) | RemapAspect(aspect, rti->signal_extra_aspects, 0);
if ((prog != nullptr) && HasBit(rti->ctrl_flags, RTCF_RESTRICTEDSIG)) SetBit(param2, 24);
RailTypeResolverObject object(rti, tile, TCX_NORMAL, RTSG_SIGNALS, param1, param2, context, prog);
@@ -170,7 +177,7 @@ CustomSignalSpriteResult GetCustomSignalSprite(const RailtypeInfo *rti, TileInde
if (!HasBit(grf->new_signal_style_mask, style)) continue;
uint32 param1 = (context == CSSC_GUI) ? 0x10 : 0x00;
- uint32 param2 = (type << 16) | (var << 8) | RemapAspect(aspect, grf->new_signal_extra_aspects);
+ uint32 param2 = (type << 16) | (var << 8) | RemapAspect(aspect, grf->new_signal_extra_aspects, style);
if ((prog != nullptr) && HasBit(grf->new_signal_ctrl_flags, NSCF_RESTRICTEDSIG)) SetBit(param2, 24);
NewSignalsResolverObject object(grf, tile, TCX_NORMAL, param1, param2, context, style, prog);
diff --git a/src/pbs.cpp b/src/pbs.cpp
index 3f66f3ab30..37f056a733 100644
--- a/src/pbs.cpp
+++ b/src/pbs.cpp
@@ -88,7 +88,7 @@ bool TryReserveRailTrackdir(TileIndex tile, Trackdir td, bool trigger_stations)
MarkSingleSignalDirty(tile, td);
if (_extra_aspects > 0) {
SetSignalAspect(tile, TrackdirToTrack(td), 0);
- UpdateAspectDeferred(tile, td);
+ UpdateAspectDeferred(tile, td, true);
}
}
return success;
@@ -667,6 +667,10 @@ static PBSTileInfo FollowReservation(Owner o, RailTypes rts, TileIndex tile, Tra
if (HasBit(_signal_style_masks.next_only, signal_style)) {
SetBit(signal_flags, TRSLAI_NEXT_ONLY);
}
+ if (HasBit(_signal_style_masks.combined_normal_shunt, signal_style)) {
+ SetBit(signal_flags, TRSLAI_COMBINED);
+ UpdateLookaheadCombinedNormalShuntSignalDeferred(tile, trackdir, lookahead->RealEndPosition());
+ }
lookahead->AddSignal(signal_speed, 0, z, signal_flags);
lookahead->SetNextExtendPositionIfUnset();
}
@@ -1011,6 +1015,18 @@ void SetTrainReservationLookaheadEnd(Train *v)
for (const TrainReservationLookAheadItem &item : v->lookahead->items) {
if (item.end >= v->lookahead->reservation_end_position) break;
if (item.type == TRLIT_SIGNAL) {
+ if (HasBit(item.data_aux, TRSLAI_COMBINED_SHUNT)) {
+ /* Combined normal/shunt in shunt mode */
+ allow_skip_no_aspect_inc = false;
+ if (item.start <= threshold) {
+ known_signals_ahead = 1;
+ continue;
+ } else {
+ if (item.start > v->lookahead->lookahead_end_position) v->lookahead->lookahead_end_position = item.start;
+ return;
+ }
+ }
+
if (item.start <= threshold) {
/* Signal is within visual range */
uint8 style = item.data_aux >> 8;
@@ -1090,6 +1106,7 @@ void FillTrainReservationLookAhead(Train *v)
}
if (!(HasAcrossTunnelBridgeReservation(end) && GetTunnelBridgeExitSignalState(end) == SIGNAL_STATE_GREEN && raw_free_tiles == INT_MAX)) {
/* do not attempt to follow through a signalled tunnel/bridge if it is not empty or the far end is not reserved */
+ FlushDeferredDetermineCombineNormalShuntMode(v);
SetTrainReservationLookaheadEnd(v);
return;
}
@@ -1097,6 +1114,7 @@ void FillTrainReservationLookAhead(Train *v)
}
if (IsRailDepotTile(tile) && !GetDepotReservationTrackBits(tile)) {
+ FlushDeferredDetermineCombineNormalShuntMode(v);
SetTrainReservationLookaheadEnd(v);
return;
}
@@ -1131,6 +1149,7 @@ void FillTrainReservationLookAhead(Train *v)
v->lookahead->reservation_end_tile = res.tile;
v->lookahead->reservation_end_trackdir = res.trackdir;
+ FlushDeferredDetermineCombineNormalShuntMode(v);
SetTrainReservationLookaheadEnd(v);
}
diff --git a/src/pbs.h b/src/pbs.h
index e933ef2f11..c7af642a69 100644
--- a/src/pbs.h
+++ b/src/pbs.h
@@ -61,6 +61,8 @@ enum TrainReservationLookAheadItemType : byte {
enum TrainReservationSignalLookAheadItemFlags {
TRSLAI_NO_ASPECT_INC = 0, ///< This signal does not increase the signal aspect (e.g. banner repeater)
TRSLAI_NEXT_ONLY = 1, ///< This signal only permits lookahead up to the next physical signal, even if that has TRSLAI_NO_ASPECT_INC (e.g. shunt)
+ TRSLAI_COMBINED = 2, ///< This signal is a combined normal/shunt signal, special handling
+ TRSLAI_COMBINED_SHUNT = 3, ///< This signal is a combined normal/shunt signal, in shunt mode
};
struct TrainReservationLookAheadItem {
diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp
index f521e18496..8336b2c853 100644
--- a/src/rail_cmd.cpp
+++ b/src/rail_cmd.cpp
@@ -1434,7 +1434,7 @@ static void SetupBridgeTunnelSignalSimulation(TileIndex entrance, TileIndex exit
SetTunnelBridgeSignalSimulationExit(exit);
if (_extra_aspects > 0) {
SetTunnelBridgeEntranceSignalAspect(entrance, 0);
- UpdateAspectDeferred(entrance, GetTunnelBridgeEntranceTrackdir(entrance));
+ UpdateAspectDeferred(entrance, GetTunnelBridgeEntranceTrackdir(entrance), false);
}
}
@@ -1583,7 +1583,7 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
SetTunnelBridgeSignalSimulationExit(t);
if (_extra_aspects > 0) {
SetTunnelBridgeEntranceSignalAspect(t, 0);
- UpdateAspectDeferred(t, GetTunnelBridgeEntranceTrackdir(t));
+ UpdateAspectDeferred(t, GetTunnelBridgeEntranceTrackdir(t), false);
}
};
diff --git a/src/signal.cpp b/src/signal.cpp
index 5fb36da98d..6961844ea3 100644
--- a/src/signal.cpp
+++ b/src/signal.cpp
@@ -25,6 +25,7 @@
#include "newgrf_newsignals.h"
#include "core/checksum_func.hpp"
#include "core/hash_func.hpp"
+#include "pathfinder/follow_track.hpp"
#include "safeguards.h"
@@ -367,7 +368,7 @@ static SigInfo ExploreSegment(Owner owner)
if (HasSignalOnTrackdir(tile, reversedir)) {
if (IsPbsSignalNonExtended(sig)) {
info.flags |= SF_PBS;
- if (_extra_aspects > 0 && GetSignalStateByTrackdir(tile, reversedir) == SIGNAL_STATE_GREEN) {
+ if (_extra_aspects > 0 && GetSignalStateByTrackdir(tile, reversedir) == SIGNAL_STATE_GREEN && !IsRailSpecialSignalAspect(tile, track)) {
_tbpset.Add(tile, reversedir);
}
} else if (!_tbuset.Add(tile, reversedir)) {
@@ -778,7 +779,7 @@ static void UpdateSignalsAroundSegment(SigInfo info)
/* don't change signal state if tile is reserved in realistic braking mode */
if ((_settings_game.vehicle.train_braking_model == TBM_REALISTIC && HasBit(GetRailReservationTrackBits(tile), track))) {
- if (_extra_aspects > 0 && GetSignalStateByTrackdir(tile, trackdir) == SIGNAL_STATE_GREEN) {
+ if (_extra_aspects > 0 && GetSignalStateByTrackdir(tile, trackdir) == SIGNAL_STATE_GREEN && !IsRailSpecialSignalAspect(tile, track)) {
uint8 aspect = GetForwardAspectAndIncrement(info, tile, trackdir);
uint8 old_aspect = GetSignalAspect(tile, track);
if (aspect != old_aspect) {
@@ -1263,7 +1264,14 @@ uint8 GetSignalAspectGeneric(TileIndex tile, Trackdir trackdir, bool check_non_i
void AdjustSignalAspectIfNonIncStyleIntl(TileIndex tile, Track track, uint8 &aspect)
{
- if (IsTileType(tile, MP_RAILWAY) && HasBit(_signal_style_masks.non_aspect_inc, GetSignalStyle(tile, track))) aspect--;
+ if (IsTileType(tile, MP_RAILWAY)) {
+ uint8 style = GetSignalStyle(tile, track);
+ if (HasBit(_signal_style_masks.combined_normal_shunt, style)) {
+ aspect--;
+ if (aspect == 0) return;
+ }
+ if (HasBit(_signal_style_masks.non_aspect_inc, style)) aspect--;
+ }
}
static void RefreshBridgeOnExitAspectChange(TileIndex entrance, TileIndex exit)
@@ -1282,6 +1290,11 @@ static void RefreshBridgeOnExitAspectChange(TileIndex entrance, TileIndex exit)
}
}
+static inline bool IsRailCombinedNormalShuntSignalStyle(TileIndex tile, Track track)
+{
+ return _signal_style_masks.combined_normal_shunt != 0 && HasBit(_signal_style_masks.combined_normal_shunt, GetSignalStyle(tile, track));
+}
+
void PropagateAspectChange(TileIndex tile, Trackdir trackdir, uint8 aspect)
{
AdjustSignalAspectIfNonIncStyle(tile, TrackdirToTrack(trackdir), aspect);
@@ -1330,7 +1343,14 @@ void PropagateAspectChange(TileIndex tile, Trackdir trackdir, uint8 aspect)
if (HasSignalOnTrackdir(tile, reversedir)) {
if (GetSignalStateByTrackdir(tile, reversedir) == SIGNAL_STATE_RED) return;
- if (GetSignalAspect(tile, track) == aspect) return; // aspect already correct
+ bool combined_mode = IsRailCombinedNormalShuntSignalStyle(tile, track);
+ const uint8 current_aspect = GetSignalAspect(tile, track);
+ if (combined_mode && current_aspect == 1) {
+ /* Don't change special combined_normal_shunt aspect */
+ return;
+ }
+ if (combined_mode && aspect > 0) aspect = std::min(aspect + 1, 7);
+ if (current_aspect == aspect) return; // aspect already correct
SetSignalAspect(tile, track, aspect);
MarkSingleSignalDirty(tile, reversedir);
AdjustSignalAspectIfNonIncStyle(tile, TrackdirToTrack(trackdir), aspect);
@@ -1426,12 +1446,29 @@ void PropagateAspectChange(TileIndex tile, Trackdir trackdir, uint8 aspect)
}
static std::vector> _deferred_aspect_updates;
+static std::vector> _deferred_determine_combined_normal_shunt_mode;
-void UpdateAspectDeferred(TileIndex tile, Trackdir trackdir)
+struct DeferredLookaheadCombinedNormalShuntModeItem {
+ TileIndex tile;
+ Trackdir trackdir;
+ int lookahead_position;
+};
+static std::vector _deferred_lookahead_combined_normal_shunt_mode;
+
+void UpdateAspectDeferred(TileIndex tile, Trackdir trackdir, bool check_combined_normal_aspect)
{
+ if (check_combined_normal_aspect && IsRailCombinedNormalShuntSignalStyle(tile, TrackdirToTrack(trackdir)) &&
+ _settings_game.vehicle.train_braking_model == TBM_REALISTIC) {
+ _deferred_determine_combined_normal_shunt_mode.push_back({ tile, trackdir });
+ }
_deferred_aspect_updates.push_back({ tile, trackdir });
}
+void UpdateLookaheadCombinedNormalShuntSignalDeferred(TileIndex tile, Trackdir trackdir, int lookahead_position)
+{
+ _deferred_lookahead_combined_normal_shunt_mode.push_back({ tile, trackdir, lookahead_position });
+}
+
void FlushDeferredAspectUpdates()
{
/* Iterate in reverse order to reduce backtracking when updating the aspects of a new reservation */
@@ -1441,7 +1478,7 @@ void FlushDeferredAspectUpdates()
switch (GetTileType(tile)) {
case MP_RAILWAY:
if (HasSignalOnTrackdir(tile, trackdir) && GetSignalStateByTrackdir(tile, trackdir) == SIGNAL_STATE_GREEN && GetSignalAspect(tile, TrackdirToTrack(trackdir)) == 0) {
- uint8 aspect = GetForwardAspectFollowingTrackAndIncrement(tile, trackdir);
+ uint8 aspect = GetForwardAspectFollowingTrackAndIncrement(tile, trackdir, IsRailCombinedNormalShuntSignalStyle(tile, TrackdirToTrack(trackdir)));
SetSignalAspect(tile, TrackdirToTrack(trackdir), aspect);
PropagateAspectChange(tile, trackdir, aspect);
}
@@ -1469,6 +1506,68 @@ void FlushDeferredAspectUpdates()
_deferred_aspect_updates.clear();
}
+void DetermineCombineNormalShuntModeWithLookahead(Train *v, TileIndex tile, Trackdir trackdir, int lookahead_position)
+{
+ size_t count = v->lookahead->items.size();
+ for (size_t i = 0; i < count; i++) {
+ TrainReservationLookAheadItem &item = v->lookahead->items[i];
+ if (item.start == lookahead_position && item.type == TRLIT_SIGNAL && HasBit(item.data_aux, TRSLAI_COMBINED)) {
+ container_unordered_remove(_deferred_determine_combined_normal_shunt_mode, std::pair({ tile, trackdir }));
+
+ for (size_t j = i + 1; j < count; j++) {
+ const TrainReservationLookAheadItem &ahead = v->lookahead->items[j];
+ if (ahead.type == TRLIT_SIGNAL) {
+ if (HasBit(item.data_aux, TRSLAI_COMBINED)) return;
+ if (!HasBit(item.data_aux, TRSLAI_NO_ASPECT_INC) && !HasBit(item.data_aux, TRSLAI_NEXT_ONLY)) return;
+ }
+ }
+
+ if (IsRailDepotTile(v->lookahead->reservation_end_tile) || IsTileType(v->lookahead->reservation_end_tile, MP_TUNNELBRIDGE)) return;
+
+ CFollowTrackRail ft(v);
+ if (ft.Follow(v->lookahead->reservation_end_tile, v->lookahead->reservation_end_trackdir)) {
+ if (KillFirstBit(ft.m_new_td_bits) != TRACKDIR_BIT_NONE) {
+ /* reached a junction tile, shouldn't be reached, just assume normal route */
+ return;
+ }
+
+ TileIndex new_tile = ft.m_new_tile;
+ Trackdir new_trackdir = FindFirstTrackdir(ft.m_new_td_bits);
+
+ if (!(IsTileType(new_tile, MP_RAILWAY) && HasSignalOnTrackdir(new_tile, new_trackdir) && !IsNoEntrySignal(new_tile, TrackdirToTrack(new_trackdir)) &&
+ HasBit(_signal_style_masks.next_only, GetSignalStyle(new_tile, TrackdirToTrack(new_trackdir))))) {
+ /* Didn't find a shunt signal at the end of the reservation */
+ return;
+ }
+ } else {
+ /* end of line */
+ return;
+ }
+
+ /* shunt mode */
+ SetSignalAspect(tile, TrackdirToTrack(trackdir), 1);
+ SetBit(item.data_aux, TRSLAI_COMBINED_SHUNT);
+ return;
+ }
+ }
+}
+
+void FlushDeferredDetermineCombineNormalShuntMode(Train *v)
+{
+ for (const auto &iter : _deferred_lookahead_combined_normal_shunt_mode) {
+ DetermineCombineNormalShuntModeWithLookahead(v, iter.tile, iter.trackdir, iter.lookahead_position);
+ }
+ _deferred_lookahead_combined_normal_shunt_mode.clear();
+
+ for (const auto &iter : _deferred_determine_combined_normal_shunt_mode) {
+ TileIndex tile = iter.first;
+ Trackdir trackdir = iter.second;
+ /* Reservation with no associated lookahead, default to a shunt route */
+ SetSignalAspect(tile, TrackdirToTrack(trackdir), 1);
+ }
+ _deferred_determine_combined_normal_shunt_mode.clear();
+}
+
void UpdateAllSignalAspects()
{
for (TileIndex tile = 0; tile != MapSize(); ++tile) {
@@ -1479,8 +1578,8 @@ void UpdateAllSignalAspects()
if (HasSignalOnTrack(tile, track)) {
Trackdir trackdir = TrackToTrackdir(track);
if (!HasSignalOnTrackdir(tile, trackdir)) trackdir = ReverseTrackdir(trackdir);
- if (GetSignalStateByTrackdir(tile, trackdir) == SIGNAL_STATE_GREEN) {
- uint8 aspect = GetForwardAspectFollowingTrackAndIncrement(tile, trackdir);
+ if (GetSignalStateByTrackdir(tile, trackdir) == SIGNAL_STATE_GREEN && !IsRailSpecialSignalAspect(tile, track)) {
+ uint8 aspect = GetForwardAspectFollowingTrackAndIncrement(tile, trackdir, IsRailCombinedNormalShuntSignalStyle(tile, track));
SetSignalAspect(tile, track, aspect);
PropagateAspectChange(tile, trackdir, aspect);
}
@@ -1613,6 +1712,12 @@ static bool DetermineExtraAspectsVariable()
if (HasBit(_new_signal_styles[i].style_flags, NSSF_OPPOSITE_SIDE)) {
SetBit(_signal_style_masks.signal_opposite_side, i + 1);
}
+ if (HasBit(_new_signal_styles[i].style_flags, NSSF_COMBINED_NORMAL_SHUNT)) {
+ SetBit(_signal_style_masks.combined_normal_shunt, i + 1);
+ SetBit(_signal_style_masks.no_tunnel_bridge, i + 1);
+ _new_signal_styles[i].electric_mask &= (1 << SIGTYPE_PBS) | (1 << SIGTYPE_PBS_ONEWAY) | (1 << SIGTYPE_NO_ENTRY);
+ _new_signal_styles[i].semaphore_mask &= (1 << SIGTYPE_PBS) | (1 << SIGTYPE_PBS_ONEWAY) | (1 << SIGTYPE_NO_ENTRY);
+ }
}
for (uint i = _num_new_signal_styles; i < MAX_NEW_SIGNAL_STYLES; i++) {
_new_signal_styles[i].lookahead_extra_aspects = new_extra_aspects;
@@ -1665,6 +1770,12 @@ void InitialiseExtraAspectsVariable()
DetermineExtraAspectsVariable();
}
+bool IsRailSpecialSignalAspect(TileIndex tile, Track track)
+{
+ return _signal_style_masks.combined_normal_shunt != 0 && GetSignalAspect(tile, track) == 1 &&
+ HasBit(_signal_style_masks.combined_normal_shunt, GetSignalStyle(tile, track));
+}
+
void UpdateSignalReserveThroughBit(TileIndex tile, Track track, bool update_signal)
{
bool reserve_through = false;
diff --git a/src/signal_func.h b/src/signal_func.h
index 8ddb8a76f4..b65097c43e 100644
--- a/src/signal_func.h
+++ b/src/signal_func.h
@@ -33,6 +33,7 @@ struct SignalStyleMasks {
uint16 always_reserve_through = 0;
uint16 no_tunnel_bridge = 0;
uint16 signal_opposite_side = 0;
+ uint16 combined_normal_shunt = 0;
};
extern SignalStyleMasks _signal_style_masks;
@@ -188,21 +189,24 @@ void UpdateSignalsInBufferIfOwnerNotAddable(Owner owner);
uint8 GetForwardAspectFollowingTrack(TileIndex tile, Trackdir trackdir);
uint8 GetSignalAspectGeneric(TileIndex tile, Trackdir trackdir, bool check_non_inc_style);
void PropagateAspectChange(TileIndex tile, Trackdir trackdir, uint8 aspect);
-void UpdateAspectDeferred(TileIndex tile, Trackdir trackdir);
+void UpdateAspectDeferred(TileIndex tile, Trackdir trackdir, bool check_combined_normal_aspect);
+void UpdateLookaheadCombinedNormalShuntSignalDeferred(TileIndex tile, Trackdir trackdir, int lookahead_position);
void FlushDeferredAspectUpdates();
+void FlushDeferredDetermineCombineNormalShuntMode(Train *v);
void UpdateAllSignalAspects();
void UpdateExtraAspectsVariable();
void InitialiseExtraAspectsVariable();
+bool IsRailSpecialSignalAspect(TileIndex tile, Track track);
inline void AdjustSignalAspectIfNonIncStyle(TileIndex tile, Track track, uint8 &aspect)
{
extern void AdjustSignalAspectIfNonIncStyleIntl(TileIndex tile, Track track, uint8 &aspect);
- if (aspect > 0 && _signal_style_masks.non_aspect_inc != 0) AdjustSignalAspectIfNonIncStyleIntl(tile, track, aspect);
+ if (aspect > 0 && (_signal_style_masks.non_aspect_inc != 0 || _signal_style_masks.combined_normal_shunt != 0)) AdjustSignalAspectIfNonIncStyleIntl(tile, track, aspect);
}
-inline uint8 GetForwardAspectFollowingTrackAndIncrement(TileIndex tile, Trackdir trackdir)
+inline uint8 GetForwardAspectFollowingTrackAndIncrement(TileIndex tile, Trackdir trackdir, bool combined_normal_mode = false)
{
- return std::min(GetForwardAspectFollowingTrack(tile, trackdir) + 1, GetMaximumSignalAspect());
+ return std::min(GetForwardAspectFollowingTrack(tile, trackdir) + (combined_normal_mode ? 2 : 1), GetMaximumSignalAspect());
}
void UpdateSignalReserveThroughBit(TileIndex tile, Track track, bool update_signal);
diff --git a/src/table/newgrf_debug_data.h b/src/table/newgrf_debug_data.h
index 6d95084aa9..fcc480b3b3 100644
--- a/src/table/newgrf_debug_data.h
+++ b/src/table/newgrf_debug_data.h
@@ -279,6 +279,8 @@ class NIHVehicle : public NIHelper {
b += seprintf(b, lastof(buffer), "signal: target speed: %u, style: %u, flags:", item.data_id, item.data_aux >> 8);
if (HasBit(item.data_aux, TRSLAI_NO_ASPECT_INC)) b += seprintf(b, lastof(buffer), "n");
if (HasBit(item.data_aux, TRSLAI_NEXT_ONLY)) b += seprintf(b, lastof(buffer), "s");
+ if (HasBit(item.data_aux, TRSLAI_COMBINED)) b += seprintf(b, lastof(buffer), "c");
+ if (HasBit(item.data_aux, TRSLAI_COMBINED_SHUNT)) b += seprintf(b, lastof(buffer), "X");
if (_settings_game.vehicle.realistic_braking_aspect_limited == TRBALM_ON && l.lookahead_end_position == item.start) {
b += seprintf(b, lastof(buffer), ", lookahead end");
print_braking_speed(item.start, 0, item.z_pos);
diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp
index ecd971cc5f..aeb1c5febe 100644
--- a/src/train_cmd.cpp
+++ b/src/train_cmd.cpp
@@ -3454,7 +3454,7 @@ static void SetTunnelBridgeEntranceSignalGreen(TileIndex tile)
MarkTunnelBridgeSignalDirty(tile, false);
if (_extra_aspects > 0) {
SetTunnelBridgeEntranceSignalAspect(tile, 0);
- UpdateAspectDeferred(tile, GetTunnelBridgeEntranceTrackdir(tile));
+ UpdateAspectDeferred(tile, GetTunnelBridgeEntranceTrackdir(tile), false);
}
} else if (_extra_aspects > 0) {
UpdateTunnelBridgeEntranceSignalAspect(tile);
@@ -4086,6 +4086,7 @@ static TileIndex CheckLongReservePbsTunnelBridgeOnTrackdir(Train* v, TileIndex t
} else {
raw_free_tiles = GetAvailableFreeTilesInSignalledTunnelBridgeWithStartOffset(tile, end, v->lookahead->tunnel_bridge_reserved_tiles + 1);
ApplyAvailableFreeTunnelBridgeTiles(v->lookahead.get(), raw_free_tiles, tile, end);
+ FlushDeferredDetermineCombineNormalShuntMode(v);
SetTrainReservationLookaheadEnd(v);
}
} else {
@@ -4156,7 +4157,7 @@ static void TryLongReserveChooseTrainTrack(Train *v, TileIndex tile, Trackdir td
} else {
if (_extra_aspects > 0) {
SetTunnelBridgeExitSignalAspect(exit_tile, 0);
- UpdateAspectDeferred(exit_tile, GetTunnelBridgeExitTrackdir(exit_tile));
+ UpdateAspectDeferred(exit_tile, GetTunnelBridgeExitTrackdir(exit_tile), false);
}
MarkTileDirtyByTile(exit_tile, VMDF_NOT_MAP_MODE);
}
@@ -4250,7 +4251,7 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir,
SetSignalStateByTrackdir(tile, changed_signal, SIGNAL_STATE_GREEN);
if (_extra_aspects > 0) {
SetSignalAspect(tile, track, 0);
- UpdateAspectDeferred(tile, changed_signal);
+ UpdateAspectDeferred(tile, changed_signal, true);
}
} else if (!do_track_reservation) {
return track;
@@ -5141,7 +5142,7 @@ static bool CheckTrainStayInWormHolePathReserve(Train *t, TileIndex tile)
if (ok) {
if (_extra_aspects > 0) {
SetTunnelBridgeExitSignalAspect(tile, 0);
- UpdateAspectDeferred(tile, GetTunnelBridgeExitTrackdir(tile));
+ UpdateAspectDeferred(tile, GetTunnelBridgeExitTrackdir(tile), false);
}
mark_dirty = true;
if (t->lookahead->reservation_end_tile == veh_orig_tile && t->lookahead->reservation_end_position - t->lookahead->current_position <= (int)TILE_SIZE) {
@@ -5186,7 +5187,7 @@ static bool CheckTrainStayInWormHolePathReserve(Train *t, TileIndex tile)
SetTunnelBridgeExitSignalState(tile, SIGNAL_STATE_GREEN);
if (_extra_aspects > 0) {
SetTunnelBridgeExitSignalAspect(tile, 0);
- UpdateAspectDeferred(tile, GetTunnelBridgeExitTrackdir(tile));
+ UpdateAspectDeferred(tile, GetTunnelBridgeExitTrackdir(tile), false);
}
mark_dirty = true;
}
|