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