From d03139b2411ebef703af47100e895d89407c4fdb Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 17 Jun 2018 03:29:47 +0100 Subject: [PATCH 1/2] Use separate bits for signals on bridge/tunnel entrance/exit red/green states --- docs/landscape.html | 3 ++- docs/landscape_grid.html | 2 +- src/pbs.cpp | 4 +-- src/rail_cmd.cpp | 6 ++--- src/saveload/afterload.cpp | 10 ++++++- src/saveload/extended_ver_sl.cpp | 3 +-- src/signal.cpp | 4 +-- src/train_cmd.cpp | 46 ++++++++++++++++++++++---------- src/tunnelbridge_cmd.cpp | 7 ++--- src/tunnelbridge_map.h | 34 +++++++++++++++++++---- 10 files changed, 85 insertions(+), 34 deletions(-) diff --git a/docs/landscape.html b/docs/landscape.html index 50e53a9f3a..86a6943fdd 100644 --- a/docs/landscape.html +++ b/docs/landscape.html @@ -1557,9 +1557,10 @@ If signal simulation entrance or exit: diff --git a/docs/landscape_grid.html b/docs/landscape_grid.html index 2db8e015fb..91a3a246f6 100644 --- a/docs/landscape_grid.html +++ b/docs/landscape_grid.html @@ -337,7 +337,7 @@ the array so you can quickly see what is used and what is not. XXXX XXXX OOOO OOOO XPPX XXXX - OPOO OOPP + PPOO OOPP XXXX XXXX diff --git a/src/pbs.cpp b/src/pbs.cpp index f1adaf0d9c..8e9edb8e55 100644 --- a/src/pbs.cpp +++ b/src/pbs.cpp @@ -125,7 +125,7 @@ bool TryReserveRailTrack(TileIndex tile, Track t, bool trigger_stations) case MP_TUNNELBRIDGE: if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL && !GetTunnelBridgeReservationTrackBits(tile)) { SetTunnelBridgeReservation(tile, true); - if (IsTunnelBridgeSignalSimulationExit(tile) && IsTunnelBridgePBS(tile)) SetTunnelBridgeSignalState(tile, SIGNAL_STATE_GREEN); + if (IsTunnelBridgeSignalSimulationExit(tile) && IsTunnelBridgePBS(tile)) SetTunnelBridgeExitSignalState(tile, SIGNAL_STATE_GREEN); MarkTileDirtyByTile(tile); return true; } @@ -181,7 +181,7 @@ void UnreserveRailTrack(TileIndex tile, Track t) case MP_TUNNELBRIDGE: if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) { SetTunnelBridgeReservation(tile, false); - if (IsTunnelBridgeSignalSimulationExit(tile) && IsTunnelBridgePBS(tile)) SetTunnelBridgeSignalState(tile, SIGNAL_STATE_RED); + if (IsTunnelBridgeSignalSimulationExit(tile) && IsTunnelBridgePBS(tile)) SetTunnelBridgeExitSignalState(tile, SIGNAL_STATE_RED); MarkTileDirtyByTile(tile); } break; diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index 4d97ee8ca9..bfc1f7c78e 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -1022,7 +1022,7 @@ static void ClearBridgeTunnelSignalSimulation(TileIndex entrance, TileIndex exit static void SetupBridgeTunnelSignalSimulation(TileIndex entrance, TileIndex exit) { SetTunnelBridgeSignalSimulationEntrance(entrance); - SetTunnelBridgeSignalState(entrance, SIGNAL_STATE_GREEN); + SetTunnelBridgeEntranceSignalState(entrance, SIGNAL_STATE_GREEN); SetTunnelBridgeSignalSimulationExit(exit); } @@ -1144,8 +1144,8 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, SetTunnelBridgePBS(tile_exit, is_pbs); } } - if (IsTunnelBridgeSignalSimulationExit(tile) && IsTunnelBridgePBS(tile) && !HasTunnelBridgeReservation(tile)) SetTunnelBridgeSignalState(tile, SIGNAL_STATE_RED); - if (IsTunnelBridgeSignalSimulationExit(tile_exit) && IsTunnelBridgePBS(tile_exit) && !HasTunnelBridgeReservation(tile_exit)) SetTunnelBridgeSignalState(tile_exit, SIGNAL_STATE_RED); + if (IsTunnelBridgeSignalSimulationExit(tile) && IsTunnelBridgePBS(tile) && !HasTunnelBridgeReservation(tile)) SetTunnelBridgeExitSignalState(tile, SIGNAL_STATE_RED); + if (IsTunnelBridgeSignalSimulationExit(tile_exit) && IsTunnelBridgePBS(tile_exit) && !HasTunnelBridgeReservation(tile_exit)) SetTunnelBridgeExitSignalState(tile_exit, SIGNAL_STATE_RED); MarkBridgeOrTunnelDirty(tile); AddSideToSignalBuffer(tile, INVALID_DIAGDIR, GetTileOwner(tile)); AddSideToSignalBuffer(tile_exit, INVALID_DIAGDIR, GetTileOwner(tile)); diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 8080e9f27c..95fc762047 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -2989,7 +2989,7 @@ bool AfterLoadGame() /* signalled tunnel entrance */ SignalState state = HasBit(_m[t].m5, 6) ? SIGNAL_STATE_RED : SIGNAL_STATE_GREEN; ClrBit(_m[t].m5, 6); - SetTunnelBridgeSignalState(t, state); + SetTunnelBridgeEntranceSignalState(t, state); } } } @@ -3005,6 +3005,14 @@ bool AfterLoadGame() } } } + if (SlXvIsFeaturePresent(XSLFI_SIG_TUNNEL_BRIDGE, 1, 5)) { + /* entrance and exit signal red/green states now have separate bits */ + for (TileIndex t = 0; t < map_size; t++) { + if (IsTileType(t, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL && IsTunnelBridgeSignalSimulationExit(t)) { + SetTunnelBridgeExitSignalState(t, HasBit(_me[t].m6, 0) ? SIGNAL_STATE_GREEN : SIGNAL_STATE_RED); + } + } + } /* Station acceptance is some kind of cache */ if (IsSavegameVersionBefore(127)) { diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp index 40779a3b3e..d42b7b8b21 100644 --- a/src/saveload/extended_ver_sl.cpp +++ b/src/saveload/extended_ver_sl.cpp @@ -45,8 +45,7 @@ std::vector _sl_xv_discardable_chunk_ids; ///< list of chunks static const uint32 _sl_xv_slxi_chunk_version = 0; ///< current version os SLXI chunk const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { - { XSLFI_SIG_TUNNEL_BRIDGE, XSCF_NULL, 5, 5, "signal_tunnel_bridge", NULL, NULL, "XBSS" }, - { XSLFI_NULL, XSCF_NULL, 0, 0, NULL, NULL, NULL, NULL },// This is the end marker + { XSLFI_SIG_TUNNEL_BRIDGE, XSCF_NULL, 6, 6, "signal_tunnel_bridge", NULL, NULL, "XBSS" }, }; /** diff --git a/src/signal.cpp b/src/signal.cpp index 57eabb5a84..8237fa723c 100644 --- a/src/signal.cpp +++ b/src/signal.cpp @@ -455,10 +455,10 @@ static void UpdateSignalsAroundSegment(SigFlags flags) while (_tbuset.Get(&tile, &trackdir)) { if (IsTileType(tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExit(tile)) { if (IsTunnelBridgePBS(tile)) continue; - SignalState old_state = GetTunnelBridgeSignalState(tile); + SignalState old_state = GetTunnelBridgeExitSignalState(tile); SignalState new_state = (flags & SF_TRAIN) ? SIGNAL_STATE_RED : SIGNAL_STATE_GREEN; if (old_state != new_state) { - SetTunnelBridgeSignalState(tile, new_state); + SetTunnelBridgeExitSignalState(tile, new_state); MarkTileDirtyByTile(tile); } continue; diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 5a6f169163..fbcdf65bb5 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -1874,10 +1874,10 @@ void ReverseTrainDirection(Train *v) return; } - /* We are inside tunnel/bidge with signals, reversing will close the entrance. */ + /* We are inside tunnel/bridge with signals, reversing will close the entrance. */ if (IsTunnelBridgeWithSignalSimulation(v->tile)) { /* Flip signal on tunnel entrance tile red. */ - SetTunnelBridgeSignalState(v->tile, SIGNAL_STATE_RED); + SetTunnelBridgeEntranceSignalState(v->tile, SIGNAL_STATE_RED); MarkTileDirtyByTile(v->tile); /* Clear counters. */ v->wait_counter = 0; @@ -2266,11 +2266,11 @@ static void HandleLastTunnelBridgeSignals(TileIndex tile, TileIndex end, DiagDir SetAllBridgeEntranceSimulatedSignalsGreen(end); } - if (IsTunnelBridgeSignalSimulationEntrance(end) && GetTunnelBridgeSignalState(end) == SIGNAL_STATE_RED) { - SetTunnelBridgeSignalState(end, SIGNAL_STATE_GREEN); + if (IsTunnelBridgeSignalSimulationEntrance(end) && GetTunnelBridgeEntranceSignalState(end) == SIGNAL_STATE_RED) { + SetTunnelBridgeEntranceSignalState(end, SIGNAL_STATE_GREEN); MarkTileDirtyByTile(end); - } else if (IsTunnelBridgeSignalSimulationEntrance(tile) && GetTunnelBridgeSignalState(tile) == SIGNAL_STATE_RED) { - SetTunnelBridgeSignalState(tile, SIGNAL_STATE_GREEN); + } else if (IsTunnelBridgeSignalSimulationEntrance(tile) && GetTunnelBridgeEntranceSignalState(tile) == SIGNAL_STATE_RED) { + SetTunnelBridgeEntranceSignalState(tile, SIGNAL_STATE_GREEN); MarkTileDirtyByTile(tile); } } @@ -2279,7 +2279,7 @@ static void HandleLastTunnelBridgeSignals(TileIndex tile, TileIndex end, DiagDir static void UnreserveBridgeTunnelTile(TileIndex tile) { SetTunnelBridgeReservation(tile, false); - if (IsTunnelBridgeSignalSimulationExit(tile) && IsTunnelBridgePBS(tile)) SetTunnelBridgeSignalState(tile, SIGNAL_STATE_RED); + if (IsTunnelBridgeSignalSimulationExit(tile) && IsTunnelBridgePBS(tile)) SetTunnelBridgeExitSignalState(tile, SIGNAL_STATE_RED); } /** @@ -3269,7 +3269,7 @@ static bool CheckTrainStayInWormHolePathReserve(Train *t, TileIndex tile) } bool ok = TryPathReserve(t); t->tile = veh_orig; - if (ok && IsTunnelBridgePBS(tile)) SetTunnelBridgeSignalState(tile, SIGNAL_STATE_GREEN); + if (ok && IsTunnelBridgePBS(tile)) SetTunnelBridgeExitSignalState(tile, SIGNAL_STATE_GREEN); return ok; } @@ -3317,8 +3317,8 @@ static void HandleSignalBehindTrain(Train *v, int signal_number) if(tile == v->tile) { /* Flip signal on ramp. */ - if (IsTunnelBridgeSignalSimulationEntrance(tile) && GetTunnelBridgeSignalState(tile) == SIGNAL_STATE_RED) { - SetTunnelBridgeSignalState(tile, SIGNAL_STATE_GREEN); + if (IsTunnelBridgeSignalSimulationEntrance(tile) && GetTunnelBridgeEntranceSignalState(tile) == SIGNAL_STATE_RED) { + SetTunnelBridgeEntranceSignalState(tile, SIGNAL_STATE_GREEN); MarkTileDirtyByTile(tile); } } else if (IsBridge(v->tile) && signal_number >= 0) { @@ -3515,7 +3515,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) if (IsTunnelBridgeWithSignalSimulation(gp.new_tile)) { /* If red signal stop. */ if (v->IsFrontEngine() && v->force_proceed == 0) { - if (IsTunnelBridgeSignalSimulationEntrance(gp.new_tile) && GetTunnelBridgeSignalState(gp.new_tile) == SIGNAL_STATE_RED) { + if (IsTunnelBridgeSignalSimulationEntrance(gp.new_tile) && GetTunnelBridgeEntranceSignalState(gp.new_tile) == SIGNAL_STATE_RED) { v->cur_speed = 0; v->vehstatus |= VS_TRAIN_SLOWING; return false; @@ -3525,7 +3525,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) goto invalid_rail; } /* Flip signal on tunnel entrance tile red. */ - SetTunnelBridgeSignalState(gp.new_tile, SIGNAL_STATE_RED); + SetTunnelBridgeEntranceSignalState(gp.new_tile, SIGNAL_STATE_RED); MarkTileDirtyByTile(gp.new_tile); } } @@ -3837,7 +3837,25 @@ static void DeleteLastWagon(Train *v) if (IsLevelCrossingTile(tile)) UpdateLevelCrossing(tile); /* Update signals */ - if (IsTileType(tile, MP_TUNNELBRIDGE) || IsRailDepotTile(tile)) { + if (IsTileType(tile, MP_TUNNELBRIDGE)) { + UpdateSignalsOnSegment(tile, INVALID_DIAGDIR, owner); + if (IsTunnelBridgeWithSignalSimulation(tile)) { + TileIndex end = GetOtherTunnelBridgeEnd(tile); + UpdateSignalsOnSegment(end, INVALID_DIAGDIR, owner); + bool is_entrance = IsTunnelBridgeSignalSimulationEntrance(tile); + TileIndex entrance = is_entrance ? tile : end; + if (TunnelBridgeIsFree(tile, end, nullptr).Succeeded()) { + if (IsBridge(entrance)) { + SetAllBridgeEntranceSimulatedSignalsGreen(entrance); + MarkBridgeDirty(entrance); + } + if (IsTunnelBridgeSignalSimulationEntrance(entrance) && GetTunnelBridgeEntranceSignalState(entrance) == SIGNAL_STATE_RED) { + SetTunnelBridgeEntranceSignalState(entrance, SIGNAL_STATE_GREEN); + MarkTileDirtyByTile(entrance); + } + } + } + } else if (IsRailDepotTile(tile)) { UpdateSignalsOnSegment(tile, INVALID_DIAGDIR, owner); } else { SetSignalsOnBothDir(tile, track, owner); @@ -4078,7 +4096,7 @@ static bool TrainCheckIfLineEnds(Train *v, bool reverse) if (IsLevelCrossingTile(tile)) MaybeBarCrossingWithSound(tile); if (IsTileType(tile, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL && - IsTunnelBridgeSignalSimulationEntrance(tile) && GetTunnelBridgeSignalState(tile) == SIGNAL_STATE_RED) { + IsTunnelBridgeSignalSimulationEntrance(tile) && GetTunnelBridgeEntranceSignalState(tile) == SIGNAL_STATE_RED) { return TrainApproachingLineEnd(v, true, reverse); } diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp index 83f82e29f5..ccb25a315f 100644 --- a/src/tunnelbridge_cmd.cpp +++ b/src/tunnelbridge_cmd.cpp @@ -1183,13 +1183,14 @@ static void DrawTunnelBridgeRampSignal(const TileInfo *ti) SignalType type = SIGTYPE_NORMAL; - bool is_green = (GetTunnelBridgeSignalState(ti->tile) == SIGNAL_STATE_GREEN); - bool show_exit; + bool is_green, show_exit; if (IsTunnelBridgeSignalSimulationExit(ti->tile)) { + is_green = (GetTunnelBridgeExitSignalState(ti->tile) == SIGNAL_STATE_GREEN); show_exit = true; position ^= 1; if (IsTunnelBridgePBS(ti->tile)) type = SIGTYPE_PBS_ONEWAY; } else { + is_green = (GetTunnelBridgeEntranceSignalState(ti->tile) == SIGNAL_STATE_GREEN); show_exit = false; } @@ -1216,7 +1217,7 @@ static void DrawTunnelBridgeRampSignal(const TileInfo *ti) } /* Draws a signal on tunnel / bridge entrance tile. */ -static void DrawBrigeSignalOnMiddlePart(const TileInfo *ti, TileIndex bridge_start_tile, uint z) +static void DrawBridgeSignalOnMiddlePart(const TileInfo *ti, TileIndex bridge_start_tile, uint z) { uint bridge_signal_position = 0; diff --git a/src/tunnelbridge_map.h b/src/tunnelbridge_map.h index 499aad99b7..f6a21e9992 100644 --- a/src/tunnelbridge_map.h +++ b/src/tunnelbridge_map.h @@ -199,29 +199,53 @@ static inline bool IsTunnelBridgeSignalSimulationExit(TileIndex t) } /** - * Get the signal state for a tunnel/bridge entrance or exit with signal simulation + * Get the signal state for a tunnel/bridge entrance with signal simulation * @param t the tunnel/bridge entrance or exit tile with signal simulation * @pre IsTunnelBridgeWithSignalSimulation(t) * @return signal state */ -static inline SignalState GetTunnelBridgeSignalState(TileIndex t) +static inline SignalState GetTunnelBridgeEntranceSignalState(TileIndex t) { - assert(IsTunnelBridgeWithSignalSimulation(t)); + assert(IsTunnelBridgeSignalSimulationEntrance(t)); return HasBit(_me[t].m6, 0) ? SIGNAL_STATE_GREEN : SIGNAL_STATE_RED; } +/** + * Get the signal state for a tunnel/bridge exit with signal simulation + * @param t the tunnel/bridge entrance or exit tile with signal simulation + * @pre IsTunnelBridgeWithSignalSimulation(t) + * @return signal state + */ +static inline SignalState GetTunnelBridgeExitSignalState(TileIndex t) +{ + assert(IsTunnelBridgeSignalSimulationExit(t)); + return HasBit(_me[t].m6, 7) ? SIGNAL_STATE_GREEN : SIGNAL_STATE_RED; +} + /** * Set the signal state for a tunnel/bridge entrance or exit with signal simulation * @param t the tunnel/bridge entrance or exit tile with signal simulation * @pre IsTunnelBridgeWithSignalSimulation(t) * @param state signal state */ -static inline void SetTunnelBridgeSignalState(TileIndex t, SignalState state) +static inline void SetTunnelBridgeEntranceSignalState(TileIndex t, SignalState state) { - assert(IsTunnelBridgeWithSignalSimulation(t)); + assert(IsTunnelBridgeSignalSimulationEntrance(t)); SB(_me[t].m6, 0, 1, (state == SIGNAL_STATE_GREEN) ? 1 : 0); } +/** + * Set the signal state for a tunnel/bridge entrance or exit with signal simulation + * @param t the tunnel/bridge entrance or exit tile with signal simulation + * @pre IsTunnelBridgeWithSignalSimulation(t) + * @param state signal state + */ +static inline void SetTunnelBridgeExitSignalState(TileIndex t, SignalState state) +{ + assert(IsTunnelBridgeSignalSimulationExit(t)); + SB(_me[t].m6, 7, 1, (state == SIGNAL_STATE_GREEN) ? 1 : 0); +} + static inline bool IsTunnelBridgeSemaphore(TileIndex t) { assert(IsTunnelBridgeWithSignalSimulation(t)); From 814f9f7e0f9bdbc506e2fc2a75ee9ecc22c85f49 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 17 Jun 2018 04:27:03 +0100 Subject: [PATCH 2/2] Implement bidirectional mode for signals on bridges/tunnels --- docs/landscape.html | 5 ++ src/lang/english.txt | 3 ++ src/pathfinder/npf/npf.cpp | 2 +- src/pathfinder/yapf/yapf_costrail.hpp | 2 +- src/pbs.cpp | 17 +++++-- src/rail_cmd.cpp | 48 ++++++++++++++++-- src/rail_gui.cpp | 1 + src/rail_map.h | 2 +- src/settings_gui.cpp | 1 + src/settings_type.h | 1 + src/table/settings.ini | 8 +++ src/train_cmd.cpp | 42 ++++++++++------ src/tunnelbridge.h | 13 +---- src/tunnelbridge_cmd.cpp | 70 ++++++++++++++------------- src/tunnelbridge_map.h | 26 +++++++++- 15 files changed, 170 insertions(+), 71 deletions(-) diff --git a/docs/landscape.html b/docs/landscape.html index 86a6943fdd..ededf0a3f0 100644 --- a/docs/landscape.html +++ b/docs/landscape.html @@ -1554,6 +1554,11 @@ 2  signal simulation exit (bit 6 set) + + + 3  + signal simulation bidirectional entrance and exit (bits 5 and 6 set) + If signal simulation entrance or exit:
    diff --git a/src/lang/english.txt b/src/lang/english.txt index e3f18abcbb..90e8ee6919 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1288,6 +1288,9 @@ STR_CONFIG_SETTING_POPULATION_IN_LABEL_HELPTEXT :Display the pop STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS :Thickness of lines in graphs: {STRING2} STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS_HELPTEXT :Width of the line in the graphs. A thin line is more precisely readable, a thicker line is easier to see and colours are easier to distinguish +STR_CONFIG_SETTING_ADV_SIG_BRIDGE_TUN_MODES :Enable signals on bridges/tunnels advanced modes: {STRING2} +STR_CONFIG_SETTING_ADV_SIG_BRIDGE_TUN_MODES_HELPTEXT :Enables use of advanced modes of signal simulation on bridges and tunnels. When disabled, bridges/tunnels which are not already in an advanced mode cannot be changed to an advanced mode, however other players may choose to enable this setting and use an advanced mode. + STR_CONFIG_SETTING_LANDSCAPE :Landscape: {STRING2} STR_CONFIG_SETTING_LANDSCAPE_HELPTEXT :Landscapes define basic gameplay scenarios with different cargos and town growth requirements. NewGRF and Game Scripts allow finer control though STR_CONFIG_SETTING_LAND_GENERATOR :Land generator: {STRING2} diff --git a/src/pathfinder/npf/npf.cpp b/src/pathfinder/npf/npf.cpp index 41ec4b53f3..880f14cfc0 100644 --- a/src/pathfinder/npf/npf.cpp +++ b/src/pathfinder/npf/npf.cpp @@ -936,7 +936,7 @@ static void NPFFollowTrack(AyStar *aystar, OpenListNode *current) break; } } - if (IsTileType(dst_tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExit(dst_tile) && DiagDirToDiagTrackdir(GetTunnelBridgeDirection(dst_tile)) == dst_trackdir) { + if (IsTileType(dst_tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExitOnly(dst_tile) && DiagDirToDiagTrackdir(GetTunnelBridgeDirection(dst_tile)) == dst_trackdir) { /* Entering a signalled bridge/tunnel from the wrong side, equivalent to encountering a one-way signal from the wrong side */ break; } diff --git a/src/pathfinder/yapf/yapf_costrail.hpp b/src/pathfinder/yapf/yapf_costrail.hpp index 5b90f0b82e..08abcb7aaf 100644 --- a/src/pathfinder/yapf/yapf_costrail.hpp +++ b/src/pathfinder/yapf/yapf_costrail.hpp @@ -244,7 +244,7 @@ public: } } } - if (IsTileType(tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExit(tile) && DiagDirToDiagTrackdir(GetTunnelBridgeDirection(tile)) == trackdir) { + if (IsTileType(tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExitOnly(tile) && DiagDirToDiagTrackdir(GetTunnelBridgeDirection(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; } diff --git a/src/pbs.cpp b/src/pbs.cpp index 8e9edb8e55..29e987c7e7 100644 --- a/src/pbs.cpp +++ b/src/pbs.cpp @@ -125,7 +125,6 @@ bool TryReserveRailTrack(TileIndex tile, Track t, bool trigger_stations) case MP_TUNNELBRIDGE: if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL && !GetTunnelBridgeReservationTrackBits(tile)) { SetTunnelBridgeReservation(tile, true); - if (IsTunnelBridgeSignalSimulationExit(tile) && IsTunnelBridgePBS(tile)) SetTunnelBridgeExitSignalState(tile, SIGNAL_STATE_GREEN); MarkTileDirtyByTile(tile); return true; } @@ -434,7 +433,7 @@ bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bo return include_line_end; } if (IsTileType(ft.m_new_tile, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(ft.m_new_tile) == TRANSPORT_RAIL && - IsTunnelBridgeSignalSimulationExit(ft.m_new_tile) && IsTunnelBridgePBS(ft.m_new_tile)) { + IsTunnelBridgeSignalSimulationExitOnly(ft.m_new_tile) && IsTunnelBridgePBS(ft.m_new_tile)) { return include_line_end; } } @@ -462,7 +461,19 @@ 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; if (IsTileType(tile, MP_RAILWAY) && HasSignalOnTrackdir(tile, trackdir) && !IsPbsSignal(GetSignalType(tile, track))) return true; - if (IsTileType(tile, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL && IsTunnelBridgeSignalSimulationEntrance(tile)) return true; + if (IsTileType(tile, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL && IsTunnelBridgeSignalSimulationEntrance(tile)) { + if (IsTunnelBridgeSignalSimulationBidirectional(tile)) { + TileIndex other_end = GetOtherTunnelBridgeEnd(tile); + if (HasTunnelBridgeReservation(other_end) && GetTunnelBridgeExitSignalState(other_end) == SIGNAL_STATE_RED) return false; + Direction dir = DiagDirToDir(GetTunnelBridgeDirection(other_end)); + if (HasVehicleOnPos(other_end, &dir, [](Vehicle *v, void *data) -> Vehicle * { + if (v->type != VEH_TRAIN) return nullptr; + if (v->direction != *((Direction *) data)) return nullptr; + return v; + })) return false; + } + return true; + } /* Check the next tile, if it's a PBS signal, it has to be free as well. */ CFollowTrackRail ft(v, GetRailTypeInfo(v->railtype)->compatible_railtypes); diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index bfc1f7c78e..6e97ad513c 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -1042,6 +1042,7 @@ static void SetupBridgeTunnelSignalSimulation(TileIndex entrance, TileIndex exit * - p1 = (bit 12-14)-wrap around after this signal type * - p1 = (bit 15-16)-cycle the signal direction this many times * - p1 = (bit 17) - 1 = don't modify an existing signal but don't fail either, 0 = always set new signal type + * - p1 = (bit 18) - permit creation of/conversion to bidirectionally signalled bridges/tunnels * @param p2 used for CmdBuildManySignals() to copy direction of first signal * @param text unused * @return the cost of this operation or an error @@ -1080,22 +1081,47 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, CommandCost cost; /* handle signals simulation on tunnel/bridge. */ if (IsTileType(tile, MP_TUNNELBRIDGE)) { + bool bidirectional = HasBit(p1, 18) && (sigtype == SIGTYPE_PBS); TileIndex tile_exit = GetOtherTunnelBridgeEnd(tile); cost = CommandCost(); bool flip_variant = false; bool is_pbs = (sigtype == SIGTYPE_PBS) || (sigtype == SIGTYPE_PBS_ONEWAY); if (!IsTunnelBridgeWithSignalSimulation(tile)) { // toggle signal zero costs. if (convert_signal) return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS); - if (p2 != 12) cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] * ((GetTunnelBridgeLength(tile, tile_exit) + 4) >> 2)); // minimal 1 + if (p2 != 12) cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] * ((GetTunnelBridgeLength(tile, tile_exit) + 4) >> 2) * (bidirectional ? 2 : 1)); // minimal 1 } else { if (HasBit(p1, 17)) return CommandCost(); + bool is_bidi = IsTunnelBridgeSignalSimulationBidirectional(tile); + bool will_be_bidi = is_bidi; + if (p2 == 0) { + if (convert_signal) { + will_be_bidi = bidirectional && !ctrl_pressed; + } else if (ctrl_pressed) { + will_be_bidi = false; + } + } else if (!is_pbs) { + will_be_bidi = false; + } if ((p2 != 0 && (sigvar == SIG_SEMAPHORE) != IsTunnelBridgeSemaphore(tile)) || (convert_signal && (ctrl_pressed || (sigvar == SIG_SEMAPHORE) != IsTunnelBridgeSemaphore(tile)))) { flip_variant = true; - cost = CommandCost(EXPENSES_CONSTRUCTION, (_price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]) * + cost = CommandCost(EXPENSES_CONSTRUCTION, ((_price[PR_BUILD_SIGNALS] * (will_be_bidi ? 2 : 1)) + (_price[PR_CLEAR_SIGNALS] * (is_bidi ? 2 : 1))) * ((GetTunnelBridgeLength(tile, tile_exit) + 4) >> 2)); // minimal 1 + } else if (is_bidi != will_be_bidi) { + cost = CommandCost(EXPENSES_CONSTRUCTION, _price[will_be_bidi ? PR_BUILD_SIGNALS : PR_CLEAR_SIGNALS] * ((GetTunnelBridgeLength(tile, tile_exit) + 4) >> 2)); // minimal 1 } } + auto remove_pbs_bidi = [&]() { + if (IsTunnelBridgeSignalSimulationBidirectional(tile)) { + ClrTunnelBridgeSignalSimulationExit(tile); + ClrTunnelBridgeSignalSimulationEntrance(tile_exit); + } + }; + auto set_bidi = [&](TileIndex t) { + SetTunnelBridgeSignalSimulationEntrance(t); + SetTunnelBridgeEntranceSignalState(t, SIGNAL_STATE_GREEN); + SetTunnelBridgeSignalSimulationExit(t); + }; if (flags & DC_EXEC) { Company * const c = Company::Get(GetTileOwner(tile)); if (IsTunnelBridgeWithSignalSimulation(tile)) c->infrastructure.signal -= GetTunnelBridgeSignalSimulationSignalCount(tile, tile_exit); @@ -1108,11 +1134,18 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, if (!ctrl_pressed) { SetTunnelBridgePBS(tile, is_pbs); SetTunnelBridgePBS(tile_exit, is_pbs); + if (bidirectional) { + set_bidi(tile); + set_bidi(tile_exit); + } else { + remove_pbs_bidi(); + } } } else if (ctrl_pressed) { SetTunnelBridgePBS(tile, !IsTunnelBridgePBS(tile)); SetTunnelBridgePBS(tile_exit, IsTunnelBridgePBS(tile)); - } else { + if (!IsTunnelBridgePBS(tile)) remove_pbs_bidi(); + } else if (!IsTunnelBridgeSignalSimulationBidirectional(tile)) { if (IsTunnelBridgeSignalSimulationEntrance(tile)) { ClearBridgeTunnelSignalSimulation(tile, tile_exit); SetupBridgeTunnelSignalSimulation(tile_exit, tile); @@ -1124,7 +1157,12 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, } else { /* Create one direction tunnel/bridge if required. */ if (p2 == 0) { - SetupBridgeTunnelSignalSimulation(tile, tile_exit); + if (bidirectional) { + set_bidi(tile); + set_bidi(tile_exit); + } else { + SetupBridgeTunnelSignalSimulation(tile, tile_exit); + } } else if (p2 == 4 || p2 == 8) { DiagDirection tbdir = GetTunnelBridgeDirection(tile); /* If signal only on one side build accoringly one-way tunnel/bridge. */ @@ -1142,6 +1180,7 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, SetTunnelBridgeSemaphore(tile_exit, sigvar == SIG_SEMAPHORE); SetTunnelBridgePBS(tile, is_pbs); SetTunnelBridgePBS(tile_exit, is_pbs); + if (!IsTunnelBridgePBS(tile)) remove_pbs_bidi(); } } if (IsTunnelBridgeSignalSimulationExit(tile) && IsTunnelBridgePBS(tile) && !HasTunnelBridgeReservation(tile)) SetTunnelBridgeExitSignalState(tile, SIGNAL_STATE_RED); @@ -1577,6 +1616,7 @@ CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1 if (!IsTunnelBridgeWithSignalSimulation(tile)) return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS); cost *= ((GetTunnelBridgeLength(tile, end) + 4) >> 2); + if (IsTunnelBridgeSignalSimulationBidirectional(tile)) cost *= 2; CommandCost ret = EnsureNoTrainOnTrack(GetOtherTunnelBridgeEnd(tile), track); if (ret.Failed()) return ret; diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index 73fe29da0d..68797ff389 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -248,6 +248,7 @@ static void GenericPlaceSignals(TileIndex tile) SB(p1, 8, 1, 0); SB(p1, 9, 6, cycle_bounds[_settings_client.gui.cycle_signal_types]); } + SB(p1, 18, 1, _settings_client.gui.adv_sig_bridge_tun_modes); DoCommandP(tile, p1, 0, CMD_BUILD_SIGNALS | CMD_MSG((w != NULL && _convert_signal_button) ? STR_ERROR_SIGNAL_CAN_T_CONVERT_SIGNALS_HERE : STR_ERROR_CAN_T_BUILD_SIGNALS_HERE), diff --git a/src/rail_map.h b/src/rail_map.h index 05faec9018..91310e6e2c 100644 --- a/src/rail_map.h +++ b/src/rail_map.h @@ -480,7 +480,7 @@ static inline bool HasOnewaySignalBlockingTrackdir(TileIndex tile, Trackdir td) !HasSignalOnTrackdir(tile, td) && IsOnewaySignal(tile, TrackdirToTrack(td))) { return true; } - if (IsTileType(tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExit(tile) && + if (IsTileType(tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExitOnly(tile) && DiagDirToDiagTrackdir(GetTunnelBridgeDirection(tile)) == td) { return true; } diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index ec415952fb..1e63016f34 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -1545,6 +1545,7 @@ static SettingsContainer &GetSettingsTree() interface->Add(new SettingEntry("gui.timetable_in_ticks")); interface->Add(new SettingEntry("gui.timetable_arrival_departure")); interface->Add(new SettingEntry("gui.expenses_layout")); + interface->Add(new SettingEntry("gui.adv_sig_bridge_tun_modes")); } SettingsPage *advisors = main->Add(new SettingsPage(STR_CONFIG_SETTING_ADVISORS)); diff --git a/src/settings_type.h b/src/settings_type.h index 4c8f695723..d954509b65 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -136,6 +136,7 @@ struct GUISettings { byte missing_strings_threshold; ///< the number of missing strings before showing the warning uint8 graph_line_thickness; ///< the thickness of the lines in the various graph guis uint8 osk_activation; ///< Mouse gesture to trigger the OSK. + bool adv_sig_bridge_tun_modes; ///< Enable advanced modes for signals on bridges/tunnels. uint16 console_backlog_timeout; ///< the minimum amount of time items should be in the console backlog before they will be removed in ~3 seconds granularity. uint16 console_backlog_length; ///< the minimum amount of items in the console backlog before items will be removed. diff --git a/src/table/settings.ini b/src/table/settings.ini index 1529cabaac..9070aa6818 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -3151,6 +3151,14 @@ strhelp = STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS_HELPTEXT strval = STR_JUST_COMMA proc = RedrawScreen +[SDTC_BOOL] +var = gui.adv_sig_bridge_tun_modes +flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC +def = false +str = STR_CONFIG_SETTING_ADV_SIG_BRIDGE_TUN_MODES +strhelp = STR_CONFIG_SETTING_ADV_SIG_BRIDGE_TUN_MODES_HELPTEXT +cat = SC_EXPERT + ; For the dedicated build we'll enable dates in logs by default. [SDTC_BOOL] ifdef = DEDICATED diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index fbcdf65bb5..64da7da717 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -2263,13 +2263,15 @@ static void HandleLastTunnelBridgeSignals(TileIndex tile, TileIndex end, DiagDir if (free) { /* Open up the wormhole and clear m2. */ if (IsBridge(end)) { - SetAllBridgeEntranceSimulatedSignalsGreen(end); + if (IsTunnelBridgeSignalSimulationEntrance(tile)) SetAllBridgeEntranceSimulatedSignalsGreen(tile); + if (IsTunnelBridgeSignalSimulationEntrance(end)) SetAllBridgeEntranceSimulatedSignalsGreen(end); } if (IsTunnelBridgeSignalSimulationEntrance(end) && GetTunnelBridgeEntranceSignalState(end) == SIGNAL_STATE_RED) { SetTunnelBridgeEntranceSignalState(end, SIGNAL_STATE_GREEN); MarkTileDirtyByTile(end); - } else if (IsTunnelBridgeSignalSimulationEntrance(tile) && GetTunnelBridgeEntranceSignalState(tile) == SIGNAL_STATE_RED) { + } + if (IsTunnelBridgeSignalSimulationEntrance(tile) && GetTunnelBridgeEntranceSignalState(tile) == SIGNAL_STATE_RED) { SetTunnelBridgeEntranceSignalState(tile, SIGNAL_STATE_GREEN); MarkTileDirtyByTile(tile); } @@ -2790,7 +2792,7 @@ bool TryPathReserve(Train *v, bool mark_as_stuck, bool first_tile_okay) } } - if (IsTileType(v->tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExit(v->tile) && + if (IsTileType(v->tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExitOnly(v->tile) && DiagDirToDiagTrackBits(GetTunnelBridgeDirection(v->tile)) == v->track) { // prevent any attempt to reserve the wrong way onto a tunnel/bridge exit return false; @@ -3520,13 +3522,19 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) v->vehstatus |= VS_TRAIN_SLOWING; return false; } - if (IsTunnelBridgeSignalSimulationExit(gp.new_tile)) { + if (IsTunnelBridgeSignalSimulationExitOnly(gp.new_tile)) { v->cur_speed = 0; goto invalid_rail; } /* Flip signal on tunnel entrance tile red. */ SetTunnelBridgeEntranceSignalState(gp.new_tile, SIGNAL_STATE_RED); MarkTileDirtyByTile(gp.new_tile); + if (IsTunnelBridgeSignalSimulationBidirectional(gp.new_tile)) { + /* Set incoming signal in other direction to red as well */ + TileIndex other_end = GetOtherTunnelBridgeEnd(gp.new_tile); + SetTunnelBridgeEntranceSignalState(other_end, SIGNAL_STATE_RED); + MarkTileDirtyByTile(other_end); + } } } @@ -3586,7 +3594,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) TileIndex old_tile = TileVirtXY(v->x_pos, v->y_pos); if (old_tile != gp.new_tile && IsTunnelBridgeWithSignalSimulation(v->tile) && (v->IsFrontEngine() || v->Next() == NULL)) { if (old_tile == v->tile) { - if (v->IsFrontEngine() && v->force_proceed == 0 && IsTunnelBridgeSignalSimulationExit(v->tile)) goto invalid_rail; + if (v->IsFrontEngine() && v->force_proceed == 0 && IsTunnelBridgeSignalSimulationExitOnly(v->tile)) goto invalid_rail; /* Entered wormhole set counters. */ v->wait_counter = (TILE_SIZE * _settings_game.construction.simulated_wormhole_signals) - TILE_SIZE; v->tunnel_bridge_signal_num = 0; @@ -3842,17 +3850,21 @@ static void DeleteLastWagon(Train *v) if (IsTunnelBridgeWithSignalSimulation(tile)) { TileIndex end = GetOtherTunnelBridgeEnd(tile); UpdateSignalsOnSegment(end, INVALID_DIAGDIR, owner); - bool is_entrance = IsTunnelBridgeSignalSimulationEntrance(tile); - TileIndex entrance = is_entrance ? tile : end; if (TunnelBridgeIsFree(tile, end, nullptr).Succeeded()) { - if (IsBridge(entrance)) { - SetAllBridgeEntranceSimulatedSignalsGreen(entrance); - MarkBridgeDirty(entrance); - } - if (IsTunnelBridgeSignalSimulationEntrance(entrance) && GetTunnelBridgeEntranceSignalState(entrance) == SIGNAL_STATE_RED) { - SetTunnelBridgeEntranceSignalState(entrance, SIGNAL_STATE_GREEN); - MarkTileDirtyByTile(entrance); - } + auto process_tile = [](TileIndex t) { + if (IsTunnelBridgeSignalSimulationEntrance(t)) { + if (IsBridge(t)) { + SetAllBridgeEntranceSimulatedSignalsGreen(t); + MarkBridgeDirty(t); + } + if (IsTunnelBridgeSignalSimulationEntrance(t) && GetTunnelBridgeEntranceSignalState(t) == SIGNAL_STATE_RED) { + SetTunnelBridgeEntranceSignalState(t, SIGNAL_STATE_GREEN); + MarkTileDirtyByTile(t); + } + } + }; + process_tile(tile); + process_tile(end); } } } else if (IsRailDepotTile(tile)) { diff --git a/src/tunnelbridge.h b/src/tunnelbridge.h index 96134272c0..6dc8c73ba2 100644 --- a/src/tunnelbridge.h +++ b/src/tunnelbridge.h @@ -17,7 +17,7 @@ void MarkBridgeDirty(TileIndex begin, TileIndex end, DiagDirection direction, uint bridge_height); void MarkBridgeDirty(TileIndex tile); void MarkBridgeOrTunnelDirty(TileIndex tile); -uint GetTunnelBridgeSignalSimulationSignalCount(uint length); +uint GetTunnelBridgeSignalSimulationSignalCount(TileIndex begin, TileIndex end); /** * Calculates the length of a tunnel or a bridge (without end tiles) @@ -35,17 +35,6 @@ static inline uint GetTunnelBridgeLength(TileIndex begin, TileIndex end) return abs(x2 + y2 - x1 - y1) - 1; } -/** - * Get number of signals on bridge or tunnel with signal simulation. - * @param begin The begin of the tunnel or bridge. - * @param end The end of the tunnel or bridge. - * @pre IsTunnelBridgeWithSignalSimulation(begin) - */ -static inline uint GetTunnelBridgeSignalSimulationSignalCount(TileIndex begin, TileIndex end) -{ - return GetTunnelBridgeSignalSimulationSignalCount(GetTunnelBridgeLength(begin, end)); -} - extern TileIndex _build_tunnel_endtile; #endif /* TUNNELBRIDGE_H */ diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp index ccb25a315f..35b1f52bac 100644 --- a/src/tunnelbridge_cmd.cpp +++ b/src/tunnelbridge_cmd.cpp @@ -97,12 +97,15 @@ void MarkBridgeOrTunnelDirty(TileIndex tile) /** * Get number of signals on bridge or tunnel with signal simulation. - * @param length Length of bridge/tunnel middle - * @return Number of signals on signalled bridge/tunnel of this length + * @param begin The begin of the tunnel or bridge. + * @param end The end of the tunnel or bridge. + * @pre IsTunnelBridgeWithSignalSimulation(begin) */ -uint GetTunnelBridgeSignalSimulationSignalCount(uint length) +uint GetTunnelBridgeSignalSimulationSignalCount(TileIndex begin, TileIndex end) { - return 2 + (length / _settings_game.construction.simulated_wormhole_signals); + uint result = 2 + (GetTunnelBridgeLength(begin, end) / _settings_game.construction.simulated_wormhole_signals); + if (IsTunnelBridgeSignalSimulationBidirectional(begin)) result *= 2; + return result; } /** Reset the data been eventually changed by the grf loaded. */ @@ -1157,10 +1160,10 @@ static void DrawBridgeTramBits(int x, int y, int z, int offset, bool overlay, bo } } -/* Draws a signal on tunnel / bridge entrance tile. */ -static void DrawTunnelBridgeRampSignal(const TileInfo *ti) +static void DrawTunnelBridgeRampSingleSignal(const TileInfo *ti, bool is_green, uint position, SignalType type, bool show_exit) { bool side = (_settings_game.vehicle.road_side != 0) &&_settings_game.construction.train_signal_side; + DiagDirection dir = GetTunnelBridgeDirection(ti->tile); static const Point SignalPositions[2][4] = { { /* X X Y Y Signals on the left side */ @@ -1170,30 +1173,6 @@ static void DrawTunnelBridgeRampSignal(const TileInfo *ti) } }; - uint position; - DiagDirection dir = GetTunnelBridgeDirection(ti->tile); - - switch (dir) { - default: NOT_REACHED(); - case DIAGDIR_NE: position = 0; break; - case DIAGDIR_SE: position = 2; break; - case DIAGDIR_SW: position = 1; break; - case DIAGDIR_NW: position = 3; break; - } - - SignalType type = SIGTYPE_NORMAL; - - bool is_green, show_exit; - if (IsTunnelBridgeSignalSimulationExit(ti->tile)) { - is_green = (GetTunnelBridgeExitSignalState(ti->tile) == SIGNAL_STATE_GREEN); - show_exit = true; - position ^= 1; - if (IsTunnelBridgePBS(ti->tile)) type = SIGTYPE_PBS_ONEWAY; - } else { - is_green = (GetTunnelBridgeEntranceSignalState(ti->tile) == SIGNAL_STATE_GREEN); - show_exit = false; - } - uint x = TileX(ti->tile) * TILE_SIZE + SignalPositions[side != show_exit][position ^ show_exit].x; uint y = TileY(ti->tile) * TILE_SIZE + SignalPositions[side != show_exit][position ^ show_exit].y; uint z = ti->z; @@ -1216,6 +1195,32 @@ static void DrawTunnelBridgeRampSignal(const TileInfo *ti) AddSortableSpriteToDraw(sprite, PAL_NONE, x, y, 1, 1, TILE_HEIGHT, z, false, 0, 0, BB_Z_SEPARATOR); } +/* Draws a signal on tunnel / bridge entrance tile. */ +static void DrawTunnelBridgeRampSignal(const TileInfo *ti) +{ + DiagDirection dir = GetTunnelBridgeDirection(ti->tile); + + uint position; + switch (dir) { + default: NOT_REACHED(); + case DIAGDIR_NE: position = 0; break; + case DIAGDIR_SE: position = 2; break; + case DIAGDIR_SW: position = 1; break; + case DIAGDIR_NW: position = 3; break; + } + + if (IsTunnelBridgeSignalSimulationExit(ti->tile)) { + SignalType type = SIGTYPE_NORMAL; + if (IsTunnelBridgePBS(ti->tile)) { + type = IsTunnelBridgeSignalSimulationEntrance(ti->tile) ? SIGTYPE_PBS : SIGTYPE_PBS_ONEWAY; + } + DrawTunnelBridgeRampSingleSignal(ti, (GetTunnelBridgeExitSignalState(ti->tile) == SIGNAL_STATE_GREEN), position ^ 1, type, true); + } + if (IsTunnelBridgeSignalSimulationEntrance(ti->tile)) { + DrawTunnelBridgeRampSingleSignal(ti, (GetTunnelBridgeEntranceSignalState(ti->tile) == SIGNAL_STATE_GREEN), position, SIGTYPE_NORMAL, false); + } +} + /* Draws a signal on tunnel / bridge entrance tile. */ static void DrawBridgeSignalOnMiddlePart(const TileInfo *ti, TileIndex bridge_start_tile, uint z) { @@ -1646,9 +1651,8 @@ void DrawBridgeMiddle(const TileInfo *ti) if (HasRailCatenaryDrawn(GetRailType(rampsouth))) { DrawRailCatenaryOnBridge(ti); } - if (IsTunnelBridgeWithSignalSimulation(rampsouth)) { - IsTunnelBridgeSignalSimulationExit(rampsouth) ? DrawBrigeSignalOnMiddlePart(ti, rampnorth, z): DrawBrigeSignalOnMiddlePart(ti, rampsouth, z); - } + if (IsTunnelBridgeSignalSimulationEntrance(rampsouth)) DrawBridgeSignalOnMiddlePart(ti, rampsouth, z); + if (IsTunnelBridgeSignalSimulationEntrance(rampnorth)) DrawBridgeSignalOnMiddlePart(ti, rampnorth, z); } /* draw roof, the component of the bridge which is logically between the vehicle and the camera */ diff --git a/src/tunnelbridge_map.h b/src/tunnelbridge_map.h index f6a21e9992..e079a23269 100644 --- a/src/tunnelbridge_map.h +++ b/src/tunnelbridge_map.h @@ -183,7 +183,7 @@ static inline bool IsTunnelBridgeWithSignalSimulation(TileIndex t) static inline bool IsTunnelBridgeSignalSimulationEntrance(TileIndex t) { assert(IsTileType(t, MP_TUNNELBRIDGE)); - return HasBit(_m[t].m5, 5) && !HasBit(_m[t].m5, 6); + return HasBit(_m[t].m5, 5); } /** @@ -193,11 +193,35 @@ static inline bool IsTunnelBridgeSignalSimulationEntrance(TileIndex t) * @return true if and only if this tile is a tunnel/bridge exit. */ static inline bool IsTunnelBridgeSignalSimulationExit(TileIndex t) +{ + assert(IsTileType(t, MP_TUNNELBRIDGE)); + return HasBit(_m[t].m5, 6); +} + +/** + * Is this a tunnel/bridge exit only? + * @param t the tile that might be a tunnel/bridge. + * @pre IsTileType(t, MP_TUNNELBRIDGE) + * @return true if and only if this tile is a tunnel/bridge exit only. + */ +static inline bool IsTunnelBridgeSignalSimulationExitOnly(TileIndex t) { assert(IsTileType(t, MP_TUNNELBRIDGE)); return !HasBit(_m[t].m5, 5) && HasBit(_m[t].m5, 6); } +/** + * Is this a tunnel/bridge entrance and exit? + * @param t the tile that might be a tunnel/bridge. + * @pre IsTileType(t, MP_TUNNELBRIDGE) + * @return true if and only if this tile is a tunnel/bridge entrance and exit. + */ +static inline bool IsTunnelBridgeSignalSimulationBidirectional(TileIndex t) +{ + assert(IsTileType(t, MP_TUNNELBRIDGE)); + return HasBit(_m[t].m5, 5) && HasBit(_m[t].m5, 6); +} + /** * Get the signal state for a tunnel/bridge entrance with signal simulation * @param t the tunnel/bridge entrance or exit tile with signal simulation