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_lookahead_single_signal_only0 or 1 Set the look-ahead to single signal only mode for the most recently defined style (defined using the 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 tyle_combined_normal_shunt.
This is similar to style_lookahead_extra_aspects with a value of 0, except the lookahead always ends at the next signal, even if that signal type sets style_no_aspect_increase.
If enabled, this property overrides style_lookahead_extra_aspects.
This can be used for shunt signals. + style_combined_normal_shunt0 or 1 + + Enable functioning as a combined normal aspect and shunt signal for the most recently defined style (defined using the define_style property).
+ When enabled and displaying a shunt aspect, the signal state in the lowest byte of extra_callback_info2 will have the value: 0xFF. + + style_opposite_side0 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; }