summaryrefslogtreecommitdiff
path: root/openttd-git/chunnel.patch
diff options
context:
space:
mode:
Diffstat (limited to 'openttd-git/chunnel.patch')
-rw-r--r--openttd-git/chunnel.patch1063
1 files changed, 0 insertions, 1063 deletions
diff --git a/openttd-git/chunnel.patch b/openttd-git/chunnel.patch
deleted file mode 100644
index 4071429f6..000000000
--- a/openttd-git/chunnel.patch
+++ /dev/null
@@ -1,1063 +0,0 @@
-diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
-index bbe66b7645..7fb18d527a 100644
---- a/src/CMakeLists.txt
-+++ b/src/CMakeLists.txt
-@@ -442,6 +442,7 @@ add_files(
- tree_cmd.cpp
- tree_gui.cpp
- tree_map.h
-+ tunnel_base.h
- tunnel_map.cpp
- tunnel_map.h
- tunnelbridge.h
-diff --git a/src/ground_vehicle.cpp b/src/ground_vehicle.cpp
-index 0f1915c964..0a734a5b55 100644
---- a/src/ground_vehicle.cpp
-+++ b/src/ground_vehicle.cpp
-@@ -11,6 +11,8 @@
- #include "train.h"
- #include "roadveh.h"
- #include "depot_map.h"
-+#include "tunnel_base.h"
-+#include "slope_type.h"
-
- #include "safeguards.h"
-
-@@ -203,6 +205,69 @@ bool GroundVehicle<T, Type>::IsChainInDepot() const
- return true;
- }
-
-+/**
-+ * Updates vehicle's Z inclination inside a wormhole, where applicable.
-+ */
-+template <class T, VehicleType Type>
-+void GroundVehicle<T, Type>::UpdateZPositionInWormhole()
-+{
-+ if (!IsTunnel(this->tile)) return;
-+
-+ const Tunnel *t = Tunnel::GetByTile(this->tile);
-+ if (!t->is_chunnel) return;
-+
-+ TileIndex pos_tile = TileVirtXY(this->x_pos, this->y_pos);
-+
-+ ClrBit(this->gv_flags, GVF_GOINGUP_BIT);
-+ ClrBit(this->gv_flags, GVF_GOINGDOWN_BIT);
-+
-+ if (pos_tile == t->tile_n || pos_tile == t->tile_s) {
-+ this->z_pos = 0;
-+ return;
-+ }
-+
-+ int north_coord, south_coord, pos_coord;
-+ Slope slope = SLOPE_FLAT;
-+ int delta;
-+ if (t->tile_s - t->tile_n > MapMaxX()) {
-+ // tunnel extends along Y axis (DIAGDIR_SE from north end), has same X values
-+ north_coord = TileY(t->tile_n);
-+ south_coord = TileY(t->tile_s);
-+ pos_coord = TileY(pos_tile);
-+
-+ if ((delta = pos_coord - north_coord) <= 3) {
-+ this->z_pos = TILE_HEIGHT * (delta == 3 ? -2 : -1);
-+ if (delta != 2) {
-+ slope = SLOPE_NW;
-+ SetBit(this->gv_flags, this->direction == DIR_NW ? GVF_GOINGUP_BIT : GVF_GOINGDOWN_BIT);
-+ }
-+ } else if ((delta = south_coord - pos_coord) <= 3) {
-+ this->z_pos = TILE_HEIGHT * (delta == 3 ? -2 : -1);
-+ if (delta != 2) {
-+ slope = SLOPE_ELEVATED ^ SLOPE_NW;
-+ SetBit(this->gv_flags, this->direction == DIR_NW ? GVF_GOINGDOWN_BIT : GVF_GOINGUP_BIT);
-+ }
-+ }
-+ } else {
-+ // tunnel extends along X axis (DIAGDIR_SW from north end), has same Y values
-+ north_coord = TileX(t->tile_n);
-+ south_coord = TileX(t->tile_s);
-+ pos_coord = TileX(pos_tile);
-+
-+ if ((delta = pos_coord - north_coord) <= 3) {
-+ this->z_pos = TILE_HEIGHT * (delta == 3 ? -3 : (delta == 2 ? -2 : -1));
-+ slope = SLOPE_NE;
-+ SetBit(this->gv_flags, this->direction == DIR_NE ? GVF_GOINGUP_BIT : GVF_GOINGDOWN_BIT);
-+ } else if ((delta = south_coord - pos_coord) <= 3) {
-+ this->z_pos = TILE_HEIGHT * (delta == 3 ? -3 : (delta == 2 ? -2 : -1));
-+ slope = SLOPE_ELEVATED ^ SLOPE_NE;
-+ SetBit(this->gv_flags, this->direction == DIR_NE ? GVF_GOINGDOWN_BIT : GVF_GOINGUP_BIT);
-+ }
-+ }
-+
-+ if (slope != SLOPE_FLAT) this->z_pos += GetPartialPixelZ(this->x_pos & 0xF, this->y_pos & 0xF, slope);
-+}
-+
- /* Instantiation for Train */
- template struct GroundVehicle<Train, VEH_TRAIN>;
- /* Instantiation for RoadVehicle */
-diff --git a/src/ground_vehicle.hpp b/src/ground_vehicle.hpp
-index af6e25c806..ae4e9ead11 100644
---- a/src/ground_vehicle.hpp
-+++ b/src/ground_vehicle.hpp
-@@ -14,6 +14,7 @@
- #include "vehicle_gui.h"
- #include "landscape.h"
- #include "window_func.h"
-+#include "tunnel_map.h"
- #include "widgets/vehicle_widget.h"
-
- /** What is the status of our acceleration? */
-@@ -52,6 +53,7 @@ enum GroundVehicleFlags {
- GVF_GOINGUP_BIT = 0, ///< Vehicle is currently going uphill. (Cached track information for acceleration)
- GVF_GOINGDOWN_BIT = 1, ///< Vehicle is currently going downhill. (Cached track information for acceleration)
- GVF_SUPPRESS_IMPLICIT_ORDERS = 2, ///< Disable insertion and removal of automatic orders until the vehicle completes the real order.
-+ GVF_CHUNNEL_BIT = 3, ///< Vehicle may currently be in a chunnel. (Cached track information for inclination changes)
- };
-
- /**
-@@ -220,20 +222,28 @@ struct GroundVehicle : public SpecializedVehicle<T, Type> {
- this->z_pos += HasBit(this->gv_flags, GVF_GOINGUP_BIT) ? d : -d;
- }
-
-+ if (HasBit(this->gv_flags, GVF_CHUNNEL_BIT) && !IsTunnelTile(this->tile)) {
-+ ClrBit(this->gv_flags, GVF_CHUNNEL_BIT);
-+ }
-+
- assert(this->z_pos == GetSlopePixelZ(this->x_pos, this->y_pos));
- }
-
-+ void UpdateZPositionInWormhole();
-+
- /**
- * Checks if the vehicle is in a slope and sets the required flags in that case.
- * @param new_tile True if the vehicle reached a new tile.
- * @param update_delta Indicates to also update the delta.
- * @return Old height of the vehicle.
- */
-- inline int UpdateInclination(bool new_tile, bool update_delta)
-+ inline int UpdateInclination(bool new_tile, bool update_delta, bool in_wormhole = false)
- {
- int old_z = this->z_pos;
-
-- if (new_tile) {
-+ if (in_wormhole) {
-+ if (HasBit(this->gv_flags, GVF_CHUNNEL_BIT)) this->UpdateZPositionInWormhole();
-+ } else if (new_tile) {
- this->UpdateZPositionAndInclination();
- } else {
- this->UpdateZPosition();
-diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp
-index 816146212f..5491936557 100644
---- a/src/industry_cmd.cpp
-+++ b/src/industry_cmd.cpp
-@@ -20,6 +20,7 @@
- #include "company_base.h"
- #include "genworld.h"
- #include "tree_map.h"
-+#include "tunnel_map.h"
- #include "newgrf_cargo.h"
- #include "newgrf_debug.h"
- #include "newgrf_industrytiles.h"
-@@ -1521,6 +1522,11 @@ static CommandCost CheckIfIndustryIsAllowed(TileIndex tile, int type, const Town
- return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_NEAR_TOWN_CENTER);
- }
-
-+ if (type == IT_OIL_RIG &&
-+ (IsTunnelInWay(tile, 0) ||
-+ IsTunnelInWay(tile + TileDiffXY(0, 1), 0) ||
-+ IsTunnelInWay(tile + TileDiffXY(1, 2), 0))) return_cmd_error(STR_ERROR_NO_DRILLING_ABOVE_CHUNNEL);
-+
- return CommandCost();
- }
-
-diff --git a/src/lang/english.txt b/src/lang/english.txt
-index 8d8a128717..765fc146a1 100644
---- a/src/lang/english.txt
-+++ b/src/lang/english.txt
-@@ -2321,6 +2321,7 @@ STR_TRANSPARENT_BRIDGES_TOOLTIP :{BLACK}Toggle t
- STR_TRANSPARENT_STRUCTURES_TOOLTIP :{BLACK}Toggle transparency for structures like lighthouses and antennas. Ctrl+Click to lock
- STR_TRANSPARENT_CATENARY_TOOLTIP :{BLACK}Toggle transparency for catenary. Ctrl+Click to lock
- STR_TRANSPARENT_LOADING_TOOLTIP :{BLACK}Toggle transparency for loading indicators. Ctrl+Click to lock
-+STR_TRANSPARENT_TUNNELS_TOOLTIP :{BLACK}Toggle transparency for vehicles in tunnels. Ctrl+Click to lock.
- STR_TRANSPARENT_INVISIBLE_TOOLTIP :{BLACK}Set objects invisible instead of transparent
-
- # Linkgraph legend window
-@@ -2720,7 +2721,9 @@ 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_CHUNNEL :Railway tunnel (underwater)
- STR_LAI_TUNNEL_DESCRIPTION_ROAD :Road tunnel
-+STR_LAI_TUNNEL_DESCRIPTION_ROAD_CHUNNEL :Road tunnel (underwater)
-
- STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_STEEL :Steel suspension rail bridge
- STR_LAI_BRIDGE_DESCRIPTION_RAIL_GIRDER_STEEL :Steel girder rail bridge
-@@ -4542,6 +4545,10 @@ STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY :{WHITE}Another
- STR_ERROR_TUNNEL_THROUGH_MAP_BORDER :{WHITE}Tunnel would end out of the map
- STR_ERROR_UNABLE_TO_EXCAVATE_LAND :{WHITE}Unable to excavate land for other end of tunnel
- STR_ERROR_TUNNEL_TOO_LONG :{WHITE}... tunnel too long
-+STR_ERROR_TUNNEL_RAMP_TOO_SHORT :{WHITE}... ramp too short, tunnels under water must have a ramp at least three tiles long at both ends.
-+STR_ERROR_TUNNEL_TOO_MANY :{WHITE}... too many tunnels
-+STR_ERROR_NO_DRILLING_ABOVE_CHUNNEL :{WHITE}No oil rigs allowed above underwater tunnels.
-+STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY_FOR_CHUNNEL :{WHITE}Three tiles are needed to pass under the other tunnel.
-
- # Object related errors
- STR_ERROR_TOO_MANY_OBJECTS :{WHITE}... too many objects
-diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp
-index 14fa8d79d8..604b51ea46 100644
---- a/src/roadveh_cmd.cpp
-+++ b/src/roadveh_cmd.cpp
-@@ -1178,6 +1178,7 @@ bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev)
- v->x_pos = gp.x;
- v->y_pos = gp.y;
- v->UpdatePosition();
-+ RoadZPosAffectSpeed(v, v->UpdateInclination(false, false, true));
- if ((v->vehstatus & VS_HIDDEN) == 0) v->Vehicle::UpdateViewport(true);
- return true;
- }
-@@ -1545,7 +1546,7 @@ again:
- v->x_pos = x;
- v->y_pos = y;
- v->UpdatePosition();
-- RoadZPosAffectSpeed(v, v->UpdateInclination(false, true));
-+ RoadZPosAffectSpeed(v, v->UpdateInclination(false, true, v->state == RVSB_WORMHOLE));
- return true;
- }
-
-diff --git a/src/saveload/CMakeLists.txt b/src/saveload/CMakeLists.txt
-index 52f103fa7e..c888a899cd 100644
---- a/src/saveload/CMakeLists.txt
-+++ b/src/saveload/CMakeLists.txt
-@@ -38,6 +38,7 @@ add_files(
- story_sl.cpp
- subsidy_sl.cpp
- town_sl.cpp
-+ tunnel_sl.cpp
- vehicle_sl.cpp
- waypoint_sl.cpp
- )
-diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp
-index 329152ab27..7ebefb7ad7 100644
---- a/src/saveload/afterload.cpp
-+++ b/src/saveload/afterload.cpp
-@@ -11,6 +11,7 @@
- #include "../void_map.h"
- #include "../signs_base.h"
- #include "../depot_base.h"
-+#include "../tunnel_base.h"
- #include "../fios.h"
- #include "../gamelog_internal.h"
- #include "../network/network.h"
-@@ -534,6 +535,25 @@ static inline bool MayHaveBridgeAbove(TileIndex t)
- IsTileType(t, MP_WATER) || IsTileType(t, MP_TUNNELBRIDGE) || IsTileType(t, MP_OBJECT);
- }
-
-+TileIndex GetOtherTunnelBridgeEndOld(TileIndex tile)
-+{
-+ DiagDirection dir = GetTunnelBridgeDirection(tile);
-+ TileIndexDiff delta = TileOffsByDiagDir(dir);
-+ int z = GetTileZ(tile);
-+
-+ dir = ReverseDiagDir(dir);
-+ do {
-+ tile += delta;
-+ } while (
-+ !IsTunnelTile(tile) ||
-+ GetTunnelBridgeDirection(tile) != dir ||
-+ GetTileZ(tile) != z
-+ );
-+
-+ return tile;
-+}
-+
-+
- /**
- * Perform a (large) amount of savegame conversion *magic* in order to
- * load older savegames and to fill the caches for various purposes.
-@@ -1944,6 +1964,32 @@ bool AfterLoadGame()
- }
- }
-
-+ /* Tunnel pool has to be initiated before reservations. */
-+ if (IsSavegameVersionBefore(SLV_196)) {
-+ for (TileIndex t = 0; t < map_size; t++) {
-+ if (IsTunnelTile(t)) {
-+ DiagDirection dir = GetTunnelBridgeDirection(t);
-+ if (dir == DIAGDIR_SE || dir == DIAGDIR_SW) {
-+ TileIndex start_tile = t;
-+ TileIndex end_tile = GetOtherTunnelBridgeEndOld(start_tile);
-+
-+ if (!Tunnel::CanAllocateItem()) {
-+ SetSaveLoadError(STR_ERROR_TUNNEL_TOO_MANY);
-+ /* Restore the signals */
-+ ResetSignalHandlers();
-+ return false;
-+ }
-+
-+ const Tunnel *t = new Tunnel(start_tile, end_tile, false);
-+
-+ _m[start_tile].m2 = t->index;
-+ _m[end_tile].m2 = t->index;
-+ }
-+ }
-+ }
-+ }
-+
-+
- /* Move the signal variant back up one bit for PBS. We don't convert the old PBS
- * format here, as an old layout wouldn't work properly anyway. To be safe, we
- * clear any possible PBS reservations as well. */
-@@ -2547,7 +2593,7 @@ bool AfterLoadGame()
- } else if (dir == ReverseDiagDir(vdir)) { // Leaving tunnel
- hidden = frame < TILE_SIZE - _tunnel_visibility_frame[dir];
- /* v->tile changes at the moment when the vehicle leaves the tunnel. */
-- v->tile = hidden ? GetOtherTunnelBridgeEnd(vtile) : vtile;
-+ v->tile = hidden ? GetOtherTunnelBridgeEndOld(vtile) : vtile;
- } else {
- /* We could get here in two cases:
- * - for road vehicles, it is reversing at the end of the tunnel
-diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp
-index 1b79ad926b..69e8b60905 100644
---- a/src/saveload/saveload.cpp
-+++ b/src/saveload/saveload.cpp
-@@ -248,6 +248,7 @@ extern const ChunkHandler _linkgraph_chunk_handlers[];
- extern const ChunkHandler _airport_chunk_handlers[];
- extern const ChunkHandler _object_chunk_handlers[];
- extern const ChunkHandler _persistent_storage_chunk_handlers[];
-+extern const ChunkHandler _tunnel_chunk_handlers[];
-
- /** Array of all chunks in a savegame, \c nullptr terminated. */
- static const ChunkHandler * const _chunk_handlers[] = {
-@@ -284,6 +285,8 @@ static const ChunkHandler * const _chunk_handlers[] = {
- _airport_chunk_handlers,
- _object_chunk_handlers,
- _persistent_storage_chunk_handlers,
-+ _tunnel_chunk_handlers,
-+
- nullptr,
- };
-
-diff --git a/src/saveload/tunnel_sl.cpp b/src/saveload/tunnel_sl.cpp
-new file mode 100644
-index 0000000000..7ad37b12b9
---- /dev/null
-+++ b/src/saveload/tunnel_sl.cpp
-@@ -0,0 +1,48 @@
-+/* $Id$ */
-+
-+/*
-+ * This file is part of OpenTTD.
-+ * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
-+ * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-+ * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+/** @file tunnel_sl.cpp Code handling saving and loading of tunnels */
-+
-+#include "../stdafx.h"
-+#include "../tunnel_base.h"
-+
-+#include "saveload.h"
-+
-+#include "../safeguards.h"
-+
-+
-+static const SaveLoad _tunnel_desc[] = {
-+ SLE_CONDVAR(Tunnel, tile_n, SLE_UINT32, SLV_196, SL_MAX_VERSION),
-+ SLE_CONDVAR(Tunnel, tile_s, SLE_UINT32, SLV_196, SL_MAX_VERSION),
-+ SLE_CONDVAR(Tunnel, is_chunnel, SLE_BOOL, SLV_196, SL_MAX_VERSION),
-+ SLE_END()
-+};
-+
-+static void Save_TUNN()
-+{
-+ for(Tunnel *tunnel : Tunnel::Iterate()) {
-+ SlSetArrayIndex(tunnel->index);
-+ SlObject(tunnel, _tunnel_desc);
-+ }
-+}
-+
-+static void Load_TUNN()
-+{
-+ int index;
-+
-+ while ((index = SlIterateArray()) != -1) {
-+ Tunnel *tunnel = new (index) Tunnel();
-+ SlObject(tunnel, _tunnel_desc);
-+ }
-+}
-+
-+
-+extern const ChunkHandler _tunnel_chunk_handlers[] = {
-+ { 'TUNN', Save_TUNN, Load_TUNN, nullptr, nullptr, CH_ARRAY | CH_LAST},
-+};
-diff --git a/src/table/misc_settings.ini b/src/table/misc_settings.ini
-index edad848165..f0322ee359 100644
---- a/src/table/misc_settings.ini
-+++ b/src/table/misc_settings.ini
-@@ -254,7 +254,7 @@ type = SLE_UINT
- var = _transparency_opt
- def = 0
- min = 0
--max = 0x1FF
-+max = 0x3FF
- cat = SC_BASIC
-
- [SDTG_VAR]
-@@ -263,7 +263,7 @@ type = SLE_UINT
- var = _transparency_lock
- def = 0
- min = 0
--max = 0x1FF
-+max = 0x3FF
- cat = SC_BASIC
-
- [SDTG_VAR]
-diff --git a/src/terraform_cmd.cpp b/src/terraform_cmd.cpp
-index 85edb73128..1a902dd59c 100644
---- a/src/terraform_cmd.cpp
-+++ b/src/terraform_cmd.cpp
-@@ -268,7 +268,7 @@ CommandCost CmdTerraformLand(TileIndex tile, DoCommandFlag flags, uint32 p1, uin
- }
- }
- /* Check if tunnel would take damage */
-- if (direction == -1 && IsTunnelInWay(tile, z_min)) {
-+ if (direction == -1 && IsTunnelInWay(tile, z_min, true)) {
- _terraform_err_tile = tile; // highlight the tile above the tunnel
- return_cmd_error(STR_ERROR_EXCAVATION_WOULD_DAMAGE);
- }
-diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp
-index ae9cb45de3..a9ca119ec3 100644
---- a/src/train_cmd.cpp
-+++ b/src/train_cmd.cpp
-@@ -1563,6 +1563,7 @@ static void UpdateStatusAfterSwap(Train *v)
- }
-
- v->UpdatePosition();
-+ if (v->track == TRACK_BIT_WORMHOLE) v->UpdateInclination(false, false, true);
- v->UpdateViewport(true, true);
- }
-
-@@ -3326,6 +3327,15 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
- v->x_pos = gp.x;
- v->y_pos = gp.y;
- v->UpdatePosition();
-+ if (v->track == TRACK_BIT_WORMHOLE) {
-+ /* update the Z position of the vehicle */
-+ int old_z = v->UpdateInclination(false, false, true);
-+
-+ if (prev == nullptr) {
-+ /* This is the first vehicle in the train */
-+ AffectSpeedByZChange(v, old_z);
-+ }
-+ }
- if ((v->vehstatus & VS_HIDDEN) == 0) v->Vehicle::UpdateViewport(true);
- continue;
- }
-@@ -3339,7 +3349,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
- v->UpdatePosition();
-
- /* update the Z position of the vehicle */
-- int old_z = v->UpdateInclination(gp.new_tile != gp.old_tile, false);
-+ int old_z = v->UpdateInclination(gp.new_tile != gp.old_tile, false, v->track == TRACK_BIT_WORMHOLE);
-
- if (prev == nullptr) {
- /* This is the first vehicle in the train */
-@@ -3853,7 +3863,7 @@ static bool TrainLocoHandler(Train *v, bool mode)
- }
-
- for (Train *u = v; u != nullptr; u = u->Next()) {
-- if ((u->vehstatus & VS_HIDDEN) != 0) continue;
-+ if (!u->IsDrawn()) continue;
-
- u->UpdateViewport(false, false);
- }
-diff --git a/src/transparency.h b/src/transparency.h
-index 54ba24e933..08b13ca9b9 100644
---- a/src/transparency.h
-+++ b/src/transparency.h
-@@ -29,6 +29,7 @@ enum TransparencyOption {
- TO_STRUCTURES, ///< other objects such as transmitters and lighthouses
- TO_CATENARY, ///< catenary
- TO_LOADING, ///< loading indicators
-+ TO_TUNNELS, ///< vehicles in tunnels
- TO_END,
- TO_INVALID, ///< Invalid transparency option
- };
-diff --git a/src/transparency_gui.cpp b/src/transparency_gui.cpp
-index 153dcb5d03..611094cdeb 100644
---- a/src/transparency_gui.cpp
-+++ b/src/transparency_gui.cpp
-@@ -50,7 +50,8 @@ public:
- case WID_TT_BRIDGES:
- case WID_TT_STRUCTURES:
- case WID_TT_CATENARY:
-- case WID_TT_LOADING: {
-+ case WID_TT_LOADING:
-+ case WID_TT_TUNNELS: {
- uint i = widget - WID_TT_BEGIN;
- if (HasBit(_transparency_lock, i)) DrawSprite(SPR_LOCK, PAL_NONE, r.left + 1, r.top + 1);
- break;
-@@ -58,6 +59,7 @@ public:
- case WID_TT_BUTTONS:
- for (uint i = WID_TT_BEGIN; i < WID_TT_END; i++) {
- if (i == WID_TT_LOADING) continue; // Do not draw button for invisible loading indicators.
-+ if (i == WID_TT_TUNNELS) continue; // Do not draw button for invisible vehicles in tunnels.
-
- const NWidgetBase *wi = this->GetWidget<NWidgetBase>(i);
- DrawFrameRect(wi->pos_x + 1, r.top + 2, wi->pos_x + wi->current_x - 2, r.bottom - 2, COLOUR_PALE_GREEN,
-@@ -69,7 +71,7 @@ public:
-
- void OnClick(Point pt, int widget, int click_count) override
- {
-- if (widget >= WID_TT_BEGIN && widget < WID_TT_END) {
-+ if (IsInsideMM(widget, WID_TT_BEGIN, WID_TT_END)) {
- if (_ctrl_pressed) {
- /* toggle the bit of the transparencies lock variable */
- ToggleTransparencyLock((TransparencyOption)(widget - WID_TT_BEGIN));
-@@ -139,6 +141,7 @@ static const NWidgetPart _nested_transparency_widgets[] = {
- NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_STRUCTURES), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_TRANSMITTER, STR_TRANSPARENT_STRUCTURES_TOOLTIP),
- NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_CATENARY), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_BUILD_X_ELRAIL, STR_TRANSPARENT_CATENARY_TOOLTIP),
- NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_LOADING), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_TRAINLIST, STR_TRANSPARENT_LOADING_TOOLTIP),
-+ NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_TUNNELS), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_ROAD_TUNNEL, STR_TRANSPARENT_TUNNELS_TOOLTIP),
- NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetFill(1, 1), EndContainer(),
- EndContainer(),
- /* Panel with 'invisibility' buttons. */
-diff --git a/src/tunnel_base.h b/src/tunnel_base.h
-new file mode 100644
-index 0000000000..4a2493fa7f
---- /dev/null
-+++ b/src/tunnel_base.h
-@@ -0,0 +1,39 @@
-+/* $Id$ */
-+
-+/*
-+ * This file is part of OpenTTD.
-+ * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
-+ * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-+ * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+/** @file tunnel_base.h Base for all tunnels */
-+
-+#ifndef TUNNEL_BASE_H
-+#define TUNNEL_BASE_H
-+
-+#include "tunnel_map.h"
-+#include "core/pool_type.hpp"
-+
-+struct Tunnel;
-+
-+typedef Pool<Tunnel, TunnelID, 64, 64000> TunnelPool;
-+extern TunnelPool _tunnel_pool;
-+
-+struct Tunnel : TunnelPool::PoolItem<&_tunnel_pool> {
-+
-+ TileIndex tile_n; // North tile of tunnel.
-+ TileIndex tile_s; // South tile of tunnel.
-+ bool is_chunnel;
-+
-+ Tunnel() {}
-+ Tunnel(TileIndex tile_n, TileIndex tile_s, bool is_chunnel) : tile_n(tile_n), tile_s(tile_s), is_chunnel(is_chunnel) {}
-+ ~Tunnel();
-+
-+ static inline Tunnel *GetByTile(TileIndex tile)
-+ {
-+ return Tunnel::Get(GetTunnelIndex(tile));
-+ }
-+};
-+
-+#endif /* TUNNEL_BASE_H */
-diff --git a/src/tunnel_map.cpp b/src/tunnel_map.cpp
-index 9de5235801..6234193e1e 100644
---- a/src/tunnel_map.cpp
-+++ b/src/tunnel_map.cpp
-@@ -10,63 +10,62 @@
- #include "stdafx.h"
- #include "tunnelbridge_map.h"
-
-+#include "core/pool_func.hpp"
-+
- #include "safeguards.h"
-
-+/** All tunnel portals tucked away in a pool. */
-+TunnelPool _tunnel_pool("Tunnel");
-+INSTANTIATE_POOL_METHODS(Tunnel)
-
- /**
-- * Gets the other end of the tunnel. Where a vehicle would reappear when it
-- * enters at the given tile.
-- * @param tile the tile to search from.
-- * @return the tile of the other end of the tunnel.
-+ * Clean up a tunnel tile
- */
--TileIndex GetOtherTunnelEnd(TileIndex tile)
-+Tunnel::~Tunnel()
- {
-- DiagDirection dir = GetTunnelBridgeDirection(tile);
-- TileIndexDiff delta = TileOffsByDiagDir(dir);
-- int z = GetTileZ(tile);
--
-- dir = ReverseDiagDir(dir);
-- do {
-- tile += delta;
-- } while (
-- !IsTunnelTile(tile) ||
-- GetTunnelBridgeDirection(tile) != dir ||
-- GetTileZ(tile) != z
-- );
--
-- return tile;
-+ if (CleaningPool()) return;
- }
-
--
- /**
-- * Is there a tunnel in the way in the given direction?
-+ * Gets the other end of the tunnel. Where a vehicle would reappear when it
-+ * enters at the given tile.
- * @param tile the tile to search from.
-- * @param z the 'z' to search on.
-- * @param dir the direction to start searching to.
-- * @return true if and only if there is a tunnel.
-+ * @return the tile of the other end of the tunnel.
- */
--bool IsTunnelInWayDir(TileIndex tile, int z, DiagDirection dir)
-+TileIndex GetOtherTunnelEnd(TileIndex tile)
- {
-- TileIndexDiff delta = TileOffsByDiagDir(dir);
-- int height;
--
-- do {
-- tile -= delta;
-- if (!IsValidTile(tile)) return false;
-- height = GetTileZ(tile);
-- } while (z < height);
--
-- return z == height && IsTunnelTile(tile) && GetTunnelBridgeDirection(tile) == dir;
-+ Tunnel *t = Tunnel::GetByTile(tile);
-+ return t->tile_n == tile ? t->tile_s : t->tile_n;
- }
-
- /**
- * Is there a tunnel in the way in any direction?
- * @param tile the tile to search from.
- * @param z the 'z' to search on.
-+ * @param chunnel_allowed True if chunnel mid-parts are allowed, used when terraforming.
- * @return true if and only if there is a tunnel.
- */
--bool IsTunnelInWay(TileIndex tile, int z)
-+bool IsTunnelInWay(TileIndex tile, int z, bool chunnel_allowed)
- {
-- return IsTunnelInWayDir(tile, z, (TileX(tile) > (MapMaxX() / 2)) ? DIAGDIR_NE : DIAGDIR_SW) ||
-- IsTunnelInWayDir(tile, z, (TileY(tile) > (MapMaxY() / 2)) ? DIAGDIR_NW : DIAGDIR_SE);
-+ uint x = TileX(tile);
-+ uint y = TileY(tile);
-+
-+ for(Tunnel *t : Tunnel::Iterate()) {
-+ if (t->tile_n > tile || tile > t->tile_s) continue;
-+
-+ if (t->tile_s - t->tile_n > MapMaxX()){
-+ if (TileX(t->tile_n) != x || (int)TileHeight(t->tile_n) != z) continue; // dir DIAGDIR_SE
-+ } else {
-+ if (TileY(t->tile_n) != y || (int)TileHeight(t->tile_n) != z) continue; // dir DIAGDIR_SW
-+ }
-+
-+ if (t->is_chunnel && chunnel_allowed) {
-+ /* Only if tunnel was build over water terraforming is allowed between portals. */
-+ TileIndexDiff delta = GetTunnelBridgeDirection(t->tile_n) == DIAGDIR_SE ? TileOffsByDiagDir(DIAGDIR_SE) * 4 : 4; // 4 tiles ramp.
-+ if (tile < t->tile_n + delta || t->tile_s - delta < tile) return true;
-+ continue;
-+ }
-+ return true;
-+ }
-+ return false;
- }
-diff --git a/src/tunnel_map.h b/src/tunnel_map.h
-index c347626d55..45589dacb4 100644
---- a/src/tunnel_map.h
-+++ b/src/tunnel_map.h
-@@ -13,6 +13,7 @@
- #include "rail_map.h"
- #include "road_map.h"
-
-+typedef uint16 TunnelID; ///< Type for the unique identifier of tunnels.
-
- /**
- * Is this a tunnel (entrance)?
-@@ -36,22 +37,34 @@ static inline bool IsTunnelTile(TileIndex t)
- return IsTileType(t, MP_TUNNELBRIDGE) && IsTunnel(t);
- }
-
-+/**
-+ * Get the index of tunnel tile.
-+ * @param t the tile
-+ * @pre IsTunnelTile(t)
-+ * @return TunnelID
-+ */
-+static inline TunnelID GetTunnelIndex(TileIndex t)
-+{
-+ assert(IsTunnelTile(t));
-+ return _m[t].m2;
-+}
-+
- TileIndex GetOtherTunnelEnd(TileIndex);
--bool IsTunnelInWay(TileIndex, int z);
--bool IsTunnelInWayDir(TileIndex tile, int z, DiagDirection dir);
-+bool IsTunnelInWay(TileIndex, int z, bool chunnel_allowed = false);
-
- /**
- * Makes a road tunnel entrance
- * @param t the entrance of the tunnel
- * @param o the owner of the entrance
-+ * @param id the tunnel ID
- * @param d the direction facing out of the tunnel
- * @param r the road type used in the tunnel
- */
--static inline void MakeRoadTunnel(TileIndex t, Owner o, DiagDirection d, RoadType road_rt, RoadType tram_rt)
-+static inline void MakeRoadTunnel(TileIndex t, Owner o, TunnelID id, DiagDirection d, RoadType road_rt, RoadType tram_rt)
- {
- SetTileType(t, MP_TUNNELBRIDGE);
- SetTileOwner(t, o);
-- _m[t].m2 = 0;
-+ _m[t].m2 = id;
- _m[t].m3 = 0;
- _m[t].m4 = 0;
- _m[t].m5 = TRANSPORT_ROAD << 2 | d;
-@@ -67,14 +80,15 @@ static inline void MakeRoadTunnel(TileIndex t, Owner o, DiagDirection d, RoadTyp
- * Makes a rail tunnel entrance
- * @param t the entrance of the tunnel
- * @param o the owner of the entrance
-+ * @param id the tunnel ID
- * @param d the direction facing out of the tunnel
- * @param r the rail type used in the tunnel
- */
--static inline void MakeRailTunnel(TileIndex t, Owner o, DiagDirection d, RailType r)
-+static inline void MakeRailTunnel(TileIndex t, Owner o, TunnelID id, DiagDirection d, RailType r)
- {
- SetTileType(t, MP_TUNNELBRIDGE);
- SetTileOwner(t, o);
-- _m[t].m2 = 0;
-+ _m[t].m2 = id;
- _m[t].m3 = 0;
- _m[t].m4 = 0;
- _m[t].m5 = TRANSPORT_RAIL << 2 | d;
-diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp
-index 0423cde1f9..159f06f3fd 100644
---- a/src/tunnelbridge_cmd.cpp
-+++ b/src/tunnelbridge_cmd.cpp
-@@ -40,12 +40,15 @@
- #include "water.h"
- #include "company_gui.h"
- #include "station_func.h"
-+#include "station_map.h"
-+#include "industry_map.h"
-
- #include "table/strings.h"
- #include "table/bridge_land.h"
-
- #include "safeguards.h"
-
-+
- BridgeSpec _bridge[MAX_BRIDGES]; ///< The specification of all bridges.
- TileIndex _build_tunnel_endtile; ///< The end of a tunnel; as hidden return from the tunnel build command for GUI purposes.
-
-@@ -649,12 +652,6 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1,
- * position, because of increased-cost-by-length: 'cost += cost >> 3' */
-
- TileIndexDiff delta = TileOffsByDiagDir(direction);
-- DiagDirection tunnel_in_way_dir;
-- if (DiagDirToAxis(direction) == AXIS_Y) {
-- tunnel_in_way_dir = (TileX(start_tile) < (MapMaxX() / 2)) ? DIAGDIR_SW : DIAGDIR_NE;
-- } else {
-- tunnel_in_way_dir = (TileY(start_tile) < (MapMaxX() / 2)) ? DIAGDIR_SE : DIAGDIR_NW;
-- }
-
- TileIndex end_tile = start_tile;
-
-@@ -662,9 +659,15 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1,
- int tiles_coef = 3;
- /* Number of tiles from start of tunnel */
- int tiles = 0;
-+ /* flag for chunnels. */
-+ bool is_chunnel = false;
-+ /* Number of chunnel head tiles. */
-+ int head_tiles = 0;
- /* Number of tiles at which the cost increase coefficient per tile is halved */
- int tiles_bump = 25;
-
-+ TileIndex found_tunnel_tile = INVALID_TILE;
-+
- CommandCost cost(EXPENSES_CONSTRUCTION);
- Slope end_tileh;
- for (;;) {
-@@ -672,13 +675,69 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1,
- if (!IsValidTile(end_tile)) return_cmd_error(STR_ERROR_TUNNEL_THROUGH_MAP_BORDER);
- end_tileh = GetTileSlope(end_tile, &end_z);
-
-- if (start_z == end_z) break;
-+ if (start_z == end_z) {
-+ _build_tunnel_endtile = found_tunnel_tile != INVALID_TILE ? found_tunnel_tile : end_tile;
-+
-+ /* Test if we are on a shore. */
-+ if (end_z == 0 &&
-+ (IsCoastTile(end_tile) ||
-+ (IsValidTile(end_tile + delta) && HasTileWaterGround(end_tile + delta)) ||
-+ (IsValidTile(end_tile + delta * 2) && HasTileWaterGround(end_tile + delta * 2)))) {
-+ if (!is_chunnel) {
-+ /*We are about to pass water for the first time so check if not to close to other tunnel */
-+ if (tiles + 1 < head_tiles + 4 && found_tunnel_tile != INVALID_TILE) return_cmd_error(STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY_FOR_CHUNNEL);
-+ if (tiles + 1 < 4) return_cmd_error(STR_ERROR_TUNNEL_RAMP_TOO_SHORT);
-+ }
-+ } else {/* We are leaving.*/
-+ if (is_chunnel) {
-+ /* Check if there is enough ramp space to come up. */
-+ if (head_tiles < 4 && found_tunnel_tile != INVALID_TILE) return_cmd_error(STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY_FOR_CHUNNEL);
-+ if (head_tiles < 4) return_cmd_error(STR_ERROR_TUNNEL_RAMP_TOO_SHORT);
-+ } else {
-+ if (found_tunnel_tile != INVALID_TILE) return_cmd_error(STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY);
-+ }
-+ break;
-+ }
-
-- if (!_cheats.crossing_tunnels.value && IsTunnelInWayDir(end_tile, start_z, tunnel_in_way_dir)) {
-- return_cmd_error(STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY);
-- }
-+ /* A shore was found so pass the water and find a proper shore tile that potentially
-+ * could have a tunnel portal behind. */
-+ for (;;) {
-+ if (!IsValidTile(end_tile)) return_cmd_error(STR_ERROR_TUNNEL_THROUGH_MAP_BORDER);
-+
-+ end_tileh = GetTileSlope(end_tile);
-+ if(direction == DIAGDIR_NE && (end_tileh & SLOPE_NE) == SLOPE_NE) break;
-+ if(direction == DIAGDIR_SE && (end_tileh & SLOPE_SE) == SLOPE_SE) break;
-+ if(direction == DIAGDIR_SW && (end_tileh & SLOPE_SW) == SLOPE_SW) break;
-+ if(direction == DIAGDIR_NW && (end_tileh & SLOPE_NW) == SLOPE_NW) break;
-+
-+ /* No drilling under oil rigs.*/
-+ if ((IsTileType(end_tile, MP_STATION) && IsOilRig(end_tile)) ||
-+ (IsTileType(end_tile, MP_INDUSTRY) &&
-+ GetIndustryGfx(end_tile) >= GFX_OILRIG_1 &&
-+ GetIndustryGfx(end_tile) <= GFX_OILRIG_5)) {
-+ _build_tunnel_endtile = end_tile;
-+ return_cmd_error(STR_ERROR_NO_DRILLING_ABOVE_CHUNNEL);
-+ }
-
-+ end_tile += delta;
-+ tiles++;
-+ }
-+ /* The water was passed */
-+ is_chunnel = true;
-+ head_tiles = 0;
-+ found_tunnel_tile = INVALID_TILE;
-+ }
-+ if (!_cheats.crossing_tunnels.value && IsTunnelInWay(end_tile, start_z, (tiles + 1 < 4 || (is_chunnel && head_tiles < 4) ? false : true))) {
-+ if (found_tunnel_tile == INVALID_TILE || is_chunnel) { // Remember the first or the last when we pass a tunnel.
-+ found_tunnel_tile = end_tile;
-+ head_tiles = 0;
-+ }
-+ }
-+ head_tiles++;
- tiles++;
-+ }
-+ /* The cost of the digging. */
-+ for (int i = tiles; i > 0; i--) {
- if (tiles == tiles_bump) {
- tiles_coef++;
- tiles_bump *= 2;
-@@ -746,21 +805,32 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1,
- default: NOT_REACHED();
- }
-
-+ if (is_chunnel) cost.MultiplyCost(2);
-+
- if (flags & DC_EXEC) {
- Company *c = Company::GetIfValid(company);
- uint num_pieces = (tiles + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR;
-+
-+ /* The most northern tile first. */
-+ TileIndex tn = start_tile;
-+ TileIndex ts = end_tile;
-+ if(start_tile > end_tile) Swap(tn, ts);
-+
-+ if (!Tunnel::CanAllocateItem()) return_cmd_error(STR_ERROR_TUNNEL_TOO_MANY);
-+ const Tunnel *t = new Tunnel(tn, ts, is_chunnel);
-+
- if (transport_type == TRANSPORT_RAIL) {
- if (c != nullptr) c->infrastructure.rail[railtype] += num_pieces;
-- MakeRailTunnel(start_tile, company, direction, railtype);
-- MakeRailTunnel(end_tile, company, ReverseDiagDir(direction), railtype);
-+ MakeRailTunnel(start_tile, company, t->index, direction, railtype);
-+ MakeRailTunnel(end_tile, company, t->index, ReverseDiagDir(direction), railtype);
- AddSideToSignalBuffer(start_tile, INVALID_DIAGDIR, company);
- YapfNotifyTrackLayoutChange(start_tile, DiagDirToDiagTrack(direction));
- } else {
- if (c != nullptr) c->infrastructure.road[roadtype] += num_pieces * 2; // A full diagonal road has two road bits.
- RoadType road_rt = RoadTypeIsRoad(roadtype) ? roadtype : INVALID_ROADTYPE;
- RoadType tram_rt = RoadTypeIsTram(roadtype) ? roadtype : INVALID_ROADTYPE;
-- MakeRoadTunnel(start_tile, company, direction, road_rt, tram_rt);
-- MakeRoadTunnel(end_tile, company, ReverseDiagDir(direction), road_rt, tram_rt);
-+ MakeRoadTunnel(start_tile, company, t->index, direction, road_rt, tram_rt);
-+ MakeRoadTunnel(end_tile, company, t->index, ReverseDiagDir(direction), road_rt, tram_rt);
- }
- DirtyCompanyInfrastructureWindows(company);
- }
-@@ -850,6 +920,8 @@ static CommandCost DoClearTunnel(TileIndex tile, DoCommandFlag flags)
- ChangeTownRating(t, RATING_TUNNEL_BRIDGE_DOWN_STEP, RATING_TUNNEL_BRIDGE_MINIMUM, flags);
- }
-
-+ const bool is_chunnel = Tunnel::GetByTile(tile)->is_chunnel;
-+
- uint len = GetTunnelBridgeLength(tile, endtile) + 2; // Don't forget the end tiles.
-
- if (flags & DC_EXEC) {
-@@ -870,6 +942,8 @@ static CommandCost DoClearTunnel(TileIndex tile, DoCommandFlag flags)
- DirtyCompanyInfrastructureWindows(owner);
- }
-
-+ delete Tunnel::GetByTile(tile);
-+
- DoClearSquare(tile);
- DoClearSquare(endtile);
-
-@@ -886,11 +960,13 @@ static CommandCost DoClearTunnel(TileIndex tile, DoCommandFlag flags)
- UpdateCompanyRoadInfrastructure(GetRoadTypeRoad(tile), GetRoadOwner(tile, RTT_ROAD), -(int)(len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR));
- UpdateCompanyRoadInfrastructure(GetRoadTypeTram(tile), GetRoadOwner(tile, RTT_TRAM), -(int)(len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR));
-
-+ delete Tunnel::GetByTile(tile);
-+
- DoClearSquare(tile);
- DoClearSquare(endtile);
- }
- }
-- return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_TUNNEL] * len);
-+ return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_TUNNEL] * len * (is_chunnel ? 2 : 1));
- }
-
-
-@@ -1866,6 +1942,7 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti
- if (frame == _tunnel_visibility_frame[dir]) {
- t->tile = tile;
- t->track = TRACK_BIT_WORMHOLE;
-+ if (Tunnel::GetByTile(tile)->is_chunnel) SetBit(t->gv_flags, GVF_CHUNNEL_BIT);
- t->vehstatus |= VS_HIDDEN;
- return VETSB_ENTERED_WORMHOLE;
- }
-@@ -1873,6 +1950,7 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti
-
- if (dir == ReverseDiagDir(vdir) && frame == TILE_SIZE - _tunnel_visibility_frame[dir] && z == 0) {
- /* We're at the tunnel exit ?? */
-+ if (t->tile != tile && GetOtherTunnelEnd(t->tile) != tile) return VETSB_CONTINUE; // In chunnel
- t->tile = tile;
- t->track = DiagDirToDiagTrackBits(vdir);
- assert(t->track);
-@@ -1889,6 +1967,7 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti
- assert(frame == rv->frame + 1);
- rv->tile = tile;
- rv->state = RVSB_WORMHOLE;
-+ if (Tunnel::GetByTile(tile)->is_chunnel) SetBit(rv->gv_flags, GVF_CHUNNEL_BIT);
- rv->vehstatus |= VS_HIDDEN;
- return VETSB_ENTERED_WORMHOLE;
- } else {
-@@ -1898,6 +1977,7 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti
-
- /* We're at the tunnel exit ?? */
- if (dir == ReverseDiagDir(vdir) && frame == TILE_SIZE - _tunnel_visibility_frame[dir] && z == 0) {
-+ if (rv->tile != tile && GetOtherTunnelEnd(rv->tile) != tile) return VETSB_CONTINUE; // In chunnel
- rv->tile = tile;
- rv->state = DiagDirToDiagTrackdir(vdir);
- rv->frame = frame;
-@@ -1906,6 +1986,7 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti
- }
- }
- } else { // IsBridge(tile)
-+ if (v->vehstatus & VS_HIDDEN) return VETSB_CONTINUE; // Building bridges between chunnel portals allowed.
- if (v->type != VEH_SHIP) {
- /* modify speed of vehicle */
- uint16 spd = GetBridgeSpec(GetBridgeType(tile))->speed;
-diff --git a/src/tunnelbridge_map.h b/src/tunnelbridge_map.h
-index 62d3c14b2d..37e00457e4 100644
---- a/src/tunnelbridge_map.h
-+++ b/src/tunnelbridge_map.h
-@@ -11,7 +11,7 @@
- #define TUNNELBRIDGE_MAP_H
-
- #include "bridge_map.h"
--#include "tunnel_map.h"
-+#include "tunnel_base.h"
-
-
- /**
-diff --git a/src/vehicle.cpp b/src/vehicle.cpp
-index e358421186..da107682f0 100644
---- a/src/vehicle.cpp
-+++ b/src/vehicle.cpp
-@@ -285,6 +285,14 @@ uint Vehicle::Crash(bool flooded)
- return RandomRange(pass + 1); // Randomise deceased passengers.
- }
-
-+bool Vehicle::IsDrawn() const
-+{
-+ return !(this->vehstatus & VS_HIDDEN) ||
-+ (!IsTransparencySet(TO_TUNNELS) &&
-+ ((this->type == VEH_TRAIN && Train::From(this)->track == TRACK_BIT_WORMHOLE) ||
-+ (this->type == VEH_ROAD && RoadVehicle::From(this)->state == RVSB_WORMHOLE)));
-+}
-+
-
- /**
- * Displays a "NewGrf Bug" error message for a engine, and pauses the game if not networking.
-@@ -1082,7 +1090,7 @@ static void DoDrawVehicle(const Vehicle *v)
- if (v->vehstatus & VS_DEFPAL) pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
-
- /* Check whether the vehicle shall be transparent due to the game state */
-- bool shadowed = (v->vehstatus & VS_SHADOW) != 0;
-+ bool shadowed = (v->vehstatus & (VS_SHADOW | VS_HIDDEN)) != 0;
-
- if (v->type == VEH_EFFECT) {
- /* Check whether the vehicle shall be transparent/invisible due to GUI settings.
-@@ -1155,7 +1163,7 @@ void ViewportAddVehicles(DrawPixelInfo *dpi)
-
- while (v != nullptr) {
-
-- if (!(v->vehstatus & VS_HIDDEN) &&
-+ if (v->IsDrawn() &&
- l <= v->coord.right &&
- t <= v->coord.bottom &&
- r >= v->coord.left &&
-@@ -1209,7 +1217,7 @@ Vehicle *CheckClickOnVehicle(const Viewport *vp, int x, int y)
- y = ScaleByZoom(y, vp->zoom) + vp->virtual_top;
-
- for (Vehicle *v : Vehicle::Iterate()) {
-- if ((v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) == 0 &&
-+ if (v->IsDrawn() && !(v->vehstatus & VS_UNCLICKABLE) &&
- x >= v->coord.left && x <= v->coord.right &&
- y >= v->coord.top && y <= v->coord.bottom) {
-
-diff --git a/src/vehicle_base.h b/src/vehicle_base.h
-index 24facfb3e4..f3a964261c 100644
---- a/src/vehicle_base.h
-+++ b/src/vehicle_base.h
-@@ -363,6 +363,12 @@ public:
-
- uint GetConsistTotalCapacity() const;
-
-+ /**
-+ * Is this vehicle drawn?
-+ * @return true if it is drawn
-+ */
-+ bool IsDrawn() const;
-+
- /**
- * Marks the vehicles to be redrawn and updates cached variables
- *
-diff --git a/src/widgets/transparency_widget.h b/src/widgets/transparency_widget.h
-index 2b096e733b..099d48a339 100644
---- a/src/widgets/transparency_widget.h
-+++ b/src/widgets/transparency_widget.h
-@@ -23,6 +23,7 @@ enum TransparencyToolbarWidgets {
- WID_TT_STRUCTURES, ///< Object structure transparency toggle button.
- WID_TT_CATENARY, ///< Catenary transparency toggle button.
- WID_TT_LOADING, ///< Loading indicators transparency toggle button.
-+ WID_TT_TUNNELS, ///< Vehicles in tunnels toggle button.
- WID_TT_END, ///< End of toggle buttons.
-
- /* Panel with buttons for invisibility */