Merge branch 'signal_tunnels_bridges' into jgrpp

# Conflicts:
#	src/pbs.cpp
#	src/saveload/extended_ver_sl.cpp
#	src/settings_gui.cpp
#	src/settings_type.h
#	src/signal.cpp
#	src/table/settings.ini
#	src/train_cmd.cpp
#	src/tunnelbridge.h
This commit is contained in:
Jonathan G Rennison
2018-06-17 09:35:18 +01:00
19 changed files with 231 additions and 98 deletions

View File

@@ -1607,12 +1607,18 @@
<td><tt>2</tt>&nbsp;</td> <td><tt>2</tt>&nbsp;</td>
<td>signal simulation exit (bit 6 set)</td> <td>signal simulation exit (bit 6 set)</td>
</tr> </tr>
<tr>
<td><tt>3</tt>&nbsp;</td>
<td>signal simulation bidirectional entrance and exit (bits 5 and 6 set)</td>
</tr>
</table> </table>
If signal simulation entrance or exit: If signal simulation entrance or exit:
<ul> <ul>
<li>m6 bit 7: set = exit signal shows green, clear = exit signal shows red</li>
<li>m6 bit 6: set = PBS signals, clear = block signals</li> <li>m6 bit 6: set = PBS signals, clear = block signals</li>
<li>m6 bit 1: set = semaphore signals, clear = light signals</li> <li>m6 bit 1: set = semaphore signals, clear = light signals</li>
<li>m6 bit 0: set = signal shows green, clear = signal shows red</li> <li>m6 bit 0: set = entrance signal shows green, clear = entrance signal shows red</li>
<li>m2 bit 15: for bridge entrances only: storage for visual red/green state of signals starting from 15 is allocated outside the map array</li> <li>m2 bit 15: for bridge entrances only: storage for visual red/green state of signals starting from 15 is allocated outside the map array</li>
<li>m2 bits 14..0: for bridge entrances only: for signals 0..14 on bridge, signal is visually red if corresponding bit in 0..14 is set</li> <li>m2 bits 14..0: for bridge entrances only: for signals 0..14 on bridge, signal is visually red if corresponding bit in 0..14 is set</li>
</ul> </ul>

View File

@@ -337,7 +337,7 @@ the array so you can quickly see what is used and what is not.
<td class="bits">XXXX XXXX</td> <td class="bits">XXXX XXXX</td>
<td class="bits"><span class="free">OOOO OOOO</span></td> <td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits">X<span class="used_p">PP</span>X XXXX</td> <td class="bits">X<span class="used_p">PP</span>X XXXX</td>
<td class="bits"><span class="free">O</span><span class="used_p">P</span><span class="free">OO OO</span><span class="used_p">PP</span></td> <td class="bits"><span class="used_p">PP</span><span class="free">OO OO</span><span class="used_p">PP</span></td>
<td class="bits">XXXX XXXX</td> <td class="bits">XXXX XXXX</td>
</tr> </tr>
<tr> <tr>

View File

@@ -1328,6 +1328,9 @@ STR_CONFIG_SETTING_SHOW_ADV_LOADING_MODE_FEATURES_HELPTEXT :Show advanced l
STR_CONFIG_SETTING_DISABLE_TOP_VEH_LIST_MASS_ACTIONS :Disable mass action buttons for top-level vehicle lists STR_CONFIG_SETTING_DISABLE_TOP_VEH_LIST_MASS_ACTIONS :Disable mass action buttons for top-level vehicle lists
STR_CONFIG_SETTING_DISABLE_TOP_VEH_LIST_MASS_ACTIONS_HELPTEXT :This disables depot/service and start/stop buttons for all vehicle and all ungrouped vehicle lists. This is intended to help avoid the negative impact of accidentally pressing one of these buttons. STR_CONFIG_SETTING_DISABLE_TOP_VEH_LIST_MASS_ACTIONS_HELPTEXT :This disables depot/service and start/stop buttons for all vehicle and all ungrouped vehicle lists. This is intended to help avoid the negative impact of accidentally pressing one of these buttons.
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 :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_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} STR_CONFIG_SETTING_LAND_GENERATOR :Land generator: {STRING2}

View File

@@ -942,7 +942,7 @@ static void NPFFollowTrack(AyStar *aystar, OpenListNode *current)
break; 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 */ /* Entering a signalled bridge/tunnel from the wrong side, equivalent to encountering a one-way signal from the wrong side */
break; break;
} }

View File

