diff options
author | Erich Eckner <git@eckner.net> | 2018-11-21 14:17:43 +0100 |
---|---|---|
committer | Erich Eckner <git@eckner.net> | 2018-11-21 14:17:43 +0100 |
commit | 2f4f4c4056e244dfb45cd5aded80781af15376f3 (patch) | |
tree | 2d720cffb01c59987476a0f4264f1ea66dd62678 /openttd-git/signaltunnel.patch | |
parent | 3744747b7abc91be0ebaa08390ab18dce34a4b7f (diff) | |
download | archlinuxewe.git.save-2f4f4c4056e244dfb45cd5aded80781af15376f3.tar.xz |
openttd-git: everything.patch -> signaltunnel.patch, sloped-stations.patch, underground.patch
Diffstat (limited to 'openttd-git/signaltunnel.patch')
-rw-r--r-- | openttd-git/signaltunnel.patch | 962 |
1 files changed, 962 insertions, 0 deletions
diff --git a/openttd-git/signaltunnel.patch b/openttd-git/signaltunnel.patch new file mode 100644 index 00000000..3660f64f --- /dev/null +++ b/openttd-git/signaltunnel.patch @@ -0,0 +1,962 @@ +diff --git a/src/lang/english.txt b/src/lang/english.txt +index cb04a5cbd9..cd0f86a863 100644 +--- a/src/lang/english.txt ++++ b/src/lang/english.txt +@@ -1531,6 +1531,8 @@ STR_CONFIG_SETTING_ALLOW_SHARES :Allow buying sh + STR_CONFIG_SETTING_ALLOW_SHARES_HELPTEXT :When enabled, allow buying and selling of company shares. Shares will only be available for companies reaching a certain age + STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE :Percentage of leg profit to pay in feeder systems: {STRING2} + STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE_HELPTEXT :Percentage of income given to the intermediate legs in feeder systems, giving more control over the income ++STR_CONFIG_SETTING_SIMULATE_SIGNALS :Simulate signals in tunnels, bridges every: {STRING2} ++STR_CONFIG_SETTING_SIMULATE_SIGNALS_VALUE :{COMMA} tile{P 0 "" s} + STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY :When dragging, place signals every: {STRING2} + STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_HELPTEXT :Set the distance at which signals will be built on a track up to the next obstacle (signal, junction), if signals are dragged + STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_VALUE :{COMMA} tile{P 0 "" s} +@@ -2669,8 +2671,10 @@ STR_LAI_WATER_DESCRIPTION_SHIP_DEPOT :Ship depot + # Industries come directly from their industry names + + STR_LAI_TUNNEL_DESCRIPTION_RAILROAD :Railway tunnel ++STR_LAI_TUNNEL_DESCRIPTION_RAILROAD_SIGNAL :Railway tunnel with signal simulation + STR_LAI_TUNNEL_DESCRIPTION_ROAD :Road tunnel + ++STR_LAI_BRIDGE_DESCRIPTION_RAILROAD_SIGNAL :Railway bridge with signal simulation + STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_STEEL :Steel suspension rail bridge + STR_LAI_BRIDGE_DESCRIPTION_RAIL_GIRDER_STEEL :Steel girder rail bridge + STR_LAI_BRIDGE_DESCRIPTION_RAIL_CANTILEVER_STEEL :Steel cantilever rail bridge +diff --git a/src/lang/russian.txt b/src/lang/russian.txt +index 542c1384a4..02e3ebf09b 100644 +--- a/src/lang/russian.txt ++++ b/src/lang/russian.txt +@@ -1681,6 +1681,8 @@ STR_CONFIG_SETTING_ALLOW_SHARES :Разреши + STR_CONFIG_SETTING_ALLOW_SHARES_HELPTEXT :Разрешает торговлю акциями транспортных компаний. Акции выпускаются компаниями через некоторое время после основания. + STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE :Процент дохода, начисляемый при частичной перевозке: {STRING} + STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE_HELPTEXT :Процент прибыли, начисляемый транспорту за частичную перевозку груза. ++STR_CONFIG_SETTING_SIMULATE_SIGNALS :Симуляция светофоров в туннелях и на мостах каждые: {STRING} ++STR_CONFIG_SETTING_SIMULATE_SIGNALS_VALUE :{COMMA} клет{P ку ки ок} + STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY :При перетаскивании ставить сигналы каждые: {STRING} + STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_HELPTEXT :Настройка периодичности расстановки сигналов методом перетаскивания. Сигналы будут устанавливаться до первого встреченного препятствия (пересечения или другого сигнала). + STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_VALUE :{COMMA} клет{P ку ки ок} +@@ -2847,8 +2849,10 @@ STR_LAI_WATER_DESCRIPTION_SHIP_DEPOT :Верфь + # Industries come directly from their industry names + + STR_LAI_TUNNEL_DESCRIPTION_RAILROAD :Железнодорожный туннель ++STR_LAI_TUNNEL_DESCRIPTION_RAILROAD_SIGNAL :Железнодорожный туннель с симуляцией светофоров + STR_LAI_TUNNEL_DESCRIPTION_ROAD :Автомобильный туннель + ++STR_LAI_BRIDGE_DESCRIPTION_RAILROAD_SIGNAL :Железнодорожный мост с симуляцией светофоров + STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_STEEL :Стальной висячий ж/д мост + STR_LAI_BRIDGE_DESCRIPTION_RAIL_GIRDER_STEEL :Стальной балочный ж/д мост + STR_LAI_BRIDGE_DESCRIPTION_RAIL_CANTILEVER_STEEL :Стальной консольный ж/д мост +diff --git a/src/pathfinder/follow_track.hpp b/src/pathfinder/follow_track.hpp +index 0aec3951ed..4a63c265eb 100644 +--- a/src/pathfinder/follow_track.hpp ++++ b/src/pathfinder/follow_track.hpp +@@ -360,7 +360,7 @@ protected: + if (IsTunnel(m_new_tile)) { + if (!m_is_tunnel) { + DiagDirection tunnel_enterdir = GetTunnelBridgeDirection(m_new_tile); +- if (tunnel_enterdir != m_exitdir) { ++ if (tunnel_enterdir != m_exitdir || IsTunnelBridgeExit(m_new_tile)) { + m_err = EC_NO_WAY; + return false; + } +@@ -368,7 +368,7 @@ protected: + } else { // IsBridge(m_new_tile) + if (!m_is_bridge) { + DiagDirection ramp_enderdir = GetTunnelBridgeDirection(m_new_tile); +- if (ramp_enderdir != m_exitdir) { ++ if (ramp_enderdir != m_exitdir || IsTunnelBridgeExit(m_new_tile)) { + m_err = EC_NO_WAY; + return false; + } +diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp +index a0fd968cc6..c18db10120 100644 +--- a/src/rail_cmd.cpp ++++ b/src/rail_cmd.cpp +@@ -1045,9 +1045,12 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, + if (sigtype > SIGTYPE_LAST) return CMD_ERROR; + if (cycle_start > cycle_stop || cycle_stop > SIGTYPE_LAST) return CMD_ERROR; + +- /* You can only build signals on plain rail tiles, and the selected track must exist */ +- if (!ValParamTrackOrientation(track) || !IsPlainRailTile(tile) || +- !HasTrack(tile, track)) { ++ /* You can only build signals on plain rail tiles or tunnel/bridges, and the selected track must exist */ ++ if (IsTileType(tile, MP_TUNNELBRIDGE)) { ++ if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) return CMD_ERROR; ++ CommandCost ret = EnsureNoTrainOnTrack(GetOtherTunnelBridgeEnd(tile), track); ++ //if (ret.Failed()) return ret; ++ } else if (!ValParamTrackOrientation(track) || !IsPlainRailTile(tile) || !HasTrack(tile, track)) { + return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK); + } + /* Protect against invalid signal copying */ +@@ -1056,6 +1059,53 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, + CommandCost ret = CheckTileOwnership(tile); + if (ret.Failed()) return ret; + ++ CommandCost cost; ++ /* handle signals simulation on tunnel/bridge. */ ++ if (IsTileType(tile, MP_TUNNELBRIDGE)) { ++ TileIndex tile_exit = GetOtherTunnelBridgeEnd(tile); ++ cost = CommandCost(); ++ if (!HasWormholeSignals(tile)) { // toggle signal zero costs. ++ if (p2 != 12) cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] * ((GetTunnelBridgeLength(tile, tile_exit) + 4) >> 2)); // minimal 1 ++ } ++ if (flags & DC_EXEC) { ++ if (p2 == 0 && HasWormholeSignals(tile)){ // Toggle signal if already signals present. ++ if (IsTunnelBridgeEntrance (tile)) { ++ ClrBitTunnelBridgeSignal(tile); ++ ClrBitTunnelBridgeExit(tile_exit); ++ SetBitTunnelBridgeExit(tile); ++ SetBitTunnelBridgeSignal(tile_exit); ++ } else { ++ ClrBitTunnelBridgeSignal(tile_exit); ++ ClrBitTunnelBridgeExit(tile); ++ SetBitTunnelBridgeExit(tile_exit); ++ SetBitTunnelBridgeSignal(tile); ++ } ++ } else{ ++ /* Create one direction tunnel/bridge if required. */ ++ if (p2 == 0) { ++ SetBitTunnelBridgeSignal(tile); ++ SetBitTunnelBridgeExit(tile_exit); ++ } else if (p2 == 4 || p2 == 8) { ++ DiagDirection tbdir = GetTunnelBridgeDirection(tile); ++ /* If signal only on one side build accoringly one-way tunnel/bridge. */ ++ if ((p2 == 8 && (tbdir == DIAGDIR_NE || tbdir == DIAGDIR_SE)) || ++ (p2 == 4 && (tbdir == DIAGDIR_SW || tbdir == DIAGDIR_NW))) { ++ SetBitTunnelBridgeSignal(tile); ++ SetBitTunnelBridgeExit(tile_exit); ++ } else { ++ SetBitTunnelBridgeSignal(tile_exit); ++ SetBitTunnelBridgeExit(tile); ++ } ++ } ++ } ++ MarkTileDirtyByTile(tile); ++ MarkTileDirtyByTile(tile_exit); ++ AddSideToSignalBuffer(tile, INVALID_DIAGDIR, _current_company); ++ YapfNotifyTrackLayoutChange(tile, track); ++ } ++ return cost; ++ } ++ + /* See if this is a valid track combination for signals (no overlap) */ + if (TracksOverlap(GetTrackBits(tile))) return_cmd_error(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK); + +@@ -1065,7 +1115,6 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, + /* you can not convert a signal if no signal is on track */ + if (convert_signal && !HasSignalOnTrack(tile, track)) return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS); + +- CommandCost cost; + if (!HasSignalOnTrack(tile, track)) { + /* build new signals */ + cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS]); +@@ -1223,6 +1272,7 @@ static bool CheckSignalAutoFill(TileIndex &tile, Trackdir &trackdir, int &signal + return true; + + case MP_TUNNELBRIDGE: { ++ if (!remove && HasWormholeSignals(tile)) return false; + TileIndex orig_tile = tile; // backup old value + + if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) return false; +@@ -1334,7 +1384,8 @@ static CommandCost CmdSignalTrackHelper(TileIndex tile, DoCommandFlag flags, uin + bool had_success = false; + for (;;) { + /* only build/remove signals with the specified density */ +- if (remove || minimise_gaps || signal_ctr % signal_density == 0) { ++ ++ if (remove || minimise_gaps || signal_ctr % signal_density == 0 || IsTileType(tile, MP_TUNNELBRIDGE)) { + uint32 p1 = GB(TrackdirToTrack(trackdir), 0, 3); + SB(p1, 3, 1, mode); + SB(p1, 4, 1, semaphores); +@@ -1370,13 +1421,20 @@ static CommandCost CmdSignalTrackHelper(TileIndex tile, DoCommandFlag flags, uin + + /* Collect cost. */ + if (!test_only) { +- /* Be user-friendly and try placing signals as much as possible */ +- if (ret.Succeeded()) { +- had_success = true; +- total_cost.AddCost(ret); +- last_used_ctr = last_suitable_ctr; +- last_suitable_tile = INVALID_TILE; ++ /* Be user-friendly and try placing signals as much as possible */ ++ if (ret.Succeeded()) { ++ had_success = true; ++ if (IsTileType(tile, MP_TUNNELBRIDGE)) { ++ if ((!autofill && GetTunnelBridgeDirection(tile) == TrackdirToExitdir(trackdir)) || ++ (autofill && GetTunnelBridgeDirection(tile) != TrackdirToExitdir(trackdir))) { ++ total_cost.AddCost(ret); ++ } + } else { ++ total_cost.AddCost(ret); ++ } ++ last_used_ctr = last_suitable_ctr; ++ last_suitable_tile = INVALID_TILE; ++ } else { + /* The "No railway" error is the least important one. */ + if (ret.GetErrorMessage() != STR_ERROR_THERE_IS_NO_RAILROAD_TRACK || + last_error.GetErrorMessage() == INVALID_STRING_ID) { +@@ -1447,22 +1505,48 @@ CommandCost CmdBuildSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, + CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) + { + Track track = Extract<Track, 0, 3>(p1); ++ Money cost = _price[PR_CLEAR_SIGNALS]; + +- if (!ValParamTrackOrientation(track) || !IsPlainRailTile(tile) || !HasTrack(tile, track)) { +- return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK); +- } +- if (!HasSignalOnTrack(tile, track)) { +- return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS); ++ if (IsTileType(tile, MP_TUNNELBRIDGE)) { ++ TileIndex end = GetOtherTunnelBridgeEnd(tile); ++ if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK); ++ if (!HasWormholeSignals(tile)) return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS); ++ ++ cost *= ((GetTunnelBridgeLength(tile, end) + 4) >> 2); ++ ++ CommandCost ret = EnsureNoTrainOnTrack(GetOtherTunnelBridgeEnd(tile), track); ++ //if (ret.Failed()) return ret; ++ } else { ++ if (!ValParamTrackOrientation(track) || !IsPlainRailTile(tile) || !HasTrack(tile, track)) { ++ return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK); ++ } ++ if (!HasSignalOnTrack(tile, track)) { ++ return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS); ++ } ++ CommandCost ret = EnsureNoTrainOnTrack(tile, track); ++ //if (ret.Failed()) return ret; + } + + /* Only water can remove signals from anyone */ + if (_current_company != OWNER_WATER) { +- CommandCost ret = CheckTileOwnership(tile); +- if (ret.Failed()) return ret; + } + + /* Do it? */ + if (flags & DC_EXEC) { ++ ++ if (HasWormholeSignals(tile)) { // handle tunnel/bridge signals. ++ TileIndex end = GetOtherTunnelBridgeEnd(tile); ++ ClrBitTunnelBridgeExit(tile); ++ ClrBitTunnelBridgeExit(end); ++ ClrBitTunnelBridgeSignal(tile); ++ ClrBitTunnelBridgeSignal(end); ++ _m[tile].m2 = 0; ++ _m[end].m2 = 0; ++ MarkTileDirtyByTile(tile); ++ MarkTileDirtyByTile(end); ++ return CommandCost(EXPENSES_CONSTRUCTION, cost); ++ } ++ + Train *v = NULL; + if (HasReservedTracks(tile, TrackToTrackBits(track))) { + v = GetTrainForReservation(tile, track); +@@ -1498,7 +1582,7 @@ CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1 + MarkTileDirtyByTile(tile); + } + +- return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_SIGNALS]); ++ return CommandCost(EXPENSES_CONSTRUCTION, cost); + } + + /** +diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp +index 5ebac02807..92b8d9e5b7 100644 +--- a/src/settings_gui.cpp ++++ b/src/settings_gui.cpp +@@ -1535,6 +1535,7 @@ static SettingsContainer &GetSettingsTree() + SettingsPage *construction = interface->Add(new SettingsPage(STR_CONFIG_SETTING_INTERFACE_CONSTRUCTION)); + { + construction->Add(new SettingEntry("gui.link_terraform_toolbar")); ++ construction->Add(new SettingEntry("construction.simulated_wormhole_signals")); + construction->Add(new SettingEntry("gui.enable_signal_gui")); + construction->Add(new SettingEntry("gui.persistent_buildingtools")); + construction->Add(new SettingEntry("gui.quick_goto")); +diff --git a/src/settings_type.h b/src/settings_type.h +index 690f6d8036..3f3b8cabcf 100644 +--- a/src/settings_type.h ++++ b/src/settings_type.h +@@ -321,6 +321,7 @@ struct ConstructionSettings { + bool freeform_edges; ///< allow terraforming the tiles at the map edges + uint8 extra_tree_placement; ///< (dis)allow building extra trees in-game + uint8 command_pause_level; ///< level/amount of commands that can't be executed while paused ++ byte simulated_wormhole_signals; ///< simulate signals in tunnel + + uint32 terraform_per_64k_frames; ///< how many tile heights may, over a long period, be terraformed per 65536 frames? + uint16 terraform_frame_burst; ///< how many tile heights may, over a short period, be terraformed? +diff --git a/src/signal.cpp b/src/signal.cpp +index b37e15074a..01b3256e4f 100644 +--- a/src/signal.cpp ++++ b/src/signal.cpp +@@ -197,6 +197,14 @@ static Vehicle *TrainOnTileEnum(Vehicle *v, void *) + return v; + } + ++/** Check whether there is a train only on ramp. */ ++static Vehicle *TrainInWormholeTileEnum(Vehicle *v, void *data) ++{ ++ /* Only look for front engine or last wagon. */ ++ if (v->type != VEH_TRAIN || (v->Previous() != NULL && v->Next() != NULL)) return NULL; ++ if (*(TileIndex *)data != TileVirtXY(v->x_pos, v->y_pos)) return NULL; ++ return v; ++} + + /** + * Perform some operations before adding data into Todo set +@@ -376,17 +384,39 @@ static SigFlags ExploreSegment(Owner owner) + if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) continue; + DiagDirection dir = GetTunnelBridgeDirection(tile); + +- if (enterdir == INVALID_DIAGDIR) { // incoming from the wormhole +- if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN; +- enterdir = dir; +- exitdir = ReverseDiagDir(dir); +- tile += TileOffsByDiagDir(exitdir); // just skip to next tile +- } else { // NOT incoming from the wormhole! +- if (ReverseDiagDir(enterdir) != dir) continue; +- if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN; +- tile = GetOtherTunnelBridgeEnd(tile); // just skip to exit tile +- enterdir = INVALID_DIAGDIR; +- exitdir = INVALID_DIAGDIR; ++ if (HasWormholeSignals(tile)) { ++ if (enterdir == INVALID_DIAGDIR) { // incoming from the wormhole ++ if (!(flags & SF_TRAIN) && IsTunnelBridgeExit(tile)) { // tunnel entrence is ignored ++ if (HasVehicleOnPos(GetOtherTunnelBridgeEnd(tile), &tile, &TrainInWormholeTileEnum)) flags |= SF_TRAIN; ++ if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, &tile, &TrainInWormholeTileEnum)) flags |= SF_TRAIN; ++ } ++ enterdir = dir; ++ exitdir = ReverseDiagDir(dir); ++ tile += TileOffsByDiagDir(exitdir); // just skip to next tile ++ } else { // NOT incoming from the wormhole! ++ if (ReverseDiagDir(enterdir) != dir) continue; ++ if (!(flags & SF_TRAIN)) { ++ if (HasVehicleOnPos(tile, &tile, &TrainInWormholeTileEnum)) flags |= SF_TRAIN; ++ if (!(flags & SF_TRAIN) && IsTunnelBridgeExit(tile)) { ++ if (HasVehicleOnPos(GetOtherTunnelBridgeEnd(tile), &tile, &TrainInWormholeTileEnum)) flags |= SF_TRAIN; ++ } ++ } ++ continue; ++ } ++ } else { ++ if (enterdir == INVALID_DIAGDIR) { // incoming from the wormhole ++ if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN; ++ enterdir = dir; ++ exitdir = ReverseDiagDir(dir); ++ tile += TileOffsByDiagDir(exitdir); // just skip to next tile ++ } else { // NOT incoming from the wormhole! ++ if (ReverseDiagDir(enterdir) != dir) continue; ++ if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN; ++ tile = GetOtherTunnelBridgeEnd(tile); // just skip to exit tile ++ enterdir = INVALID_DIAGDIR; ++ exitdir = INVALID_DIAGDIR; ++ } ++ + } + } + break; +@@ -494,7 +524,9 @@ static SigSegState UpdateSignalsInBuffer(Owner owner) + assert(GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL); + assert(dir == INVALID_DIAGDIR || dir == ReverseDiagDir(GetTunnelBridgeDirection(tile))); + _tbdset.Add(tile, INVALID_DIAGDIR); // we can safely start from wormhole centre +- _tbdset.Add(GetOtherTunnelBridgeEnd(tile), INVALID_DIAGDIR); ++ if (!HasWormholeSignals(tile)) { // Don't worry with other side of tunnel. ++ _tbdset.Add(GetOtherTunnelBridgeEnd(tile), INVALID_DIAGDIR); ++ } + break; + + case MP_RAILWAY: +diff --git a/src/table/settings.ini b/src/table/settings.ini +index c061c394f0..cc05404bda 100644 +--- a/src/table/settings.ini ++++ b/src/table/settings.ini +@@ -541,6 +541,20 @@ str = STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH + strhelp = STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH_HELPTEXT + strval = STR_CONFIG_SETTING_TILE_LENGTH + ++[SDT_VAR] ++base = GameSettings ++var = construction.simulated_wormhole_signals ++type = SLE_UINT8 ++flags = 0 ++def = 2 ++min = 1 ++max = 16 ++str = STR_CONFIG_SETTING_SIMULATE_SIGNALS ++strval = STR_CONFIG_SETTING_SIMULATE_SIGNALS_VALUE ++proc = RedrawScreen ++from = 0 ++cat = SC_BASIC ++ + # construction.longbridges + [SDT_NULL] + length = 1 +diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp +index 0672ac2093..e675bd6d02 100644 +--- a/src/train_cmd.cpp ++++ b/src/train_cmd.cpp +@@ -1852,6 +1852,17 @@ void ReverseTrainDirection(Train *v) + return; + } + ++ /* We are inside tunnel/bidge with signals, reversing will close the entrance. */ ++ if (HasWormholeSignals(v->tile)) { ++ /* Flip signal on tunnel entrance tile red. */ ++ SetBitTunnelBridgeExit(v->tile); ++ MarkTileDirtyByTile(v->tile); ++ /* Clear counters. */ ++ v->wait_counter = 0; ++ v->load_unload_ticks = 0; ++ return; ++ } ++ + /* VehicleExitDir does not always produce the desired dir for depots and + * tunnels/bridges that is needed for UpdateSignalsOnSegment. */ + DiagDirection dir = VehicleExitDir(v->direction, v->track); +@@ -2188,6 +2199,42 @@ static bool CheckTrainStayInDepot(Train *v) + return false; + } + ++static void HandleLastTunnelBridgeSignals(TileIndex tile, TileIndex end, DiagDirection dir, bool free) ++{ ++ if (IsBridge(end) && _m[end].m2 > 0){ ++ /* Clearing last bridge signal. */ ++ uint16 m = _m[end].m2; ++ byte i = 15; ++ while((m & 0x8000) == 0 && --i > 0) m <<= 1; ++ ClrBit(_m[end].m2, i); ++ ++ uint x = TileX(end)* TILE_SIZE; ++ uint y = TileY(end)* TILE_SIZE; ++ uint distance = (TILE_SIZE * _settings_game.construction.simulated_wormhole_signals) * ++i; ++ switch (dir) { ++ default: NOT_REACHED(); ++ case DIAGDIR_NE: MarkTileDirtyByTile(TileVirtXY(x - distance, y)); break; ++ case DIAGDIR_SE: MarkTileDirtyByTile(TileVirtXY(x, y + distance)); break; ++ case DIAGDIR_SW: MarkTileDirtyByTile(TileVirtXY(x + distance, y)); break; ++ case DIAGDIR_NW: MarkTileDirtyByTile(TileVirtXY(x, y - distance)); break; ++ } ++ MarkTileDirtyByTile(tile); ++ } ++ if (free) { ++ /* Open up the wormhole and clear m2. */ ++ _m[tile].m2 = 0; ++ _m[end].m2 = 0; ++ ++ if (IsTunnelBridgeWithSignRed(end)) { ++ ClrBitTunnelBridgeExit(end); ++ if (!_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(end); ++ } else if (IsTunnelBridgeWithSignRed(tile)) { ++ ClrBitTunnelBridgeExit(tile); ++ if (!_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(tile); ++ } ++ } ++} ++ + /** + * Clear the reservation of \a tile that was just left by a wagon on \a track_dir. + * @param v %Train owning the reservation. +@@ -2203,7 +2250,8 @@ static void ClearPathReservation(const Train *v, TileIndex tile, Trackdir track_ + if (GetTunnelBridgeDirection(tile) == ReverseDiagDir(dir)) { + TileIndex end = GetOtherTunnelBridgeEnd(tile); + +- if (TunnelBridgeIsFree(tile, end, v).Succeeded()) { ++ bool free = TunnelBridgeIsFree(tile, end, v).Succeeded(); ++ if (free) { + /* Free the reservation only if no other train is on the tiles. */ + SetTunnelBridgeReservation(tile, false); + SetTunnelBridgeReservation(end, false); +@@ -2217,6 +2265,7 @@ static void ClearPathReservation(const Train *v, TileIndex tile, Trackdir track_ + } + } + } ++ if (HasWormholeSignals(tile)) HandleLastTunnelBridgeSignals(tile, end, dir, free); + } + } else if (IsRailStationTile(tile)) { + TileIndex new_tile = TileAddByDiagDir(tile, dir); +@@ -3083,6 +3132,99 @@ static Vehicle *CheckTrainAtSignal(Vehicle *v, void *data) + return t; + } + ++/** Find train in front and keep distance between trains in tunnel/bridge. */ ++static Vehicle *FindSpaceBetweenTrainsEnum(Vehicle *v, void *data) ++{ ++ /* Don't look at wagons between front and back of train. */ ++ if (v->type != VEH_TRAIN || (v->Previous() != NULL && v->Next() != NULL)) return NULL; ++ ++ const Vehicle *u = (Vehicle*)data; ++ int32 a, b = 0; ++ ++ switch (u->direction) { ++ default: NOT_REACHED(); ++ case DIR_NE: a = u->x_pos; b = v->x_pos; break; ++ case DIR_SE: a = v->y_pos; b = u->y_pos; break; ++ case DIR_SW: a = v->x_pos; b = u->x_pos; break; ++ case DIR_NW: a = u->y_pos; b = v->y_pos; break; ++ } ++ ++ if (a > b && a <= (b + (int)(Train::From(u)->wait_counter)) + (int)(TILE_SIZE)) return v; ++ return NULL; ++} ++ ++static bool IsToCloseBehindTrain(Vehicle *v, TileIndex tile, bool check_endtile) ++{ ++ Train *t = (Train *)v; ++ ++ if (t->force_proceed != 0) return false; ++ ++ if (HasVehicleOnPos(t->tile, v, &FindSpaceBetweenTrainsEnum)) { ++ /* Revert train if not going with tunnel direction. */ ++ if (DirToDiagDir(t->direction) != GetTunnelBridgeDirection(t->tile)) { ++ v->cur_speed = 0; ++ ToggleBit(t->flags, VRF_REVERSING); ++ } ++ return true; ++ } ++ /* Cover blind spot at end of tunnel bridge. */ ++ if (check_endtile){ ++ if (HasVehicleOnPos(GetOtherTunnelBridgeEnd(t->tile), v, &FindSpaceBetweenTrainsEnum)) { ++ /* Revert train if not going with tunnel direction. */ ++ if (DirToDiagDir(t->direction) != GetTunnelBridgeDirection(t->tile)) { ++ v->cur_speed = 0; ++ ToggleBit(t->flags, VRF_REVERSING); ++ } ++ return true; ++ } ++ } ++ ++ return false; ++} ++ ++/** Simulate signals in tunnel - bridge. */ ++static bool CheckTrainStayInWormHole(Train *t, TileIndex tile) ++{ ++ if (t->force_proceed != 0) return false; ++ ++ /* When not exit reverse train. */ ++ if (!IsTunnelBridgeExit(tile)) { ++ t->cur_speed = 0; ++ ToggleBit(t->flags, VRF_REVERSING); ++ return true; ++ } ++ SigSegState seg_state = _settings_game.pf.reserve_paths ? SIGSEG_PBS : UpdateSignalsOnSegment(tile, INVALID_DIAGDIR, t->owner); ++ if (seg_state == SIGSEG_FULL || (seg_state == SIGSEG_PBS && !TryPathReserve(t))) { ++ t->cur_speed = 0; ++ return true; ++ } ++ ++ return false; ++} ++ ++static void HandleSignalBehindTrain(Train *v, uint signal_number) ++{ ++ TileIndex tile; ++ switch (v->direction) { ++ default: NOT_REACHED(); ++ case DIR_NE: tile = TileVirtXY(v->x_pos + (TILE_SIZE * _settings_game.construction.simulated_wormhole_signals), v->y_pos); break; ++ case DIR_SE: tile = TileVirtXY(v->x_pos, v->y_pos - (TILE_SIZE * _settings_game.construction.simulated_wormhole_signals) ); break; ++ case DIR_SW: tile = TileVirtXY(v->x_pos - (TILE_SIZE * _settings_game.construction.simulated_wormhole_signals), v->y_pos); break; ++ case DIR_NW: tile = TileVirtXY(v->x_pos, v->y_pos + (TILE_SIZE * _settings_game.construction.simulated_wormhole_signals)); break; ++ } ++ ++ if(tile == v->tile) { ++ /* Flip signal on ramp. */ ++ if (IsTunnelBridgeWithSignRed(tile)) { ++ ClrBitTunnelBridgeExit(tile); ++ MarkTileDirtyByTile(tile); ++ } ++ } else if (IsBridge(v->tile) && signal_number <= 16) { ++ ClrBit(_m[v->tile].m2, signal_number); ++ MarkTileDirtyByTile(tile); ++ } ++} ++ + /** + * Move a vehicle chain one movement stop forwards. + * @param v First vehicle to move. +@@ -3268,6 +3410,23 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) + goto invalid_rail; + } + ++ if (HasWormholeSignals(gp.new_tile)) { ++ /* If red signal stop. */ ++ if (v->IsFrontEngine() && v->force_proceed == 0) { ++ if (IsTunnelBridgeWithSignRed(gp.new_tile)) { ++ v->cur_speed = 0; ++ return false; ++ } ++ if (IsTunnelBridgeExit(gp.new_tile)) { ++ v->cur_speed = 0; ++ goto invalid_rail; ++ } ++ /* Flip signal on tunnel entrance tile red. */ ++ SetBitTunnelBridgeExit(gp.new_tile); ++ MarkTileDirtyByTile(gp.new_tile); ++ } ++ } ++ + if (!HasBit(r, VETS_ENTERED_WORMHOLE)) { + Track track = FindFirstTrack(chosen_track); + Trackdir tdir = TrackDirectionToTrackdir(track, chosen_dir); +@@ -3320,6 +3479,64 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) + } + } + } else { ++ /* Handle signal simulation on tunnel/bridge. */ ++ TileIndex old_tile = TileVirtXY(v->x_pos, v->y_pos); ++ if (old_tile != gp.new_tile && HasWormholeSignals(v->tile) && (v->IsFrontEngine() || v->Next() == NULL)){ ++ if (old_tile == v->tile) { ++ if (v->IsFrontEngine() && v->force_proceed == 0 && IsTunnelBridgeExit(v->tile)) goto invalid_rail; ++ /* Entered wormhole set counters. */ ++ v->wait_counter = (TILE_SIZE * _settings_game.construction.simulated_wormhole_signals) - TILE_SIZE; ++ v->load_unload_ticks = 0; ++ } ++ ++ uint distance = v->wait_counter; ++ bool leaving = false; ++ if (distance == 0) v->wait_counter = (TILE_SIZE * _settings_game.construction.simulated_wormhole_signals); ++ ++ if (v->IsFrontEngine()) { ++ /* Check if track in front is free and see if we can leave wormhole. */ ++ int z = GetSlopePixelZ(gp.x, gp.y) - v->z_pos; ++ if (IsTileType(gp.new_tile, MP_TUNNELBRIDGE) && !(abs(z) > 2)) { ++ if (CheckTrainStayInWormHole(v, gp.new_tile)) return false; ++ leaving = true; ++ } else { ++ if (IsToCloseBehindTrain(v, gp.new_tile, distance == 0)) { ++ if (distance == 0) v->wait_counter = 0; ++ v->cur_speed = 0; ++ return false; ++ } ++ /* flip signal in front to red on bridges*/ ++ if (distance == 0 && v->load_unload_ticks <= 15 && IsBridge(v->tile)){ ++ SetBit(_m[v->tile].m2, v->load_unload_ticks); ++ MarkTileDirtyByTile(gp.new_tile); ++ } ++ } ++ } ++ if (v->Next() == NULL) { ++ if (v->load_unload_ticks > 0 && v->load_unload_ticks <= 16 && distance == (TILE_SIZE * _settings_game.construction.simulated_wormhole_signals) - TILE_SIZE) HandleSignalBehindTrain(v, v->load_unload_ticks - 2); ++ if (old_tile == v->tile) { ++ /* We left ramp into wormhole. */ ++ v->x_pos = gp.x; ++ v->y_pos = gp.y; ++ UpdateSignalsOnSegment(old_tile, INVALID_DIAGDIR, v->owner); ++ } ++ } ++ if (distance == 0) v->load_unload_ticks++; ++ v->wait_counter -= TILE_SIZE; ++ ++ if (leaving) { // Reset counters. ++ v->force_proceed = 0; ++ v->wait_counter = 0; ++ v->load_unload_ticks = 0; ++ v->x_pos = gp.x; ++ v->y_pos = gp.y; ++ v->UpdatePosition(); ++ v->UpdateViewport(false, false); ++ UpdateSignalsOnSegment(gp.new_tile, INVALID_DIAGDIR, v->owner); ++ continue; ++ } ++ } ++ + if (IsTileType(gp.new_tile, MP_TUNNELBRIDGE) && HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) { + /* Perform look-ahead on tunnel exit. */ + if (v->IsFrontEngine()) { +diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp +index 297a01d30a..460388e623 100644 +--- a/src/tunnelbridge_cmd.cpp ++++ b/src/tunnelbridge_cmd.cpp +@@ -30,6 +30,7 @@ + #include "date_func.h" + #include "clear_func.h" + #include "vehicle_func.h" ++#include "vehicle_gui.h" + #include "sound_func.h" + #include "tunnelbridge.h" + #include "cheat_type.h" +@@ -1127,6 +1128,103 @@ 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) ++{ ++ bool side = (_settings_game.vehicle.road_side != 0) &&_settings_game.construction.train_signal_side; ++ ++ static const Point SignalPositions[2][4] = { ++ { /* X X Y Y Signals on the left side */ ++ {13, 3}, { 2, 13}, { 3, 4}, {13, 14} ++ }, {/* X X Y Y Signals on the right side */ ++ {14, 13}, { 3, 3}, {13, 2}, { 3, 13} ++ } ++ }; ++ ++ 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; ++ } ++ ++ uint x = TileX(ti->tile) * TILE_SIZE + SignalPositions[side][position].x; ++ uint y = TileY(ti->tile) * TILE_SIZE + SignalPositions[side][position].y; ++ uint z = ti->z; ++ ++ if (ti->tileh != SLOPE_FLAT && IsBridge(ti->tile)) z += 8; // sloped bridge head ++ SignalVariant variant = (_cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC); ++ ++ SpriteID sprite; ++ if (variant == SIG_ELECTRIC) { ++ /* Normal electric signals are picked from original sprites. */ ++ sprite = SPR_ORIGINAL_SIGNALS_BASE + ((position << 1) + IsTunnelBridgeWithSignGreen(ti->tile)); ++ } else { ++ /* All other signals are picked from add on sprites. */ ++ sprite = SPR_SIGNALS_BASE + ((SIGTYPE_NORMAL - 1) * 16 + variant * 64 + (position << 1) + IsTunnelBridgeWithSignGreen(ti->tile)); ++ } ++ ++ 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) ++{ ++ ++ uint bridge_signal_position = 0; ++ int m2_position = 0; ++ ++ uint bridge_section = GetTunnelBridgeLength(ti->tile, bridge_start_tile) + 1; ++ ++ while (bridge_signal_position <= bridge_section) { ++ bridge_signal_position += _settings_game.construction.simulated_wormhole_signals; ++ if (bridge_signal_position == bridge_section) { ++ bool side = (_settings_game.vehicle.road_side != 0) && _settings_game.construction.train_signal_side; ++ ++ static const Point SignalPositions[2][4] = { ++ { /* X X Y Y Signals on the left side */ ++ {11, 3}, { 4, 13}, { 3, 4}, {11, 13} ++ }, {/* X X Y Y Signals on the right side */ ++ {11, 13}, { 4, 3}, {13, 4}, { 3, 11} ++ } ++ }; ++ ++ uint position; ++ ++ switch (GetTunnelBridgeDirection(bridge_start_tile)) { ++ 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; ++ } ++ ++ uint x = TileX(ti->tile) * TILE_SIZE + SignalPositions[side][position].x; ++ uint y = TileY(ti->tile) * TILE_SIZE + SignalPositions[side][position].y; ++ z += 5; ++ ++ SignalVariant variant = (_cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC); ++ ++ SpriteID sprite; ++ ++ if (variant == SIG_ELECTRIC) { ++ /* Normal electric signals are picked from original sprites. */ ++ sprite = SPR_ORIGINAL_SIGNALS_BASE + ((position << 1) + !HasBit(_m[bridge_start_tile].m2, m2_position)); ++ } else { ++ /* All other signals are picked from add on sprites. */ ++ sprite = SPR_SIGNALS_BASE + ((SIGTYPE_NORMAL - 1) * 16 + variant * 64 + (position << 1) + !HasBit(_m[bridge_start_tile].m2, m2_position)); ++ } ++ ++ AddSortableSpriteToDraw(sprite, PAL_NONE, x, y, 1, 1, TILE_HEIGHT, z, false, 0, 0, BB_Z_SEPARATOR); ++ } ++ m2_position++; ++ } ++} ++ + /** + * Draws a tunnel of bridge tile. + * For tunnels, this is rather simple, as you only need to draw the entrance. +@@ -1241,6 +1339,9 @@ static void DrawTile_TunnelBridge(TileInfo *ti) + AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, ti->x, ti->y, BB_data[6], BB_data[7], TILE_HEIGHT, ti->z); + AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, ti->x + BB_data[4], ti->y + BB_data[5], BB_data[6], BB_data[7], TILE_HEIGHT, ti->z); + ++ /* Draw signals for tunnel. */ ++ if (IsTunnelBridgeEntrance(ti->tile)) DrawTunnelBridgeRampSignal(ti); ++ + DrawBridgeMiddle(ti); + } else { // IsBridge(ti->tile) + const PalSpriteID *psid; +@@ -1348,6 +1449,9 @@ static void DrawTile_TunnelBridge(TileInfo *ti) + } + } + ++ /* Draw signals for bridge. */ ++ if (HasWormholeSignals(ti->tile)) DrawTunnelBridgeRampSignal(ti); ++ + DrawBridgeMiddle(ti); + } + } +@@ -1496,6 +1600,9 @@ void DrawBridgeMiddle(const TileInfo *ti) + if (HasRailCatenaryDrawn(GetRailType(rampsouth))) { + DrawRailCatenaryOnBridge(ti); + } ++ if (HasWormholeSignals(rampsouth)) { ++ IsTunnelBridgeExit(rampsouth) ? DrawBrigeSignalOnMiddelPart(ti, rampnorth, z): DrawBrigeSignalOnMiddelPart(ti, rampsouth, z); ++ } + } + + /* draw roof, the component of the bridge which is logically between the vehicle and the camera */ +@@ -1584,9 +1691,9 @@ static void GetTileDesc_TunnelBridge(TileIndex tile, TileDesc *td) + TransportType tt = GetTunnelBridgeTransportType(tile); + + if (IsTunnel(tile)) { +- td->str = (tt == TRANSPORT_RAIL) ? STR_LAI_TUNNEL_DESCRIPTION_RAILROAD : STR_LAI_TUNNEL_DESCRIPTION_ROAD; +- } else { // IsBridge(tile) +- td->str = (tt == TRANSPORT_WATER) ? STR_LAI_BRIDGE_DESCRIPTION_AQUEDUCT : GetBridgeSpec(GetBridgeType(tile))->transport_name[tt]; ++ td->str = (tt == TRANSPORT_RAIL) ? HasWormholeSignals(tile) ? STR_LAI_TUNNEL_DESCRIPTION_RAILROAD_SIGNAL : STR_LAI_TUNNEL_DESCRIPTION_RAILROAD : STR_LAI_TUNNEL_DESCRIPTION_ROAD; ++ } else { // IsBridge(tile) ++ td->str = (tt == TRANSPORT_WATER) ? STR_LAI_BRIDGE_DESCRIPTION_AQUEDUCT : HasWormholeSignals(tile) ? STR_LAI_BRIDGE_DESCRIPTION_RAILROAD_SIGNAL : GetBridgeSpec(GetBridgeType(tile))->transport_name[tt]; + } + td->owner[0] = GetTileOwner(tile); + +@@ -1656,6 +1763,26 @@ static void TileLoop_TunnelBridge(TileIndex tile) + } + } + ++static bool ClickTile_TunnelBridge(TileIndex tile) ++{ ++ /* Show vehicles found in tunnel. */ ++ if (IsTunnelTile(tile)) { ++ int count = 0; ++ const Train *t; ++ TileIndex tile_end = GetOtherTunnelBridgeEnd(tile); ++ FOR_ALL_TRAINS(t) { ++ if (!t->IsFrontEngine()) continue; ++ if (tile == t->tile || tile_end == t->tile) { ++ ShowVehicleViewWindow(t); ++ count++; ++ } ++ if (count > 19) break; // no more than 20 windows open ++ } ++ if (count > 0) return true; ++ } ++ return false; ++} ++ + static TrackStatus GetTileTrackStatus_TunnelBridge(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side) + { + TransportType transport_type = GetTunnelBridgeTransportType(tile); +@@ -1908,7 +2035,7 @@ extern const TileTypeProcs _tile_type_tunnelbridge_procs = { + NULL, // add_accepted_cargo_proc + GetTileDesc_TunnelBridge, // get_tile_desc_proc + GetTileTrackStatus_TunnelBridge, // get_tile_track_status_proc +- NULL, // click_tile_proc ++ ClickTile_TunnelBridge, // click_tile_proc + NULL, // animate_tile_proc + TileLoop_TunnelBridge, // tile_loop_proc + ChangeTileOwner_TunnelBridge, // change_tile_owner_proc +diff --git a/src/tunnelbridge_map.h b/src/tunnelbridge_map.h +index 0f7f17b3ac..57f338b8be 100644 +--- a/src/tunnelbridge_map.h ++++ b/src/tunnelbridge_map.h +@@ -121,4 +121,98 @@ static inline TrackBits GetTunnelBridgeReservationTrackBits(TileIndex t) + return HasTunnelBridgeReservation(t) ? DiagDirToDiagTrackBits(GetTunnelBridgeDirection(t)) : TRACK_BIT_NONE; + } + ++/** ++ * Declare tunnel/bridge with signal simulation. ++ * @param t the tunnel/bridge tile. ++ */ ++static inline void SetBitTunnelBridgeSignal(TileIndex t) ++{ ++ assert(IsTileType(t, MP_TUNNELBRIDGE)); ++ SetBit(_m[t].m5, 5); ++} ++ ++/** ++ * Remove tunnel/bridge with signal simulation. ++ * @param t the tunnel/bridge tile. ++ */ ++static inline void ClrBitTunnelBridgeSignal(TileIndex t) ++{ ++ assert(IsTileType(t, MP_TUNNELBRIDGE)); ++ ClrBit(_m[t].m5, 5); ++} ++ ++/** ++ * Declare tunnel/bridge exit. ++ * @param t the tunnel/bridge tile. ++ */ ++static inline void SetBitTunnelBridgeExit(TileIndex t) ++{ ++ assert(IsTileType(t, MP_TUNNELBRIDGE)); ++ SetBit(_m[t].m5, 6); ++} ++ ++/** ++ * Remove tunnel/bridge exit declaration. ++ * @param t the tunnel/bridge tile. ++ */ ++static inline void ClrBitTunnelBridgeExit(TileIndex t) ++{ ++ assert(IsTileType(t, MP_TUNNELBRIDGE)); ++ ClrBit(_m[t].m5, 6); ++} ++ ++/** ++ * Is this a tunnel/bridge pair with signal simulation? ++ * On tunnel/bridge pair minimal one of the two bits is set. ++ * @param t the tile that might be a tunnel/bridge. ++ * @return true if and only if this tile is a tunnel/bridge with signal simulation. ++ */ ++static inline bool HasWormholeSignals(TileIndex t) ++{ ++ return IsTileType(t, MP_TUNNELBRIDGE) && (HasBit(_m[t].m5, 5) || HasBit(_m[t].m5, 6)) ; ++} ++ ++/** ++ * Is this a tunnel/bridge with sign on green? ++ * @param t the tile that might be a tunnel/bridge with sign set green. ++ * @pre IsTileType(t, MP_TUNNELBRIDGE) ++ * @return true if and only if this tile is a tunnel/bridge entrance. ++ */ ++static inline bool IsTunnelBridgeWithSignGreen(TileIndex t) ++{ ++ assert(IsTileType(t, MP_TUNNELBRIDGE)); ++ return HasBit(_m[t].m5, 5) && !HasBit(_m[t].m5, 6); ++} ++ ++static inline bool IsTunnelBridgeWithSignRed(TileIndex t) ++{ ++ assert(IsTileType(t, MP_TUNNELBRIDGE)); ++ return HasBit(_m[t].m5, 5) && HasBit(_m[t].m5, 6); ++} ++ ++/** ++ * Is this a tunnel/bridge entrance tile with signal? ++ * Tunnel bridge signal simulation has allways bit 5 on at entrance. ++ * @param t the tile that might be a tunnel/bridge. ++ * @return true if and only if this tile is a tunnel/bridge entrance. ++ */ ++static inline bool IsTunnelBridgeEntrance(TileIndex t) ++{ ++ assert(IsTileType(t, MP_TUNNELBRIDGE)); ++ return HasBit(_m[t].m5, 5) ; ++} ++ ++/** ++ * Is this a tunnel/bridge exit? ++ * @param t the tile that might be a tunnel/bridge. ++ * @return true if and only if this tile is a tunnel/bridge exit. ++ */ ++static inline bool IsTunnelBridgeExit(TileIndex t) ++{ ++ assert(IsTileType(t, MP_TUNNELBRIDGE)); ++ return !HasBit(_m[t].m5, 5) && HasBit(_m[t].m5, 6); ++} ++ ++ ++ + #endif /* TUNNELBRIDGE_MAP_H */ |