Implement bidirectional mode for signals on bridges/tunnels

pull/59/head
Jonathan G Rennison 6 years ago
parent d03139b241
commit 814f9f7e0f

@ -1554,6 +1554,11 @@
<td><tt>2</tt>&nbsp;</td>
<td>signal simulation exit (bit 6 set)</td>
</tr>
<tr>
<td><tt>3</tt>&nbsp;</td>
<td>signal simulation bidirectional entrance and exit (bits 5 and 6 set)</td>
</tr>
</table>
If signal simulation entrance or exit:
<ul>

@ -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}

@ -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;
}

@ -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;
}

@ -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);

@ -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;

@ -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),

@ -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;
}

@ -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));

@ -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.

@ -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

@ -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)) {

@ -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 */

@ -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 */

@ -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

Loading…
Cancel
Save