@@ -378,7 +378,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 */ /* 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; n.m_segment->m_end_segment_reason |= ESRB_DEAD_END;
} }

View File

@@ -155,7 +155,6 @@ bool TryReserveRailTrack(TileIndex tile, Track t, bool trigger_stations)
case MP_TUNNELBRIDGE: case MP_TUNNELBRIDGE:
if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL && !GetTunnelBridgeReservationTrackBits(tile)) { if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL && !GetTunnelBridgeReservationTrackBits(tile)) {
SetTunnelBridgeReservation(tile, true); SetTunnelBridgeReservation(tile, true);
if (IsTunnelBridgeSignalSimulationExit(tile) && IsTunnelBridgePBS(tile)) SetTunnelBridgeSignalState(tile, SIGNAL_STATE_GREEN);
MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP); MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
return true; return true;
} }
@@ -225,7 +224,7 @@ void UnreserveRailTrack(TileIndex tile, Track t)
case MP_TUNNELBRIDGE: case MP_TUNNELBRIDGE:
if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) { if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) {
SetTunnelBridgeReservation(tile, false); 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, ZOOM_LVL_DRAW_MAP); MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
} }
break; break;
@@ -534,7 +533,7 @@ bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bo
return include_line_end; return include_line_end;
} }
if (IsTileType(ft.m_new_tile, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(ft.m_new_tile) == TRANSPORT_RAIL && 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; return include_line_end;
} }
} }
@@ -562,7 +561,19 @@ bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bo
/* Not reserved and depot or not a pbs signal -> free. */ /* Not reserved and depot or not a pbs signal -> free. */
if (IsRailDepotTile(tile)) return true; if (IsRailDepotTile(tile)) return true;
if (IsTileType(tile, MP_RAILWAY) && HasSignalOnTrackdir(tile, trackdir) && !IsPbsSignal(GetSignalType(tile, track))) 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. */ /* 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); CFollowTrackRail ft(v, GetRailTypeInfo(v->railtype)->compatible_railtypes);

View File

@@ -1045,7 +1045,7 @@ static void ClearBridgeTunnelSignalSimulation(TileIndex entrance, TileIndex exit
static void SetupBridgeTunnelSignalSimulation(TileIndex entrance, TileIndex exit) static void SetupBridgeTunnelSignalSimulation(TileIndex entrance, TileIndex exit)
{ {
SetTunnelBridgeSignalSimulationEntrance(entrance); SetTunnelBridgeSignalSimulationEntrance(entrance);
SetTunnelBridgeSignalState(entrance, SIGNAL_STATE_GREEN); SetTunnelBridgeEntranceSignalState(entrance, SIGNAL_STATE_GREEN);
SetTunnelBridgeSignalSimulationExit(exit); SetTunnelBridgeSignalSimulationExit(exit);
} }
@@ -1064,6 +1064,7 @@ static void SetupBridgeTunnelSignalSimulation(TileIndex entrance, TileIndex exit
* - p1 = (bit 9-14)- cycle through which signal set? * - p1 = (bit 9-14)- cycle through which signal set?
* - p1 = (bit 15-16)-cycle the signal direction this many times * - 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 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 p2 used for CmdBuildManySignals() to copy direction of first signal
* @param text unused * @param text unused
* @return the cost of this operation or an error * @return the cost of this operation or an error
@@ -1099,22 +1100,47 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
CommandCost cost; CommandCost cost;
/* handle signals simulation on tunnel/bridge. */ /* handle signals simulation on tunnel/bridge. */
if (IsTileType(tile, MP_TUNNELBRIDGE)) { if (IsTileType(tile, MP_TUNNELBRIDGE)) {
bool bidirectional = HasBit(p1, 18) && (sigtype == SIGTYPE_PBS);
TileIndex tile_exit = GetOtherTunnelBridgeEnd(tile); TileIndex tile_exit = GetOtherTunnelBridgeEnd(tile);
cost = CommandCost(); cost = CommandCost();
bool flip_variant = false; bool flip_variant = false;
bool is_pbs = (sigtype == SIGTYPE_PBS) || (sigtype == SIGTYPE_PBS_ONEWAY); bool is_pbs = (sigtype == SIGTYPE_PBS) || (sigtype == SIGTYPE_PBS_ONEWAY);
if (!IsTunnelBridgeWithSignalSimulation(tile)) { // toggle signal zero costs. if (!IsTunnelBridgeWithSignalSimulation(tile)) { // toggle signal zero costs.
if (convert_signal) return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS); 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 { } else {
if (HasBit(p1, 17)) return CommandCost(); 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)) || if ((p2 != 0 && (sigvar == SIG_SEMAPHORE) != IsTunnelBridgeSemaphore(tile)) ||
(convert_signal && (ctrl_pressed || (sigvar == SIG_SEMAPHORE) != IsTunnelBridgeSemaphore(tile)))) { (convert_signal && (ctrl_pressed || (sigvar == SIG_SEMAPHORE) != IsTunnelBridgeSemaphore(tile)))) {
flip_variant = true; 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 ((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) { if (flags & DC_EXEC) {
Company * const c = Company::Get(GetTileOwner(tile)); Company * const c = Company::Get(GetTileOwner(tile));
if (IsTunnelBridgeWithSignalSimulation(tile)) c->infrastructure.signal -= GetTunnelBridgeSignalSimulationSignalCount(tile, tile_exit); if (IsTunnelBridgeWithSignalSimulation(tile)) c->infrastructure.signal -= GetTunnelBridgeSignalSimulationSignalCount(tile, tile_exit);
@@ -1127,11 +1153,18 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
if (!ctrl_pressed) { if (!ctrl_pressed) {
SetTunnelBridgePBS(tile, is_pbs); SetTunnelBridgePBS(tile, is_pbs);
SetTunnelBridgePBS(tile_exit, is_pbs); SetTunnelBridgePBS(tile_exit, is_pbs);
if (bidirectional) {
set_bidi(tile);
set_bidi(tile_exit);
} else {
remove_pbs_bidi();
}
} }
} else if (ctrl_pressed) { } else if (ctrl_pressed) {
SetTunnelBridgePBS(tile, !IsTunnelBridgePBS(tile)); SetTunnelBridgePBS(tile, !IsTunnelBridgePBS(tile));
SetTunnelBridgePBS(tile_exit, IsTunnelBridgePBS(tile)); SetTunnelBridgePBS(tile_exit, IsTunnelBridgePBS(tile));
} else { if (!IsTunnelBridgePBS(tile)) remove_pbs_bidi();
} else if (!IsTunnelBridgeSignalSimulationBidirectional(tile)) {
if (IsTunnelBridgeSignalSimulationEntrance(tile)) { if (IsTunnelBridgeSignalSimulationEntrance(tile)) {
ClearBridgeTunnelSignalSimulation(tile, tile_exit); ClearBridgeTunnelSignalSimulation(tile, tile_exit);
SetupBridgeTunnelSignalSimulation(tile_exit, tile); SetupBridgeTunnelSignalSimulation(tile_exit, tile);
@@ -1143,7 +1176,12 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
} else { } else {
/* Create one direction tunnel/bridge if required. */ /* Create one direction tunnel/bridge if required. */
if (p2 == 0) { if (p2 == 0) {
if (bidirectional) {
set_bidi(tile);
set_bidi(tile_exit);
} else {
SetupBridgeTunnelSignalSimulation(tile, tile_exit); SetupBridgeTunnelSignalSimulation(tile, tile_exit);
}
} else if (p2 == 4 || p2 == 8) { } else if (p2 == 4 || p2 == 8) {
DiagDirection tbdir = GetTunnelBridgeDirection(tile); DiagDirection tbdir = GetTunnelBridgeDirection(tile);
/* If signal only on one side build accoringly one-way tunnel/bridge. */ /* If signal only on one side build accoringly one-way tunnel/bridge. */
@@ -1161,10 +1199,11 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
SetTunnelBridgeSemaphore(tile_exit, sigvar == SIG_SEMAPHORE); SetTunnelBridgeSemaphore(tile_exit, sigvar == SIG_SEMAPHORE);
SetTunnelBridgePBS(tile, is_pbs); SetTunnelBridgePBS(tile, is_pbs);
SetTunnelBridgePBS(tile_exit, is_pbs); SetTunnelBridgePBS(tile_exit, is_pbs);
if (!IsTunnelBridgePBS(tile)) remove_pbs_bidi();
} }
} }
if (IsTunnelBridgeSignalSimulationExit(tile) && IsTunnelBridgePBS(tile) && !HasTunnelBridgeReservation(tile)) SetTunnelBridgeSignalState(tile, 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)) SetTunnelBridgeSignalState(tile_exit, SIGNAL_STATE_RED); if (IsTunnelBridgeSignalSimulationExit(tile_exit) && IsTunnelBridgePBS(tile_exit) && !HasTunnelBridgeReservation(tile_exit)) SetTunnelBridgeExitSignalState(tile_exit, SIGNAL_STATE_RED);
MarkBridgeOrTunnelDirty(tile); MarkBridgeOrTunnelDirty(tile);
AddSideToSignalBuffer(tile, INVALID_DIAGDIR, GetTileOwner(tile)); AddSideToSignalBuffer(tile, INVALID_DIAGDIR, GetTileOwner(tile));
AddSideToSignalBuffer(tile_exit, INVALID_DIAGDIR, GetTileOwner(tile)); AddSideToSignalBuffer(tile_exit, INVALID_DIAGDIR, GetTileOwner(tile));
@@ -1604,6 +1643,7 @@ CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1
if (!IsTunnelBridgeWithSignalSimulation(tile)) return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS); if (!IsTunnelBridgeWithSignalSimulation(tile)) return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS);
cost *= ((GetTunnelBridgeLength(tile, end) + 4) >> 2); cost *= ((GetTunnelBridgeLength(tile, end) + 4) >> 2);
if (IsTunnelBridgeSignalSimulationBidirectional(tile)) cost *= 2;
CommandCost ret = EnsureNoTrainOnTrack(GetOtherTunnelBridgeEnd(tile), track); CommandCost ret = EnsureNoTrainOnTrack(GetOtherTunnelBridgeEnd(tile), track);
if (ret.Failed()) return ret; if (ret.Failed()) return ret;

View File

@@ -284,6 +284,7 @@ static void GenericPlaceSignals(TileIndex tile)
SB(p1, 8, 1, 0); SB(p1, 8, 1, 0);
SB(p1, 9, 6, _settings_client.gui.cycle_signal_types); SB(p1, 9, 6, _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 | 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), CMD_MSG((w != NULL && _convert_signal_button) ? STR_ERROR_SIGNAL_CAN_T_CONVERT_SIGNALS_HERE : STR_ERROR_CAN_T_BUILD_SIGNALS_HERE),

View File

@@ -485,7 +485,7 @@ static inline bool HasOnewaySignalBlockingTrackdir(TileIndex tile, Trackdir td)
!HasSignalOnTrackdir(tile, td) && IsOnewaySignal(tile, TrackdirToTrack(td))) { !HasSignalOnTrackdir(tile, td) && IsOnewaySignal(tile, TrackdirToTrack(td))) {
return true; return true;
} }
if (IsTileType(tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExit(tile) && if (IsTileType(tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExitOnly(tile) &&
DiagDirToDiagTrackdir(GetTunnelBridgeDirection(tile)) == td) { DiagDirToDiagTrackdir(GetTunnelBridgeDirection(tile)) == td) {
return true; return true;
} }

View File

@@ -3351,7 +3351,7 @@ bool AfterLoadGame()
/* signalled tunnel entrance */ /* signalled tunnel entrance */
SignalState state = HasBit(_m[t].m5, 6) ? SIGNAL_STATE_RED : SIGNAL_STATE_GREEN; SignalState state = HasBit(_m[t].m5, 6) ? SIGNAL_STATE_RED : SIGNAL_STATE_GREEN;
ClrBit(_m[t].m5, 6); ClrBit(_m[t].m5, 6);
SetTunnelBridgeSignalState(t, state); SetTunnelBridgeEntranceSignalState(t, state);
} }
} }
} }
@@ -3367,6 +3367,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);
}
}
}
if (SlXvIsFeatureMissing(XSLFI_CUSTOM_BRIDGE_HEADS)) { if (SlXvIsFeatureMissing(XSLFI_CUSTOM_BRIDGE_HEADS)) {
/* ensure that previously unused custom bridge-head bits are cleared */ /* ensure that previously unused custom bridge-head bits are cleared */

View File

@@ -56,7 +56,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
{ XSLFI_DEPARTURE_BOARDS, XSCF_IGNORABLE_UNKNOWN, 1, 1, "departure_boards", NULL, NULL, NULL }, { XSLFI_DEPARTURE_BOARDS, XSCF_IGNORABLE_UNKNOWN, 1, 1, "departure_boards", NULL, NULL, NULL },
{ XSLFI_TIMETABLES_START_TICKS, XSCF_NULL, 2, 2, "timetable_start_ticks", NULL, NULL, NULL }, { XSLFI_TIMETABLES_START_TICKS, XSCF_NULL, 2, 2, "timetable_start_ticks", NULL, NULL, NULL },
{ XSLFI_TOWN_CARGO_ADJ, XSCF_IGNORABLE_UNKNOWN, 2, 2, "town_cargo_adj", NULL, NULL, NULL }, { XSLFI_TOWN_CARGO_ADJ, XSCF_IGNORABLE_UNKNOWN, 2, 2, "town_cargo_adj", NULL, NULL, NULL },
{ XSLFI_SIG_TUNNEL_BRIDGE, XSCF_NULL, 5, 5, "signal_tunnel_bridge", NULL, NULL, "XBSS" }, { XSLFI_SIG_TUNNEL_BRIDGE, XSCF_NULL, 6, 6, "signal_tunnel_bridge", NULL, NULL, "XBSS" },
{ XSLFI_IMPROVED_BREAKDOWNS, XSCF_NULL, 6, 6, "improved_breakdowns", NULL, NULL, NULL }, { XSLFI_IMPROVED_BREAKDOWNS, XSCF_NULL, 6, 6, "improved_breakdowns", NULL, NULL, NULL },
{ XSLFI_TT_WAIT_IN_DEPOT, XSCF_NULL, 1, 1, "tt_wait_in_depot", NULL, NULL, NULL }, { XSLFI_TT_WAIT_IN_DEPOT, XSCF_NULL, 1, 1, "tt_wait_in_depot", NULL, NULL, NULL },
{ XSLFI_AUTO_TIMETABLE, XSCF_NULL, 4, 4, "auto_timetables", NULL, NULL, NULL }, { XSLFI_AUTO_TIMETABLE, XSCF_NULL, 4, 4, "auto_timetables", NULL, NULL, NULL },

View File

@@ -1616,6 +1616,7 @@ static SettingsContainer &GetSettingsTree()
interface->Add(new SettingEntry("gui.show_veh_list_cargo_filter")); interface->Add(new SettingEntry("gui.show_veh_list_cargo_filter"));
interface->Add(new SettingEntry("gui.show_adv_load_mode_features")); interface->Add(new SettingEntry("gui.show_adv_load_mode_features"));
interface->Add(new SettingEntry("gui.disable_top_veh_list_mass_actions")); interface->Add(new SettingEntry("gui.disable_top_veh_list_mass_actions"));
interface->Add(new SettingEntry("gui.adv_sig_bridge_tun_modes"));
} }
SettingsPage *advisors = main->Add(new SettingsPage(STR_CONFIG_SETTING_ADVISORS)); SettingsPage *advisors = main->Add(new SettingsPage(STR_CONFIG_SETTING_ADVISORS));

