From 35b93a42ace803cc0ce8463e1f540b8a33b38734 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sat, 20 Feb 2016 23:26:16 +0000 Subject: [PATCH] Enable bridge/tunnel exit signals to be one-way PBS. Add signal conversion support. --- src/pbs.cpp | 6 +++++- src/rail_cmd.cpp | 15 +++++++++++++-- src/signal.cpp | 9 +++++++-- src/train_cmd.cpp | 20 +++++++++++++------- src/tunnelbridge_cmd.cpp | 11 +++++++---- src/tunnelbridge_map.h | 12 ++++++++++++ 6 files changed, 57 insertions(+), 16 deletions(-) diff --git a/src/pbs.cpp b/src/pbs.cpp index 2ca4422cc8..f0511a73b3 100644 --- a/src/pbs.cpp +++ b/src/pbs.cpp @@ -125,6 +125,7 @@ bool TryReserveRailTrack(TileIndex tile, Track t, bool trigger_stations) case MP_TUNNELBRIDGE: if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL && !GetTunnelBridgeReservationTrackBits(tile)) { SetTunnelBridgeReservation(tile, true); + if (IsTunnelBridgeExit(tile) && IsTunnelBridgePBS(tile)) SetTunnelBridgeExitGreen(tile, true); return true; } break; @@ -177,7 +178,10 @@ void UnreserveRailTrack(TileIndex tile, Track t) break; case MP_TUNNELBRIDGE: - if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) SetTunnelBridgeReservation(tile, false); + if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) { + SetTunnelBridgeReservation(tile, false); + if (IsTunnelBridgeExit(tile) && IsTunnelBridgePBS(tile)) SetTunnelBridgeExitGreen(tile, false); + } break; default: diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index 33c97cebf4..bfdfcbfea8 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -1057,12 +1057,12 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, TileIndex tile_exit = GetOtherTunnelBridgeEnd(tile); cost = CommandCost(); bool flip_variant = false; + bool is_pbs = (sigtype == SIGTYPE_PBS) || (sigtype == SIGTYPE_PBS_ONEWAY); if (!HasWormholeSignals(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 } else { if (HasBit(p1, 17)) return CommandCost(); - if (ctrl_pressed && !convert_signal) return CommandCost(); if ((p2 != 0 && (sigvar == SIG_SEMAPHORE) != IsTunnelBridgeSemaphore(tile)) || (convert_signal && (ctrl_pressed || (sigvar == SIG_SEMAPHORE) != IsTunnelBridgeSemaphore(tile)))) { flip_variant = true; @@ -1075,8 +1075,15 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, if (convert_signal) { if (flip_variant) { SetTunnelBridgeSemaphore(tile, !IsTunnelBridgeSemaphore(tile)); - SetTunnelBridgeSemaphore(tile_exit, !IsTunnelBridgeSemaphore(tile_exit)); + SetTunnelBridgeSemaphore(tile_exit, IsTunnelBridgeSemaphore(tile)); } + if (!ctrl_pressed) { + SetTunnelBridgePBS(tile, is_pbs); + SetTunnelBridgePBS(tile_exit, is_pbs); + } + } else if (ctrl_pressed) { + SetTunnelBridgePBS(tile, !IsTunnelBridgePBS(tile)); + SetTunnelBridgePBS(tile_exit, IsTunnelBridgePBS(tile)); } else { if (IsTunnelBridgeEntrance(tile)) { ClrBitTunnelBridgeSignal(tile); @@ -1113,7 +1120,11 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, } SetTunnelBridgeSemaphore(tile, sigvar == SIG_SEMAPHORE); SetTunnelBridgeSemaphore(tile_exit, sigvar == SIG_SEMAPHORE); + SetTunnelBridgePBS(tile, is_pbs); + SetTunnelBridgePBS(tile_exit, is_pbs); } + if (IsTunnelBridgeExit(tile) && IsTunnelBridgePBS(tile) && !HasTunnelBridgeReservation(tile)) SetTunnelBridgeExitGreen(tile, false); + if (IsTunnelBridgeExit(tile_exit) && IsTunnelBridgePBS(tile_exit) && !HasTunnelBridgeReservation(tile_exit)) SetTunnelBridgeExitGreen(tile_exit, false); MarkBridgeOrTunnelDirty(tile); AddSideToSignalBuffer(tile, INVALID_DIAGDIR, GetTileOwner(tile)); AddSideToSignalBuffer(tile_exit, INVALID_DIAGDIR, GetTileOwner(tile)); diff --git a/src/signal.cpp b/src/signal.cpp index 6893bb4ef5..4639def78f 100644 --- a/src/signal.cpp +++ b/src/signal.cpp @@ -398,8 +398,12 @@ static SigFlags ExploreSegment(Owner owner) tile += TileOffsByDiagDir(exitdir); // just skip to next tile } else { // NOT incoming from the wormhole! if (ReverseDiagDir(enterdir) != dir) continue; - if (IsTunnelBridgeExit(tile) && !_tbuset.Add(tile, INVALID_TRACKDIR)) { - return flags | SF_FULL; + if (IsTunnelBridgeExit(tile)) { + if (IsTunnelBridgePBS(tile)) { + flags |= SF_PBS; + } else if (!_tbuset.Add(tile, INVALID_TRACKDIR)) { + return flags | SF_FULL; + } } if (!(flags & SF_TRAIN)) { if (HasVehicleOnPos(tile, &tile, &TrainInWormholeTileEnum)) flags |= SF_TRAIN; @@ -450,6 +454,7 @@ static void UpdateSignalsAroundSegment(SigFlags flags) while (_tbuset.Get(&tile, &trackdir)) { if (IsTileType(tile, MP_TUNNELBRIDGE) && IsTunnelBridgeExit(tile)) { + if (IsTunnelBridgePBS(tile)) continue; bool old_state = IsTunnelBridgeExitGreen(tile); bool new_state = !(flags & SF_TRAIN); if (old_state != new_state) { diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 78b19e8e3a..af4ec021f0 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -2244,6 +2244,12 @@ static void HandleLastTunnelBridgeSignals(TileIndex tile, TileIndex end, DiagDir } } +static void UnreserveBridgeTunnelTile(TileIndex tile) +{ + SetTunnelBridgeReservation(tile, false); + if (IsTunnelBridgeExit(tile) && IsTunnelBridgePBS(tile)) SetTunnelBridgeExitGreen(tile, false); +} + /** * Clear the reservation of \a tile that was just left by a wagon on \a track_dir. * @param v %Train owning the reservation. @@ -2261,15 +2267,15 @@ static void ClearPathReservation(const Train *v, TileIndex tile, Trackdir track_ bool free = TunnelBridgeIsFree(tile, end, v).Succeeded(); if (HasWormholeSignals(tile)) { - SetTunnelBridgeReservation(tile, false); + UnreserveBridgeTunnelTile(tile); HandleLastTunnelBridgeSignals(tile, end, dir, free); if (_settings_client.gui.show_track_reservation) { MarkTileDirtyByTile(tile); } } else if (free) { /* Free the reservation only if no other train is on the tiles. */ - SetTunnelBridgeReservation(tile, false); - SetTunnelBridgeReservation(end, false); + UnreserveBridgeTunnelTile(tile); + UnreserveBridgeTunnelTile(end); if (_settings_client.gui.show_track_reservation) { if (IsBridge(tile)) { @@ -2282,7 +2288,7 @@ static void ClearPathReservation(const Train *v, TileIndex tile, Trackdir track_ } } else if (GetTunnelBridgeDirection(tile) == dir && HasWormholeSignals(tile)) { /* cancelling reservation of entry ramp, due to reverse */ - SetTunnelBridgeReservation(tile, false); + UnreserveBridgeTunnelTile(tile); if (_settings_client.gui.show_track_reservation) { MarkTileDirtyByTile(tile); } @@ -3012,7 +3018,7 @@ uint Train::Crash(bool flooded) if (IsTileType(v->tile, MP_TUNNELBRIDGE)) { /* ClearPathReservation will not free the wormhole exit * if the train has just entered the wormhole. */ - SetTunnelBridgeReservation(GetOtherTunnelBridgeEnd(v->tile), false); + UnreserveBridgeTunnelTile(GetOtherTunnelBridgeEnd(v->tile)); } } @@ -3229,7 +3235,7 @@ static bool CheckTrainStayInWormHole(Train *t, TileIndex tile) ToggleBit(t->flags, VRF_REVERSING); return true; } - SigSegState seg_state = _settings_game.pf.reserve_paths ? SIGSEG_PBS : UpdateSignalsOnSegment(tile, INVALID_DIAGDIR, t->owner); + SigSegState seg_state = (_settings_game.pf.reserve_paths || IsTunnelBridgePBS(tile)) ? SIGSEG_PBS : UpdateSignalsOnSegment(tile, INVALID_DIAGDIR, t->owner); if (seg_state == SIGSEG_FULL || (seg_state == SIGSEG_PBS && !CheckTrainStayInWormHolePathReserve(t, tile))) { t->vehstatus |= VS_TRAIN_SLOWING; t->cur_speed = 0; @@ -3558,7 +3564,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) v->x_pos = gp.x; v->y_pos = gp.y; UpdateSignalsOnSegment(old_tile, INVALID_DIAGDIR, v->owner); - SetTunnelBridgeReservation(old_tile, false); + UnreserveBridgeTunnelTile(old_tile); } } if (distance == 0) v->load_unload_ticks++; diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp index e17ee62a19..64bd366b15 100644 --- a/src/tunnelbridge_cmd.cpp +++ b/src/tunnelbridge_cmd.cpp @@ -1164,12 +1164,15 @@ static void DrawTunnelBridgeRampSignal(const TileInfo *ti) case DIAGDIR_NW: position = 3; break; } + SignalType type = SIGTYPE_NORMAL; + bool is_green; bool show_exit; if (IsTunnelBridgeExit(ti->tile)) { is_green = IsTunnelBridgeExitGreen(ti->tile); show_exit = true; position ^= 1; + if (IsTunnelBridgePBS(ti->tile)) type = SIGTYPE_PBS_ONEWAY; } else { is_green = IsTunnelBridgeWithSignGreen(ti->tile); show_exit = false; @@ -1186,19 +1189,19 @@ static void DrawTunnelBridgeRampSignal(const TileInfo *ti) SignalVariant variant = IsTunnelBridgeSemaphore(ti->tile) ? SIG_SEMAPHORE : SIG_ELECTRIC; SpriteID sprite; - if (variant == SIG_ELECTRIC) { + if (variant == SIG_ELECTRIC && type == SIGTYPE_NORMAL) { /* Normal electric signals are picked from original sprites. */ sprite = SPR_ORIGINAL_SIGNALS_BASE + ((position << 1) + is_green); } else { /* All other signals are picked from add on sprites. */ - sprite = SPR_SIGNALS_BASE + ((SIGTYPE_NORMAL - 1) * 16 + variant * 64 + (position << 1) + is_green); + sprite = SPR_SIGNALS_BASE + ((type - 1) * 16 + variant * 64 + (position << 1) + is_green) + (type > SIGTYPE_LAST_NOPBS ? 64 : 0); } 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 DrawBrigeSignalOnMiddelPart(const TileInfo *ti, TileIndex bridge_start_tile, uint z) +static void DrawBrigeSignalOnMiddlePart(const TileInfo *ti, TileIndex bridge_start_tile, uint z) { uint bridge_signal_position = 0; @@ -1628,7 +1631,7 @@ void DrawBridgeMiddle(const TileInfo *ti) DrawCatenaryOnBridge(ti); } if (HasWormholeSignals(rampsouth)) { - IsTunnelBridgeExit(rampsouth) ? DrawBrigeSignalOnMiddelPart(ti, rampnorth, z): DrawBrigeSignalOnMiddelPart(ti, rampsouth, z); + IsTunnelBridgeExit(rampsouth) ? DrawBrigeSignalOnMiddlePart(ti, rampnorth, z): DrawBrigeSignalOnMiddlePart(ti, rampsouth, z); } } diff --git a/src/tunnelbridge_map.h b/src/tunnelbridge_map.h index ccaface2fc..2196f794f1 100644 --- a/src/tunnelbridge_map.h +++ b/src/tunnelbridge_map.h @@ -237,4 +237,16 @@ static inline void SetTunnelBridgeSemaphore(TileIndex t, bool is_semaphore) SB(_me[t].m6, 1, 1, is_semaphore ? 1 : 0); } +static inline bool IsTunnelBridgePBS(TileIndex t) +{ + assert(IsTileType(t, MP_TUNNELBRIDGE) && HasWormholeSignals(t)); + return HasBit(_me[t].m6, 6); +} + +static inline void SetTunnelBridgePBS(TileIndex t, bool is_pbs) +{ + assert(IsTileType(t, MP_TUNNELBRIDGE) && HasWormholeSignals(t)); + SB(_me[t].m6, 6, 1, is_pbs ? 1 : 0); +} + #endif /* TUNNELBRIDGE_MAP_H */