View File

@@ -190,6 +190,7 @@ struct GUISettings {
bool enable_single_veh_shared_order_gui; ///< enable showing a single vehicle in the shared order GUI window bool enable_single_veh_shared_order_gui; ///< enable showing a single vehicle in the shared order GUI window
bool show_adv_load_mode_features; ///< enable advanced loading mode features in UI bool show_adv_load_mode_features; ///< enable advanced loading mode features in UI
bool disable_top_veh_list_mass_actions; ///< disable mass actions buttons for non-group vehicle lists bool disable_top_veh_list_mass_actions; ///< disable mass actions buttons for non-group vehicle lists
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_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. uint16 console_backlog_length; ///< the minimum amount of items in the console backlog before items will be removed.

View File

@@ -484,10 +484,10 @@ static void UpdateSignalsAroundSegment(SigInfo info)
while (_tbuset.Get(&tile, &trackdir)) { while (_tbuset.Get(&tile, &trackdir)) {
if (IsTileType(tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExit(tile)) { if (IsTileType(tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExit(tile)) {
if (IsTunnelBridgePBS(tile)) continue; if (IsTunnelBridgePBS(tile)) continue;
SignalState old_state = GetTunnelBridgeSignalState(tile); SignalState old_state = GetTunnelBridgeExitSignalState(tile);
SignalState new_state = (info.flags & SF_TRAIN) ? SIGNAL_STATE_RED : SIGNAL_STATE_GREEN; SignalState new_state = (info.flags & SF_TRAIN) ? SIGNAL_STATE_RED : SIGNAL_STATE_GREEN;
if (old_state != new_state) { if (old_state != new_state) {
SetTunnelBridgeSignalState(tile, new_state); SetTunnelBridgeExitSignalState(tile, new_state);
MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP); MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
} }
continue; continue;

View File

@@ -4169,6 +4169,14 @@ strhelp = STR_CONFIG_SETTING_DISABLE_TOP_VEH_LIST_MASS_ACTIONS_HELPTEXT
proc = RedrawScreen proc = RedrawScreen
cat = SC_EXPERT cat = SC_EXPERT
[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. ; For the dedicated build we'll enable dates in logs by default.
[SDTC_BOOL] [SDTC_BOOL]
ifdef = DEDICATED ifdef = DEDICATED

View File

@@ -2202,10 +2202,10 @@ void ReverseTrainDirection(Train *v)
return; 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)) { if (IsTunnelBridgeWithSignalSimulation(v->tile)) {
/* Flip signal on tunnel entrance tile red. */ /* Flip signal on tunnel entrance tile red. */
SetTunnelBridgeSignalState(v->tile, SIGNAL_STATE_RED); SetTunnelBridgeEntranceSignalState(v->tile, SIGNAL_STATE_RED);
MarkTileDirtyByTile(v->tile); MarkTileDirtyByTile(v->tile);
/* Clear counters. */ /* Clear counters. */
v->wait_counter = 0; v->wait_counter = 0;
@@ -2601,14 +2601,16 @@ static void HandleLastTunnelBridgeSignals(TileIndex tile, TileIndex end, DiagDir
if (free) { if (free) {
/* Open up the wormhole and clear m2. */ /* Open up the wormhole and clear m2. */
if (IsBridge(end)) { if (IsBridge(end)) {
SetAllBridgeEntranceSimulatedSignalsGreen(end); if (IsTunnelBridgeSignalSimulationEntrance(tile)) SetAllBridgeEntranceSimulatedSignalsGreen(tile);
if (IsTunnelBridgeSignalSimulationEntrance(end)) SetAllBridgeEntranceSimulatedSignalsGreen(end);
} }
if (IsTunnelBridgeSignalSimulationEntrance(end) && GetTunnelBridgeSignalState(end) == SIGNAL_STATE_RED) { if (IsTunnelBridgeSignalSimulationEntrance(end) && GetTunnelBridgeEntranceSignalState(end) == SIGNAL_STATE_RED) {
SetTunnelBridgeSignalState(end, SIGNAL_STATE_GREEN); SetTunnelBridgeEntranceSignalState(end, SIGNAL_STATE_GREEN);
MarkTileDirtyByTile(end); MarkTileDirtyByTile(end);
} else 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); MarkTileDirtyByTile(tile);
} }
} }
@@ -2617,7 +2619,7 @@ static void HandleLastTunnelBridgeSignals(TileIndex tile, TileIndex end, DiagDir
static void UnreserveBridgeTunnelTile(TileIndex tile) static void UnreserveBridgeTunnelTile(TileIndex tile)
{ {
SetTunnelBridgeReservation(tile, false); SetTunnelBridgeReservation(tile, false);
if (IsTunnelBridgeSignalSimulationExit(tile) && IsTunnelBridgePBS(tile)) SetTunnelBridgeSignalState(tile, SIGNAL_STATE_RED); if (IsTunnelBridgeSignalSimulationExit(tile) && IsTunnelBridgePBS(tile)) SetTunnelBridgeExitSignalState(tile, SIGNAL_STATE_RED);
} }
/** /**
@@ -3197,7 +3199,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) { DiagDirToDiagTrackBits(GetTunnelBridgeDirection(v->tile)) == v->track) {
// prevent any attempt to reserve the wrong way onto a tunnel/bridge exit // prevent any attempt to reserve the wrong way onto a tunnel/bridge exit
return false; return false;
@@ -3707,7 +3709,7 @@ static bool CheckTrainStayInWormHolePathReserve(Train *t, TileIndex tile)
} }
bool ok = TryPathReserve(t); bool ok = TryPathReserve(t);
t->tile = veh_orig; t->tile = veh_orig;
if (ok && IsTunnelBridgePBS(tile)) SetTunnelBridgeSignalState(tile, SIGNAL_STATE_GREEN); if (ok && IsTunnelBridgePBS(tile)) SetTunnelBridgeExitSignalState(tile, SIGNAL_STATE_GREEN);
return ok; return ok;
} }
@@ -3755,8 +3757,8 @@ static void HandleSignalBehindTrain(Train *v, int signal_number)
if(tile == v->tile) { if(tile == v->tile) {
/* Flip signal on ramp. */ /* Flip signal on ramp. */
if (IsTunnelBridgeSignalSimulationEntrance(tile) && GetTunnelBridgeSignalState(tile) == SIGNAL_STATE_RED) { if (IsTunnelBridgeSignalSimulationEntrance(tile) && GetTunnelBridgeEntranceSignalState(tile) == SIGNAL_STATE_RED) {
SetTunnelBridgeSignalState(tile, SIGNAL_STATE_GREEN); SetTunnelBridgeEntranceSignalState(tile, SIGNAL_STATE_GREEN);
MarkTileDirtyByTile(tile); MarkTileDirtyByTile(tile);
} }
} else if (IsBridge(v->tile) && signal_number >= 0) { } else if (IsBridge(v->tile) && signal_number >= 0) {
@@ -3987,18 +3989,24 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
if (IsTunnelBridgeWithSignalSimulation(gp.new_tile)) { if (IsTunnelBridgeWithSignalSimulation(gp.new_tile)) {
/* If red signal stop. */ /* If red signal stop. */
if (v->IsFrontEngine() && v->force_proceed == 0) { 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->cur_speed = 0;
v->vehstatus |= VS_TRAIN_SLOWING; v->vehstatus |= VS_TRAIN_SLOWING;
return false; return false;
} }
if (IsTunnelBridgeSignalSimulationExit(gp.new_tile)) { if (IsTunnelBridgeSignalSimulationExitOnly(gp.new_tile)) {
v->cur_speed = 0; v->cur_speed = 0;
goto invalid_rail; goto invalid_rail;
} }
/* Flip signal on tunnel entrance tile red. */ /* 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); 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);
}
} }
} }
@@ -4058,7 +4066,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
TileIndex old_tile = TileVirtXY(v->x_pos, v->y_pos); 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 != gp.new_tile && IsTunnelBridgeWithSignalSimulation(v->tile) && (v->IsFrontEngine() || v->Next() == NULL)) {
if (old_tile == v->tile) { 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. */ /* Entered wormhole set counters. */
v->wait_counter = (TILE_SIZE * _settings_game.construction.simulated_wormhole_signals) - TILE_SIZE; v->wait_counter = (TILE_SIZE * _settings_game.construction.simulated_wormhole_signals) - TILE_SIZE;
v->tunnel_bridge_signal_num = 0; v->tunnel_bridge_signal_num = 0;
@@ -4365,18 +4373,22 @@ static void DeleteLastWagon(Train *v)
if (IsTunnelBridgeWithSignalSimulation(tile)) { if (IsTunnelBridgeWithSignalSimulation(tile)) {
TileIndex end = GetOtherTunnelBridgeEnd(tile); TileIndex end = GetOtherTunnelBridgeEnd(tile);
UpdateSignalsOnSegment(end, INVALID_DIAGDIR, owner); UpdateSignalsOnSegment(end, INVALID_DIAGDIR, owner);
bool is_entrance = IsTunnelBridgeSignalSimulationEntrance(tile);
TileIndex entrance = is_entrance ? tile : end;
if (TunnelBridgeIsFree(tile, end, nullptr).Succeeded()) { if (TunnelBridgeIsFree(tile, end, nullptr).Succeeded()) {
if (IsBridge(entrance)) { auto process_tile = [](TileIndex t) {
SetAllBridgeEntranceSimulatedSignalsGreen(entrance); if (IsTunnelBridgeSignalSimulationEntrance(t)) {
MarkBridgeDirty(entrance, ZOOM_LVL_DRAW_MAP); if (IsBridge(t)) {
SetAllBridgeEntranceSimulatedSignalsGreen(t);
MarkBridgeDirty(t, ZOOM_LVL_DRAW_MAP);
} }
if (IsTunnelBridgeSignalSimulationEntrance(entrance) && GetTunnelBridgeSignalState(entrance) == SIGNAL_STATE_RED) { if (IsTunnelBridgeSignalSimulationEntrance(t) && GetTunnelBridgeEntranceSignalState(t) == SIGNAL_STATE_RED) {
SetTunnelBridgeSignalState(entrance, SIGNAL_STATE_GREEN); SetTunnelBridgeEntranceSignalState(t, SIGNAL_STATE_GREEN);
MarkTileDirtyByTile(entrance); MarkTileDirtyByTile(t, ZOOM_LVL_DRAW_MAP);
} }
} }
};
process_tile(tile);
process_tile(end);
}
} }
} else if (IsRailDepotTile(tile)) { } else if (IsRailDepotTile(tile)) {
UpdateSignalsOnSegment(tile, INVALID_DIAGDIR, owner); UpdateSignalsOnSegment(tile, INVALID_DIAGDIR, owner);
@@ -4615,7 +4627,7 @@ static bool TrainCheckIfLineEnds(Train *v, bool reverse)
if (IsLevelCrossingTile(tile)) MaybeBarCrossingWithSound(tile); if (IsLevelCrossingTile(tile)) MaybeBarCrossingWithSound(tile);
if (IsTileType(tile, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL && 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); return TrainApproachingLineEnd(v, true, reverse);
} }

View File

@@ -17,7 +17,7 @@
void MarkBridgeDirty(TileIndex begin, TileIndex end, DiagDirection direction, uint bridge_height, const ZoomLevel mark_dirty_if_zoomlevel_is_below = ZOOM_LVL_END); void MarkBridgeDirty(TileIndex begin, TileIndex end, DiagDirection direction, uint bridge_height, const ZoomLevel mark_dirty_if_zoomlevel_is_below = ZOOM_LVL_END);
void MarkBridgeDirty(TileIndex tile, const ZoomLevel mark_dirty_if_zoomlevel_is_below = ZOOM_LVL_END); void MarkBridgeDirty(TileIndex tile, const ZoomLevel mark_dirty_if_zoomlevel_is_below = ZOOM_LVL_END);
void MarkBridgeOrTunnelDirty(TileIndex tile, const ZoomLevel mark_dirty_if_zoomlevel_is_below = ZOOM_LVL_END); void MarkBridgeOrTunnelDirty(TileIndex tile, const ZoomLevel mark_dirty_if_zoomlevel_is_below = ZOOM_LVL_END);
uint GetTunnelBridgeSignalSimulationSignalCount(uint length); uint GetTunnelBridgeSignalSimulationSignalCount(TileIndex begin, TileIndex end);
/** /**
* Calculates the length of a tunnel or a bridge (without end tiles) * 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; 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; extern TileIndex _build_tunnel_endtile;
#endif /* TUNNELBRIDGE_H */ #endif /* TUNNELBRIDGE_H */

View File

@@ -104,12 +104,15 @@ void MarkBridgeOrTunnelDirty(TileIndex tile, const ZoomLevel mark_dirty_if_zooml
/** /**
* Get number of signals on bridge or tunnel with signal simulation. * Get number of signals on bridge or tunnel with signal simulation.
* @param length Length of bridge/tunnel middle * @param begin The begin of the tunnel or bridge.
* @return Number of signals on signalled bridge/tunnel of this length * @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. */ /** Reset the data been eventually changed by the grf loaded. */
@@ -1282,10 +1285,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 DrawTunnelBridgeRampSingleSignal(const TileInfo *ti, bool is_green, uint position, SignalType type, bool show_exit)
static void DrawTunnelBridgeRampSignal(const TileInfo *ti)
{ {
bool side = (_settings_game.vehicle.road_side != 0) &&_settings_game.construction.train_signal_side; 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] = { static const Point SignalPositions[2][4] = {
{ /* X X Y Y Signals on the left side */ { /* X X Y Y Signals on the left side */
@@ -1295,29 +1298,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 = (GetTunnelBridgeSignalState(ti->tile) == SIGNAL_STATE_GREEN);
bool show_exit;
if (IsTunnelBridgeSignalSimulationExit(ti->tile)) {
show_exit = true;
position ^= 1;
if (IsTunnelBridgePBS(ti->tile)) type = SIGTYPE_PBS_ONEWAY;
} else {
show_exit = false;
}
uint x = TileX(ti->tile) * TILE_SIZE + SignalPositions[side != show_exit][position ^ show_exit].x; 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 y = TileY(ti->tile) * TILE_SIZE + SignalPositions[side != show_exit][position ^ show_exit].y;
uint z = ti->z; uint z = ti->z;
@@ -1348,7 +1328,33 @@ static void DrawTunnelBridgeRampSignal(const TileInfo *ti)
} }
/* Draws a signal on tunnel / bridge entrance tile. */ /* Draws a signal on tunnel / bridge entrance tile. */
static void DrawBrigeSignalOnMiddlePart(const TileInfo *ti, TileIndex bridge_start_tile, uint z) 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)
{ {
uint bridge_signal_position = 0; uint bridge_signal_position = 0;
@@ -1791,9 +1797,8 @@ void DrawBridgeMiddle(const TileInfo *ti)
if (HasRailCatenaryDrawn(GetRailType(rampsouth))) { if (HasRailCatenaryDrawn(GetRailType(rampsouth))) {
DrawRailCatenaryOnBridge(ti); DrawRailCatenaryOnBridge(ti);
} }
if (IsTunnelBridgeWithSignalSimulation(rampsouth)) { if (IsTunnelBridgeSignalSimulationEntrance(rampsouth)) DrawBridgeSignalOnMiddlePart(ti, rampsouth, z);
IsTunnelBridgeSignalSimulationExit(rampsouth) ? DrawBrigeSignalOnMiddlePart(ti, rampnorth, z): DrawBrigeSignalOnMiddlePart(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 */ /* draw roof, the component of the bridge which is logically between the vehicle and the camera */

View File

@@ -197,7 +197,7 @@ static inline bool IsTunnelBridgeWithSignalSimulation(TileIndex t)
static inline bool IsTunnelBridgeSignalSimulationEntrance(TileIndex t) static inline bool IsTunnelBridgeSignalSimulationEntrance(TileIndex t)
{ {
assert(IsTileType(t, MP_TUNNELBRIDGE)); assert(IsTileType(t, MP_TUNNELBRIDGE));
return HasBit(_m[t].m5, 5) && !HasBit(_m[t].m5, 6); return HasBit(_m[t].m5, 5);
} }
/** /**
@@ -207,35 +207,83 @@ static inline bool IsTunnelBridgeSignalSimulationEntrance(TileIndex t)
* @return true if and only if this tile is a tunnel/bridge exit. * @return true if and only if this tile is a tunnel/bridge exit.
*/ */
static inline bool IsTunnelBridgeSignalSimulationExit(TileIndex t) 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)); assert(IsTileType(t, MP_TUNNELBRIDGE));
return !HasBit(_m[t].m5, 5) && HasBit(_m[t].m5, 6); return !HasBit(_m[t].m5, 5) && HasBit(_m[t].m5, 6);
} }
/** /**
* Get the signal state for a tunnel/bridge entrance or exit with signal simulation * 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 * @param t the tunnel/bridge entrance or exit tile with signal simulation
* @pre IsTunnelBridgeWithSignalSimulation(t) * @pre IsTunnelBridgeWithSignalSimulation(t)
* @return signal state * @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; 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 * 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 * @param t the tunnel/bridge entrance or exit tile with signal simulation
* @pre IsTunnelBridgeWithSignalSimulation(t) * @pre IsTunnelBridgeWithSignalSimulation(t)
* @param state signal state * @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); 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) static inline bool IsTunnelBridgeSemaphore(TileIndex t)
{ {
assert(IsTunnelBridgeWithSignalSimulation(t)); assert(IsTunnelBridgeWithSignalSimulation(t));