summaryrefslogtreecommitdiff
path: root/openttd-git
diff options
context:
space:
mode:
authorErich Eckner <git@eckner.net>2022-02-27 09:29:15 +0100
committerErich Eckner <git@eckner.net>2022-02-27 09:49:56 +0100
commit9109ea8eefa791688066eb3cda857eeb706a2e54 (patch)
tree989a3ce83c6cb6f4bc24456a8b59a2afe00e7c5b /openttd-git
parent56aca79487c0f287dcd5bed3bf7ffc563a3d74ce (diff)
downloadarchlinuxewe-9109ea8eefa791688066eb3cda857eeb706a2e54.tar.xz
openttd-git: 31316.802ca4e72-4 -> 31416.1c256a4be-1
Diffstat (limited to 'openttd-git')
-rw-r--r--openttd-git/PKGBUILD14
-rw-r--r--openttd-git/chunnel-pre.patch12
-rw-r--r--openttd-git/chunnel-signaltunnel-pre.patch22
-rw-r--r--openttd-git/chunnel-underground-pre.patch22
-rw-r--r--openttd-git/chunnel.patch1063
-rw-r--r--openttd-git/signaltunnel.patch86
-rw-r--r--openttd-git/sloped-stations.patch449
-rw-r--r--openttd-git/underground.patch3664
8 files changed, 49 insertions, 5283 deletions
diff --git a/openttd-git/PKGBUILD b/openttd-git/PKGBUILD
index d4f72b49c..b3665497f 100644
--- a/openttd-git/PKGBUILD
+++ b/openttd-git/PKGBUILD
@@ -1,8 +1,8 @@
# Maintainer: Erich Eckner <arch at eckner dot net>
pkgname=openttd-git
-pkgver=31316.802ca4e72
+pkgver=31416.1c256a4be
_commit=${pkgver#*.}
-pkgrel=4
+pkgrel=1
pkgdesc="A FOSS clone of Transport Tycoon Deluxe."
arch=('x86_64' 'i686' 'pentium4')
url="http://www.openttd.org"
@@ -46,14 +46,12 @@ source=(
# "chunnel-underground-pre.patch"
# "chunnel.patch"
"signaltunnel.patch"
- "sloped-stations.patch"
- "underground.patch"
+# "sloped-stations.patch"
+# "underground.patch"
'opntitle.dat'
)
sha512sums=('SKIP'
- 'fc6bdcdadc40221073741a48e57a115f31918f4ead5c73f9fc3bf8b63f9d002391710a8b79dcb5bcda7a06b570fa8c179fda8a8b9be8809572d738219c3d1793'
- '880c049177ede4033698b819471fe7c0cf552c584e91b971dbfa179bbff88adbf7da2ba12cd0ae2e7f2b902c32ec8c8f96d5266221c728c0de0fb79f0d6ed3de'
- 'b3ec4edd1d3c393726f4a4406224cb9237cd87a57f1b4aa86ec9977dfa561c0750a81ac9df5ce91e57fd89b320afae2a0a682cf42065ecd53cb7cd3aaef60b73'
+ '2595106d104a6e0247e6b62c8ff7a3ece452a6397459121616f46f9bf68824b276a05fd4dccfce1f9c27c41784805f583e04f2e7250ffa572855dd45eac8e979'
'a3fd5b230b7cdd67a1b6607887433c0cb85ba1dfd30cedfddf573a58b23ccce7c470a22cf7f65a29c173bba12976c5889482cef24f49c8c0a829883a71bcd87d')
pkgver() {
@@ -97,7 +95,7 @@ prepare() {
' cmake/scripts/FindVersion.cmake
# for _p in "${srcdir}/"{signaltunnel,sloped-stations,underground,chunnel.pre}.patch; do
- for _p in "${srcdir}/"{signaltunnel,underground}.patch; do
+ for _p in "${srcdir}/signaltunnel.patch"; do
>&2 echo "patching ${_p##*/} ..."
patch -p1 -i "${_p}"
>&2 echo "... ok"
diff --git a/openttd-git/chunnel-pre.patch b/openttd-git/chunnel-pre.patch
deleted file mode 100644
index 9b42f5a93..000000000
--- a/openttd-git/chunnel-pre.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff --git a/openttd-git/chunnel.patch b/openttd-git/chunnel.patch
-index 33ab7405..6ad137ae 100644
---- a/openttd-git/chunnel.patch
-+++ b/openttd-git/chunnel.patch
-@@ -1018,6 +1018,7 @@ index e014944a9f..cb6239f597 100644
- const Vehicle *v = _vehicle_viewport_hash[x + y]; // already masked & 0xFFF
-
- while (v != nullptr) {
-+ if (LayerIndex(v->tile) == dpi->layer)
- - if (!(v->vehstatus & VS_HIDDEN) &&
- + if (v->IsDrawn() &&
- l <= v->coord.right &&
diff --git a/openttd-git/chunnel-signaltunnel-pre.patch b/openttd-git/chunnel-signaltunnel-pre.patch
deleted file mode 100644
index 572e40504..000000000
--- a/openttd-git/chunnel-signaltunnel-pre.patch
+++ /dev/null
@@ -1,22 +0,0 @@
---- a/chunnel.pre.patch 2021-01-03 22:39:24.363263631 +0100
-+++ b/chunnel.pre.patch 2021-01-03 22:39:24.363263631 +0100
-@@ -180,16 +180,17 @@
- STR_TRANSPARENT_INVISIBLE_TOOLTIP :{BLACK}Set objects invisible instead of transparent
-
- # Linkgraph legend window
--@@ -2724,7 +2725,9 @@ STR_LAI_WATER_DESCRIPTION_SHIP_DEPOT :Ship depot
-+@@ -2724,8 +2725,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_CHUNNEL :Railway tunnel (underwater)
-+ STR_LAI_TUNNEL_DESCRIPTION_RAILROAD_SIGNAL :Railway tunnel with signal simulation
- STR_LAI_TUNNEL_DESCRIPTION_ROAD :Road tunnel
- +STR_LAI_TUNNEL_DESCRIPTION_ROAD_CHUNNEL :Road tunnel (underwater)
-
-+ 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
- @@ -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
diff --git a/openttd-git/chunnel-underground-pre.patch b/openttd-git/chunnel-underground-pre.patch
deleted file mode 100644
index 4a055d66d..000000000
--- a/openttd-git/chunnel-underground-pre.patch
+++ /dev/null
@@ -1,22 +0,0 @@
---- a/chunnel.pre.patch 2021-01-03 22:30:58.721115549 +0100
-+++ b/chunnel.pre.patch 2021-01-03 22:30:58.721115549 +0100
-@@ -790,7 +790,7 @@
- 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;
-@@ -1015,9 +1015,9 @@
- if (v->type == VEH_EFFECT) {
- /* Check whether the vehicle shall be transparent/invisible due to GUI settings.
- @@ -1139,7 +1147,7 @@ void ViewportAddVehicles(DrawPixelInfo *dpi)
-- const Vehicle *v = _vehicle_viewport_hash[x + y]; // already masked & 0xFFF
-
- while (v != nullptr) {
-+ if (LayerIndex(v->tile) == dpi->layer)
- - if (!(v->vehstatus & VS_HIDDEN) &&
- + if (v->IsDrawn() &&
- l <= v->coord.right &&
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 */
diff --git a/openttd-git/signaltunnel.patch b/openttd-git/signaltunnel.patch
index 65a4395b4..d3483e816 100644
--- a/openttd-git/signaltunnel.patch
+++ b/openttd-git/signaltunnel.patch
@@ -1,5 +1,5 @@
diff --git a/src/lang/english.txt b/src/lang/english.txt
-index becf8d35c..8645b5cd1 100644
+index becf8d35c2..8645b5cd15 100644
--- a/src/lang/english.txt
+++ b/src/lang/english.txt
@@ -1812,6 +1812,9 @@ STR_CONFIG_SETTING_MIN_YEARS_FOR_SHARES_HELPTEXT :Set the minimum
@@ -24,7 +24,7 @@ index becf8d35c..8645b5cd1 100644
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 534be43c1..658e41ca2 100644
+index 534be43c18..658e41ca28 100644
--- a/src/lang/russian.txt
+++ b/src/lang/russian.txt
@@ -1963,6 +1963,8 @@ STR_CONFIG_SETTING_MIN_YEARS_FOR_SHARES_HELPTEXT :Минимал
@@ -48,7 +48,7 @@ index 534be43c1..658e41ca2 100644
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 a9a51da68..5558c0226 100644
+index a9a51da68a..5558c02265 100644
--- a/src/pathfinder/follow_track.hpp
+++ b/src/pathfinder/follow_track.hpp
@@ -350,7 +350,7 @@ protected:
@@ -70,12 +70,12 @@ index a9a51da68..5558c0226 100644
return false;
}
diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp
-index 4c34f1ca8..e71f562ac 100644
+index 88f4adb0f6..7503464dba 100644
--- a/src/rail_cmd.cpp
+++ b/src/rail_cmd.cpp
-@@ -1069,9 +1069,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;
+@@ -1039,9 +1039,12 @@ CommandCost CmdBuildSingleSignal(DoCommandFlag flags, TileIndex tile, Track trac
+
+ if (ctrl_pressed) sigvar = (SignalVariant)(sigvar ^ SIG_SEMAPHORE);
- /* You can only build signals on plain rail tiles, and the selected track must exist */
- if (!ValParamTrackOrientation(track) || !IsPlainRailTile(tile) ||
@@ -89,7 +89,7 @@ index 4c34f1ca8..e71f562ac 100644
return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
}
/* Protect against invalid signal copying */
-@@ -1080,6 +1083,53 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
+@@ -1050,6 +1053,53 @@ CommandCost CmdBuildSingleSignal(DoCommandFlag flags, TileIndex tile, Track trac
CommandCost ret = CheckTileOwnership(tile);
if (ret.Failed()) return ret;
@@ -99,10 +99,10 @@ index 4c34f1ca8..e71f562ac 100644
+ 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 (signals_copy != 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 (signals_copy == 0 && HasWormholeSignals(tile)){ // Toggle signal if already signals present.
+ if (IsTunnelBridgeEntrance (tile)) {
+ ClrBitTunnelBridgeSignal(tile);
+ ClrBitTunnelBridgeExit(tile_exit);
@@ -116,14 +116,14 @@ index 4c34f1ca8..e71f562ac 100644
+ }
+ } else{
+ /* Create one direction tunnel/bridge if required. */
-+ if (p2 == 0) {
++ if (signals_copy == 0) {
+ SetBitTunnelBridgeSignal(tile);
+ SetBitTunnelBridgeExit(tile_exit);
-+ } else if (p2 == 4 || p2 == 8) {
++ } else if (signals_copy == 4 || signals_copy == 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))) {
++ if ((signals_copy == 8 && (tbdir == DIAGDIR_NE || tbdir == DIAGDIR_SE)) ||
++ (signals_copy == 4 && (tbdir == DIAGDIR_SW || tbdir == DIAGDIR_NW))) {
+ SetBitTunnelBridgeSignal(tile);
+ SetBitTunnelBridgeExit(tile_exit);
+ } else {
@@ -143,7 +143,7 @@ index 4c34f1ca8..e71f562ac 100644
/* 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);
-@@ -1089,7 +1139,6 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
+@@ -1059,7 +1109,6 @@ CommandCost CmdBuildSingleSignal(DoCommandFlag flags, TileIndex tile, Track trac
/* 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);
@@ -151,7 +151,7 @@ index 4c34f1ca8..e71f562ac 100644
if (!HasSignalOnTrack(tile, track)) {
/* build new signals */
cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS]);
-@@ -1243,6 +1292,7 @@ static bool AdvanceSignalAutoFill(TileIndex &tile, Trackdir &trackdir, bool remo
+@@ -1213,6 +1262,7 @@ static bool AdvanceSignalAutoFill(TileIndex &tile, Trackdir &trackdir, bool remo
break;
case MP_TUNNELBRIDGE: {
@@ -159,17 +159,17 @@ index 4c34f1ca8..e71f562ac 100644
if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) return false;
if (GetTunnelBridgeDirection(tile) != TrackdirToExitdir(trackdir)) return false;
break;
-@@ -1501,22 +1551,48 @@ CommandCost CmdBuildSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1,
- CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const std::string &text)
+@@ -1443,21 +1493,48 @@ CommandCost CmdBuildSignalTrack(DoCommandFlag flags, TileIndex tile, TileIndex e
+ */
+ CommandCost CmdRemoveSingleSignal(DoCommandFlag flags, TileIndex tile, Track track)
{
- 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);
++ Money cost = _price[PR_CLEAR_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);
@@ -215,7 +215,7 @@ index 4c34f1ca8..e71f562ac 100644
Train *v = nullptr;
if (HasReservedTracks(tile, TrackToTrackBits(track))) {
v = GetTrainForReservation(tile, track);
-@@ -1552,7 +1628,7 @@ CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1
+@@ -1493,7 +1570,7 @@ CommandCost CmdRemoveSingleSignal(DoCommandFlag flags, TileIndex tile, Track tra
MarkTileDirtyByTile(tile);
}
@@ -225,7 +225,7 @@ index 4c34f1ca8..e71f562ac 100644
/**
diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp
-index f99ef8f3e..a913884da 100644
+index f99ef8f3e2..a913884da4 100644
--- a/src/settings_gui.cpp
+++ b/src/settings_gui.cpp
@@ -1625,6 +1625,7 @@ static SettingsContainer &GetSettingsTree()
@@ -237,7 +237,7 @@ index f99ef8f3e..a913884da 100644
construction->Add(new SettingEntry("gui.quick_goto"));
construction->Add(new SettingEntry("gui.default_rail_type"));
diff --git a/src/settings_type.h b/src/settings_type.h
-index 9da2655d6..d37f5e18d 100644
+index 9da2655d6b..d37f5e18d2 100644
--- a/src/settings_type.h
+++ b/src/settings_type.h
@@ -345,6 +345,7 @@ struct ConstructionSettings {
@@ -249,7 +249,7 @@ index 9da2655d6..d37f5e18d 100644
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 329b1b05d..e058edf5e 100644
+index 329b1b05d9..e058edf5e2 100644
--- a/src/signal.cpp
+++ b/src/signal.cpp
@@ -195,6 +195,14 @@ static Vehicle *TrainOnTileEnum(Vehicle *v, void *)
@@ -330,7 +330,7 @@ index 329b1b05d..e058edf5e 100644
case MP_RAILWAY:
diff --git a/src/table/settings/game_settings.ini b/src/table/settings/game_settings.ini
-index 79fac7513..503863c96 100644
+index 79fac75136..503863c969 100644
--- a/src/table/settings/game_settings.ini
+++ b/src/table/settings/game_settings.ini
@@ -406,6 +406,20 @@ min = 5
@@ -355,10 +355,10 @@ index 79fac7513..503863c96 100644
[SDTC_BOOL]
diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp
-index f5eb32d7f..5b9830b02 100644
+index 2fd081898e..ff143dd879 100644
--- a/src/train_cmd.cpp
+++ b/src/train_cmd.cpp
-@@ -1876,6 +1876,17 @@ void ReverseTrainDirection(Train *v)
+@@ -1866,6 +1866,17 @@ void ReverseTrainDirection(Train *v)
return;
}
@@ -376,7 +376,7 @@ index f5eb32d7f..5b9830b02 100644
/* 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);
-@@ -2210,6 +2221,42 @@ static bool CheckTrainStayInDepot(Train *v)
+@@ -2195,6 +2206,42 @@ static bool CheckTrainStayInDepot(Train *v)
return false;
}
@@ -419,7 +419,7 @@ index f5eb32d7f..5b9830b02 100644
/**
* Clear the reservation of \a tile that was just left by a wagon on \a track_dir.
* @param v %Train owning the reservation.
-@@ -2225,7 +2272,8 @@ static void ClearPathReservation(const Train *v, TileIndex tile, Trackdir track_
+@@ -2210,7 +2257,8 @@ static void ClearPathReservation(const Train *v, TileIndex tile, Trackdir track_
if (GetTunnelBridgeDirection(tile) == ReverseDiagDir(dir)) {
TileIndex end = GetOtherTunnelBridgeEnd(tile);
@@ -429,7 +429,7 @@ index f5eb32d7f..5b9830b02 100644
/* Free the reservation only if no other train is on the tiles. */
SetTunnelBridgeReservation(tile, false);
SetTunnelBridgeReservation(end, false);
-@@ -2239,6 +2287,7 @@ static void ClearPathReservation(const Train *v, TileIndex tile, Trackdir track_
+@@ -2224,6 +2272,7 @@ static void ClearPathReservation(const Train *v, TileIndex tile, Trackdir track_
}
}
}
@@ -437,7 +437,7 @@ index f5eb32d7f..5b9830b02 100644
}
} else if (IsRailStationTile(tile)) {
TileIndex new_tile = TileAddByDiagDir(tile, dir);
-@@ -3105,6 +3154,99 @@ static Vehicle *CheckTrainAtSignal(Vehicle *v, void *data)
+@@ -3090,6 +3139,99 @@ static Vehicle *CheckTrainAtSignal(Vehicle *v, void *data)
return t;
}
@@ -537,7 +537,7 @@ index f5eb32d7f..5b9830b02 100644
/**
* Move a vehicle chain one movement stop forwards.
* @param v First vehicle to move.
-@@ -3290,6 +3432,23 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
+@@ -3275,6 +3417,23 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
goto invalid_rail;
}
@@ -561,7 +561,7 @@ index f5eb32d7f..5b9830b02 100644
if (!HasBit(r, VETS_ENTERED_WORMHOLE)) {
Track track = FindFirstTrack(chosen_track);
Trackdir tdir = TrackDirectionToTrackdir(track, chosen_dir);
-@@ -3342,6 +3501,64 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
+@@ -3327,6 +3486,64 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
}
}
} else {
@@ -627,7 +627,7 @@ index f5eb32d7f..5b9830b02 100644
/* Perform look-ahead on tunnel exit. */
if (v->IsFrontEngine()) {
diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp
-index 5181dfdca..e9df7e23b 100644
+index 543ac8b284..550becea91 100644
--- a/src/tunnelbridge_cmd.cpp
+++ b/src/tunnelbridge_cmd.cpp
@@ -28,6 +28,7 @@
@@ -638,7 +638,7 @@ index 5181dfdca..e9df7e23b 100644
#include "sound_func.h"
#include "tunnelbridge.h"
#include "cheat_type.h"
-@@ -1259,6 +1260,103 @@ static void DrawBridgeRoadBits(TileIndex head_tile, int x, int y, int z, int off
+@@ -1250,6 +1251,103 @@ static void DrawBridgeRoadBits(TileIndex head_tile, int x, int y, int z, int off
}
}
@@ -742,7 +742,7 @@ index 5181dfdca..e9df7e23b 100644
/**
* Draws a tunnel of bridge tile.
* For tunnels, this is rather simple, as you only need to draw the entrance.
-@@ -1390,6 +1488,9 @@ static void DrawTile_TunnelBridge(TileInfo *ti)
+@@ -1381,6 +1479,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);
@@ -752,7 +752,7 @@ index 5181dfdca..e9df7e23b 100644
DrawBridgeMiddle(ti);
} else { // IsBridge(ti->tile)
const PalSpriteID *psid;
-@@ -1495,6 +1596,9 @@ static void DrawTile_TunnelBridge(TileInfo *ti)
+@@ -1486,6 +1587,9 @@ static void DrawTile_TunnelBridge(TileInfo *ti)
}
}
@@ -762,7 +762,7 @@ index 5181dfdca..e9df7e23b 100644
DrawBridgeMiddle(ti);
}
}
-@@ -1636,6 +1740,9 @@ void DrawBridgeMiddle(const TileInfo *ti)
+@@ -1627,6 +1731,9 @@ void DrawBridgeMiddle(const TileInfo *ti)
if (HasRailCatenaryDrawn(GetRailType(rampsouth))) {
DrawRailCatenaryOnBridge(ti);
}
@@ -772,7 +772,7 @@ index 5181dfdca..e9df7e23b 100644
}
/* draw roof, the component of the bridge which is logically between the vehicle and the camera */
-@@ -1709,9 +1816,9 @@ static void GetTileDesc_TunnelBridge(TileIndex tile, TileDesc *td)
+@@ -1700,9 +1807,9 @@ static void GetTileDesc_TunnelBridge(TileIndex tile, TileDesc *td)
TransportType tt = GetTunnelBridgeTransportType(tile);
if (IsTunnel(tile)) {
@@ -784,7 +784,7 @@ index 5181dfdca..e9df7e23b 100644
}
td->owner[0] = GetTileOwner(tile);
-@@ -1794,6 +1901,25 @@ static void TileLoop_TunnelBridge(TileIndex tile)
+@@ -1785,6 +1892,25 @@ static void TileLoop_TunnelBridge(TileIndex tile)
}
}
@@ -810,7 +810,7 @@ index 5181dfdca..e9df7e23b 100644
static TrackStatus GetTileTrackStatus_TunnelBridge(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
{
TransportType transport_type = GetTunnelBridgeTransportType(tile);
-@@ -2047,8 +2173,8 @@ extern const TileTypeProcs _tile_type_tunnelbridge_procs = {
+@@ -2038,8 +2164,8 @@ extern const TileTypeProcs _tile_type_tunnelbridge_procs = {
nullptr, // add_accepted_cargo_proc
GetTileDesc_TunnelBridge, // get_tile_desc_proc
GetTileTrackStatus_TunnelBridge, // get_tile_track_status_proc
@@ -822,7 +822,7 @@ index 5181dfdca..e9df7e23b 100644
ChangeTileOwner_TunnelBridge, // change_tile_owner_proc
nullptr, // add_produced_cargo_proc
diff --git a/src/tunnelbridge_map.h b/src/tunnelbridge_map.h
-index 62d3c14b2..fa029dcf4 100644
+index 62d3c14b2d..fa029dcf4d 100644
--- a/src/tunnelbridge_map.h
+++ b/src/tunnelbridge_map.h
@@ -119,4 +119,98 @@ static inline TrackBits GetTunnelBridgeReservationTrackBits(TileIndex t)
diff --git a/openttd-git/sloped-stations.patch b/openttd-git/sloped-stations.patch
deleted file mode 100644
index b113d848c..000000000
--- a/openttd-git/sloped-stations.patch
+++ /dev/null
@@ -1,449 +0,0 @@
-diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp
-index 4c34f1ca8..4100ae31d 100644
---- a/src/rail_cmd.cpp
-+++ b/src/rail_cmd.cpp
-@@ -187,14 +187,6 @@ RailType AllocateRailType(RailTypeLabel label)
- return INVALID_RAILTYPE;
- }
-
--static const byte _track_sloped_sprites[14] = {
-- 14, 15, 22, 13,
-- 0, 21, 17, 12,
-- 23, 0, 18, 20,
-- 19, 16
--};
--
--
- /* 4
- * ---------
- * |\ /|
-diff --git a/src/road_cmd.cpp b/src/road_cmd.cpp
-index 70a014434..a72ff4eb7 100644
---- a/src/road_cmd.cpp
-+++ b/src/road_cmd.cpp
-@@ -37,6 +37,7 @@
- #include "genworld.h"
- #include "company_gui.h"
- #include "road_func.h"
-+#include "road_cmd.h"
-
- #include "table/strings.h"
- #include "table/roadtypes.h"
-@@ -251,8 +252,6 @@ static const RoadBits _invalid_tileh_slopes_road[2][15] = {
- }
- };
-
--static Foundation GetRoadFoundation(Slope tileh, RoadBits bits);
--
- /**
- * Is it allowed to remove the given road bits from the given tile?
- * @param tile the tile to remove the road from
-@@ -1296,7 +1295,7 @@ struct DrawRoadTileStruct {
- * @param bits The RoadBits part
- * @return The resulting Foundation
- */
--static Foundation GetRoadFoundation(Slope tileh, RoadBits bits)
-+Foundation GetRoadFoundation(Slope tileh, RoadBits bits)
- {
- /* Flat land and land without a road doesn't require a foundation */
- if (tileh == SLOPE_FLAT || bits == ROAD_NONE) return FOUNDATION_NONE;
-@@ -1318,13 +1317,6 @@ static Foundation GetRoadFoundation(Slope tileh, RoadBits bits)
- return (bits == ROAD_X ? FOUNDATION_INCLINED_X : FOUNDATION_INCLINED_Y);
- }
-
--const byte _road_sloped_sprites[14] = {
-- 0, 0, 2, 0,
-- 0, 1, 0, 0,
-- 3, 0, 0, 0,
-- 0, 0
--};
--
- /**
- * Get the sprite offset within a spritegroup.
- * @param slope Slope
-diff --git a/src/road_cmd.h b/src/road_cmd.h
-index 753ebd21d..87dee9722 100644
---- a/src/road_cmd.h
-+++ b/src/road_cmd.h
-@@ -12,8 +12,11 @@
-
- #include "direction_type.h"
- #include "road_type.h"
-+#include "slope_type.h"
-
- void DrawRoadDepotSprite(int x, int y, DiagDirection dir, RoadType rt);
- void UpdateNearestTownForRoadTiles(bool invalidate);
-
-+Foundation GetRoadFoundation(Slope tileh, RoadBits bits);
-+
- #endif /* ROAD_CMD_H */
-diff --git a/src/road_type.h b/src/road_type.h
-index 969b141ba..1af4275eb 100644
---- a/src/road_type.h
-+++ b/src/road_type.h
-@@ -68,4 +68,11 @@ enum RoadBits {
- DECLARE_ENUM_AS_BIT_SET(RoadBits)
- template <> struct EnumPropsT<RoadBits> : MakeEnumPropsT<RoadBits, byte, ROAD_NONE, ROAD_END, ROAD_NONE, 4> {};
-
-+const byte _road_sloped_sprites[14] = {
-+ 0, 0, 2, 0,
-+ 0, 1, 0, 0,
-+ 3, 0, 0, 0,
-+ 0, 0
-+};
-+
- #endif /* ROAD_TYPE_H */
-diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp
-index 9c444d1d3..a83e7fda9 100644
---- a/src/roadveh_cmd.cpp
-+++ b/src/roadveh_cmd.cpp
-@@ -1511,7 +1511,7 @@ again:
- v->x_pos = x;
- v->y_pos = y;
- v->UpdatePosition();
-- RoadZPosAffectSpeed(v, v->UpdateInclination(true, false));
-+ RoadZPosAffectSpeed(v, v->UpdateInclination(false, false));
- return true;
- }
- }
-diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp
-index 1a188252c..9304f5efc 100644
---- a/src/station_cmd.cpp
-+++ b/src/station_cmd.cpp
-@@ -56,6 +56,7 @@
- #include "linkgraph/refresh.h"
- #include "widgets/station_widget.h"
- #include "tunnelbridge_map.h"
-+#include "road_cmd.h"
-
- #include "table/strings.h"
-
-@@ -776,7 +777,7 @@ CommandCost ClearTile_Station(TileIndex tile, DoCommandFlag flags);
- * Checks if the given tile is buildable, flat and has a certain height.
- * @param tile TileIndex to check.
- * @param invalid_dirs Prohibited directions for slopes (set of #DiagDirection).
-- * @param allowed_z Height allowed for the tile. If allowed_z is negative, it will be set to the height of this tile.
-+ * @param allowed_z Height allowed for the tile. If allowed_z is -1, it will be set to the height of this tile.
- * @param allow_steep Whether steep slopes are allowed.
- * @param check_bridge Check for the existence of a bridge.
- * @return The cost in case of success, or an error code if it failed.
-@@ -815,10 +816,10 @@ CommandCost CheckBuildableTile(TileIndex tile, uint invalid_dirs, int &allowed_z
- }
-
- /* The level of this tile must be equal to allowed_z. */
-- if (allowed_z < 0) {
-+ if (allowed_z == -1) {
- /* First tile. */
- allowed_z = flat_z;
-- } else if (allowed_z != flat_z) {
-+ } else if (allowed_z != flat_z && allowed_z >= 0) {
- return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
- }
-
-@@ -866,14 +867,14 @@ static CommandCost CheckFlatLandAirport(AirportTileTableIterator tile_iter, DoCo
- static CommandCost CheckFlatLandRailStation(TileArea tile_area, DoCommandFlag flags, Axis axis, StationID *station, RailType rt, std::vector<Train *> &affected_vehicles, StationClassID spec_class, byte spec_index, byte plat_len, byte numtracks)
- {
- CommandCost cost(EXPENSES_CONSTRUCTION);
-- int allowed_z = -1;
-+ int allowed_z = -2;
- uint invalid_dirs = 5 << axis;
-
- const StationSpec *statspec = StationClass::Get(spec_class)->GetSpec(spec_index);
- bool slope_cb = statspec != nullptr && HasBit(statspec->callback_mask, CBM_STATION_SLOPE_CHECK);
-
- for (TileIndex tile_cur : tile_area) {
-- CommandCost ret = CheckBuildableTile(tile_cur, invalid_dirs, allowed_z, false);
-+ CommandCost ret = CheckBuildableTile(tile_cur, 0, allowed_z, true);
- if (ret.Failed()) return ret;
- cost.AddCost(ret);
-
-@@ -952,10 +953,10 @@ static CommandCost CheckFlatLandRailStation(TileArea tile_area, DoCommandFlag fl
- static CommandCost CheckFlatLandRoadStop(TileArea tile_area, DoCommandFlag flags, uint invalid_dirs, bool is_drive_through, bool is_truck_stop, Axis axis, StationID *station, RoadType rt)
- {
- CommandCost cost(EXPENSES_CONSTRUCTION);
-- int allowed_z = -1;
-+ int allowed_z = -2;
-
- for (TileIndex cur_tile : tile_area) {
-- CommandCost ret = CheckBuildableTile(cur_tile, invalid_dirs, allowed_z, !is_drive_through);
-+ CommandCost ret = CheckBuildableTile(cur_tile, invalid_dirs, allowed_z, true);
- if (ret.Failed()) return ret;
- cost.AddCost(ret);
-
-@@ -1878,7 +1879,7 @@ CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uin
- /* Total road stop cost. */
- CommandCost cost(EXPENSES_CONSTRUCTION, roadstop_area.w * roadstop_area.h * _price[type ? PR_BUILD_STATION_TRUCK : PR_BUILD_STATION_BUS]);
- StationID est = INVALID_STATION;
-- ret = CheckFlatLandRoadStop(roadstop_area, flags, is_drive_through ? 5 << axis : 1 << ddir, is_drive_through, type, axis, &est, rt);
-+ ret = CheckFlatLandRoadStop(roadstop_area, flags, is_drive_through ? 0 : 1 << ddir, is_drive_through, type, axis, &est, rt);
- if (ret.Failed()) return ret;
- cost.AddCost(ret);
-
-@@ -2895,6 +2896,32 @@ static void DrawTile_Station(TileInfo *ti)
- palette = PALETTE_TO_GREY;
- }
-
-+ /* always draw leveled foundations only for airports and road bays! */
-+ if (ti->tileh != SLOPE_FLAT && (IsAirport(ti->tile) || IsStandardRoadStopTile(ti->tile)))
-+ DrawFoundation(ti, FOUNDATION_LEVELED);
-+
-+ if (HasStationTileRail(ti->tile) && IsCustomStationSpecIndex(ti->tile)) {
-+ /* look for customization */
-+ st = BaseStation::GetByTile(ti->tile);
-+ statspec = st->speclist[GetCustomStationSpecIndex(ti->tile)].spec;
-+
-+ if (statspec != nullptr) {
-+ uint tile = GetStationGfx(ti->tile);
-+
-+ relocation = GetCustomStationRelocation(statspec, st, ti->tile);
-+
-+ if (HasBit(statspec->callback_mask, CBM_STATION_SPRITE_LAYOUT)) {
-+ uint16 callback = GetStationCallback(CBID_STATION_SPRITE_LAYOUT, 0, 0, statspec, st, ti->tile);
-+ if (callback != CALLBACK_FAILED) tile = (callback & ~1) + GetRailStationAxis(ti->tile);
-+ }
-+
-+ /* Ensure the chosen tile layout is valid for this custom station */
-+ if (statspec->renderdata != nullptr) {
-+ t = &statspec->renderdata[tile < statspec->tiles ? tile : (uint)GetRailStationAxis(ti->tile)];
-+ }
-+ }
-+ }
-+
- if (layout == nullptr && (t == nullptr || t->seq == nullptr)) t = GetStationTileLayout(GetStationType(ti->tile), gfx);
-
- /* don't show foundation for docks */
-@@ -2961,10 +2988,10 @@ static void DrawTile_Station(TileInfo *ti)
- }
-
- OffsetGroundSprite(31, 1);
-- ti->z += ApplyPixelFoundationToSlope(FOUNDATION_LEVELED, &ti->tileh);
-+ ti->z += ApplyPixelFoundationToSlope(FOUNDATION_NONE, &ti->tileh); //FOUNDATION_LEVELED, &ti->tileh);
- } else {
- draw_default_foundation:
-- DrawFoundation(ti, FOUNDATION_LEVELED);
-+ DrawFoundation(ti, FOUNDATION_NONE); //FOUNDATION_LEVELED);
- }
- }
-
-@@ -3019,14 +3046,64 @@ draw_default_foundation:
- DrawGroundSprite(overlay + overlay_offset, PALETTE_CRASH);
- }
- } else {
-- image += HasBit(image, SPRITE_MODIFIER_CUSTOM_SPRITE) ? ground_relocation : total_offset;
-- if (HasBit(pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) pal += ground_relocation;
-+ if (HasBit(pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) {
-+ pal += ground_relocation;
-+ } else {
-+ if (HasBit(image, SPRITE_MODIFIER_CUSTOM_SPRITE)) {
-+ image += ground_relocation;
-+ } else {
-+ if (ti->tileh != SLOPE_FLAT && (IsRailStation(ti->tile) || IsRoadStop(ti->tile))) {
-+ /* It's a sloped rail station? */
-+ Foundation rf = FOUNDATION_NONE;
-+ if (IsRoadStop(ti->tile)) {
-+ /* Roadstops without foundation on a slope
-+ * and on Slopes with one corner raised */
-+ rf = GetRoadFoundation(ti->tileh, AxisToRoadBits(DiagDirToAxis(GetRoadStopDir(ti->tile))));
-+ DrawFoundation(ti, rf);
-+ /* Draws the sloped road */
-+ if (ti->tileh != SLOPE_FLAT) image = _road_sloped_sprites[ti->tileh - 1] + 0x53F;
-+ } else {
-+ /* sloped rail station */
-+ TrackBits track = AxisToTrackBits(GetRailStationAxis(ti->tile));
-+ rf = GetRailFoundation(ti->tileh, track);
-+ DrawFoundation(ti, rf);
-+ if (rf != FOUNDATION_LEVELED) {
-+ image = _track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.track_y;
-+ } else {
-+ (image = rti->base_sprites.track_y, track == TRACK_BIT_Y ) || (image++, track == TRACK_BIT_X);
-+ }
-+ }
-+ } else {
-+ /* it's not a slope */
-+ image += total_offset;
-+ }
-+ }
-+ }
- DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, palette));
-
- /* PBS debugging, draw reserved tracks darker */
- if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasStationRail(ti->tile) && HasStationReservation(ti->tile)) {
- const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
-- DrawGroundSprite(GetRailStationAxis(ti->tile) == AXIS_X ? rti->base_sprites.single_x : rti->base_sprites.single_y, PALETTE_CRASH);
-+ TrackBits pbs = AxisToTrackBits(GetRailStationAxis(ti->tile));
-+ // TODO: possibly inverted in 7b136d1fddbb2d0840076dfe2ddbe666b29fee8d
-+ if (pbs & TRACK_BIT_X) {
-+ if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
-+ DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH);
-+ } else {
-+ DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
-+ }
-+ }
-+ if (pbs & TRACK_BIT_Y) {
-+ if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
-+ DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH);
-+ } else {
-+ DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
-+ }
-+ }
-+ if (pbs & TRACK_BIT_UPPER) AddSortableSpriteToDraw(rti->base_sprites.single_n, PALETTE_CRASH, ti->x, ti->y, 16, 16, 0, ti->z + (ti->tileh & SLOPE_N ? 8 : 0));
-+ if (pbs & TRACK_BIT_LOWER) AddSortableSpriteToDraw(rti->base_sprites.single_s, PALETTE_CRASH, ti->x, ti->y, 16, 16, 0, ti->z + (ti->tileh & SLOPE_S ? 8 : 0));
-+ if (pbs & TRACK_BIT_LEFT) AddSortableSpriteToDraw(rti->base_sprites.single_w, PALETTE_CRASH, ti->x, ti->y, 16, 16, 0, ti->z + (ti->tileh & SLOPE_W ? 8 : 0));
-+ if (pbs & TRACK_BIT_RIGHT) AddSortableSpriteToDraw(rti->base_sprites.single_e, PALETTE_CRASH, ti->x, ti->y, 16, 16, 0, ti->z + (ti->tileh & SLOPE_E ? 8 : 0));
- }
- }
- }
-@@ -3120,6 +3197,16 @@ void StationPickerDrawSprite(int x, int y, StationType st, RailType railtype, Ro
-
- static int GetSlopePixelZ_Station(TileIndex tile, uint x, uint y)
- {
-+ /* this code makes vehicles and trains follow the slope on sloped stations */
-+ if (IsRailStation(tile) || IsRoadStopTile(tile) && !IsStandardRoadStopTile(tile)) {
-+ int z;
-+ Slope tileh = GetTilePixelSlope(tile, &z);
-+ Axis axis = IsRailStation(tile)?GetRailStationAxis(tile):DiagDirToAxis(GetRoadStopDir(tile));
-+
-+ z += 8*ApplyFoundationToSlope(GetRailFoundation(tileh,AxisToTrackBits(axis)), &tileh);
-+ return z + GetPartialPixelZ(x & 0xF, y & 0xF, tileh);
-+ }
-+
- return GetTileMaxPixelZ(tile);
- }
-
-diff --git a/src/table/sprites.h b/src/table/sprites.h
-index b7bb91020..732a2dae7 100644
---- a/src/table/sprites.h
-+++ b/src/table/sprites.h
-@@ -266,7 +266,26 @@ static const SpriteID SPR_TRUCK_STOP_DT_Y_W = SPR_ROADSTOP_BASE + 4;
- static const SpriteID SPR_TRUCK_STOP_DT_Y_E = SPR_ROADSTOP_BASE + 5;
- static const SpriteID SPR_TRUCK_STOP_DT_X_W = SPR_ROADSTOP_BASE + 6;
- static const SpriteID SPR_TRUCK_STOP_DT_X_E = SPR_ROADSTOP_BASE + 7;
--static const uint16 ROADSTOP_SPRITE_COUNT = 8;
-+
-+/* sprites for sloped graphics */
-+static const SpriteID SPR_BUS_STOP_DT_SE_W = SPR_ROADSTOP_BASE + 12;
-+static const SpriteID SPR_BUS_STOP_DT_SE_E = SPR_ROADSTOP_BASE + 13;
-+static const SpriteID SPR_BUS_STOP_DT_NE_E = SPR_ROADSTOP_BASE + 14;
-+static const SpriteID SPR_BUS_STOP_DT_NE_W = SPR_ROADSTOP_BASE + 15;
-+static const SpriteID SPR_BUS_STOP_DT_NW_W = SPR_ROADSTOP_BASE + 16;
-+static const SpriteID SPR_BUS_STOP_DT_NW_E = SPR_ROADSTOP_BASE + 17;
-+static const SpriteID SPR_BUS_STOP_DT_SW_E = SPR_ROADSTOP_BASE + 18;
-+static const SpriteID SPR_BUS_STOP_DT_SW_W = SPR_ROADSTOP_BASE + 19;
-+static const SpriteID SPR_TRUCK_STOP_DT_SE_W = SPR_ROADSTOP_BASE + 20;
-+static const SpriteID SPR_TRUCK_STOP_DT_SE_E = SPR_ROADSTOP_BASE + 21;
-+static const SpriteID SPR_TRUCK_STOP_DT_NE_E = SPR_ROADSTOP_BASE + 22;
-+static const SpriteID SPR_TRUCK_STOP_DT_NE_W = SPR_ROADSTOP_BASE + 23;
-+static const SpriteID SPR_TRUCK_STOP_DT_NW_W = SPR_ROADSTOP_BASE + 24;
-+static const SpriteID SPR_TRUCK_STOP_DT_NW_E = SPR_ROADSTOP_BASE + 25;
-+static const SpriteID SPR_TRUCK_STOP_DT_SW_E = SPR_ROADSTOP_BASE + 26;
-+static const SpriteID SPR_TRUCK_STOP_DT_SW_W = SPR_ROADSTOP_BASE + 27;
-+
-+static const uint16 ROADSTOP_SPRITE_COUNT = 28;
-
- /** Tramway sprites */
- static const SpriteID SPR_TRAMWAY_BASE = SPR_ROADSTOP_BASE + ROADSTOP_SPRITE_COUNT;
-diff --git a/src/table/station_land.h b/src/table/station_land.h
-index 53a69e1e2..2b6deecd0 100644
---- a/src/table/station_land.h
-+++ b/src/table/station_land.h
-@@ -775,6 +775,62 @@ static const DrawTileSeqStruct _station_display_datas_waypoint_Y[] = {
- TILE_SEQ_END()
- };
-
-+// drive-through bus stop SE slope
-+static const DrawTileSeqStruct _station_display_datas_0172[] = {
-+ TILE_SEQ_LINE( 0, 0, 0, 16, 3, 16, SPR_BUS_STOP_DT_SE_W | (1 << PALETTE_MODIFIER_COLOUR))
-+ TILE_SEQ_LINE( 0, 13, 0, 16, 3, 16, SPR_BUS_STOP_DT_SE_E | (1 << PALETTE_MODIFIER_COLOUR))
-+ TILE_SEQ_END()
-+};
-+
-+// drive-through bus stop NE slope
-+static const DrawTileSeqStruct _station_display_datas_0173[] = {
-+ TILE_SEQ_LINE( 0, 0, 0, 16, 3, 16, SPR_BUS_STOP_DT_NE_W | (1 << PALETTE_MODIFIER_COLOUR))
-+ TILE_SEQ_LINE( 0, 13, 0, 16, 3, 16, SPR_BUS_STOP_DT_NE_E | (1 << PALETTE_MODIFIER_COLOUR))
-+ TILE_SEQ_END()
-+};
-+
-+// drive-through bus stop NW slope
-+static const DrawTileSeqStruct _station_display_datas_0174[] = {
-+ TILE_SEQ_LINE( 0, 0, 0, 16, 3, 16, SPR_BUS_STOP_DT_NW_W | (1 << PALETTE_MODIFIER_COLOUR))
-+ TILE_SEQ_LINE( 0, 13, 0, 16, 3, 16, SPR_BUS_STOP_DT_NW_E | (1 << PALETTE_MODIFIER_COLOUR))
-+ TILE_SEQ_END()
-+};
-+
-+// drive-through bus stop SW slope
-+static const DrawTileSeqStruct _station_display_datas_0175[] = {
-+ TILE_SEQ_LINE( 0, 0, 0, 16, 3, 16, SPR_BUS_STOP_DT_SW_W | (1 << PALETTE_MODIFIER_COLOUR))
-+ TILE_SEQ_LINE( 0, 13, 0, 16, 3, 16, SPR_BUS_STOP_DT_SW_E | (1 << PALETTE_MODIFIER_COLOUR))
-+ TILE_SEQ_END()
-+};
-+
-+// drive-through truck stop SE slope
-+static const DrawTileSeqStruct _station_display_datas_0176[] = {
-+ TILE_SEQ_LINE( 0, 0, 0, 16, 3, 16, SPR_TRUCK_STOP_DT_SE_W | (1 << PALETTE_MODIFIER_COLOUR))
-+ TILE_SEQ_LINE( 0, 13, 0, 16, 3, 16, SPR_TRUCK_STOP_DT_SE_E | (1 << PALETTE_MODIFIER_COLOUR))
-+ TILE_SEQ_END()
-+};
-+
-+// drive-through truck stop NE slope
-+static const DrawTileSeqStruct _station_display_datas_0177[] = {
-+ TILE_SEQ_LINE( 0, 0, 0, 16, 3, 16, SPR_TRUCK_STOP_DT_NE_W | (1 << PALETTE_MODIFIER_COLOUR))
-+ TILE_SEQ_LINE( 0, 13, 0, 16, 3, 16, SPR_TRUCK_STOP_DT_NE_E | (1 << PALETTE_MODIFIER_COLOUR))
-+ TILE_SEQ_END()
-+};
-+
-+// drive-through truck stop NW slope
-+static const DrawTileSeqStruct _station_display_datas_0178[] = {
-+ TILE_SEQ_LINE( 0, 0, 0, 16, 3, 16, SPR_TRUCK_STOP_DT_NW_W | (1 << PALETTE_MODIFIER_COLOUR))
-+ TILE_SEQ_LINE( 0, 13, 0, 16, 3, 16, SPR_TRUCK_STOP_DT_NW_E | (1 << PALETTE_MODIFIER_COLOUR))
-+ TILE_SEQ_END()
-+};
-+
-+// drive-through truck stop SW slope
-+static const DrawTileSeqStruct _station_display_datas_0179[] = {
-+ TILE_SEQ_LINE( 0, 0, 0, 16, 3, 16, SPR_TRUCK_STOP_DT_SW_W | (1 << PALETTE_MODIFIER_COLOUR))
-+ TILE_SEQ_LINE( 0, 13, 0, 16, 3, 16, SPR_TRUCK_STOP_DT_SW_E | (1 << PALETTE_MODIFIER_COLOUR))
-+ TILE_SEQ_END()
-+};
-+
- #undef TILE_SEQ_END
- #undef TILE_SEQ_LINE
- #undef TILE_SEQ_LINE_PAL
-@@ -944,6 +1000,10 @@ static const DrawTileSprites _station_display_datas_truck[] = {
- TILE_SPRITE_LINE(SPR_TRUCK_STOP_NW_GROUND | (1U << PALETTE_MODIFIER_COLOUR), _station_display_datas_70)
- TILE_SPRITE_LINE(SPR_ROAD_PAVED_STRAIGHT_X, _station_display_datas_0168)
- TILE_SPRITE_LINE(SPR_ROAD_PAVED_STRAIGHT_Y, _station_display_datas_0169)
-+ TILE_SPRITE_LINE(SPR_ROAD_PAVED_STRAIGHT_X, _station_display_datas_0176)
-+ TILE_SPRITE_LINE(SPR_ROAD_PAVED_STRAIGHT_Y, _station_display_datas_0177)
-+ TILE_SPRITE_LINE(SPR_ROAD_PAVED_STRAIGHT_X, _station_display_datas_0178)
-+ TILE_SPRITE_LINE(SPR_ROAD_PAVED_STRAIGHT_Y, _station_display_datas_0179)
- };
-
- static const DrawTileSprites _station_display_datas_bus[] = {
-@@ -953,6 +1013,10 @@ static const DrawTileSprites _station_display_datas_bus[] = {
- TILE_SPRITE_LINE(SPR_BUS_STOP_NW_GROUND | (1U << PALETTE_MODIFIER_COLOUR), _station_display_datas_74)
- TILE_SPRITE_LINE(SPR_ROAD_PAVED_STRAIGHT_X, _station_display_datas_0170)
- TILE_SPRITE_LINE(SPR_ROAD_PAVED_STRAIGHT_Y, _station_display_datas_0171)
-+ TILE_SPRITE_LINE(SPR_ROAD_PAVED_STRAIGHT_X, _station_display_datas_0172)
-+ TILE_SPRITE_LINE(SPR_ROAD_PAVED_STRAIGHT_Y, _station_display_datas_0173)
-+ TILE_SPRITE_LINE(SPR_ROAD_PAVED_STRAIGHT_X, _station_display_datas_0174)
-+ TILE_SPRITE_LINE(SPR_ROAD_PAVED_STRAIGHT_Y, _station_display_datas_0175)
- };
-
- static const DrawTileSprites _station_display_datas_oilrig[] = {
-diff --git a/src/track_type.h b/src/track_type.h
-index 70278c58d..0c64b9978 100644
---- a/src/track_type.h
-+++ b/src/track_type.h
-@@ -120,4 +120,11 @@ DECLARE_ENUM_AS_BIT_SET(TrackdirBits)
-
- typedef uint32 TrackStatus;
-
-+static const byte _track_sloped_sprites[14] = {
-+ 14, 15, 22, 13,
-+ 0, 21, 17, 12,
-+ 23, 0, 18, 20,
-+ 19, 16
-+};
-+
- #endif /* TRACK_TYPE_H */
diff --git a/openttd-git/underground.patch b/openttd-git/underground.patch
deleted file mode 100644
index 57e331a16..000000000
--- a/openttd-git/underground.patch
+++ /dev/null
@@ -1,3664 +0,0 @@
-diff --git a/layer.txt b/layer.txt
-new file mode 100644
-index 000000000..a5947189b
---- /dev/null
-+++ b/layer.txt
-@@ -0,0 +1,48 @@
-+* Card generation (extended card)
-+
-+VISUALIZATION
-+
-+* arrange a "shift" of the viewport to select a layer
-+- and restriction on movement
-++ each viewport has its own layer
-+
-+LOGICS
-+
-+dungeon:
-+ unavailability:
-+* flood
-+* landscape change
-+* building
-+* houses
-+* trees
-+* water
-+* factories
-+* bridges
-+* tunnels
-+* airports
-+* roads at the intersection of layers
-+? generator
-+? rivers, cities
-+* edges (independent lifting, void)
-+
-+activity restriction
-+synchronization of landscape changes
-+
-+GUI
-+
-+** construction of a two-level station
-+- construction of a worm-hole from one layer to a neighbour layer
-+** work with the station (construction, removal / blocking of parts / cost)
-+* menu template for management / construction
-+
-++ add selection of number of layers
-++ only show layer switches for available layers
-+? only show tiles of current layer
-++ fix the coordinates in the "help area"
-+- fix the coordinates in the start screen
-+- signatures, station names (on all layers), effects (on the desired layer)
-+
-+BAGI
-++ station deletion (departure)
-+* Expansion of the underground station does not work (when adding cells, a new one is added)
-+- GF. "jumps" (the non-editable part of the station changes randomly when the station is modified)
-diff --git a/media/baseset/opntitle.dat b/media/baseset/opntitle.dat
-index 264aaff60..9793856b7 100644
-Binary files a/media/baseset/opntitle.dat and b/media/baseset/opntitle.dat differ
-diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
-index 631eaf6de..c253e8295 100644
---- a/src/CMakeLists.txt
-+++ b/src/CMakeLists.txt
-@@ -210,6 +210,10 @@ add_files(
- landscape.h
- landscape_type.h
- language.h
-+ layer.cpp
-+ layer_func.h
-+ layer_gui.h
-+ layer_type.h
- livery.h
- main_gui.cpp
- map.cpp
-@@ -451,6 +455,8 @@ add_files(
- tunnelbridge.h
- tunnelbridge_cmd.cpp
- tunnelbridge_map.h
-+ underground_gui.cpp
-+ underground_gui.h
- vehicle.cpp
- vehicle_base.h
- vehicle_cmd.cpp
-diff --git a/src/base_station_base.h b/src/base_station_base.h
-index 40543f1b8..ace01445a 100644
---- a/src/base_station_base.h
-+++ b/src/base_station_base.h
-@@ -26,6 +26,13 @@ struct StationSpecList {
-
-
- /** StationRect - used to track station spread out rectangle - cheaper than scanning whole map */
-+/*
-+** Патч "layer"
-+** Критическое изменение:
-+** "Rect" подразумевает только верхний слой (поверхность)
-+** (станция может располагаться на любом слое, --
-+** Rect описывает соответствующую часть верхнего слоя)
-+*/
- struct StationRect : public Rect {
- enum StationRectMode
- {
-@@ -36,7 +43,7 @@ struct StationRect : public Rect {
-
- StationRect();
- void MakeEmpty();
-- bool PtInExtendedRect(int x, int y, int distance = 0) const;
-+ bool PtInExtendedRect(int topx, int topy, int distance = 0) const;
- bool IsEmpty() const;
- CommandCost BeforeAddTile(TileIndex tile, StationRectMode mode);
- CommandCost BeforeAddRect(TileIndex tile, int w, int h, StationRectMode mode);
-diff --git a/src/clear_cmd.cpp b/src/clear_cmd.cpp
-index 403631312..61704487e 100644
---- a/src/clear_cmd.cpp
-+++ b/src/clear_cmd.cpp
-@@ -12,6 +12,7 @@
- #include "command_func.h"
- #include "landscape.h"
- #include "genworld.h"
-+#include "layer_func.h"
- #include "viewport_func.h"
- #include "water.h"
- #include "core/random_func.hpp"
-@@ -98,8 +99,28 @@ static void DrawClearLandFence(const TileInfo *ti)
- EndSpriteCombine();
- }
-
-+static void DrawUndergroundTile_Clear(TileInfo *ti)
-+{
-+
-+}
-+
- static void DrawTile_Clear(TileInfo *ti)
- {
-+ uint base_tile = TopTile(ti->tile);
-+ uint underground_tile = DownTile(base_tile);
-+
-+ bool self_underground = IsUnderground(ti->tile);
-+
-+ bool have_canalization = IsTileType(base_tile, MP_HOUSE);
-+ bool have_underground = !IsTileType(underground_tile, MP_CLEAR);
-+
-+ if (self_underground && !have_canalization)
-+ DrawGroundSprite(SPR_FLAT_BARE_LAND + SlopeToSpriteOffset(ti->tileh), PAL_NONE);
-+
-+ if (self_underground && have_canalization)
-+ DrawGroundSprite(SPR_FLAT_GRASS_TILE + SlopeToSpriteOffset(ti->tileh), PAL_NONE);
-+
-+ if (!self_underground)
- switch (GetClearGround(ti->tile)) {
- case CLEAR_GRASS:
- DrawClearLandTile(ti, GetClearDensity(ti->tile));
-@@ -124,6 +145,9 @@ static void DrawTile_Clear(TileInfo *ti)
- break;
- }
-
-+ if (!self_underground && have_underground)
-+ DrawGroundSprite(SPR_FLAT_BARE_LAND + SlopeToSpriteOffset(ti->tileh), PAL_NONE);
-+
- DrawBridgeMiddle(ti);
- }
-
-@@ -321,7 +345,7 @@ void GenerateClearTile()
- SetGeneratingWorldProgress(GWP_ROUGH_ROCKY, gi + i);
- do {
- IncreaseGeneratingWorldProgress(GWP_ROUGH_ROCKY);
-- tile = RandomTile();
-+ tile = TopTile(RandomTile());
- if (IsTileType(tile, MP_CLEAR) && !IsClearGround(tile, CLEAR_DESERT)) SetClearGroundDensity(tile, CLEAR_ROUGH, 3);
- } while (--i);
-
-@@ -329,7 +353,7 @@ void GenerateClearTile()
- i = gi;
- do {
- uint32 r = Random();
-- tile = RandomTileSeed(r);
-+ tile = TopTile(RandomTileSeed(r));
-
- IncreaseGeneratingWorldProgress(GWP_ROUGH_ROCKY);
- if (IsTileType(tile, MP_CLEAR) && !IsClearGround(tile, CLEAR_DESERT)) {
-diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp
-index 5cdb744ab..ed1f30af7 100644
---- a/src/console_cmds.cpp
-+++ b/src/console_cmds.cpp
-@@ -26,6 +26,7 @@
- #include "screenshot.h"
- #include "genworld.h"
- #include "strings_func.h"
-+#include "layer_func.h"
- #include "viewport_func.h"
- #include "window_func.h"
- #include "date_func.h"
-@@ -1070,6 +1071,7 @@ DEF_CONSOLE_CMD(ConRestart)
- }
-
- /* Don't copy the _newgame pointers to the real pointers, so call SwitchToMode directly */
-+ _settings_game.game_creation.layers = FindFirstBit(LayerCount());
- _settings_game.game_creation.map_x = MapLogX();
- _settings_game.game_creation.map_y = FindFirstBit(MapSizeY());
- _switch_mode = SM_RESTARTGAME;
-diff --git a/src/disaster_vehicle.cpp b/src/disaster_vehicle.cpp
-index cc245b38f..66a088595 100644
---- a/src/disaster_vehicle.cpp
-+++ b/src/disaster_vehicle.cpp
-@@ -325,7 +325,7 @@ static bool DisasterTick_Ufo(DisasterVehicle *v)
- return true;
- }
- if (++v->age < 6) {
-- v->dest_tile = RandomTile();
-+ v->dest_tile = TopTile(RandomTile());
- return true;
- }
- v->current_order.SetDestination(1);
-@@ -572,12 +572,12 @@ static bool DisasterTick_Big_Ufo(DisasterVehicle *v)
- }
-
- if (++v->age < 6) {
-- v->dest_tile = RandomTile();
-+ v->dest_tile = TopTile(RandomTile());
- return true;
- }
- v->current_order.SetDestination(1);
-
-- TileIndex tile_org = RandomTile();
-+ TileIndex tile_org = TopTile(RandomTile());
- TileIndex tile = tile_org;
- do {
- if (IsPlainRailTile(tile) &&
-@@ -958,7 +958,7 @@ void ReleaseDisastersTargetingVehicle(VehicleID vehicle)
- if (v->current_order.GetDestination() != 0 && v->dest_tile == vehicle) {
- /* Revert to target-searching */
- v->current_order.SetDestination(0);
-- v->dest_tile = RandomTile();
-+ v->dest_tile = TopTile(RandomTile());
- GetAircraftFlightLevelBounds(v, &v->z_pos, nullptr);
- v->age = 0;
- }
-diff --git a/src/genworld.cpp b/src/genworld.cpp
-index 587d100b5..fc0f763c3 100644
---- a/src/genworld.cpp
-+++ b/src/genworld.cpp
-@@ -321,7 +321,7 @@ void GenerateWorld(GenWorldMode mode, uint size_x, uint size_y, bool reset_setti
-
- /* Centre the view on the map */
- if (FindWindowById(WC_MAIN_WINDOW, 0) != nullptr) {
-- ScrollMainWindowToTile(TileXY(MapSizeX() / 2, MapSizeY() / 2), true);
-+ ScrollMainWindowToTile(TileXY(MapSizeX() / 2, MapSizeY() / LayerCount() / 2), true);
- }
-
- _GenerateWorld();
-diff --git a/src/genworld_gui.cpp b/src/genworld_gui.cpp
-index 2489105c2..00f18699c 100644
---- a/src/genworld_gui.cpp
-+++ b/src/genworld_gui.cpp
-@@ -16,6 +16,8 @@
- #include "window_func.h"
- #include "date_func.h"
- #include "sound_func.h"
-+#include "map_type.h"
-+#include "layer_type.h"
- #include "fios.h"
- #include "string_func.h"
- #include "widgets/dropdown_type.h"
-@@ -91,6 +93,7 @@ static const NWidgetPart _nested_generate_landscape_widgets[] = {
- /* Left column with labels. */
- NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(0, 4, 0),
- NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_MAPSIZE, STR_MAPGEN_MAPSIZE_TOOLTIP), SetFill(1, 1),
-+ NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_UNDERGROUND_LAYER_COUNT, STR_NULL), SetFill(1, 1),
- NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_LAND_GENERATOR, STR_NULL), SetFill(1, 1),
- NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_TERRAIN_TYPE, STR_NULL), SetFill(1, 1),
- NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_VARIETY, STR_NULL), SetFill(1, 1),
-@@ -107,6 +110,7 @@ static const NWidgetPart _nested_generate_landscape_widgets[] = {
- NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_BY, STR_NULL), SetPadding(1, 0, 0, 0), SetFill(1, 1),
- NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_MAPSIZE_Y_PULLDOWN), SetDataTip(STR_JUST_INT, STR_MAPGEN_MAPSIZE_TOOLTIP), SetFill(1, 0),
- EndContainer(),
-+ NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_LAYER_COUNT_PULLDOWN), SetDataTip(STR_JUST_INT, STR_NULL), SetFill(1, 0),
- NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_LANDSCAPE_PULLDOWN), SetDataTip(STR_JUST_STRING, STR_NULL), SetFill(1, 0),
- NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_TERRAIN_PULLDOWN), SetDataTip(STR_JUST_STRING, STR_NULL), SetFill(1, 0),
- NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_VARIETY_PULLDOWN), SetDataTip(STR_JUST_STRING, STR_NULL), SetFill(1, 0),
-@@ -216,6 +220,7 @@ static const NWidgetPart _nested_heightmap_load_widgets[] = {
- NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_HEIGHTMAP_SIZE_LABEL, STR_NULL), SetFill(1, 1),
- NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_MAPSIZE, STR_NULL), SetFill(1, 1),
- NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_HEIGHTMAP_ROTATION, STR_NULL), SetFill(1, 1),
-+ NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_UNDERGROUND_LAYER_COUNT, STR_NULL), SetFill(1, 1),
- NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_NUMBER_OF_TOWNS, STR_NULL), SetFill(1, 1),
- NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_NUMBER_OF_INDUSTRIES, STR_NULL), SetFill(1, 1),
- NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_QUANTITY_OF_RIVERS, STR_NULL), SetFill(1, 1),
-@@ -233,6 +238,7 @@ static const NWidgetPart _nested_heightmap_load_widgets[] = {
- NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_MAPSIZE_Y_PULLDOWN), SetDataTip(STR_JUST_INT, STR_NULL), SetFill(1, 0),
- EndContainer(),
- NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_HEIGHTMAP_ROTATION_PULLDOWN), SetDataTip(STR_JUST_STRING, STR_NULL), SetFill(1, 0),
-+ NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_LAYER_COUNT_PULLDOWN), SetDataTip(STR_JUST_INT, STR_NULL), SetFill(1, 0),
- NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_TOWN_PULLDOWN), SetDataTip(STR_JUST_STRING, STR_NULL), SetFill(1, 0),
- NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_INDUSTRY_PULLDOWN), SetDataTip(STR_JUST_STRING, STR_NULL), SetFill(1, 0),
- NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_RIVER_PULLDOWN), SetDataTip(STR_JUST_STRING, STR_NULL), SetFill(1, 0),
-@@ -306,11 +312,11 @@ static void LandscapeGenerationCallback(Window *w, bool confirmed)
- if (confirmed) StartGeneratingLandscape((GenerateLandscapeWindowMode)w->window_number);
- }
-
--static DropDownList BuildMapsizeDropDown()
-+static DropDownList BuildBitListDropDown(uint min_bits, uint max_bits)
- {
- DropDownList list;
-
-- for (uint i = MIN_MAP_SIZE_BITS; i <= MAX_MAP_SIZE_BITS; i++) {
-+ for (uint i = min_bits; i <= max_bits; i++) {
- DropDownListParamStringItem *item = new DropDownListParamStringItem(STR_JUST_INT, i, false);
- item->SetParam(0, 1LL << i);
- list.emplace_back(item);
-@@ -346,6 +352,15 @@ static DropDownList BuildTownNameDropDown()
- return list;
- }
-
-+static DropDownList BuildMapsizeDropDown()
-+{
-+ return BuildBitListDropDown(MIN_MAP_SIZE_BITS, MAX_MAP_SIZE_BITS);
-+}
-+
-+static DropDownList BuildLayerDropDown()
-+{
-+ return BuildBitListDropDown(MIN_LAYER_COUNT_BITS, MAX_LAYER_COUNT_BITS);
-+}
-
- static const StringID _elevations[] = {STR_TERRAIN_TYPE_VERY_FLAT, STR_TERRAIN_TYPE_FLAT, STR_TERRAIN_TYPE_HILLY, STR_TERRAIN_TYPE_MOUNTAINOUS, STR_TERRAIN_TYPE_ALPINIST, STR_TERRAIN_TYPE_CUSTOM, INVALID_STRING_ID};
- static const StringID _sea_lakes[] = {STR_SEA_LEVEL_VERY_LOW, STR_SEA_LEVEL_LOW, STR_SEA_LEVEL_MEDIUM, STR_SEA_LEVEL_HIGH, STR_SEA_LEVEL_CUSTOM, INVALID_STRING_ID};
-@@ -392,6 +407,7 @@ struct GenerateLandscapeWindow : public Window {
- case WID_GL_START_DATE_TEXT: SetDParam(0, ConvertYMDToDate(_settings_newgame.game_creation.starting_year, 0, 1)); break;
- case WID_GL_MAPSIZE_X_PULLDOWN: SetDParam(0, 1LL << _settings_newgame.game_creation.map_x); break;
- case WID_GL_MAPSIZE_Y_PULLDOWN: SetDParam(0, 1LL << _settings_newgame.game_creation.map_y); break;
-+ case WID_GL_LAYER_COUNT_PULLDOWN: SetDParam(0, 1 << _settings_newgame.game_creation.layers); break;
- case WID_GL_HEIGHTMAP_HEIGHT_TEXT: SetDParam(0, _settings_newgame.game_creation.heightmap_height); break;
- case WID_GL_SNOW_COVERAGE_TEXT: SetDParam(0, _settings_newgame.game_creation.snow_coverage); break;
- case WID_GL_DESERT_COVERAGE_TEXT: SetDParam(0, _settings_newgame.game_creation.desert_coverage); break;
-@@ -551,6 +567,11 @@ struct GenerateLandscapeWindow : public Window {
- *size = maxdim(*size, GetStringBoundingBox(STR_JUST_INT));
- break;
-
-+ case WID_GL_LAYER_COUNT_PULLDOWN:
-+ SetDParam(0, MAX_LAYER_COUNT);
-+ *size = GetStringBoundingBox(STR_JUST_INT);
-+ break;
-+
- case WID_GL_SNOW_COVERAGE_TEXT:
- SetDParamMaxValue(0, MAX_TILE_HEIGHT);
- *size = maxdim(*size, GetStringBoundingBox(STR_MAPGEN_SNOW_COVERAGE_TEXT));
-@@ -647,6 +668,10 @@ struct GenerateLandscapeWindow : public Window {
- ShowDropDownList(this, BuildMapsizeDropDown(), _settings_newgame.game_creation.map_y, WID_GL_MAPSIZE_Y_PULLDOWN);
- break;
-
-+ case WID_GL_LAYER_COUNT_PULLDOWN: // Mapsize Z
-+ ShowDropDownList(this, BuildLayerDropDown(), _settings_newgame.game_creation.layers, WID_GL_LAYER_COUNT_PULLDOWN);
-+ break;
-+
- case WID_GL_TOWN_PULLDOWN: // Number of towns
- ShowDropDownMenu(this, _num_towns, _settings_newgame.difficulty.number_towns, WID_GL_TOWN_PULLDOWN, 0, 0);
- break;
-@@ -842,6 +867,7 @@ struct GenerateLandscapeWindow : public Window {
- switch (widget) {
- case WID_GL_MAPSIZE_X_PULLDOWN: _settings_newgame.game_creation.map_x = index; break;
- case WID_GL_MAPSIZE_Y_PULLDOWN: _settings_newgame.game_creation.map_y = index; break;
-+ case WID_GL_LAYER_COUNT_PULLDOWN: _settings_newgame.game_creation.layers = index; break;
- case WID_GL_RIVER_PULLDOWN: _settings_newgame.game_creation.amount_of_rivers = index; break;
- case WID_GL_SMOOTHNESS_PULLDOWN: _settings_newgame.game_creation.tgen_smoothness = index; break;
- case WID_GL_VARIETY_PULLDOWN: _settings_newgame.game_creation.variety = index; break;
-@@ -1051,6 +1077,10 @@ struct CreateScenarioWindow : public Window
- SetDParam(0, 1LL << _settings_newgame.game_creation.map_y);
- break;
-
-+ case WID_CS_LAYER_COUNT_PULLDOWN:
-+ SetDParam(0, 1 << _settings_newgame.game_creation.layers);
-+ break;
-+
- case WID_CS_FLAT_LAND_HEIGHT_TEXT:
- SetDParam(0, _settings_newgame.game_creation.se_flat_world_height);
- break;
-@@ -1084,6 +1114,10 @@ struct CreateScenarioWindow : public Window
- case WID_CS_MAPSIZE_X_PULLDOWN:
- case WID_CS_MAPSIZE_Y_PULLDOWN:
- SetDParamMaxValue(0, MAX_MAP_SIZE);
-+ break;
-+
-+ case WID_CS_LAYER_COUNT_PULLDOWN:
-+ SetDParam(0, MAX_LAYER_COUNT);
- break;
-
- case WID_CS_FLAT_LAND_HEIGHT_TEXT:
-@@ -1117,6 +1151,10 @@ struct CreateScenarioWindow : public Window
- ShowDropDownList(this, BuildMapsizeDropDown(), _settings_newgame.game_creation.map_y, WID_CS_MAPSIZE_Y_PULLDOWN);
- break;
-
-+ case WID_CS_LAYER_COUNT_PULLDOWN: // Mapsize Y
-+ ShowDropDownList(this, BuildLayerDropDown(), _settings_newgame.game_creation.layers, WID_CS_LAYER_COUNT_PULLDOWN);
-+ break;
-+
- case WID_CS_EMPTY_WORLD: // Empty world / flat world
- StartGeneratingLandscape(GLWM_SCENARIO);
- break;
-@@ -1179,6 +1217,7 @@ struct CreateScenarioWindow : public Window
- switch (widget) {
- case WID_CS_MAPSIZE_X_PULLDOWN: _settings_newgame.game_creation.map_x = index; break;
- case WID_CS_MAPSIZE_Y_PULLDOWN: _settings_newgame.game_creation.map_y = index; break;
-+ case WID_CS_LAYER_COUNT_PULLDOWN: _settings_newgame.game_creation.layers = index; break;
- }
- this->SetDirty();
- }
-@@ -1234,6 +1273,7 @@ static const NWidgetPart _nested_create_scenario_widgets[] = {
- NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_CS_MAPSIZE_X_PULLDOWN), SetDataTip(STR_JUST_INT, STR_NULL), SetPadding(0, 4, 0, 0),
- NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_BY, STR_NULL), SetPadding(1, 2, 0, 0),
- NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_CS_MAPSIZE_Y_PULLDOWN), SetDataTip(STR_JUST_INT, STR_NULL),
-+ NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_CS_LAYER_COUNT_PULLDOWN), SetDataTip(STR_JUST_INT, STR_NULL),
- EndContainer(),
- /* Date. */
- NWidget(NWID_HORIZONTAL),
-diff --git a/src/gfx_type.h b/src/gfx_type.h
-index a6bf3cf6d..a7c157ada 100644
---- a/src/gfx_type.h
-+++ b/src/gfx_type.h
-@@ -156,6 +156,7 @@ struct DrawPixelInfo {
- void *dst_ptr;
- int left, top, width, height;
- int pitch;
-+ int layer;
- ZoomLevel zoom;
- };
-
-diff --git a/src/heightmap.cpp b/src/heightmap.cpp
-index 0c726371c..a073c7cf4 100644
---- a/src/heightmap.cpp
-+++ b/src/heightmap.cpp
-@@ -14,6 +14,7 @@
- #include "error.h"
- #include "saveload/saveload.h"
- #include "bmp.h"
-+#include "layer_func.h"
- #include "gfx_func.h"
- #include "fios.h"
- #include "fileio_func.h"
-@@ -429,6 +430,9 @@ void FixSlopes()
- width = MapSizeX();
- height = MapSizeY();
-
-+ /* Layers height correct */
-+ FixUndergroundHeights();
-+
- /* Top and left edge */
- for (row = 0; (uint)row < height; row++) {
- for (col = 0; (uint)col < width; col++) {
-diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp
-index b03a722b7..fd00ec0cd 100644
---- a/src/industry_cmd.cpp
-+++ b/src/industry_cmd.cpp
-@@ -12,6 +12,7 @@
- #include "industry.h"
- #include "station_base.h"
- #include "landscape.h"
-+#include "layer_func.h"
- #include "viewport_func.h"
- #include "command_func.h"
- #include "town.h"
-@@ -1444,7 +1445,7 @@ static CommandCost CheckIfIndustryTilesAreFree(TileIndex tile, const IndustryTil
- IndustryGfx gfx = GetTranslatedIndustryTileID(it.gfx);
- TileIndex cur_tile = TileAddWrap(tile, it.ti.x, it.ti.y);
-
-- if (!IsValidTile(cur_tile)) {
-+ if (!IsValidTile(cur_tile) || IsUnderground(cur_tile)) {
- return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
- }
-
-@@ -2023,7 +2024,7 @@ CommandCost CmdBuildIndustry(TileIndex tile, DoCommandFlag flags, uint32 p1, uin
- /* We should not have more than one Random() in a function call
- * because parameter evaluation order is not guaranteed in the c++ standard
- */
-- tile = RandomTile();
-+ tile = TopTile(RandomTile());
- /* Start with a random layout */
- size_t layout = RandomRange((uint32)num_layouts);
- /* Check now each layout, starting with the random one */
-@@ -2229,7 +2230,7 @@ static Industry *PlaceIndustry(IndustryType type, IndustryAvailabilityCallType c
- {
- uint tries = try_hard ? 10000u : 2000u;
- for (; tries > 0; tries--) {
-- Industry *ind = CreateNewIndustry(RandomTile(), type, creation_type);
-+ Industry *ind = CreateNewIndustry(TopTile(RandomTile()), type, creation_type);
- if (ind != nullptr) return ind;
- }
- return nullptr;
-diff --git a/src/landscape.cpp b/src/landscape.cpp
-index f13d1835f..6ed0c6569 100644
---- a/src/landscape.cpp
-+++ b/src/landscape.cpp
-@@ -34,6 +34,7 @@
- #include <array>
- #include <list>
- #include <set>
-+#include "layer_func.h"
-
- #include "table/strings.h"
- #include "table/sprites.h"
-@@ -813,10 +814,10 @@ void RunTileLoop()
- 0xD8F, 0x1296, 0x2496, 0x4357, 0x8679, 0x1030E, 0x206CD, 0x403FE, 0x807B8, 0x1004B2, 0x2006A8, 0x4004B2, 0x800B87
- };
- static_assert(lengthof(feedbacks) == 2 * MAX_MAP_SIZE_BITS - 2 * MIN_MAP_SIZE_BITS + 1);
-- const uint32 feedback = feedbacks[MapLogX() + MapLogY() - 2 * MIN_MAP_SIZE_BITS];
-+ const uint32 feedback = feedbacks[MapLogX() + MapLogY() - LayerCountLog() - 2 * MIN_MAP_SIZE_BITS];
-
- /* We update every tile every 256 ticks, so divide the map size by 2^8 = 256 */
-- uint count = 1 << (MapLogX() + MapLogY() - 8);
-+ uint count = 1 << (MapLogX() + MapLogY() - LayerCountLog() - 8);
-
- TileIndex tile = _cur_tileloop_tile;
- /* The LFSR cannot have a zeroed state. */
-@@ -840,17 +841,23 @@ void RunTileLoop()
-
- void InitializeLandscape()
- {
-- for (uint y = _settings_game.construction.freeform_edges ? 1 : 0; y < MapMaxY(); y++) {
-- for (uint x = _settings_game.construction.freeform_edges ? 1 : 0; x < MapMaxX(); x++) {
-- MakeClear(TileXY(x, y), CLEAR_GRASS, 3);
-- SetTileHeight(TileXY(x, y), 0);
-- SetTropicZone(TileXY(x, y), TROPICZONE_NORMAL);
-- ClearBridgeMiddle(TileXY(x, y));
-+ uint maxx = LayerMaxX();
-+ uint maxy = LayerMaxY();
-+ uint sizex = MapSizeX();
-+ uint layersize = LayerSize();
-+
-+ FOR_ALL_LAYERS(layer) {
-+ for (uint y = _settings_game.construction.freeform_edges ? 1 : 0; y < LayerMaxY(); y++) {
-+ for (uint x = _settings_game.construction.freeform_edges ? 1 : 0; x < LayerMaxX(); x++) {
-+ MakeClear(layer * layersize + TileXY(x, y), CLEAR_GRASS, 3);
-+ SetTileHeight(layer * layersize + TileXY(x, y), 0);
-+ SetTropicZone(layer * layersize + TileXY(x, y), TROPICZONE_NORMAL);
-+ ClearBridgeMiddle(layer * layersize + TileXY(x, y));
-+ }
-+ MakeVoid(layer * layersize + TileXY(LayerMaxX(), y));
- }
-+ for (uint x = 0; x < LayerSizeX(); x++) MakeVoid(TileXY(x, LayerMaxY()));
- }
--
-- for (uint x = 0; x < MapSizeX(); x++) MakeVoid(TileXY(x, MapMaxY()));
-- for (uint y = 0; y < MapSizeY(); y++) MakeVoid(TileXY(MapMaxX(), y));
- }
-
- static const byte _genterrain_tbl_1[5] = { 10, 22, 33, 37, 4 };
-@@ -1281,7 +1288,7 @@ static void CreateRivers()
- for (; wells != 0; wells--) {
- IncreaseGeneratingWorldProgress(GWP_RIVER);
- for (int tries = 0; tries < 128; tries++) {
-- TileIndex t = RandomTile();
-+ TileIndex t = TopTile(RandomTile());
- if (!CircularTileSearch(&t, 8, FindSpring, nullptr)) continue;
- if (FlowRiver(t, t)) break;
- }
-diff --git a/src/lang/afrikaans.txt b/src/lang/afrikaans.txt
-index 1ad648233..dafb1b733 100644
---- a/src/lang/afrikaans.txt
-+++ b/src/lang/afrikaans.txt
-@@ -2730,7 +2730,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Tremweg
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Spoorweg eienaar: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Plaaslike raad: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Geen
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koördinate: {LTBLUE}{NUM}x{NUM}x{NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koördinate: {LTBLUE}{NUM}x{NUM}x{NUM}x-{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Gebou: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Stasie klas: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Stasie tiepe: {LTBLUE}{STRING}
-diff --git a/src/lang/arabic_egypt.txt b/src/lang/arabic_egypt.txt
-index 5aacaf933..533380300 100644
---- a/src/lang/arabic_egypt.txt
-+++ b/src/lang/arabic_egypt.txt
-@@ -2472,7 +2472,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Щ…Ш§Щ„Щѓ
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Щ…Ш§Щ„Щѓ ШіЩѓШ© Ш§Щ„Ш­ШЇЩЉШЇ: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Ш§Щ„ШіЩ„Ш·Ш© Ш§Щ„Щ…Ш­Щ„ЩЉШ©: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :ЩЃШ§Ш±Шє
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Ш§Щ„ШЈШ­ШЇШ§Ш«ЩЉШ§ШЄ: {LTBLUE}{NUM}x{NUM}x{NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Ш§Щ„ШЈШ­ШЇШ§Ш«ЩЉШ§ШЄ: {LTBLUE}{NUM}x{NUM}x{NUM}x-{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}ШЁЩ†ЩЉ: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK} ЩЃШ¦Ш© Ш§Щ„Щ…Ш­Ш·Ш©: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Щ†Щ€Ш№ Ш§Щ„Щ…Ш­Ш·Ш©: {LTBLUE}{STRING}
-diff --git a/src/lang/basque.txt b/src/lang/basque.txt
-index 305520635..c83d88823 100644
---- a/src/lang/basque.txt
-+++ b/src/lang/basque.txt
-@@ -2593,7 +2593,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Tranbia
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Trenbidearen jabea: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Udaletxea {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Ezer ez
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordenadak: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordenadak: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Eraikia: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Geltoki mota: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Geltoki mota: {LTBLUE}{STRING}
-diff --git a/src/lang/belarusian.txt b/src/lang/belarusian.txt
-index 1dbc92f0b..532900688 100644
---- a/src/lang/belarusian.txt
-+++ b/src/lang/belarusian.txt
-@@ -3056,7 +3056,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Улад
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Уладальнiк чыгункi: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Мясцовая адміністрацыя: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :РќСЏРјР°
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Каардынаты: {LTBLUE}{NUM}x{NUM}x{NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Каардынаты: {LTBLUE}{NUM}x{NUM}x{NUM}x-{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Пабудавана: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Кляса станцыі: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Тып станцыi: {LTBLUE}{STRING}
-diff --git a/src/lang/brazilian_portuguese.txt b/src/lang/brazilian_portuguese.txt
-index 55872e2c4..e62dc9fb3 100644
---- a/src/lang/brazilian_portuguese.txt
-+++ b/src/lang/brazilian_portuguese.txt
-@@ -2921,7 +2921,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Dono da
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Dono da linha ferroviГЎria: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Prefeitura: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Nenhum
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordenadas: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordenadas: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}ConstruГ­do: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Classe de Estação: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Tipo de Estação: {LTBLUE}{STRING}
-diff --git a/src/lang/bulgarian.txt b/src/lang/bulgarian.txt
-index 72c553124..2cd79f0bc 100644
---- a/src/lang/bulgarian.txt
-+++ b/src/lang/bulgarian.txt
-@@ -2643,7 +2643,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}РЎРѕР±СЃ
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Собственик на железопътната линия: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Община: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Нищо
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Координати: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Координати: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Построен: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Клас на станцията: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Тип на станцията: {LTBLUE}{STRING}
-diff --git a/src/lang/catalan.txt b/src/lang/catalan.txt
-index 6409ddd26..dab10e967 100644
---- a/src/lang/catalan.txt
-+++ b/src/lang/catalan.txt
-@@ -2923,7 +2923,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Propieta
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Propietari del rail: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Autoritat local: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Cap
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordenades: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordenades: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}ConstruГЇt: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Classe d'estaciГі: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Tipus d'estaciГі: {LTBLUE}{STRING}
-diff --git a/src/lang/croatian.txt b/src/lang/croatian.txt
-index 59ba78ef9..a8c6b83da 100644
---- a/src/lang/croatian.txt
-+++ b/src/lang/croatian.txt
-@@ -2835,7 +2835,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Vlasnik
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Vlasnik Еѕeljeznice: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}PodruДЌna nadleЕѕnost: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Nijedan/Nitko/NiЕЎta
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinate: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinate: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}IzgraД‘eno: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Klasa postaje: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Vrsta postaje: {LTBLUE}{STRING}
-diff --git a/src/lang/czech.txt b/src/lang/czech.txt
-index 8b6bdb437..35010f968 100644
---- a/src/lang/czech.txt
-+++ b/src/lang/czech.txt
-@@ -3011,7 +3011,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Majitel
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Majitel tratД›: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}MГ­stnГ­ sprГЎva: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Nic
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}SouЕ™adnice: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}SouЕ™adnice: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Postaveno: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}TЕ™Г­da stanice: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Druh stanice: {LTBLUE}{STRING}
-diff --git a/src/lang/danish.txt b/src/lang/danish.txt
-index f3d32bce8..1338a15ba 100644
---- a/src/lang/danish.txt
-+++ b/src/lang/danish.txt
-@@ -2922,7 +2922,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Ejer af
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Ejer af jernbane: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Lokal myndighed: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Ingen
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinater: {LTBLUE}{NUM}x{NUM}x{NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinater: {LTBLUE}{NUM}x{NUM}x{NUM}x-{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Produceret: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Stationsklasse: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Stationstype: {LTBLUE}{STRING}
-diff --git a/src/lang/dutch.txt b/src/lang/dutch.txt
-index ff15afbf6..7f320f552 100644
---- a/src/lang/dutch.txt
-+++ b/src/lang/dutch.txt
-@@ -2922,7 +2922,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Eigenaar
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Eigenaar van spoorweg: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Gemeente: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Geen
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coördinaten: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coördinaten: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Bouwjaar: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Stationsklasse: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Stationstype: {LTBLUE}{STRING}
-diff --git a/src/lang/english.txt b/src/lang/english.txt
-index becf8d35c..0a3ea67f2 100644
---- a/src/lang/english.txt
-+++ b/src/lang/english.txt
-@@ -477,6 +477,19 @@ STR_AIRCRAFT_MENU_AIRPORT_CONSTRUCTION :Airport constru
- STR_LANDSCAPING_MENU_LANDSCAPING :Landscaping
- STR_LANDSCAPING_MENU_PLANT_TREES :Plant trees
- STR_LANDSCAPING_MENU_PLACE_SIGN :Place sign
-+############ range ends here
-+
-+############ range for underground menu starts
-+STR_LANDSCAPING_MENU_UNDERGROUND :Special constructions
-+STR_LANDSCAPING_MENU_LAYER_1 :Surface
-+STR_LANDSCAPING_MENU_LAYER_2 :Undergroound (-1)
-+STR_LANDSCAPING_MENU_LAYER_3 :Undergroound (-2)
-+STR_LANDSCAPING_MENU_LAYER_4 :Undergroound (-3)
-+STR_LANDSCAPING_MENU_LAYER_5 :Undergroound (-4)
-+STR_LANDSCAPING_MENU_LAYER_6 :Undergroound (-5)
-+STR_LANDSCAPING_MENU_LAYER_7 :Undergroound (-6)
-+STR_LANDSCAPING_MENU_LAYER_8 :Undergroound (-7)
-+############ range ends here
-
- # Music menu
- ###length 1
-@@ -2922,7 +2935,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Tramway
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Railway owner: {LTBLUE}{STRING1}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Local authority: {LTBLUE}{STRING1}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :None
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordinates: {LTBLUE}{NUM} x {NUM} x {NUM} ({RAW_STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordinates: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({RAW_STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Built: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Station class: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Station type: {LTBLUE}{STRING}
-@@ -5556,3 +5569,35 @@ STR_PLANE :{BLACK}{PLANE}
- STR_SHIP :{BLACK}{SHIP}
-
- STR_TOOLBAR_RAILTYPE_VELOCITY :{STRING} ({VELOCITY})
-+
-+# underground
-+
-+# error
-+STR_ERROR_UNDERGROUND_CAN_T_BUILD_UNDER_GROUND :{WHITE}Can't build this underground
-+STR_ERROR_UNDERGROUND_CAN_T_BUILD_OVER_GROUND :{WHITE}Can't build this on surface
-+STR_ERROR_UNDERGROUND_CAN_T_TERRAFORM :{WHITE}Can't terraform underground
-+STR_ERROR_UNDERGROUND_CAN_T_BUILD_PART :{WHITE}Can't build escalator here...
-+STR_ERROR_UNDERGROUND_CAN_T_BUILD_TOP_PART :{WHITE}Can't build escalator top here...
-+STR_ERROR_UNDERGROUND_CAN_T_BUILD_BOTTOM_PART :{WHITE}Can't build escalator bottom here...
-+
-+# menus
-+STR_UNDERGROUND_LAYER_COUNT :{BLACK}Layers count
-+STR_UNDERGROUND_BUILD :{WHITE}Underground
-+
-+# underground land types
-+STR_UNDERGROUND_FLAT :Cave
-+STR_UNDERGROUND_SOLID :Ground
-+STR_UNDERGROUND_ROCKS :Rocks
-+STR_UNDERGROUND_HEAVY_ROCKS :Hard rocks
-+
-+# underground special build types
-+STR_UNDERGROUND_ESCALATOR :Escalator
-+STR_UNDERGROUND_CONNECT :Connect
-+STR_UNDERGROUND_PIPE :Pipe
-+
-+# underground tool tip
-+STR_UNDERGROUND_TOOLTIP_ESCALATOR :{BLACK}Build escalator (underground station connect with surface)
-+STR_UNDERGROUND_TOOLTIP_CONNECT :{BLACK}Build connect (underground track connect with surface)
-+STR_UNDERGROUND_TOOLTIP_PIPE :{BLACK}Pipe (xm... anything...)
-+
-+# end underground string
-diff --git a/src/lang/english_AU.txt b/src/lang/english_AU.txt
-index 07a31fe0f..119f957b4 100644
---- a/src/lang/english_AU.txt
-+++ b/src/lang/english_AU.txt
-@@ -2655,7 +2655,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Tramway
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Railway owner: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Local authority: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :None
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordinates: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordinates: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Built: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Station class: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Station type: {LTBLUE}{STRING}
-diff --git a/src/lang/english_US.txt b/src/lang/english_US.txt
-index 764f484fe..dd0345629 100644
---- a/src/lang/english_US.txt
-+++ b/src/lang/english_US.txt
-@@ -2922,7 +2922,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Streetca
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Railroad owner: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Local authority: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :None
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Co-ordinates: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Co-ordinates: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Built: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Station class: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Station type: {LTBLUE}{STRING}
-diff --git a/src/lang/esperanto.txt b/src/lang/esperanto.txt
-index d9f5377ea..d0f4e5291 100644
---- a/src/lang/esperanto.txt
-+++ b/src/lang/esperanto.txt
-@@ -2294,7 +2294,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Posedant
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Posedanto de fervojo: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Lokaj estroj: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Neniu
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}TroviДќo: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}TroviДќo: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Kreite: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Stacioklaso: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Staciotipo: {LTBLUE}{STRING}
-diff --git a/src/lang/estonian.txt b/src/lang/estonian.txt
-index c98a8a242..a0865eef0 100644
---- a/src/lang/estonian.txt
-+++ b/src/lang/estonian.txt
-@@ -2927,7 +2927,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Trammite
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Raudtee omanik: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Kohalik omavalitsus: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :puudub
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinaadid: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinaadid: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Ehitatud: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Jaama järk: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Jaama liik: {LTBLUE}{STRING}
-diff --git a/src/lang/faroese.txt b/src/lang/faroese.txt
-index ff2312ab7..46895e640 100644
---- a/src/lang/faroese.txt
-+++ b/src/lang/faroese.txt
-@@ -2427,7 +2427,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Sporvogn
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Jarnbreyta eigari: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Mynduleikar ГЎ staГ°num: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Eingin
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinatar: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinatar: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Bygt: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}StГёГ° klassi: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}StГёГ° slag: {LTBLUE}{STRING}
-diff --git a/src/lang/finnish.txt b/src/lang/finnish.txt
-index 2d08b1e3c..5632d8b5e 100644
---- a/src/lang/finnish.txt
-+++ b/src/lang/finnish.txt
-@@ -2920,7 +2920,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Raitioti
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Rautatien omistaja: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Kunta: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Ei mitään
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinaatit: {LTBLUE}{NUM}Г—{NUM}Г—{NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinaatit: {LTBLUE}{NUM}Г—{NUM}Г—{NUM}x-{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Rakennettu: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Aseman luokka: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Aseman tyyppi: {LTBLUE}{STRING}
-diff --git a/src/lang/french.txt b/src/lang/french.txt
-index fd4bdd431..fe21b4da0 100644
---- a/src/lang/french.txt
-+++ b/src/lang/french.txt
-@@ -2923,7 +2923,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}PropriГ©
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}PropriГ©taire des rails{NBSP}: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}MunicipalitГ©{NBSP}: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Aucune
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}CoordonnГ©es{NBSP}: {LTBLUE}{NUM} Г— {NUM} Г— {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}CoordonnГ©es{NBSP}: {LTBLUE}{NUM} Г— {NUM} Г— {NUM} Г— -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Construit le{NBSP}: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Type de station{NBSP}: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Type de station{NBSP}: {LTBLUE}{STRING}
-diff --git a/src/lang/gaelic.txt b/src/lang/gaelic.txt
-index 13f1d7f74..5ccf9aa7c 100644
---- a/src/lang/gaelic.txt
-+++ b/src/lang/gaelic.txt
-@@ -2910,7 +2910,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Seilbhea
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Seilbheadair na rathaid-iarainn: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Г™ghdarras ionadail: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Chan eil gin
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Ionad: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Ionad: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Air a thogail: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}SeГІrsa an stГЁisein: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}SeГІrsa an stГЁisein: {LTBLUE}{STRING}
-diff --git a/src/lang/galician.txt b/src/lang/galician.txt
-index b281dbc26..535fc65d6 100644
---- a/src/lang/galician.txt
-+++ b/src/lang/galician.txt
-@@ -2731,7 +2731,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Propieta
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Propietario da vГ­a ferroviaria: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Autoridade local: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Ningunha
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordenadas: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordenadas: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}ConstruГ­do: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Clase de estaciГіn: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Tipo de estaciГіn: {LTBLUE}{STRING}
-diff --git a/src/lang/german.txt b/src/lang/german.txt
-index 8b1d81dba..aa1282c29 100644
---- a/src/lang/german.txt
-+++ b/src/lang/german.txt
-@@ -2923,7 +2923,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}StraГџen
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}GleiseigentГјmer: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Gehört zur Gemeinde: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Keine
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinaten: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinaten: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Errichtet am: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Stationsklasse: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Stationstyp: {LTBLUE}{STRING}
-diff --git a/src/lang/greek.txt b/src/lang/greek.txt
-index ca18521d5..5d69b32e1 100644
---- a/src/lang/greek.txt
-+++ b/src/lang/greek.txt
-@@ -3029,7 +3029,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}О™ОґО№Ої
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}О™ОґО№ОїОєП„О®П„О·П‚ П„ОїП… ПѓО№ОґО·ПЃОїОґПЃПЊОјОїП…: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}О¤ОїПЂО№ОєО® О±ПЃП‡О®: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :ОљО±ОјО№О¬
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}ОЈП…ОЅП„ОµП„О±ОіОјО­ОЅОµП‚: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}ОЈП…ОЅП„ОµП„О±ОіОјО­ОЅОµП‚: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}ОљО±П„О±ПѓОєОµП…О®: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}ОљО±П„О·ОіОїПЃОЇО± ПѓП„О±ОёОјОїПЌ: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}О¤ПЌПЂОїП‚ ПѓП„О±ОёОјОїПЌ: {LTBLUE}{STRING}
-diff --git a/src/lang/hebrew.txt b/src/lang/hebrew.txt
-index cd97ba5fe..fb5dbf1dd 100644
---- a/src/lang/hebrew.txt
-+++ b/src/lang/hebrew.txt
-@@ -2703,7 +2703,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}:Ч‘ЧўЧњ
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Ч‘ЧўЧњЧ™ ЧћЧЎЧ™ЧњЧЄ Ч”ЧЁЧ›Ч‘ЧЄ: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{LTBLUE}{STRING}{BLACK} :ЧЁЧ©Ч•ЧЄ ЧћЧ§Ч•ЧћЧ™ЧЄ
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :ЧђЧ™Чџ
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Ч§Ч•ЧђЧ•ЧЁЧ“Ч™Ч ЧЧ•ЧЄ: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Ч§Ч•ЧђЧ•ЧЁЧ“Ч™Ч ЧЧ•ЧЄ: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{LTBLUE}{DATE_LONG}{BLACK} : ЧЄЧђЧЁЧ™Чљ Ч‘Ч Ч™Ч”
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}{LTBLUE}{STRING}: ЧђЧ•Ч¤Ч™ Ч”ЧЄЧ—Ч Ч”
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK} {LTBLUE}{STRING}: ЧЎЧ•Ч’ Ч”ЧЄЧ—Ч Ч”
-diff --git a/src/lang/hungarian.txt b/src/lang/hungarian.txt
-index 931b1475e..de42765a3 100644
---- a/src/lang/hungarian.txt
-+++ b/src/lang/hungarian.txt
-@@ -2982,7 +2982,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}A villam
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}A vasГєti pГЎlya tulajdonosa: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Helyi Г¶nkormГЎnyzat: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Nincs
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}KoordinГЎtГЎk: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}KoordinГЎtГЎk: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Г‰pГјlt: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}ГЃllomГЎs osztГЎlya: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}ГЃllomГЎs tГ­pusa: {LTBLUE}{STRING}
-diff --git a/src/lang/icelandic.txt b/src/lang/icelandic.txt
-index 2d3bda353..44a916f2b 100644
---- a/src/lang/icelandic.txt
-+++ b/src/lang/icelandic.txt
-@@ -2535,7 +2535,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Eigandi
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Eigandi jГЎrnbrautarspors: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Bæjaryfirvöld: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Enginn
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Hnit: {LTBLUE}{NUM}x{NUM}x{NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Hnit: {LTBLUE}{NUM}x{NUM}x{NUM}x-{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Byggt: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Tegund stöðvar: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Tegund stöðvar: {LTBLUE}{STRING}
-diff --git a/src/lang/indonesian.txt b/src/lang/indonesian.txt
-index f2628aa05..c2947b55b 100644
---- a/src/lang/indonesian.txt
-+++ b/src/lang/indonesian.txt
-@@ -2920,7 +2920,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Pemilik
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Pemilik Rel Kereta: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Pemkot setempat: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Kosong
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinat: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinat: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Dibuat: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Kelas Stasiun: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Tipe Stasiun: {LTBLUE}{STRING}
-diff --git a/src/lang/irish.txt b/src/lang/irish.txt
-index 88d8449d9..ba04daa46 100644
---- a/src/lang/irish.txt
-+++ b/src/lang/irish.txt
-@@ -2912,7 +2912,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}ГљinГ©ir
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}ГљinГ©ir an iarnrГіid: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}ГљdarГЎs ГЎitiГєil: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Ceann ar bith
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}ComhordanГЎidГ­: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}ComhordanГЎidГ­: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}TГіgtha: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Aicme an stГЎisiГєin: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}CineГЎl stГЎisiГєin: {LTBLUE}{STRING}
-diff --git a/src/lang/italian.txt b/src/lang/italian.txt
-index 340ee9d4e..19444aef5 100644
---- a/src/lang/italian.txt
-+++ b/src/lang/italian.txt
-@@ -2886,7 +2886,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Propriet
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Proprietario ferrovia: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}AutoritГ  locale: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Nessuna
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordinate: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordinate: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Costruito il: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Tipo stazione: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Tipo stazione: {LTBLUE}{STRING}
-diff --git a/src/lang/korean.txt b/src/lang/korean.txt
-index 448c73802..5fd406ddb 100644
---- a/src/lang/korean.txt
-+++ b/src/lang/korean.txt
-@@ -2923,7 +2923,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}м „м°»
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}мІ лЏ„ м†Њмњ мЈј: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}м§Ђм—­ л‹№кµ­: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :м—†мќЊ
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}мўЊн‘њ: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}мўЊн‘њ: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}건설날짜: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}м—­ 분лҐ: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}м—­ мў…лҐ: {LTBLUE}{STRING}
-diff --git a/src/lang/latin.txt b/src/lang/latin.txt
-index 88f0a360e..7097884f8 100644
---- a/src/lang/latin.txt
-+++ b/src/lang/latin.txt
-@@ -2911,7 +2911,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Possesso
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Possessor ferriviae: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Auctoritas vicinalis: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Nulla
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordinatae: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordinatae: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Dies struendi: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Classis stationis: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Typus stationis: {LTBLUE}{STRING}
-diff --git a/src/lang/latvian.txt b/src/lang/latvian.txt
-index 2416d61e4..bacbfb1e5 100644
---- a/src/lang/latvian.txt
-+++ b/src/lang/latvian.txt
-@@ -2923,7 +2923,7 @@ STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Dzelzce
- STR_LAND_AREA_INFORMATION_RAIL_OWNER.kas :{BLACK}DzelzceДјa Д«paЕЎniece: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}PaЕЎvaldД«ba: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Neviena
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}KoordinДЃtes: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}KoordinДЃtes: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}UzbЕ«vД“ts: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Stacijas klase: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Stacijas tips: {LTBLUE}{STRING}
-diff --git a/src/lang/lithuanian.txt b/src/lang/lithuanian.txt
-index ebd40a474..4bca69e73 100644
---- a/src/lang/lithuanian.txt
-+++ b/src/lang/lithuanian.txt
-@@ -3078,7 +3078,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Tramvaja
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}GeleЕѕinkelio savininkas: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Vietos valdЕѕia: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :NД—ra
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}KoordinatД—s: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}KoordinatД—s: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Pastatytas: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}StotelД—s rЕ«ЕЎis: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}StotelД—s tipas: {LTBLUE}{STRING}
-diff --git a/src/lang/luxembourgish.txt b/src/lang/luxembourgish.txt
-index 38cece0de..24b831122 100644
---- a/src/lang/luxembourgish.txt
-+++ b/src/lang/luxembourgish.txt
-@@ -2918,7 +2918,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Tramschi
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}SchinnebesГ«tzer: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Gemeng: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Keng
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinaten: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinaten: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Gebaut: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Statiounsklass: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Statiounstyp: {LTBLUE}{STRING}
-diff --git a/src/lang/malay.txt b/src/lang/malay.txt
-index 2f4811261..3e04e3d4a 100644
---- a/src/lang/malay.txt
-+++ b/src/lang/malay.txt
-@@ -2433,7 +2433,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Pemilik
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Pemilik landasan keretapi: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Pihak berkuasa: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Tiada
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinat: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinat: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Dibina: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Kelas stesen: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Jenis stesen: {LTBLUE}{STRING}
-diff --git a/src/lang/norwegian_bokmal.txt b/src/lang/norwegian_bokmal.txt
-index 911b7ba78..02e359b91 100644
---- a/src/lang/norwegian_bokmal.txt
-+++ b/src/lang/norwegian_bokmal.txt
-@@ -2922,7 +2922,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Eier av
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Eier av jernbanespor: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Bystyret: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Ingen
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinater: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinater: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Bygget: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Stasjonstype: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Stasjonstype: {LTBLUE}{STRING}
-diff --git a/src/lang/norwegian_nynorsk.txt b/src/lang/norwegian_nynorsk.txt
-index d45fb4d56..a4329a177 100644
---- a/src/lang/norwegian_nynorsk.txt
-+++ b/src/lang/norwegian_nynorsk.txt
-@@ -2603,7 +2603,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Trikkesp
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Jernbaneskjene-eigar: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Bystyret: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Ingen
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinatar: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinatar: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Byggd: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Stasjonsklasse: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Stasjontype: {LTBLUE}{STRING}
-diff --git a/src/lang/persian.txt b/src/lang/persian.txt
-index 7ebfe1503..d5b98ab5a 100644
---- a/src/lang/persian.txt
-+++ b/src/lang/persian.txt
-@@ -2393,7 +2393,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Щ…Ш§Щ„Ъ©
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Щ…Ш§Щ„Ъ© Ш±ЫЊЩ„ Ш±Ш§Щ‡ ШўЩ‡Щ†: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}ЩЃШ±Щ…Ш§Щ†ШЇШ§Ш± Щ…Ш­Щ„ЫЊ: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Щ‡ЫЊЪ†Ъ©ШЇШ§Щ…
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Щ…Ш®ШЄШµШ§ШЄ: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Щ…Ш®ШЄШµШ§ШЄ: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}ШіШ§Ш®ШЄЩ‡ ШґШЇЩ‡ ШЇШ±: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Ъ©Щ„Ш§Ші Ш§ЫЊШіШЄЪЇШ§Щ‡: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Щ†Щ€Ш№ Ш§ЫЊШіШЄЪЇШ§Щ‡: {LTBLUE}{STRING}
-diff --git a/src/lang/polish.txt b/src/lang/polish.txt
-index c621eb314..ddc00c8c8 100644
---- a/src/lang/polish.txt
-+++ b/src/lang/polish.txt
-@@ -3300,7 +3300,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}WЕ‚aЕ›ci
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}WЕ‚aЕ›ciciel linii kolejowej: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Lokalne wЕ‚adze: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Brak
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}WspГіЕ‚rzД™dne: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}WspГіЕ‚rzД™dne: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Zbudowano: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Rodzaj stacji: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Typ stacji: {LTBLUE}{STRING}
-diff --git a/src/lang/portuguese.txt b/src/lang/portuguese.txt
-index 4d8a23429..e750af281 100644
---- a/src/lang/portuguese.txt
-+++ b/src/lang/portuguese.txt
-@@ -2923,7 +2923,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Dono da
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Dono da linha fГ©rrea: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Autoridade local: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Nenhum
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordenadas: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordenadas: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}ConstruГ­do: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Tipo de estação: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Tipo de estação: {LTBLUE}{STRING}
-diff --git a/src/lang/romanian.txt b/src/lang/romanian.txt
-index 20778ce5a..f3410b16d 100644
---- a/src/lang/romanian.txt
-+++ b/src/lang/romanian.txt
-@@ -2913,7 +2913,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Propriet
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Proprietar al cДѓii ferate: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Autoritatea localДѓ: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Niciuna
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordonate: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordonate: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Data construcЕЈiei: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Clasa staЕЈiei: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Tip staЕЈie: {LTBLUE}{STRING}
-diff --git a/src/lang/russian.txt b/src/lang/russian.txt
-index 534be43c1..1b1e97c9c 100644
---- a/src/lang/russian.txt
-+++ b/src/lang/russian.txt
-@@ -604,6 +604,19 @@ STR_LANDSCAPING_MENU_LANDSCAPING :Ландшаф
- STR_LANDSCAPING_MENU_PLANT_TREES :Высадка деревьев
- STR_LANDSCAPING_MENU_PLACE_SIGN :Поставить метку
-
-+# Underground menu
-+###length 10
-+STR_LANDSCAPING_MENU_SEPARATOR1 :
-+STR_LANDSCAPING_MENU_UNDERGROUND :Спец. конструкции
-+STR_LANDSCAPING_MENU_LAYER_1 :Поверхность
-+STR_LANDSCAPING_MENU_LAYER_2 :Подземелье (-1)
-+STR_LANDSCAPING_MENU_LAYER_3 :Подземелье (-2)
-+STR_LANDSCAPING_MENU_LAYER_4 :Подземелье (-3)
-+STR_LANDSCAPING_MENU_LAYER_5 :Подземелье (-4)
-+STR_LANDSCAPING_MENU_LAYER_6 :Подземелье (-5)
-+STR_LANDSCAPING_MENU_LAYER_7 :Подземелье (-6)
-+STR_LANDSCAPING_MENU_LAYER_8 :Подземелье (-7)
-+
- # Music menu
- ###length 1
- STR_TOOLBAR_SOUND_MUSIC :Звук/музыка
-@@ -3097,7 +3110,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Влад
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Владелец ж/д пути: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Администрация: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Нет
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Координаты: {LTBLUE}{NUM} × {NUM} × {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Координаты: {LTBLUE}{NUM} × {NUM} × {NUM} × -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Построено: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Класс станции: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Тип станции: {LTBLUE}{STRING}
-@@ -5780,3 +5793,35 @@ STR_PLANE :{BLACK}{PLANE}
- STR_SHIP :{BLACK}{SHIP}
-
- STR_TOOLBAR_RAILTYPE_VELOCITY :{STRING} ({VELOCITY})
-+
-+# underground
-+
-+# error
-+STR_ERROR_UNDERGROUND_CAN_T_BUILD_UNDER_GROUND :{WHITE}Не может строиться под землей
-+STR_ERROR_UNDERGROUND_CAN_T_BUILD_OVER_GROUND :{WHITE}Не может строиться на поверхности
-+STR_ERROR_UNDERGROUND_CAN_T_TERRAFORM :{WHITE}Рзменение ландшафта недоступно
-+STR_ERROR_UNDERGROUND_CAN_T_BUILD_PART :{WHITE}Нельзя построить эскалатор...
-+STR_ERROR_UNDERGROUND_CAN_T_BUILD_TOP_PART :{WHITE}Нельзя построить верхнюю часть эскалатора...
-+STR_ERROR_UNDERGROUND_CAN_T_BUILD_BOTTOM_PART :{WHITE}Нельзя построить нижнюю часть эскалатора...
-+
-+# menus
-+STR_UNDERGROUND_LAYER_COUNT :{BLACK}Количество слоев
-+STR_UNDERGROUND_BUILD :{WHITE}Подземелье
-+
-+# underground land types
-+STR_UNDERGROUND_FLAT :Пещера
-+STR_UNDERGROUND_SOLID :Грунт
-+STR_UNDERGROUND_ROCKS :Скалы
-+STR_UNDERGROUND_HEAVY_ROCKS :Твердые породы
-+
-+# underground special build types
-+STR_UNDERGROUND_ESCALATOR :Эскалатор
-+STR_UNDERGROUND_CONNECT :Соединение
-+STR_UNDERGROUND_PIPE :РўСЂСѓР±С‹
-+
-+# underground tool tip
-+STR_UNDERGROUND_TOOLTIP_ESCALATOR :{BLACK}Постройка эскалатора (связь подземной станции с поверхностью)
-+STR_UNDERGROUND_TOOLTIP_CONNECT :{BLACK}Постройка подъема (подземные рельсы выходят наружу)
-+STR_UNDERGROUND_TOOLTIP_PIPE :{BLACK}Трубы (хм... что-то...)
-+
-+# end underground string
-diff --git a/src/lang/serbian.txt b/src/lang/serbian.txt
-index 10f341a6f..27a18ebaa 100644
---- a/src/lang/serbian.txt
-+++ b/src/lang/serbian.txt
-@@ -3113,7 +3113,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Vlasnik
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Vlasnik ЕѕelezniДЌke pruge: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Lokalna vlast: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Nema
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinate: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinate: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}SagraД‘eno: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Klasa stanice: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Vrsta stanice: {LTBLUE}{STRING}
-diff --git a/src/lang/simplified_chinese.txt b/src/lang/simplified_chinese.txt
-index 5f92aff44..f189e145e 100644
---- a/src/lang/simplified_chinese.txt
-+++ b/src/lang/simplified_chinese.txt
-@@ -2922,7 +2922,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}жњ‰иЅЁ
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}й“Ѓи·ЇеЅ’е±ћпјљ{LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}ењ°ж–№ж”їеєњпјљ{LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :жІЎжњ‰
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}еќђж ‡пјљ {LTBLUE}{NUM} Г— {NUM} Г— {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}еќђж ‡пјљ {LTBLUE}{NUM} Г— {NUM} Г— {NUM} Г— -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}е»єйЂ ж—¶й—ґпјљ{LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}车站分类: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}иЅ¦з«™з±»ећ‹: {LTBLUE}{STRING}
-diff --git a/src/lang/slovak.txt b/src/lang/slovak.txt
-index 102592dec..ad034fcfb 100644
---- a/src/lang/slovak.txt
-+++ b/src/lang/slovak.txt
-@@ -2986,7 +2986,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}VlastnГ­
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}VlastnГ­k Еѕeleznice: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Miestna sprГЎva: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :NeznГЎme
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}SГєradnice: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}SГєradnice: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}PostavenГ©: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Trieda stanice: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Typ stanice: {LTBLUE}{STRING}
-diff --git a/src/lang/slovenian.txt b/src/lang/slovenian.txt
-index 7215adc07..9a06c71a3 100644
---- a/src/lang/slovenian.txt
-+++ b/src/lang/slovenian.txt
-@@ -2848,7 +2848,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Lastnik
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Lastnik Еѕeleznice: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Lokalna oblast: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Brez
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinate: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinate: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Zgrajeno: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Razred postaje: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Vrsta postaje: {LTBLUE}{STRING}
-diff --git a/src/lang/spanish.txt b/src/lang/spanish.txt
-index 4af060379..7d30f6587 100644
---- a/src/lang/spanish.txt
-+++ b/src/lang/spanish.txt
-@@ -2920,7 +2920,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Propieta
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Propietario del ferrocarril: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Autoridad local: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Ninguna
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordenadas: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordenadas: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Construido: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Clase de estaciГіn: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Tipo de estaciГіn: {LTBLUE}{STRING}
-diff --git a/src/lang/spanish_MX.txt b/src/lang/spanish_MX.txt
-index 4bfac233f..829699c54 100644
---- a/src/lang/spanish_MX.txt
-+++ b/src/lang/spanish_MX.txt
-@@ -2919,7 +2919,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Propieta
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Propietario del ferrocarril: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Ayuntamiento: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Ninguno
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordenadas: {LTBLUE}{NUM}Г—{NUM}Г—{NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordenadas: {LTBLUE}{NUM}Г—{NUM}Г—{NUM}Г—-{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Construido: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Clase de estaciГіn: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Tipo de estaciГіn: {LTBLUE}{STRING}
-diff --git a/src/lang/swedish.txt b/src/lang/swedish.txt
-index a39e3925a..d4e43ebb1 100644
---- a/src/lang/swedish.txt
-+++ b/src/lang/swedish.txt
-@@ -2920,7 +2920,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Spårvä
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Järnvägens ägare: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Lokala myndigheter: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Ingen
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinater: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinater: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Byggt: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Stationsklass: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Stationstyp: {LTBLUE}{STRING}
-diff --git a/src/lang/tamil.txt b/src/lang/tamil.txt
-index 8894401bc..e84e9080b 100644
---- a/src/lang/tamil.txt
-+++ b/src/lang/tamil.txt
-@@ -2566,7 +2566,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}а®џаЇЌ
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}இரயில்வே உரிமையாளர்: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}а®Ёа®•а®°а®ѕа®џаЇЌа®ља®ї: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :а®’а®©аЇЌа®±аЇЃа®®а®їа®ІаЇЌа®ІаЇ€
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}அச்சுத் தூரங்கள்: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}அச்சுத் தூரங்கள்: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}கட்டப்பட்டது: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}நிலையத்தின் பிரிவு: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}நிலையத்தின் வகை: {LTBLUE}{STRING}
-diff --git a/src/lang/thai.txt b/src/lang/thai.txt
-index 5a9fe48bd..770e775e1 100644
---- a/src/lang/thai.txt
-+++ b/src/lang/thai.txt
-@@ -2628,7 +2628,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}аёњаё№
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}ผู้ครอบครองทางรถไฟ: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}ขึ้นตรงกับผู้ดูแลในท้องถิ่น: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :ไม่มี
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}аё•аёіа№Ѓаё«аё™а№€аё‡: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}аё•аёіа№Ѓаё«аё™а№€аё‡: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}สร้างเมื่อ: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}аё›аёЈаё°а№Ђаё аё—аё‚аё­аё‡аёЄаё–аёІаё™аёµ: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}аёЈаё№аё›а№Ѓаёљаёљаё‚аё­аё‡аёЄаё–аёІаё™аёµ: {LTBLUE}{STRING}
-diff --git a/src/lang/traditional_chinese.txt b/src/lang/traditional_chinese.txt
-index 941462a07..51815a232 100644
---- a/src/lang/traditional_chinese.txt
-+++ b/src/lang/traditional_chinese.txt
-@@ -2716,7 +2716,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}й›»и»Љ
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}йђµи·Їж‰Ђжњ‰иЂ…пјљ{LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}ењ°ж–№ж”їеєњпјљ{LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :з„Ў
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}еє§жЁ™пјљ{LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}еє§жЁ™пјљ{LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}е»єж–јпјљ{LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}и»Љз«™йўЁж јпјљ{LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}и»Љз«™зЁ®йЎћпјљ{LTBLUE}{STRING}
-diff --git a/src/lang/turkish.txt b/src/lang/turkish.txt
-index 0d35521c3..9bb95d6e5 100644
---- a/src/lang/turkish.txt
-+++ b/src/lang/turkish.txt
-@@ -2919,7 +2919,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Tramvay
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Demiryolu sahibi: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Belediyesi: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Hiçbiri
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinatlar: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinatlar: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}YapД±m: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Д°stasyon sД±nД±fД±: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Д°stasyon tГјrГј: {LTBLUE}{STRING}
-diff --git a/src/lang/ukrainian.txt b/src/lang/ukrainian.txt
-index 77530aa42..b78a9b590 100644
---- a/src/lang/ukrainian.txt
-+++ b/src/lang/ukrainian.txt
-@@ -3049,7 +3049,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Влас
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Власник залізниці: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Місцева влада: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Немає
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Координати: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Координати: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Р С–Рє РІРёРїСѓСЃРєСѓ: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Клас станції: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Тип станції: {LTBLUE}{STRING}
-diff --git a/src/lang/vietnamese.txt b/src/lang/vietnamese.txt
-index 478f75c69..499479052 100644
---- a/src/lang/vietnamese.txt
-+++ b/src/lang/vietnamese.txt
-@@ -2922,7 +2922,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Chủ đ
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Chủ đường ray: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Thuб»™c vб»Ѓ Д‘б»‹a phЖ°ЖЎng: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :KhГґng
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}ToбєЎ Д‘б»™: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}ToбєЎ Д‘б»™: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}XГўy lГєc: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}LoбєЎi ga,bбєїn: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Kiб»ѓu ga,bбєїn: {LTBLUE}{STRING}
-diff --git a/src/lang/welsh.txt b/src/lang/welsh.txt
-index 4b970c919..b244655bd 100644
---- a/src/lang/welsh.txt
-+++ b/src/lang/welsh.txt
-@@ -2685,7 +2685,7 @@ STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Perchenn
- STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Perchennog rheilffordd: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Awdurdod Lleol: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Dim
--STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Cyfeirnodau: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
-+STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Cyfeirnodau: {LTBLUE}{NUM} x {NUM} x {NUM} x -{NUM} ({STRING})
- STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Adeiladwyd: {LTBLUE}{DATE_LONG}
- STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Dosbarth gorsaf: {LTBLUE}{STRING}
- STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Math gorsaf: {LTBLUE}{STRING}
-diff --git a/src/layer.cpp b/src/layer.cpp
-new file mode 100644
-index 000000000..aab234e53
---- /dev/null
-+++ b/src/layer.cpp
-@@ -0,0 +1,136 @@
-+/* $Id: map.cpp 23740 2012-01-03 21:32:51Z $ */
-+/*
-+
-+Это модуль, для возможности полноценной игры в трех измерениях
-+(подземелье, метро, итп.)
-+
-+
-+Плоское игровое поле выглядит примерно так:
-+*-----------*
-+| |
-+| |
-+| |
-+*-----------*
-+
-+Мысленно нарежем его на одинаковые части:
-+*---*---*---*
-+| | | |
-+| | | |
-+| | | |
-+*---*---*---*
-+
-+Мысленно соберем части в вертикальную стопочку:
-+*---*
-+| *---*
-+| | *---*
-+| | | |
-+* | | |
-+ * | |
-+ *---*
-+
-+Таким образом имея плоскую карту мы описываем 3д пространство.
-+
-+Для простоты вся карта делится только по оси Y (разрезы параллельны оси X)
-+Деление происходит на 1, 2, 4, или 8 кусочков.
-+
-+Например было выбрано поле 64х64, с 4-мя слоями:
-+Создается карта 64х256, подразумевается, что:
-+
-+ X Y
-+ верхний слой 0--63 0--63
-+ второй слой 0--63 64--127
-+ третий слой 0--63 128--191
-+ четвертый слой 0--63 192--255
-+
-+
-+Обычная карта
-+ MapSizeX х (MapSizeY)
-+
-+Представление в виде слоев
-+ LayerSizeX x (LayerSizeY x LayerCount)
-+
-+Иными словами игровые координаты "плоского" пространства
-+
-+ MapX, MapY, MapZ
-+
-+переходят в координаты нового "3д" пространства
-+
-+ // Константы
-+ LayerCount = число кусочков... (1, или 2, или 4, итд.)
-+ LayerSizeZ = сдвиг слоя по вертикали (например 1)
-+
-+ // Аксиомы
-+ MapSizeX == LayerSizeX
-+ MapSizeY == LayerSizeY * LayerCount
-+
-+ // Расчет координат
-+ LayerIndex = MapY / LayerSizeY
-+
-+ WorldX = MapX
-+ WorldY = MapY - LayerIndex*LayerSizeY
-+ WorldZ = MapZ + LayerIndex*LayerSizeZ
-+*/
-+
-+/** @file map.cpp Base functions related to the map and distances on them. */
-+
-+#include "stdafx.h"
-+#include "debug.h"
-+#include "core/alloc_func.hpp"
-+#include "void_map.h"
-+#include "layer_func.h"
-+#include "layer_type.h"
-+#include "landscape.h"
-+
-+#if defined(_MSC_VER)
-+/* Why the hell is that not in all MSVC headers?? */
-+extern "C" _CRTIMP void __cdecl _assert(void *, void *, unsigned);
-+#endif
-+
-+uint _layer_size_x; ///< Size of the map along the X
-+uint _layer_size_y; ///< Size of the map along the Y
-+uint _layer_count; ///< The number of tiles on the map
-+uint _layer_count_log;
-+uint _layer_size; ///< Layer size (sizeX * sizeY)
-+
-+void InstallLayerSystem(uint size_x, uint size_y, uint layer_count)
-+{
-+ if (!IsInsideMM(layer_count, MIN_LAYER_COUNT, MAX_LAYER_COUNT+1))
-+ error("invalid layer count");
-+
-+ _layer_size_x = size_x;
-+ _layer_size_y = size_y;
-+ _layer_size = size_x * size_y;
-+ _layer_count = layer_count;
-+ _layer_count_log = FindFirstBit(layer_count);
-+}
-+
-+void FixUndergroundHeights()
-+{
-+ uint width = MapSizeX();
-+ uint height = MapSizeY();
-+
-+ /* Layer correct */
-+ for (uint row = 0; (uint)row < height; row++) {
-+
-+ /* Граница между слоями */
-+ if (!(row % LayerSizeY()))
-+ for (uint x = 0; x < width; x++) MakeVoid(width * row + x);
-+
-+ for (uint col = 0; (uint)col < width; col++) {
-+ uint tile = TileXY(row, col);
-+ if (IsUnderground(tile))
-+ SetTileHeight(tile, 0);
-+ }
-+ }
-+}
-+
-+uint8 calculateLayer(const Viewport *vp)
-+{
-+ // Функция ViewportDoDraw вызывается несколько раз с разными параметрами
-+ // Нужно же найти только один слой.
-+ // Опираемся на вьюпорт.
-+
-+ Point pt = InverseRemapCoords(vp->virtual_left+(vp->virtual_width >> 1),vp->virtual_top+(vp->virtual_height >> 1));
-+ TileIndex center = TileVirtXY(pt.x, pt.y);
-+ return LayerIndex(center);
-+}
-diff --git a/src/layer_func.h b/src/layer_func.h
-new file mode 100644
-index 000000000..05022163a
---- /dev/null
-+++ b/src/layer_func.h
-@@ -0,0 +1,102 @@
-+/* $Id: layer_func.h 2012-09-07 18:11:11 constructor $ */
-+
-+/*
-+* Подробое описание см. в layer.cpp
-+*/
-+
-+/** @file layer_func.h Functions related to layer in maps. */
-+
-+#ifndef LAYER_FUNC_H
-+#define LAYER_FUNC_H
-+
-+#include "map_func.h"
-+#include "viewport_type.h"
-+
-+/*
-+*
-+* Инициализация "подземелий"
-+* Количество слоев "1" равносильно игре без "подземелий"
-+*
-+*/
-+void InstallLayerSystem(uint size_x, uint size_y, uint layer_count);
-+
-+/* Корректировка "подземных" слоев
-+* (в будущем слои могут менять высоты -- в пределах соседей) */
-+void FixUndergroundHeights();
-+
-+#define UNDERGROUND_COST_MULTIPLIER(tile) (1 + 100 * (TileHeight(TopTile(tile))-TileHeight(tile)-LayerIndex(tile)))
-+
-+#define FOR_ALL_LAYERS(var) for (uint var = 0; var < LayerCount(); var++)
-+
-+/**
-+ * Get the X component of a tile
-+ * @param tile the tile to get the X component of
-+ * @return the X component
-+ */
-+static inline uint LayerX(TileIndex tile)
-+{
-+ return tile & LayerMaxX();
-+}
-+
-+/**
-+ * Get the Y component of a tile
-+ * @param tile the tile to get the Y component of
-+ * @return the Y component
-+ */
-+static inline uint LayerY(TileIndex tile)
-+{
-+ return (tile >> MapLogX()) & LayerMaxY();
-+}
-+
-+static inline uint LayerIndex(TileIndex tile)
-+{
-+ return (tile >> MapLogX()) / LayerSizeY();
-+}
-+
-+static inline bool IsUnderground(TileIndex tile)
-+{
-+ return LayerIndex(tile) != 0;
-+}
-+
-+/**
-+* Размер слоя.
-+* Можно прибавить к клетке, чтобы получить клетку ниже
-+*/
-+static inline uint LayerSize()
-+{
-+ extern uint _layer_size;
-+ return _layer_size;
-+}
-+
-+/**
-+ * Ищем клетку поверхности для данной (самую верхнюю клетку)
-+ * @param tile the tile to get the Y component of
-+ * @return the Y component
-+ */
-+static inline uint TopTile(TileIndex tile)
-+{
-+ uint layer = LayerIndex(tile);
-+ return (tile - layer * LayerSize());
-+}
-+
-+/* Определить верхняя ли клеточка очень просто */
-+static inline bool IsTopTile(TileIndex tile)
-+{
-+ return (tile < LayerSize());
-+}
-+
-+/* Ищет клетку над данной. (Для самой верхней вернет нижнюю??)
-+*/
-+static inline uint UpTile(TileIndex tile)
-+{
-+ return TILE_MASK(tile - LayerSize());
-+}
-+
-+/* Ищет клетку под данной. (Для самой нижней вернет верхнюю??)
-+*/
-+static inline uint DownTile(TileIndex tile)
-+{
-+ return TILE_MASK(tile + LayerSize());
-+}
-+
-+#endif /* LAYER_FUNC_H */
-diff --git a/src/layer_gui.h b/src/layer_gui.h
-new file mode 100644
-index 000000000..7b791b7e9
---- /dev/null
-+++ b/src/layer_gui.h
-@@ -0,0 +1,17 @@
-+/* $Id: layer_func.h 2012-09-07 18:11:11 constructor $ */
-+
-+/*
-+* Подробое описание см. в layer.cpp
-+*/
-+
-+/** @file layer_gui.h Functions for visualisation map with support layers */
-+
-+#ifndef LAYER_GUI_H
-+#define LAYER_GUI_H
-+
-+#include "layer_func.h"
-+#include "viewport_type.h"
-+
-+uint8 calculateLayer(const Viewport *vp);
-+
-+#endif /* LAYER_GUI_H */
-diff --git a/src/layer_type.h b/src/layer_type.h
-new file mode 100644
-index 000000000..53eafdde6
---- /dev/null
-+++ b/src/layer_type.h
-@@ -0,0 +1,22 @@
-+/* $Id: layer_type.h 21493 2012-09-11 2:21:53Z constructor $ */
-+
-+/*
-+ * 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 layer_type.h Types related to maps. */
-+
-+#ifndef LAYER_TYPE_H
-+#define LAYER_TYPE_H
-+
-+/** Minimal and maximal layer counts */
-+static const uint MIN_LAYER_COUNT_BITS = 0; ///< Minimal size of map is equal to 2 ^ MIN_LAYER_SIZE_BITS
-+static const uint MAX_LAYER_COUNT_BITS = 3; ///< Maximal size of map is equal to 2 ^ MAX_LAYER_SIZE_BITS
-+static const uint MIN_LAYER_COUNT = 1 << MIN_LAYER_COUNT_BITS; ///< Minimal layer count = 1
-+static const uint MAX_LAYER_COUNT = 1 << MAX_LAYER_COUNT_BITS; ///< Maximal layer count = 8
-+
-+
-+#endif /* LAYER_TYPE_H */
-diff --git a/src/main_gui.cpp b/src/main_gui.cpp
-index 6131050cf..5a9a2c2e7 100644
---- a/src/main_gui.cpp
-+++ b/src/main_gui.cpp
-@@ -33,6 +33,9 @@
- #include "guitimer_func.h"
- #include "error.h"
- #include "news_gui.h"
-+#include "gfx_func.h"
-+#include "layer_gui.h"
-+#include "landscape.h"
-
- #include "saveload/saveload.h"
-
-@@ -65,7 +68,7 @@ bool HandlePlacePushButton(Window *w, int widget, CursorID cursor, HighLightStyl
- if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
- w->SetDirty();
-
-- if (w->IsWidgetLowered(widget)) {
-+ if (w->IsWidgetLowered(widget) && mode == _thd.place_mode) {
- ResetObjectToPlace();
- return false;
- }
-@@ -152,6 +155,22 @@ void ZoomInOrOutToCursorWindow(bool in, Window *w)
- }
- }
-
-+void LayerUpOrDownToCursorWindow(bool in, Window *w)
-+{
-+ assert(w != NULL);
-+
-+ if (_game_mode != GM_MENU) {
-+ int layer = calculateLayer(w->viewport) + (in ? -1 : 1);
-+ if ((layer < 0) || (layer >= LayerCount())) return;
-+
-+ Point pt = RemapCoords(0, (in ? -1 : 1) * LayerSizeY() * TILE_SIZE, 0);
-+ w->viewport->dest_scrollpos_x += pt.x;
-+ w->viewport->dest_scrollpos_y += pt.y;
-+ w->InvalidateData();
-+
-+ }
-+}
-+
- void FixTitleGameZoom(int zoom_adjust)
- {
- if (_game_mode != GM_MENU) return;
-@@ -421,7 +440,11 @@ struct MainWindow : Window
- void OnMouseWheel(int wheel) override
- {
- if (_settings_client.gui.scrollwheel_scrolling != 2) {
-- ZoomInOrOutToCursorWindow(wheel < 0, this);
-+ if (_ctrl_pressed) {
-+ LayerUpOrDownToCursorWindow(wheel < 0, this);
-+ } else {
-+ ZoomInOrOutToCursorWindow(wheel < 0, this);
-+ }
- }
- }
-
-diff --git a/src/map.cpp b/src/map.cpp
-index 308e28e49..b49dceb9c 100644
---- a/src/map.cpp
-+++ b/src/map.cpp
-@@ -11,6 +11,7 @@
- #include "debug.h"
- #include "core/alloc_func.hpp"
- #include "water_map.h"
-+#include "layer_func.h"
- #include "string_func.h"
-
- #include "safeguards.h"
-@@ -36,7 +37,7 @@ TileExtended *_me = nullptr; ///< Extended Tiles of the map
- * @param size_x the width of the map along the NE/SW edge
- * @param size_y the 'height' of the map along the SE/NW edge
- */
--void AllocateMap(uint size_x, uint size_y)
-+void AllocateMap(uint size_x, uint size_y, uint layer_count)
- {
- /* Make sure that the map size is within the limits and that
- * size of both axes is a power of 2. */
-@@ -47,6 +48,10 @@ void AllocateMap(uint size_x, uint size_y)
- error("Invalid map size");
- }
-
-+ /* Поскольку слои часть карты, включаем их здесь */
-+ InstallLayerSystem(size_x, size_y, layer_count);
-+ size_y *= layer_count;
-+
- Debug(map, 1, "Allocating map of size {}x{}", size_x, size_y);
-
- _map_log_x = FindFirstBit(size_x);
-@@ -268,6 +273,7 @@ bool CircularTileSearch(TileIndex *tile, uint size, TestTileOnSearchProc proc, v
- /* If tile test is not successful, get one tile up,
- * ready for a test in first circle around center tile */
- *tile = TileAddByDir(*tile, DIR_N);
-+ if (size / 2 == 0) return false;
- return CircularTileSearch(tile, size / 2, 1, 1, proc, user_data);
- } else {
- return CircularTileSearch(tile, size / 2, 0, 0, proc, user_data);
-diff --git a/src/map_func.h b/src/map_func.h
-index b02ba5777..5ee5360c5 100644
---- a/src/map_func.h
-+++ b/src/map_func.h
-@@ -41,7 +41,7 @@ extern Tile *_m;
- */
- extern TileExtended *_me;
-
--void AllocateMap(uint size_x, uint size_y);
-+void AllocateMap(uint size_x, uint size_y, uint layer_count);
-
- /**
- * Logarithm of the map size along the X side.
-@@ -113,6 +113,65 @@ static inline uint MapMaxY()
- return MapSizeY() - 1;
- }
-
-+/**
-+ * Get the size of the layer along the X
-+ * @return the number of tiles along the X of the layer
-+ */
-+static inline uint LayerSizeX()
-+{
-+ extern uint _map_size_x;
-+ return _map_size_x;
-+}
-+
-+/**
-+ * Get the size of the layer along the Y
-+ * @return the number of tiles along the Y of the layer
-+ */
-+static inline uint LayerSizeY()
-+{
-+ extern uint _layer_size_y;
-+ return _layer_size_y;
-+}
-+
-+/**
-+ * Gets the maximum X coordinate within the map, including MP_VOID
-+ * @return the maximum X coordinate
-+ */
-+static inline uint LayerMaxX()
-+{
-+ return LayerSizeX() - 1;
-+}
-+
-+/**
-+ * Gets the maximum Y coordinate within the map, including MP_VOID
-+ * @return the maximum Y coordinate
-+ */
-+static inline uint LayerMaxY()
-+{
-+ return LayerSizeY() - 1;
-+}
-+
-+extern uint _layer_count;
-+
-+/**
-+ * Get the layer counts
-+ * @return the number of layers
-+ */
-+static inline uint LayerCount()
-+{
-+ return _layer_count;
-+}
-+
-+/**
-+ * Get the layer counts
-+ * @return the number of layers
-+ */
-+static inline uint LayerCountLog()
-+{
-+ extern uint _layer_count_log;
-+ return _layer_count_log;
-+}
-+
- /**
- * Scales the given value by the map size, where the given value is
- * for a 256 by 256 map.
-@@ -123,7 +182,7 @@ static inline uint ScaleByMapSize(uint n)
- {
- /* Subtract 12 from shift in order to prevent integer overflow
- * for large values of n. It's safe since the min mapsize is 64x64. */
-- return CeilDiv(n << (MapLogX() + MapLogY() - 12), 1 << 4);
-+ return CeilDiv(n << (MapLogX() + MapLogY() - LayerCountLog() - 12), 1 << 4);
- }
-
-
-diff --git a/src/misc.cpp b/src/misc.cpp
-index c46a1c11d..afbbc7506 100644
---- a/src/misc.cpp
-+++ b/src/misc.cpp
-@@ -8,6 +8,7 @@
- /** @file misc.cpp Misc functions that shouldn't be here. */
-
- #include "stdafx.h"
-+#include "layer_func.h"
- #include "landscape.h"
- #include "news_func.h"
- #include "ai/ai.hpp"
-@@ -61,7 +62,7 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settin
- * related to the new game we're about to start/load. */
- UnInitWindowSystem();
-
-- AllocateMap(size_x, size_y);
-+ AllocateMap(size_x, size_y, 1 << _settings_game.game_creation.layers);
-
- _pause_mode = PM_UNPAUSED;
- _game_speed = 100;
-diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp
-index f0492925d..9523abcd3 100644
---- a/src/misc_gui.cpp
-+++ b/src/misc_gui.cpp
-@@ -210,10 +210,11 @@ public:
- tile_ss << "0x" << std::setfill('0') << std::setw(4) << std::hex << std::uppercase << tile; // 0x%.4X
- std::string tile_str = tile_ss.str(); // Can't pass it directly to SetDParamStr as the string is only a temporary and would be destructed before the GetString call.
-
-- SetDParam(0, TileX(tile));
-- SetDParam(1, TileY(tile));
-+ SetDParam(0, LayerX(tile));
-+ SetDParam(1, LayerY(tile));
- SetDParam(2, GetTileZ(tile));
-- SetDParamStr(3, tile_str);
-+ SetDParam(3, LayerIndex(tile));
-+ SetDParamStr(4, tile_str);
- this->landinfo_data.push_back(GetString(STR_LAND_AREA_INFORMATION_LANDINFO_COORDS));
-
- /* Local authority */
-diff --git a/src/object_cmd.cpp b/src/object_cmd.cpp
-index 7e1e36c1f..d6f46ef09 100644
---- a/src/object_cmd.cpp
-+++ b/src/object_cmd.cpp
-@@ -711,7 +711,7 @@ static bool TryBuildLightHouse()
- */
- static bool TryBuildTransmitter()
- {
-- TileIndex tile = RandomTile();
-+ TileIndex tile = TopTile(RandomTile());
- int h;
- if (IsTileType(tile, MP_CLEAR) && IsTileFlat(tile, &h) && h >= 4 && !IsBridgeAbove(tile)) {
- TileIndex t = tile;
-@@ -775,7 +775,7 @@ void GenerateObjects()
-
- default:
- uint8 view = RandomRange(spec->views);
-- if (CmdBuildObject(RandomTile(), DC_EXEC | DC_AUTO | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING, i, view, {}).Succeeded()) amount--;
-+ if (CmdBuildObject(TopTile(RandomTile()), DC_EXEC | DC_AUTO | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING, i, view, {}).Succeeded()) amount--;
- break;
- }
- }
-diff --git a/src/rail.h b/src/rail.h
-index a0bbb0109..553acf76f 100644
---- a/src/rail.h
-+++ b/src/rail.h
-@@ -158,7 +158,7 @@ public:
- SpriteID signals[SIGTYPE_END][2][2]; ///< signal GUI sprites (type, variant, state)
- } gui_sprites;
-
-- struct {
-+ struct Cursor {
- CursorID rail_ns; ///< Cursor for building rail in N-S direction
- CursorID rail_swne; ///< Cursor for building rail in X direction
- CursorID rail_ew; ///< Cursor for building rail in E-W direction
-diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp
-index 4c34f1ca8..48d377282 100644
---- a/src/rail_cmd.cpp
-+++ b/src/rail_cmd.cpp
-@@ -541,12 +541,12 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u
-
- uint num_new_road_pieces = (road != ROAD_NONE) ? 2 - CountBits(road) : 0;
- if (num_new_road_pieces > 0) {
-- cost.AddCost(num_new_road_pieces * RoadBuildCost(roadtype_road));
-+ cost.AddCost(num_new_road_pieces * RoadBuildCost(roadtype_road) * UNDERGROUND_COST_MULTIPLIER(tile));
- }
-
- uint num_new_tram_pieces = (tram != ROAD_NONE) ? 2 - CountBits(tram) : 0;
- if (num_new_tram_pieces > 0) {
-- cost.AddCost(num_new_tram_pieces * RoadBuildCost(roadtype_tram));
-+ cost.AddCost(num_new_tram_pieces * RoadBuildCost(roadtype_tram) * UNDERGROUND_COST_MULTIPLIER(tile));
- }
-
- if (flags & DC_EXEC) {
-@@ -609,7 +609,7 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u
- YapfNotifyTrackLayoutChange(tile, track);
- }
-
-- cost.AddCost(RailBuildCost(railtype));
-+ cost.AddCost(RailBuildCost(railtype) * UNDERGROUND_COST_MULTIPLIER(tile));
- return cost;
- }
-
-@@ -653,7 +653,7 @@ CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1,
- if (ret.Failed()) return ret;
- }
-
-- cost.AddCost(RailClearCost(GetRailType(tile)));
-+ cost.AddCost(RailClearCost(GetRailType(tile)) * UNDERGROUND_COST_MULTIPLIER(tile));
-
- if (flags & DC_EXEC) {
- if (HasReservedTracks(tile, trackbit)) {
-@@ -687,7 +687,7 @@ CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1,
- if ((present & trackbit) == 0) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
- if (present == (TRACK_BIT_X | TRACK_BIT_Y)) crossing = true;
-
-- cost.AddCost(RailClearCost(GetRailType(tile)));
-+ cost.AddCost(RailClearCost(GetRailType(tile)) * UNDERGROUND_COST_MULTIPLIER(tile));
-
- /* Charge extra to remove signals on the track, if they are there */
- if (HasSignalOnTrack(tile, track)) {
-@@ -1004,7 +1004,7 @@ CommandCost CmdBuildTrainDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, u
- if (!_settings_game.construction.build_on_slopes || !CanBuildDepotByTileh(dir, tileh)) {
- return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
- }
-- cost.AddCost(_price[PR_BUILD_FOUNDATION]);
-+ cost.AddCost(_price[PR_BUILD_FOUNDATION] * UNDERGROUND_COST_MULTIPLIER(tile));
- }
-
- cost.AddCost(DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR));
-@@ -1029,8 +1029,8 @@ CommandCost CmdBuildTrainDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, u
- YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
- }
-
-- cost.AddCost(_price[PR_BUILD_DEPOT_TRAIN]);
-- cost.AddCost(RailBuildCost(railtype));
-+ cost.AddCost(_price[PR_BUILD_DEPOT_TRAIN] * UNDERGROUND_COST_MULTIPLIER(tile));
-+ cost.AddCost(RailBuildCost(railtype) * UNDERGROUND_COST_MULTIPLIER(tile));
- return cost;
- }
-
-@@ -1712,7 +1712,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
- InvalidateWindowData(WC_BUILD_VEHICLE, tile);
- }
- found_convertible_track = true;
-- cost.AddCost(RailConvertCost(type, totype));
-+ cost.AddCost(RailConvertCost(type, totype) * UNDERGROUND_COST_MULTIPLIER(tile));
- break;
-
- default: // RAIL_TILE_NORMAL, RAIL_TILE_SIGNALS
-@@ -1724,7 +1724,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
- }
- }
- found_convertible_track = true;
-- cost.AddCost(RailConvertCost(type, totype) * CountBits(GetTrackBits(tile)));
-+ cost.AddCost(RailConvertCost(type, totype) * CountBits(GetTrackBits(tile)) * UNDERGROUND_COST_MULTIPLIER(tile));
- break;
- }
- break;
-@@ -1787,7 +1787,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
- }
-
- found_convertible_track = true;
-- cost.AddCost((GetTunnelBridgeLength(tile, endtile) + 2) * RailConvertCost(type, totype));
-+ cost.AddCost((GetTunnelBridgeLength(tile, endtile) + 2) * RailConvertCost(type, totype) * UNDERGROUND_COST_MULTIPLIER(tile));
- break;
- }
-
-@@ -1798,7 +1798,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
- }
-
- found_convertible_track = true;
-- cost.AddCost(RailConvertCost(type, totype));
-+ cost.AddCost(RailConvertCost(type, totype) * UNDERGROUND_COST_MULTIPLIER(tile));
- break;
- }
-
-diff --git a/src/road_cmd.cpp b/src/road_cmd.cpp
-index 70a014434..649c4a56a 100644
---- a/src/road_cmd.cpp
-+++ b/src/road_cmd.cpp
-@@ -402,7 +402,7 @@ static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits piec
- }
- } else {
- assert(IsDriveThroughStopTile(tile));
-- cost.AddCost(RoadClearCost(existing_rt) * 2);
-+ cost.AddCost(RoadClearCost(existing_rt) * 2 * UNDERGROUND_COST_MULTIPLIER(tile));
- if (flags & DC_EXEC) {
- /* A full diagonal road tile has two road bits. */
- UpdateCompanyRoadInfrastructure(existing_rt, GetRoadOwner(tile, rtt), -2);
-@@ -883,7 +883,7 @@ do_clear:;
- /* Count pieces */
- CountBits(pieces);
-
-- cost.AddCost(num_pieces * RoadBuildCost(rt));
-+ cost.AddCost(num_pieces * RoadBuildCost(rt) * UNDERGROUND_COST_MULTIPLIER(tile));
-
- if (flags & DC_EXEC) {
- switch (GetTileType(tile)) {
-@@ -1198,7 +1198,7 @@ CommandCost CmdBuildRoadDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, ui
- MarkTileDirtyByTile(tile);
- MakeDefaultName(dep);
- }
-- cost.AddCost(_price[PR_BUILD_DEPOT_ROAD]);
-+ cost.AddCost(_price[PR_BUILD_DEPOT_ROAD] * UNDERGROUND_COST_MULTIPLIER(tile));
- return cost;
- }
-
-diff --git a/src/saveload/compat/map_sl_compat.h b/src/saveload/compat/map_sl_compat.h
-index 84cfb2865..87ff25630 100644
---- a/src/saveload/compat/map_sl_compat.h
-+++ b/src/saveload/compat/map_sl_compat.h
-@@ -16,6 +16,7 @@
- const SaveLoadCompat _map_sl_compat[] = {
- SLC_VAR("dim_x"),
- SLC_VAR("dim_y"),
-+ SLC_VAR("layer_count"),
- };
-
- #endif /* SAVELOAD_COMPAT_MAP_H */
-diff --git a/src/saveload/map_sl.cpp b/src/saveload/map_sl.cpp
-index 07a36d6a3..b86328de8 100644
---- a/src/saveload/map_sl.cpp
-+++ b/src/saveload/map_sl.cpp
-@@ -13,6 +13,7 @@
- #include "compat/map_sl_compat.h"
-
- #include "../map_func.h"
-+#include "../layer_func.h"
- #include "../core/bitmath_func.hpp"
- #include "../fios.h"
- #include <array>
-@@ -25,6 +26,7 @@ static uint32 _map_dim_y;
- static const SaveLoad _map_desc[] = {
- SLEG_CONDVAR("dim_x", _map_dim_x, SLE_UINT32, SLV_6, SL_MAX_VERSION),
- SLEG_CONDVAR("dim_y", _map_dim_y, SLE_UINT32, SLV_6, SL_MAX_VERSION),
-+ SLEG_CONDVAR("layer_count", _layer_count, SLE_UINT32, SLV_UNDERGROUND, SL_MAX_VERSION),
- };
-
- struct MAPSChunkHandler : ChunkHandler {
-@@ -36,6 +38,7 @@ struct MAPSChunkHandler : ChunkHandler {
-
- _map_dim_x = MapSizeX();
- _map_dim_y = MapSizeY();
-+ _layer_count = LayerCount();
-
- SlSetArrayIndex(0);
- SlGlobList(_map_desc);
-@@ -49,7 +52,9 @@ struct MAPSChunkHandler : ChunkHandler {
- SlGlobList(slt);
- if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() != -1) SlErrorCorrupt("Too many MAPS entries");
-
-- AllocateMap(_map_dim_x, _map_dim_y);
-+ if (IsSavegameVersionBefore(SLV_UNDERGROUND))
-+ _layer_count = 1;
-+ AllocateMap(_map_dim_x, _map_dim_y/_layer_count, _layer_count);
- }
-
- void LoadCheck(size_t) const override
-diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h
-index 0d4e0fb98..a8ef3fbe3 100644
---- a/src/saveload/saveload.h
-+++ b/src/saveload/saveload.h
-@@ -307,6 +307,7 @@ enum SaveLoadVersion : uint16 {
- SLV_MULTITILE_DOCKS, ///< 216 PR#7380 Multiple docks per station.
- SLV_TRADING_AGE, ///< 217 PR#7780 Configurable company trading age.
- SLV_ENDING_YEAR, ///< 218 PR#7747 v1.10 Configurable ending year.
-+ SLV_UNDERGROUND, ///< 219 Underground levels.
- SLV_REMOVE_TOWN_CARGO_CACHE, ///< 219 PR#8258 Remove town cargo acceptance and production caches.
-
- /* Patchpacks for a while considered it a good idea to jump a few versions
-diff --git a/src/script/api/script_window.hpp.in b/src/script/api/script_window.hpp.in
-index a1dbb6567..b0c3656dc 100644
---- a/src/script/api/script_window.hpp.in
-+++ b/src/script/api/script_window.hpp.in
-@@ -65,6 +65,7 @@
- #include "../../widgets/town_widget.h"
- #include "../../widgets/transparency_widget.h"
- #include "../../widgets/tree_widget.h"
-+#include "../../widgets/underground_widget.h"
- #include "../../widgets/vehicle_widget.h"
- #include "../../widgets/viewport_widget.h"
- #include "../../widgets/waypoint_widget.h"
-diff --git a/src/settings_table.cpp b/src/settings_table.cpp
-index 4b94a8be7..bf6493391 100644
---- a/src/settings_table.cpp
-+++ b/src/settings_table.cpp
-@@ -17,6 +17,7 @@
- #include "network/network_func.h"
- #include "network/core/config.h"
- #include "pathfinder/pathfinder_type.h"
-+#include "layer_type.h"
- #include "genworld.h"
- #include "train.h"
- #include "news_func.h"
-diff --git a/src/settings_type.h b/src/settings_type.h
-index 9da2655d6..52cd66359 100644
---- a/src/settings_type.h
-+++ b/src/settings_type.h
-@@ -171,6 +171,8 @@ struct GUISettings {
- uint16 refresh_rate; ///< How often we refresh the screen (time between draw-ticks).
- uint16 fast_forward_speed_limit; ///< Game speed to use when fast-forward is enabled.
-
-+ uint32 layer_view_type; ///< зарезервировано (тип отображения)
-+
- 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.
-
-@@ -306,6 +308,7 @@ struct GameCreationSettings {
- Year ending_year; ///< scoring end date
- uint8 map_x; ///< X size of map
- uint8 map_y; ///< Y size of map
-+ uint8 layers; ///< map layer count
- byte land_generator; ///< the landscape generator
- byte oil_refinery_limit; ///< distance oil refineries allowed from map edge
- byte snow_line_height; ///< the configured snow line height (deduced from "snow_coverage")
-diff --git a/src/station.cpp b/src/station.cpp
-index 877f53d4e..14ac504a8 100644
---- a/src/station.cpp
-+++ b/src/station.cpp
-@@ -11,6 +11,7 @@
- #include "company_func.h"
- #include "company_base.h"
- #include "roadveh.h"
-+#include "layer_func.h"
- #include "viewport_func.h"
- #include "viewport_kdtree.h"
- #include "date_func.h"
-@@ -493,7 +494,7 @@ void StationRect::MakeEmpty()
- /**
- * Determines whether a given point (x, y) is within a certain distance of
- * the station rectangle.
-- * @note x and y are in Tile coordinates
-+ * @note x and y are in Tile coordinates (in top layer)
- * @param x X coordinate
- * @param y Y coordinate
- * @param distance The maximum distance a point may have (L1 norm)
-@@ -512,8 +513,10 @@ bool StationRect::IsEmpty() const
-
- CommandCost StationRect::BeforeAddTile(TileIndex tile, StationRectMode mode)
- {
-- int x = TileX(tile);
-- int y = TileY(tile);
-+ /* Станция может находится на любом уровне.
-+ * Но охватывает только поверхность */
-+ int x = LayerX(tile);
-+ int y = LayerY(tile);
- if (this->IsEmpty()) {
- /* we are adding the first station tile */
- if (mode != ADD_TEST) {
-@@ -566,28 +569,35 @@ CommandCost StationRect::BeforeAddRect(TileIndex tile, int w, int h, StationRect
- */
- /* static */ bool StationRect::ScanForStationTiles(StationID st_id, int left_a, int top_a, int right_a, int bottom_a)
- {
-- TileArea ta(TileXY(left_a, top_a), TileXY(right_a, bottom_a));
-- for (TileIndex tile : ta) {
-- if (IsTileType(tile, MP_STATION) && GetStationIndex(tile) == st_id) return true;
-+ /* Станция может находится на любом уровне.
-+ * Значит надо обойти все слои */
-+ TileArea ta(TopTile(TileXY(left_a, top_a)), TopTile(TileXY(right_a, bottom_a)));
-+
-+ FOR_ALL_LAYERS(layer) {
-+ ta.tile = TopTile(ta.tile) + layer * LayerSize();
-+ for (TileIndex tile : ta) {
-+ if (IsTileType(tile, MP_STATION) && GetStationIndex(tile) == st_id) return true;
-+ }
- }
--
- return false;
- }
-
- bool StationRect::AfterRemoveTile(BaseStation *st, TileIndex tile)
- {
-- int x = TileX(tile);
-- int y = TileY(tile);
-+ /* Станция может находится на любом уровне.
-+ * Но охватывает только поверхность */
-+ int x = LayerX(tile);
-+ int y = LayerY(tile);
-
- /* look if removed tile was on the bounding rect edge
- * and try to reduce the rect by this edge
- * do it until we have empty rect or nothing to do */
- for (;;) {
- /* check if removed tile is on rect edge */
-- bool left_edge = (x == this->left);
-- bool right_edge = (x == this->right);
-- bool top_edge = (y == this->top);
-- bool bottom_edge = (y == this->bottom);
-+ bool left_edge = (x == TopTile(this->left));
-+ bool right_edge = (x == TopTile(this->right));
-+ bool top_edge = (y == TopTile(this->top));
-+ bool bottom_edge = (y == TopTile(this->bottom));
-
- /* can we reduce the rect in either direction? */
- bool reduce_x = ((left_edge || right_edge) && !ScanForStationTiles(st->index, x, this->top, x, this->bottom));
-@@ -626,8 +636,13 @@ bool StationRect::AfterRemoveTile(BaseStation *st, TileIndex tile)
-
- bool StationRect::AfterRemoveRect(BaseStation *st, TileArea ta)
- {
-- assert(this->PtInExtendedRect(TileX(ta.tile), TileY(ta.tile)));
-- assert(this->PtInExtendedRect(TileX(ta.tile) + ta.w - 1, TileY(ta.tile) + ta.h - 1));
-+ /* Станция может находится на любом уровне.
-+ * Но охватывает только поверхность */
-+ int topx = LayerX(ta.tile);
-+ int topy = LayerY(ta.tile);
-+
-+ assert(this->PtInExtendedRect(topx, topy));
-+ assert(this->PtInExtendedRect(topx + ta.w - 1, topy + ta.h - 1));
-
- bool empty = this->AfterRemoveTile(st, ta.tile);
- if (ta.w != 1 || ta.h != 1) empty = empty || this->AfterRemoveTile(st, TILE_ADDXY(ta.tile, ta.w - 1, ta.h - 1));
-diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp
-index 1a188252c..c5f3f94ac 100644
---- a/src/station_cmd.cpp
-+++ b/src/station_cmd.cpp
-@@ -11,6 +11,7 @@
- #include "aircraft.h"
- #include "bridge_map.h"
- #include "cmd_helper.h"
-+#include "layer_func.h"
- #include "viewport_func.h"
- #include "viewport_kdtree.h"
- #include "command_func.h"
-@@ -100,21 +101,24 @@ bool IsHangar(TileIndex t)
- * @return Succeeded command (if zero or one station found) or failed command (for two or more stations found).
- */
- template <class T>
--CommandCost GetStationAround(TileArea ta, StationID closest_station, CompanyID company, T **st)
-+CommandCost GetStationAround(TileArea ta, StationID closest_station, CompanyID company, T **st, bool layers=false)
- {
- ta.Expand(1);
-
- /* check around to see if there are any stations there owned by the company */
-- for (TileIndex tile_cur : ta) {
-- if (IsTileType(tile_cur, MP_STATION)) {
-- StationID t = GetStationIndex(tile_cur);
-- if (!T::IsValidID(t) || Station::Get(t)->owner != company) continue;
-- if (closest_station == INVALID_STATION) {
-- closest_station = t;
-- } else if (closest_station != t) {
-- return_cmd_error(STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING);
-+ FOR_ALL_LAYERS(layer) {
-+ for (TileIndex tile_cur : ta) {
-+ if (IsTileType(tile_cur, MP_STATION)) {
-+ StationID t = GetStationIndex(tile_cur);
-+ if (!T::IsValidID(t) || Station::Get(t)->owner != company) continue;
-+ if (closest_station == INVALID_STATION) {
-+ closest_station = t;
-+ } else if (closest_station != t) {
-+ return_cmd_error(STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING);
-+ }
- }
- }
-+ if (!layers) break;
- }
- *st = (closest_station == INVALID_STATION) ? nullptr : T::Get(closest_station);
- return CommandCost();
-@@ -811,7 +815,7 @@ CommandCost CheckBuildableTile(TileIndex tile, uint invalid_dirs, int &allowed_z
- return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
- }
- }
-- cost.AddCost(_price[PR_BUILD_FOUNDATION]);
-+ cost.AddCost(_price[PR_BUILD_FOUNDATION] * UNDERGROUND_COST_MULTIPLIER(tile));
- }
-
- /* The level of this tile must be equal to allowed_z. */
-@@ -1049,7 +1053,7 @@ static CommandCost CheckFlatLandRoadStop(TileArea tile_area, DoCommandFlag flags
- ret = DoCommand(cur_tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
- if (ret.Failed()) return ret;
- cost.AddCost(ret);
-- cost.AddCost(RoadBuildCost(rt) * 2);
-+ cost.AddCost(RoadBuildCost(rt) * 2 * UNDERGROUND_COST_MULTIPLIER(cur_tile));
- }
- }
- }
-@@ -1069,11 +1073,13 @@ CommandCost CanExpandRailStation(const BaseStation *st, TileArea &new_ta, Axis a
- TileArea cur_ta = st->train_station;
-
- /* determine new size of train station region.. */
-- int x = std::min(TileX(cur_ta.tile), TileX(new_ta.tile));
-- int y = std::min(TileY(cur_ta.tile), TileY(new_ta.tile));
-- new_ta.w = std::max(TileX(cur_ta.tile) + cur_ta.w, TileX(new_ta.tile) + new_ta.w) - x;
-- new_ta.h = std::max(TileY(cur_ta.tile) + cur_ta.h, TileY(new_ta.tile) + new_ta.h) - y;
-- new_ta.tile = TileXY(x, y);
-+ /* Фактически, подземная станция ("эскалатор") больше ширины карты.
-+ * Поэтому проверям размер в пределах одного слоя */
-+ int topx = std::min(LayerX(cur_ta.tile), LayerX(new_ta.tile));
-+ int topy = std::min(LayerY(cur_ta.tile), LayerY(new_ta.tile));
-+ new_ta.w = std::max(LayerX(cur_ta.tile) + cur_ta.w, LayerX(new_ta.tile) + new_ta.w) - topx;
-+ new_ta.h = std::max(LayerY(cur_ta.tile) + cur_ta.h, LayerY(new_ta.tile) + new_ta.h) - topy;
-+ new_ta.tile = TileXY(topx, topy);
-
- /* make sure the final size is not too big. */
- if (new_ta.w > _settings_game.station.station_spread || new_ta.h > _settings_game.station.station_spread) {
-@@ -1145,7 +1151,7 @@ void GetStationLayout(byte *layout, uint numtracks, uint plat_len, const Station
- * @return command cost with the error or 'okay'
- */
- template <class T, StringID error_message>
--CommandCost FindJoiningBaseStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, T **st)
-+CommandCost FindJoiningBaseStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, T **st, bool layers=false)
- {
- assert(*st == nullptr);
- bool check_surrounding = true;
-@@ -1171,7 +1177,7 @@ CommandCost FindJoiningBaseStation(StationID existing_station, StationID station
-
- if (check_surrounding) {
- /* Make sure there is no more than one other station around us that is owned by us. */
-- CommandCost ret = GetStationAround(ta, existing_station, _current_company, st);
-+ CommandCost ret = GetStationAround(ta, existing_station, _current_company, st, layers);
- if (ret.Failed()) return ret;
- }
-
-@@ -1190,9 +1196,9 @@ CommandCost FindJoiningBaseStation(StationID existing_station, StationID station
- * @param st 'return' pointer for the found station
- * @return command cost with the error or 'okay'
- */
--static CommandCost FindJoiningStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, Station **st)
-+static CommandCost FindJoiningStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, Station **st, bool layers=false)
- {
-- return FindJoiningBaseStation<Station, STR_ERROR_MUST_REMOVE_RAILWAY_STATION_FIRST>(existing_station, station_to_join, adjacent, ta, st);
-+ return FindJoiningBaseStation<Station, STR_ERROR_MUST_REMOVE_RAILWAY_STATION_FIRST>(existing_station, station_to_join, adjacent, ta, st, layers);
- }
-
- /**
-@@ -1301,8 +1307,8 @@ CommandCost CmdBuildRailStation(TileIndex tile_org, DoCommandFlag flags, uint32
- CommandCost cost = CheckFlatLandRailStation(new_location, flags, axis, &est, rt, affected_vehicles, spec_class, spec_index, plat_len, numtracks);
- if (cost.Failed()) return cost;
- /* Add construction expenses. */
-- cost.AddCost((numtracks * _price[PR_BUILD_STATION_RAIL] + _price[PR_BUILD_STATION_RAIL_LENGTH]) * plat_len);
-- cost.AddCost(numtracks * plat_len * RailBuildCost(rt));
-+ cost.AddCost((numtracks * _price[PR_BUILD_STATION_RAIL] + _price[PR_BUILD_STATION_RAIL_LENGTH]) * plat_len * UNDERGROUND_COST_MULTIPLIER(tile_org));
-+ cost.AddCost(numtracks * plat_len * RailBuildCost(rt) * UNDERGROUND_COST_MULTIPLIER(tile_org));
-
- Station *st = nullptr;
- ret = FindJoiningStation(est, station_to_join, adjacent, new_location, &st);
-@@ -1342,8 +1348,10 @@ CommandCost CmdBuildRailStation(TileIndex tile_org, DoCommandFlag flags, uint32
- byte numtracks_orig;
- Track track;
-
-+ TileIndex top_tile = TopTile(new_location.tile);
- st->train_station = new_location;
-- st->AddFacility(FACIL_TRAIN, new_location.tile);
-+ st->train_station.tile = top_tile;
-+ st->AddFacility(FACIL_TRAIN, tile_org);
-
- st->rect.BeforeAddRect(tile_org, w_org, h_org, StationRect::ADD_TRY);
-
-@@ -1583,7 +1591,7 @@ CommandCost RemoveFromRailBaseStation(TileArea ta, std::vector<T *> &affected_st
- }
-
- /* If we reached here, the tile is valid so increase the quantity of tiles we will remove */
-- quantity++;
-+ quantity += UNDERGROUND_COST_MULTIPLIER(tile);
-
- if (keep_rail || IsStationTileBlocked(tile)) {
- /* Don't refund the 'steel' of the track when we keep the
-@@ -1662,7 +1670,7 @@ CommandCost RemoveFromRailBaseStation(TileArea ta, std::vector<T *> &affected_st
- CommandCost CmdRemoveFromRailStation(TileIndex start, DoCommandFlag flags, uint32 p1, uint32 p2, const std::string &text)
- {
- TileIndex end = p1 == 0 ? start : p1;
-- if (start >= MapSize() || end >= MapSize()) return CMD_ERROR;
-+ if (start >= MapSize() || end >= MapSize() || (LayerIndex(start) != LayerIndex(end))) return CMD_ERROR;
-
- TileArea ta(start, end);
- std::vector<Station *> affected_stations;
-@@ -1725,11 +1733,16 @@ CommandCost RemoveRailStation(T *st, DoCommandFlag flags, Money removal_cost)
- /* determine width and height of platforms */
- TileArea ta = st->train_station;
-
-- assert(ta.w != 0 && ta.h != 0);
-+ /* TileArea is top finite area */
-+ assert(IsTopTile(ta.tile));
-+ assert(ta.IsFinite());
-
- CommandCost cost(EXPENSES_CONSTRUCTION);
-+ /* Check all layers */
-+ FOR_ALL_LAYERS(layer)
- /* clear all areas of the station */
-- for (TileIndex tile : ta) {
-+ for (TileIndex top_tile : ta) {
-+ TileIndex tile = top_tile + layer * LayerSize();
- /* only remove tiles that are actually train station tiles */
- if (st->TileBelongsToRailStation(tile)) {
- std::vector<T*> affected_stations; // dummy
-@@ -2095,13 +2108,21 @@ CommandCost CmdRemoveRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, ui
- /* Bankrupting company is not supposed to remove roads, there may be road vehicles. */
- if (!keep_drive_through_roads && (flags & DC_BANKRUPT)) return CMD_ERROR;
-
-- TileArea roadstop_area(tile, width, height);
-+ /* Это территория удаления остановок (НЕ самих остановок) */
-+ TileArea roadstop_area(TopTile(tile), width, height);
-+
-+ /* TileArea is top finite area */
-+ assert(IsTopTile(roadstop_area.tile));
-+ assert(roadstop_area.IsFinite());
-
- CommandCost cost(EXPENSES_CONSTRUCTION);
- CommandCost last_error(STR_ERROR_THERE_IS_NO_STATION);
- bool had_success = false;
-
-- for (TileIndex cur_tile : roadstop_area) {
-+ /* Check all layers */
-+ FOR_ALL_LAYERS(layer)
-+ for (TileIndex top_tile : roadstop_area) {
-+ TileIndex cur_tile = top_tile + layer * LayerSize();
- /* Make sure the specified tile is a road stop of the correct type */
- if (!IsTileType(cur_tile, MP_STATION) || !IsRoadStop(cur_tile) || (uint32)GetRoadStopType(cur_tile) != GB(p2, 0, 1)) continue;
-
-@@ -2271,6 +2292,10 @@ CommandCost CmdBuildAirport(TileIndex tile, DoCommandFlag flags, uint32 p1, uint
- if (w > _settings_game.station.station_spread || h > _settings_game.station.station_spread) {
- return_cmd_error(STR_ERROR_STATION_TOO_SPREAD_OUT);
- }
-+ /* can't make underground airport */
-+ if (IsUnderground(tile)) {
-+ return_cmd_error(STR_ERROR_UNDERGROUND_CAN_T_BUILD_UNDER_GROUND);
-+ }
-
- AirportTileTableIterator iter(as->table[layout], tile);
- CommandCost cost = CheckFlatLandAirport(iter, flags);
-diff --git a/src/station_gui.cpp b/src/station_gui.cpp
-index ecc7ea77c..221be09c1 100644
---- a/src/station_gui.cpp
-+++ b/src/station_gui.cpp
-@@ -19,6 +19,7 @@
- #include "strings_func.h"
- #include "string_func.h"
- #include "window_func.h"
-+#include "layer_func.h"
- #include "viewport_func.h"
- #include "widgets/dropdown_func.h"
- #include "station_base.h"
-@@ -2211,20 +2212,27 @@ static const T *FindStationsNearby(TileArea ta, bool distant_join)
- _deleted_stations_nearby.clear();
-
- /* Check the inside, to return, if we sit on another station */
-- for (TileIndex t : ta) {
-- if (t < MapSize() && IsTileType(t, MP_STATION) && T::IsValidID(GetStationIndex(t))) return T::GetByTile(t);
-+ FOR_ALL_LAYERS(layer) {
-+ for (TileIndex tile : ta) {
-+ TileIndex t = TopTile(tile) + layer * LayerSize();
-+ if (t < MapSize() && IsTileType(t, MP_STATION) && T::IsValidID(GetStationIndex(t)))
-+ {
-+ if (t == tile) return T::GetByTile(t);
-+ AddNearbyStation<T>(t, &ctx);
-+ }
-+ }
- }
-
- /* Look for deleted stations */
- for (const BaseStation *st : BaseStation::Iterate()) {
- if (T::IsExpected(st) && !st->IsInUse() && st->owner == _local_company) {
- /* Include only within station spread (yes, it is strictly less than) */
-- if (std::max(DistanceMax(ta.tile, st->xy), DistanceMax(TILE_ADDXY(ta.tile, ta.w - 1, ta.h - 1), st->xy)) < _settings_game.station.station_spread) {
-+ if (std::max(DistanceMax(TopTile(ta.tile), TopTile(st->xy)), DistanceMax(TILE_ADDXY(TopTile(ta.tile), ta.w - 1, ta.h - 1), TopTile(st->xy))) < _settings_game.station.station_spread) {
- _deleted_stations_nearby.push_back({st->xy, st->index});
-
- /* Add the station when it's within where we're going to build */
-- if (IsInsideBS(TileX(st->xy), TileX(ctx.tile), ctx.w) &&
-- IsInsideBS(TileY(st->xy), TileY(ctx.tile), ctx.h)) {
-+ if (IsInsideBS(LayerX(st->xy), LayerX(ctx.tile), ctx.w) &&
-+ IsInsideBS(LayerY(st->xy), LayerY(ctx.tile), ctx.h)) {
- AddNearbyStation<T>(st->xy, &ctx);
- }
- }
-@@ -2237,8 +2245,11 @@ static const T *FindStationsNearby(TileArea ta, bool distant_join)
- if (distant_join && std::min(ta.w, ta.h) >= _settings_game.station.station_spread) return nullptr;
- uint max_dist = distant_join ? _settings_game.station.station_spread - std::min(ta.w, ta.h) : 1;
-
-- TileIndex tile = TileAddByDir(ctx.tile, DIR_N);
-- CircularTileSearch(&tile, max_dist, ta.w, ta.h, AddNearbyStation<T>, &ctx);
-+ FOR_ALL_LAYERS(layer) {
-+ ctx.tile = TopTile(ctx.tile) + layer * LayerSize();
-+ TileIndex tile = TileAddByDir(ctx.tile, DIR_N);
-+ CircularTileSearch(&tile, max_dist, ta.w, ta.h, AddNearbyStation<T>, &ctx);
-+ }
-
- return nullptr;
- }
-diff --git a/src/table/settings/game_settings.ini b/src/table/settings/game_settings.ini
-index 79fac7513..f4b7258a0 100644
---- a/src/table/settings/game_settings.ini
-+++ b/src/table/settings/game_settings.ini
-@@ -419,3 +419,12 @@ var = gui.sg_new_nonstop
- from = SLV_22
- to = SLV_93
- def = false
-+
-+[SDT_VAR]
-+base = GameSettings
-+var = game_creation.layers
-+type = SLE_UINT8
-+flags = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC
-+def = 1
-+min = MIN_LAYER_COUNT_BITS
-+max = MAX_LAYER_COUNT_BITS
-diff --git a/src/table/settings/gui_settings.ini b/src/table/settings/gui_settings.ini
-index ad18f8318..5b1a63001 100644
---- a/src/table/settings/gui_settings.ini
-+++ b/src/table/settings/gui_settings.ini
-@@ -848,3 +848,11 @@ min = 1
- max = 65535
- cat = SC_EXPERT
-
-+[SDTC_VAR]
-+var = gui.layer_view_type
-+type = SLE_UINT32
-+flags = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC
-+def = 0
-+min = 0
-+max = UINT32_MAX
-+proc = RedrawScreen
-diff --git a/src/terraform_cmd.cpp b/src/terraform_cmd.cpp
-index eaed9e71c..4778fd050 100644
---- a/src/terraform_cmd.cpp
-+++ b/src/terraform_cmd.cpp
-@@ -8,6 +8,7 @@
- /** @file terraform_cmd.cpp Commands related to terraforming. */
-
- #include "stdafx.h"
-+#include "layer_func.h"
- #include "command_func.h"
- #include "tunnel_map.h"
- #include "bridge_map.h"
-@@ -252,6 +253,10 @@ CommandCost CmdTerraformLand(TileIndex tile, DoCommandFlag flags, uint32 p1, uin
- if (z_N > z_min) tileh |= SLOPE_N;
-
- if (pass == 0) {
-+ /* Terrafrom enable only top layer */
-+ if (IsUnderground(tile)) {
-+ return_cmd_error(STR_ERROR_UNDERGROUND_CAN_T_TERRAFORM);
-+ }
- /* Check if bridge would take damage */
- if (IsBridgeAbove(t)) {
- int bridge_height = GetBridgeHeight(GetSouthernBridgeEnd(t));
-diff --git a/src/tgp.cpp b/src/tgp.cpp
-index 511b998e2..eef52853e 100644
---- a/src/tgp.cpp
-+++ b/src/tgp.cpp
-@@ -12,6 +12,7 @@
- #include "clear_map.h"
- #include "void_map.h"
- #include "genworld.h"
-+#include "layer_func.h"
- #include "core/random_func.hpp"
- #include "landscape_type.h"
-
-@@ -167,6 +168,8 @@ struct HeightMap
- int dim_x; //< height map size_x MapSizeX() + 1
- int size_x; //< MapSizeX()
- int size_y; //< MapSizeY()
-+ int map_x; //< MapSizeX()
-+ int map_y; //< MapSizeY()
-
- /**
- * Height map accessor
-@@ -322,8 +325,11 @@ static inline bool AllocHeightMap()
- {
- assert(_height_map.h.empty());
-
-- _height_map.size_x = MapSizeX();
-- _height_map.size_y = MapSizeY();
-+ _height_map.map_x = MapSizeX();
-+ _height_map.map_y = MapSizeY();
-+
-+ _height_map.size_x = LayerSizeX();
-+ _height_map.size_y = LayerSizeY();
-
- /* Allocate memory block for height map row pointers */
- size_t total_size = (_height_map.size_x + 1) * (_height_map.size_y + 1);
-@@ -1004,8 +1010,8 @@ void GenerateTerrainPerlin()
-
- /* First make sure the tiles at the north border are void tiles if needed. */
- if (_settings_game.construction.freeform_edges) {
-- for (uint x = 0; x < MapSizeX(); x++) MakeVoid(TileXY(x, 0));
-- for (uint y = 0; y < MapSizeY(); y++) MakeVoid(TileXY(0, y));
-+ for (uint x = 0; x < _height_map.map_x; x++) MakeVoid(x);
-+ for (uint y = 0; y < _height_map.map_y - 1; y++) MakeVoid(_height_map.size_x * y);
- }
-
- int max_height = H2I(TGPGetMaxHeight());
-diff --git a/src/tile_map.h b/src/tile_map.h
-index b6c715e8a..c191ab904 100644
---- a/src/tile_map.h
-+++ b/src/tile_map.h
-@@ -14,6 +14,7 @@
- #include "map_func.h"
- #include "core/bitmath_func.hpp"
- #include "settings_type.h"
-+#include "layer_func.h"
-
- /**
- * Returns the height of a tile
-@@ -110,10 +111,10 @@ static inline bool IsInnerTile(TileIndex tile)
- {
- assert(tile < MapSize());
-
-- uint x = TileX(tile);
-- uint y = TileY(tile);
-+ uint x = LayerX(tile);
-+ uint y = LayerY(tile);
-
-- return x < MapMaxX() && y < MapMaxY() && ((x > 0 && y > 0) || !_settings_game.construction.freeform_edges);
-+ return x < LayerMaxX() && y < LayerMaxY() && ((x > 0 && y > 0) || !_settings_game.construction.freeform_edges);
- }
-
- /**
-@@ -134,7 +135,7 @@ static inline void SetTileType(TileIndex tile, TileType type)
- /* VOID tiles (and no others) are exactly allowed at the lower left and right
- * edges of the map. If _settings_game.construction.freeform_edges is true,
- * the upper edges of the map are also VOID tiles. */
-- assert(IsInnerTile(tile) == (type != MP_VOID));
-+ assert(IsInnerTile(tile) == (type != MP_VOID)); // was commented in <underground>
- SB(_m[tile].type, 4, 4, type);
- }
-
-diff --git a/src/tilearea_type.h b/src/tilearea_type.h
-index e6d9bad60..a256832f5 100644
---- a/src/tilearea_type.h
-+++ b/src/tilearea_type.h
-@@ -44,6 +44,16 @@ struct OrthogonalTileArea {
- this->h = 0;
- }
-
-+ inline bool IsEmpty() const
-+ {
-+ return (w==0 && h==0);
-+ }
-+
-+ inline bool IsFinite() const
-+ {
-+ return (w!=0 && h!=0);
-+ }
-+
- bool Intersects(const OrthogonalTileArea &ta) const;
-
- bool Contains(TileIndex tile) const;
-diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp
-index f5b3fa3b7..f4185426d 100644
---- a/src/toolbar_gui.cpp
-+++ b/src/toolbar_gui.cpp
-@@ -11,7 +11,10 @@
- #include "gui.h"
- #include "window_gui.h"
- #include "window_func.h"
-+#include "layer_gui.h"
-+#include "layer_func.h"
- #include "viewport_func.h"
-+#include "landscape.h"
- #include "command_func.h"
- #include "vehicle_gui.h"
- #include "rail_gui.h"
-@@ -21,6 +24,7 @@
- #include "vehicle_func.h"
- #include "sound_func.h"
- #include "terraform_gui.h"
-+#include "underground_gui.h"
- #include "strings_func.h"
- #include "company_func.h"
- #include "company_gui.h"
-@@ -995,6 +999,39 @@ static CallBackFunction MenuClickForest(int index)
- return CBF_NONE;
- }
-
-+/* --- Underground button menu --- */
-+
-+/**
-+ * Handle click on the entry in the underground menu.
-+ *
-+ * @param index Menu entry clicked.
-+ * @return #CBF_NONE
-+ */
-+static CallBackFunction MenuClickUnderground(int index)
-+{
-+ if (index==0) {
-+ ShowUndergroundToolbar();
-+ return CBF_NONE;
-+ }
-+ index -= 1;
-+ if ((index<0) || (uint(index) >= LayerCount()))
-+ return CBF_NONE;
-+ Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
-+ int delta_layer = calculateLayer(w->viewport) - index;
-+ Point pt = RemapCoords(0, -delta_layer * LayerSizeY() * TILE_SIZE, 0);
-+ w->viewport->dest_scrollpos_x += pt.x;
-+ w->viewport->dest_scrollpos_y += pt.y;
-+ w->InvalidateData();
-+ return CBF_NONE;
-+}
-+
-+static CallBackFunction ToolbarUndergroundClick(Window *w)
-+{
-+ PopupMainToolbMenu(w, WID_TN_UNDERGROUND, STR_LANDSCAPING_MENU_UNDERGROUND, 1+LayerCount());
-+ if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
-+ return CBF_NONE;
-+}
-+
- /* --- Music button menu --- */
-
- static CallBackFunction ToolbarMusicClick(Window *w)
-@@ -1305,9 +1342,10 @@ static MenuClickedProc * const _menu_clicked_procs[] = {
- MenuClickBuildWater, // 24
- MenuClickBuildAir, // 25
- MenuClickForest, // 26
-- MenuClickMusicWindow, // 27
-- MenuClickNewspaper, // 28
-- MenuClickHelp, // 29
-+ MenuClickUnderground, // 27
-+ MenuClickMusicWindow, // 28
-+ MenuClickNewspaper, // 29
-+ MenuClickHelp, // 30
- };
-
- /** Full blown container to make it behave exactly as we want :) */
-@@ -1472,7 +1510,7 @@ class NWidgetMainToolbarContainer : public NWidgetToolbarContainer {
- const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const override
- {
- static const uint SMALLEST_ARRANGEMENT = 14;
-- static const uint BIGGEST_ARRANGEMENT = 20;
-+ static const uint BIGGEST_ARRANGEMENT = 21;
-
- /* The number of buttons of each row of the toolbar should match the number of items which we want to be visible.
- * The total number of buttons should be equal to arrangable_count * 2.
-@@ -1739,6 +1777,67 @@ class NWidgetMainToolbarContainer : public NWidgetToolbarContainer {
- WID_TN_ZOOM_OUT,
- WID_TN_SWITCH_BAR,
- };
-+ static const byte arrange21[] = {
-+ WID_TN_PAUSE,
-+ WID_TN_FAST_FORWARD,
-+ WID_TN_SETTINGS,
-+ WID_TN_SMALL_MAP,
-+ WID_TN_TOWNS,
-+ WID_TN_SUBSIDIES,
-+ WID_TN_STATIONS,
-+ WID_TN_FINANCES,
-+ WID_TN_COMPANIES,
-+ WID_TN_STORY,
-+ WID_TN_GOAL,
-+ WID_TN_GRAPHS,
-+ WID_TN_LEAGUE,
-+ WID_TN_INDUSTRIES,
-+ WID_TN_TRAINS,
-+ WID_TN_ROADVEHS,
-+ WID_TN_SHIPS,
-+ WID_TN_AIRCRAFT,
-+ WID_TN_ZOOM_IN,
-+ WID_TN_ZOOM_OUT,
-+ WID_TN_RAILS,
-+ WID_TN_ROADS,
-+ WID_TN_WATER,
-+ WID_TN_AIR,
-+ WID_TN_LANDSCAPE,
-+ WID_TN_UNDERGROUND,
-+ WID_TN_MUSIC_SOUND,
-+ WID_TN_MESSAGES,
-+ WID_TN_HELP,
-+ // lower toolbar
-+ WID_TN_PAUSE,
-+ WID_TN_FAST_FORWARD,
-+ WID_TN_SAVE,
-+ WID_TN_SMALL_MAP,
-+ WID_TN_TOWNS,
-+ WID_TN_SUBSIDIES,
-+ WID_TN_STATIONS,
-+ WID_TN_FINANCES,
-+ WID_TN_COMPANIES,
-+ WID_TN_STORY,
-+ WID_TN_GOAL,
-+ WID_TN_GRAPHS,
-+ WID_TN_LEAGUE,
-+ WID_TN_INDUSTRIES,
-+ WID_TN_TRAINS,
-+ WID_TN_ROADVEHS,
-+ WID_TN_SHIPS,
-+ WID_TN_AIRCRAFT,
-+ WID_TN_ZOOM_IN,
-+ WID_TN_ZOOM_OUT,
-+ WID_TN_RAILS,
-+ WID_TN_ROADS,
-+ WID_TN_WATER,
-+ WID_TN_AIR,
-+ WID_TN_LANDSCAPE,
-+ WID_TN_UNDERGROUND,
-+ WID_TN_MUSIC_SOUND,
-+ WID_TN_MESSAGES,
-+ WID_TN_HELP,
-+ };
- static const byte arrange_all[] = {
- WID_TN_PAUSE,
- WID_TN_FAST_FORWARD,
-@@ -1767,6 +1866,7 @@ class NWidgetMainToolbarContainer : public NWidgetToolbarContainer {
- WID_TN_WATER,
- WID_TN_AIR,
- WID_TN_LANDSCAPE,
-+ WID_TN_UNDERGROUND,
- WID_TN_MUSIC_SOUND,
- WID_TN_MESSAGES,
- WID_TN_HELP
-@@ -1781,7 +1881,7 @@ class NWidgetMainToolbarContainer : public NWidgetToolbarContainer {
- }
-
- /* Introduce the split toolbar */
-- static const byte * const arrangements[] = { arrange14, arrange15, arrange16, arrange17, arrange18, arrange19, arrange20 };
-+ static const byte * const arrangements[] = { arrange14, arrange15, arrange16, arrange17, arrange18, arrange19, arrange20, arrange21 };
-
- button_count = arrangable_count = full_buttons;
- spacer_count = this->spacers;
-@@ -1938,6 +2038,7 @@ static ToolbarButtonProc * const _toolbar_button_procs[] = {
- ToolbarBuildWaterClick,
- ToolbarBuildAirClick,
- ToolbarForestClick,
-+ ToolbarUndergroundClick,
- ToolbarMusicClick,
- ToolbarNewspaperClick,
- ToolbarHelpClick,
-@@ -2186,6 +2287,7 @@ static NWidgetBase *MakeMainToolbar(int *biggest_index)
- SPR_IMG_BUILDWATER, // WID_TN_WATER
- SPR_IMG_BUILDAIR, // WID_TN_AIR
- SPR_IMG_LANDSCAPING, // WID_TN_LANDSCAPE
-+ SPR_IMG_LANDSCAPING, // WID_TN_UNDERGROUND
- SPR_IMG_MUSIC, // WID_TN_MUSIC_SOUND
- SPR_IMG_MESSAGES, // WID_TN_MESSAGES
- SPR_IMG_QUERY, // WID_TN_HELP
-diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp
-index 2863b4d6f..e2f8d65b4 100644
---- a/src/town_cmd.cpp
-+++ b/src/town_cmd.cpp
-@@ -12,6 +12,7 @@
- #include "road_internal.h" /* Cleaning up road bits */
- #include "road_cmd.h"
- #include "landscape.h"
-+#include "layer_func.h"
- #include "viewport_func.h"
- #include "viewport_kdtree.h"
- #include "cmd_helper.h"
-@@ -2157,7 +2158,7 @@ static Town *CreateRandomTown(uint attempts, uint32 townnameparts, TownSize size
-
- do {
- /* Generate a tile index not too close from the edge */
-- TileIndex tile = AlignTileToGrid(RandomTile(), layout);
-+ TileIndex tile = AlignTileToGrid(TopTile(RandomTile()), layout);
-
- /* if we tried to place the town on water, slide it over onto
- * the nearest likely-looking spot */
-@@ -2330,6 +2331,9 @@ static inline bool CanBuildHouseHere(TileIndex tile, bool noslope)
- Slope slope = GetTileSlope(tile);
- if ((noslope && slope != SLOPE_FLAT) || IsSteepSlope(slope)) return false;
-
-+ /* Недопустимо строительство объекта под землей */
-+ if (IsUnderground(tile)) return false;
-+
- /* at least one RoadTypes allow building the house here? */
- if (!RoadTypesAllowHouseHere(tile)) return false;
-
-@@ -2765,6 +2769,8 @@ CommandCost CmdRenameTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
- InvalidateWindowData(WC_TOWN_DIRECTORY, 0, TDIWD_FORCE_RESORT);
- ClearAllStationCachedNames();
- ClearAllIndustryCachedNames();
-+ InvalidateWindowClassesData(WC_TOWN_VIEW);
-+ InvalidateWindowClassesData(WC_INDUSTRY_VIEW);
- UpdateAllStationVirtCoords();
- }
- return CommandCost();
-diff --git a/src/tree_cmd.cpp b/src/tree_cmd.cpp
-index 237b34fff..b3671bbfd 100644
---- a/src/tree_cmd.cpp
-+++ b/src/tree_cmd.cpp
-@@ -11,6 +11,7 @@
- #include "clear_map.h"
- #include "landscape.h"
- #include "tree_map.h"
-+#include "layer_func.h"
- #include "viewport_func.h"
- #include "command_func.h"
- #include "town.h"
-@@ -72,7 +73,8 @@ static bool CanPlantTreesOnTile(TileIndex tile, bool allow_desert)
-
- case MP_CLEAR:
- return !IsBridgeAbove(tile) && !IsClearGround(tile, CLEAR_FIELDS) && GetRawClearGround(tile) != CLEAR_ROCKS &&
-- (allow_desert || !IsClearGround(tile, CLEAR_DESERT));
-+ (allow_desert || !IsClearGround(tile, CLEAR_DESERT))
-+ && !IsUnderground(tile);
-
- default: return false;
- }
-@@ -187,7 +189,7 @@ static void PlaceTree(TileIndex tile, uint32 r)
- static void PlaceTreeGroups(uint num_groups)
- {
- do {
-- TileIndex center_tile = RandomTile();
-+ TileIndex center_tile = TopTile(RandomTile());
-
- for (uint i = 0; i < DEFAULT_TREE_STEPS; i++) {
- uint32 r = Random();
-@@ -252,7 +254,7 @@ void PlaceTreesRandomly()
- if (_game_mode == GM_EDITOR) i /= EDITOR_TREE_DIV;
- do {
- uint32 r = Random();
-- TileIndex tile = RandomTileSeed(r);
-+ TileIndex tile = TopTile(RandomTileSeed(r));
-
- IncreaseGeneratingWorldProgress(GWP_TREE);
-
-@@ -281,7 +283,7 @@ void PlaceTreesRandomly()
-
- do {
- uint32 r = Random();
-- TileIndex tile = RandomTileSeed(r);
-+ TileIndex tile = TopTile(RandomTileSeed(r));
-
- IncreaseGeneratingWorldProgress(GWP_TREE);
-
-@@ -392,6 +394,10 @@ CommandCost CmdPlantTree(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
- const byte tree_to_plant = GB(p1, 0, 8); // We cannot use Extract as min and max are climate specific.
-
- if (p2 >= MapSize()) return CMD_ERROR;
-+
-+ /* tree only top layer */
-+ if (IsUnderground(p2)) return CMD_ERROR;
-+
- /* Check the tree type within the current climate */
- if (tree_to_plant != TREE_INVALID && !IsInsideBS(tree_to_plant, _tree_base_by_landscape[_settings_game.game_creation.landscape], _tree_count_by_landscape[_settings_game.game_creation.landscape])) return CMD_ERROR;
-
-@@ -846,7 +852,7 @@ void OnTick_Trees()
- /* place a tree at a random rainforest spot */
- if (_settings_game.game_creation.landscape == LT_TROPIC) {
- for (uint c = ScaleByMapSize(1); c > 0; c--) {
-- if ((r = Random(), tile = RandomTileSeed(r), GetTropicZone(tile) == TROPICZONE_RAINFOREST) &&
-+ if ((r = Random(), tile = TopTile(RandomTileSeed(r)), GetTropicZone(tile) == TROPICZONE_RAINFOREST) &&
- CanPlantTreesOnTile(tile, false) &&
- (tree = GetRandomTreeType(tile, GB(r, 24, 8))) != TREE_INVALID) {
- PlantTreesOnTile(tile, tree, 0, 0);
-@@ -858,7 +864,7 @@ void OnTick_Trees()
-
- /* place a tree at a random spot */
- r = Random();
-- tile = RandomTileSeed(r);
-+ tile = TopTile(RandomTileSeed(r));
- if (CanPlantTreesOnTile(tile, false) && (tree = GetRandomTreeType(tile, GB(r, 24, 8))) != TREE_INVALID) {
- PlantTreesOnTile(tile, tree, 0, 0);
- }
-diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp
-index 5181dfdca..98aaf2771 100644
---- a/src/tunnelbridge_cmd.cpp
-+++ b/src/tunnelbridge_cmd.cpp
-@@ -13,6 +13,7 @@
-
- #include "stdafx.h"
- #include "newgrf_object.h"
-+#include "layer_func.h"
- #include "viewport_func.h"
- #include "cmd_helper.h"
- #include "command_func.h"
-@@ -309,6 +310,10 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u
- return_cmd_error(STR_ERROR_CAN_T_START_AND_END_ON);
- }
-
-+ if (IsUnderground(tile_start) || IsUnderground(tile_end)) {
-+ return_cmd_error(STR_ERROR_UNDERGROUND_CAN_T_BUILD_UNDER_GROUND);
-+ }
-+
- Axis direction;
- if (TileX(tile_start) == TileX(tile_end)) {
- direction = AXIS_Y;
-@@ -702,6 +707,12 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1,
- for (;;) {
- end_tile += delta;
- if (!IsValidTile(end_tile)) return_cmd_error(STR_ERROR_TUNNEL_THROUGH_MAP_BORDER);
-+
-+
-+ if (IsUnderground(start_tile) || IsUnderground(end_tile)) {
-+ return_cmd_error(STR_ERROR_UNDERGROUND_CAN_T_BUILD_UNDER_GROUND);
-+ }
-+
- end_tileh = GetTileSlope(end_tile, &end_z);
-
- if (start_z == end_z) break;
-diff --git a/src/underground_gui.cpp b/src/underground_gui.cpp
-new file mode 100644
-index 000000000..be4ebe4e5
---- /dev/null
-+++ b/src/underground_gui.cpp
-@@ -0,0 +1,321 @@
-+/* $Id: terraform_gui.cpp 23547 2011-12-16 18:21:13Z truebrain $ */
-+
-+/*
-+ * 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 terraform_gui.cpp GUI related to terraforming the map. */
-+
-+#include "stdafx.h"
-+#include "clear_map.h"
-+#include "company_func.h"
-+#include "company_base.h"
-+#include "gui.h"
-+#include "window_gui.h"
-+#include "window_func.h"
-+#include "layer_func.h"
-+#include "viewport_func.h"
-+#include "command_func.h"
-+#include "signs_func.h"
-+#include "sound_func.h"
-+#include "base_station_base.h"
-+#include "textbuf_gui.h"
-+#include "genworld.h"
-+#include "tree_map.h"
-+#include "landscape_type.h"
-+#include "tilehighlight_func.h"
-+#include "strings_func.h"
-+#include "newgrf_object.h"
-+#include "newgrf_station.h"
-+#include "object.h"
-+#include "hotkeys.h"
-+#include "engine_base.h"
-+
-+#include "widgets/underground_widget.h"
-+
-+#include "table/strings.h"
-+#include "error.h"
-+
-+void ShowError(TileIndex tile, CommandCost res, uint32 cmd)
-+{
-+ int x = TileX(tile) * TILE_SIZE;
-+ int y = TileY(tile) * TILE_SIZE;
-+ StringID error_part1 = GB(cmd, 16, 16);
-+
-+ if (IsLocalCompany() && error_part1 != 0) {
-+ ShowErrorMessage(error_part1, res.GetErrorMessage(), WL_INFO, x, y, res.GetTextRefStackGRF(), res.GetTextRefStackSize(), res.GetTextRefStack());
-+ }
-+}
-+
-+
-+/**
-+ * Place a escalator.
-+ * @param tile Position to place or start dragging a station.
-+ */
-+static void PlaceUnderground_Escalator(TileIndex tile)
-+{
-+ RailType railtype = RAILTYPE_RAIL;
-+ Axis orientation = AXIS_X;
-+ StationClassID station_class = STAT_CLASS_DFLT;
-+ byte station_type = 0;
-+
-+ uint32 p1 = railtype | orientation << 4 | 1 << 8 | 1 << 16 | _ctrl_pressed << 24;
-+ uint32 p2 = station_class | station_type << 8 | INVALID_STATION << 16;
-+
-+ int w = 1;
-+ int h = 1;
-+
-+ uint top_tile = TopTile(tile);
-+ uint base_tile = tile;
-+ bool from_top = false; // Строим от верхнего слоя
-+
-+ if (top_tile == base_tile)
-+ {
-+ from_top = true;
-+ base_tile += LayerSize();
-+ };
-+
-+ uint32 cmdS = CMD_BUILD_RAIL_STATION | CMD_MSG(STR_ERROR_UNDERGROUND_CAN_T_BUILD_PART);
-+ uint32 cmdT = CMD_BUILD_RAIL_STATION | CMD_MSG(STR_ERROR_UNDERGROUND_CAN_T_BUILD_TOP_PART);
-+ uint32 cmdB = CMD_BUILD_RAIL_STATION | CMD_MSG(STR_ERROR_UNDERGROUND_CAN_T_BUILD_BOTTOM_PART);
-+ CommandContainer cmdTop = { top_tile, p1, p2, cmdT, CcStation, "" };
-+ CommandContainer cmdBase = { base_tile, p1, p2, cmdB, CcStation, "" };
-+
-+ DoCommandFlag flags = DC_AUTO | DC_NO_WATER;
-+ CommandCost resTop;
-+ CommandCost res;
-+
-+ // Проверяем возможность постройки верха и низа:
-+ resTop=DoCommand(&cmdTop, flags | DC_QUERY_COST);
-+ if (resTop.Failed())
-+ {
-+ ShowError(tile, resTop, cmdT);
-+ return;
-+ }
-+
-+ res=DoCommand(&cmdBase, flags | DC_QUERY_COST);
-+ if (res.Failed())
-+ {
-+ ShowError(tile, res, cmdB);
-+ return;
-+ }
-+
-+ res.AddCost(resTop.GetCost());
-+ if (_shift_pressed || !CheckCompanyHasMoney(res))
-+ {
-+ if (res.Failed()) ShowError(tile, res, cmdS);
-+ else ShowEstimatedCostOrIncome(res.GetCost(), TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE);
-+ return;
-+ }
-+
-+ // Станции могут быть сверху и снизу.
-+ // Чтобы не было конфликта, нужно строить от активного слоя
-+ CommandContainer *cmd1 = from_top ? &cmdTop : &cmdBase;
-+ CommandContainer *cmd2 = from_top ? &cmdBase : &cmdTop;
-+
-+ // Строим уровень (в активном слое)
-+ res=DoCommand(cmd1, flags | DC_EXEC);
-+ assert(!res.Failed());
-+
-+ // Уточняем параметры
-+ StationID station = GetStationIndex(cmd1->tile);
-+ cmd2->p2 = station_class | station_type << 8 | station << 16;
-+
-+ // Строим уровень (в другом слое)
-+ res=DoCommand(cmd2, flags | DC_EXEC);
-+ assert(!res.Failed());
-+}
-+
-+/** Underground toolbar managing class. */
-+struct UndergroundToolbarWindow : Window {
-+ int last_user_action; ///< Last started user action.
-+
-+ UndergroundToolbarWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc)
-+ {
-+ /* This is needed as we like to have the tree available on OnInit. */
-+ this->CreateNestedTree(desc);
-+ this->FinishInitNested(window_number);
-+ this->last_user_action = WIDGET_LIST_END;
-+ }
-+
-+ ~UndergroundToolbarWindow()
-+ {
-+ }
-+
-+ virtual void OnInit()
-+ {
-+ }
-+
-+ virtual void OnClick(Point pt, int widget, int click_count)
-+ {
-+ switch (widget) {
-+ case WID_UT_BUILD_ESCALATOR: // WID_TT_BUILD_ESCALATOR
-+ HandlePlacePushButton(this, WID_UT_BUILD_ESCALATOR, SPR_CURSOR_RAIL_STATION, HT_RECT);
-+ this->last_user_action = widget;
-+ break;
-+
-+ case WID_UT_DEMOLISH: // Demolish aka dynamite button
-+ HandlePlacePushButton(this, WID_UT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL);
-+ this->last_user_action = widget;
-+ break;
-+
-+ default: NOT_REACHED();
-+ }
-+ }
-+
-+ virtual void OnTimeout()
-+ {
-+ }
-+
-+ virtual void OnPlaceObject(Point pt, TileIndex tile)
-+ {
-+ switch (this->last_user_action) {
-+ case WID_UT_BUILD_ESCALATOR:
-+ PlaceUnderground_Escalator(tile);
-+ break;
-+
-+ case WID_UT_DEMOLISH: // Demolish aka dynamite button
-+ PlaceProc_DemolishArea(tile);
-+ break;
-+
-+ default: NOT_REACHED();
-+ }
-+ }
-+
-+ virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt)
-+ {
-+ VpSelectTilesWithMethod(pt.x, pt.y, select_method);
-+ }
-+
-+ virtual Point OnInitialPosition(const WindowDesc *desc, int16 sm_width, int16 sm_height, int window_number)
-+ {
-+ Point pt = GetToolbarAlignedWindowPosition(sm_width);
-+ pt.y += sm_height;
-+ return pt;
-+ }
-+
-+ virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile)
-+ {
-+ if (pt.x != -1) {
-+ switch (select_proc) {
-+ default: NOT_REACHED();
-+ case DDSP_DEMOLISH_AREA:
-+ GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
-+ break;
-+ }
-+ }
-+ }
-+
-+ virtual void OnPlaceObjectAbort()
-+ {
-+ CloseWindowById(WC_BUILD_OBJECT, 0);
-+ this->RaiseButtons();
-+ }
-+
-+ static HotkeyList hotkeys;
-+};
-+
-+/**
-+ * Handler for global hotkeys of the UndergroundToolbarWindow.
-+ * @param hotkey Hotkey
-+ * @return ES_HANDLED if hotkey was accepted.
-+ */
-+static EventState UndergroundToolbarGlobalHotkeys(int hotkey)
-+{
-+ if (_game_mode != GM_NORMAL) return ES_NOT_HANDLED;
-+/* TODO Window *w = ShowAIDebugWindow(INVALID_COMPANY);
-+ if (w == NULL) return ES_NOT_HANDLED;
-+ return w->OnHotkey(hotkey); */
-+}
-+
-+EventState UndergroundToolbarGlobalHotkeys(uint16 key, uint16 keycode)
-+{
-+/* int num = CheckHotkeyMatch<UndergroundToolbarWindow>(_underground_hotkeys, keycode, NULL, true);
-+ if (num == -1) return ES_NOT_HANDLED;
-+ Window *w = ShowUndergroundToolbar(NULL); TODO
-+ if (w == NULL) return ES_NOT_HANDLED;
-+ return w->OnKeyPress(key, keycode);
-+}
-+ int num = CheckHotkeyMatch(underground_hotkeys, keycode, this);
-+ if (num == -1) return ES_NOT_HANDLED;
-+ this->OnClick(Point(), num, 1);
-+ return ES_HANDLED;
-++static EventState AIDebugGlobalHotkeys(int hotkey)
-++{
-++ if (_game_mode != GM_NORMAL) return ES_NOT_HANDLED;
-++ Window *w = ShowAIDebugWindow(INVALID_COMPANY);
-++ if (w == NULL) return ES_NOT_HANDLED;
-++ return w->OnHotkey(hotkey);
-++}
-+-EventState AIDebugGlobalHotkeys(uint16 key, uint16 keycode)
-+-{
-+- int num = CheckHotkeyMatch<AIDebugWindow>(_aidebug_hotkeys, keycode, NULL, true);
-+- if (num == -1) return ES_NOT_HANDLED;
-+- Window *w = ShowAIDebugWindow(INVALID_COMPANY);
-+- if (w == NULL) return ES_NOT_HANDLED;
-+- return w->OnKeyPress(key, keycode);
-+-}
-+- */
-+ return ES_NOT_HANDLED;
-+}
-+
-+static Hotkey underground_hotkeys[] = {
-+ Hotkey('D' | WKC_GLOBAL_HOTKEY, "dynamite", WID_UT_DEMOLISH),
-+ Hotkey('0', "placeescalator", WID_UT_BUILD_ESCALATOR),
-+ HOTKEY_LIST_END
-+};
-+HotkeyList UndergroundToolbarWindow::hotkeys("undergroundtoolbar", underground_hotkeys, UndergroundToolbarGlobalHotkeys);
-+
-+static const NWidgetPart _nested_underground_widgets[] = {
-+ NWidget(NWID_HORIZONTAL),
-+ NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
-+ NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_UNDERGROUND_BUILD, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
-+ NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN),
-+ EndContainer(),
-+ NWidget(NWID_HORIZONTAL),
-+ NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_UT_BUILD_ESCALATOR),
-+ SetFill(0, 1), SetMinimalSize(42, 22), SetDataTip(SPR_IMG_RAIL_STATION, STR_UNDERGROUND_TOOLTIP_ESCALATOR),
-+ NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetMinimalSize(64, 22), EndContainer(),
-+ NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_UT_DEMOLISH), SetMinimalSize(22, 22),
-+ SetFill(0, 1), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC),
-+ EndContainer(),
-+};
-+
-+static WindowDesc _underground_desc(
-+ WDP_MANUAL, "undergroundtoolbar", 0, 0,
-+ WC_UNDERGROUND, WC_NONE,
-+ WDF_CONSTRUCTION,
-+ _nested_underground_widgets, lengthof(_nested_underground_widgets)
-+);
-+
-+/**
-+ * Show the toolbar for terraforming in the game.
-+ * @param link The toolbar we might want to link to.
-+ * @return The allocated toolbar.
-+ */
-+Window *ShowUndergroundToolbar(Window *link)
-+{
-+ if (!Company::IsValidID(_local_company)) return NULL;
-+
-+ Window *w;
-+ if (link == NULL) {
-+ w = AllocateWindowDescFront<UndergroundToolbarWindow>(&_underground_desc, 0);
-+ return w;
-+ }
-+
-+ /* Delete the terraform toolbar to place it again. */
-+ CloseWindowById(WC_UNDERGROUND, 0, true);
-+ w = AllocateWindowDescFront<UndergroundToolbarWindow>(&_underground_desc, 0);
-+ /* Align the terraform toolbar under the main toolbar. */
-+ w->top -= w->height;
-+ w->SetDirty();
-+ /* Put the linked toolbar to the left / right of it. */
-+ link->left = w->left + (_current_text_dir == TD_RTL ? w->width : -link->width);
-+ link->top = w->top;
-+ link->SetDirty();
-+
-+ return w;
-+}
-diff --git a/src/underground_gui.h b/src/underground_gui.h
-new file mode 100644
-index 000000000..81b119545
---- /dev/null
-+++ b/src/underground_gui.h
-@@ -0,0 +1,19 @@
-+/* $Id: underground_gui.h 21608 2012-09-08 1:13:14 constructor $ */
-+
-+/*
-+ * 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 underground_gui.h GUI stuff related to terraforming. */
-+
-+#ifndef UNDERGROUND_GUI_H
-+#define UNDERGROUND_GUI_H
-+
-+#include "window_type.h"
-+
-+Window *ShowUndergroundToolbar(Window *link = NULL);
-+
-+#endif /* UNDERGROUND_GUI_H */
-diff --git a/src/vehicle.cpp b/src/vehicle.cpp
-index 30e1c477c..053337a78 100644
---- a/src/vehicle.cpp
-+++ b/src/vehicle.cpp
-@@ -13,6 +13,7 @@
- #include "ship.h"
- #include "spritecache.h"
- #include "timetable.h"
-+#include "layer_func.h"
- #include "viewport_func.h"
- #include "news_func.h"
- #include "command_func.h"
-@@ -1158,6 +1159,7 @@ void ViewportAddVehicles(DrawPixelInfo *dpi)
-
- while (v != nullptr) {
-
-+ if (LayerIndex(v->tile) == dpi->layer)
- if (!(v->vehstatus & VS_HIDDEN) &&
- l <= v->coord.right + xb &&
- t <= v->coord.bottom + yb &&
-diff --git a/src/viewport.cpp b/src/viewport.cpp
-index b3ccba2b5..5f88aa38c 100644
---- a/src/viewport.cpp
-+++ b/src/viewport.cpp
-@@ -62,6 +62,8 @@
-
- #include "stdafx.h"
- #include "landscape.h"
-+#include "layer_gui.h"
-+#include "layer_func.h"
- #include "viewport_func.h"
- #include "station_base.h"
- #include "waypoint_base.h"
-@@ -1246,24 +1248,27 @@ static void ViewportAddLandscape()
- int min_visible_height = viewport_y - (_vd.dpi.top + _vd.dpi.height);
- bool tile_visible = min_visible_height <= 0;
-
-- if (tile_type != MP_VOID) {
-- /* Is tile with buildings visible? */
-- if (min_visible_height < MAX_TILE_EXTENT_TOP) tile_visible = true;
--
-- if (IsBridgeAbove(tile_info.tile)) {
-- /* Is the bridge visible? */
-- TileIndex bridge_tile = GetNorthernBridgeEnd(tile_info.tile);
-- int bridge_height = ZOOM_LVL_BASE * (GetBridgePixelHeight(bridge_tile) - TilePixelHeight(tile_info.tile));
-- if (min_visible_height < bridge_height + MAX_TILE_EXTENT_TOP) tile_visible = true;
-- }
-+ /* Валидны только клетки текущего слоя */
-+ if (LayerIndex(tile_info.tile) == _vd.dpi.layer) {
-+ if (tile_type != MP_VOID) {
-+ /* Is tile with buildings visible? */
-+ if (min_visible_height < MAX_TILE_EXTENT_TOP) tile_visible = true;
-+
-+ if (IsBridgeAbove(tile_info.tile)) {
-+ /* Is the bridge visible? */
-+ TileIndex bridge_tile = GetNorthernBridgeEnd(tile_info.tile);
-+ int bridge_height = ZOOM_LVL_BASE * (GetBridgePixelHeight(bridge_tile) - TilePixelHeight(tile_info.tile));
-+ if (min_visible_height < bridge_height + MAX_TILE_EXTENT_TOP) tile_visible = true;
-+ }
-
-- /* Would a higher bridge on a more southern tile be visible?
-- * If yes, we need to loop over more rows to possibly find one. */
-- if (min_visible_height < potential_bridge_height + MAX_TILE_EXTENT_TOP) last_row = false;
-- } else {
-- /* Outside of map. If we are on the north border of the map, there may still be a bridge visible,
-- * so we need to loop over more rows to possibly find one. */
-- if ((tilecoord.x <= 0 || tilecoord.y <= 0) && min_visible_height < potential_bridge_height + MAX_TILE_EXTENT_TOP) last_row = false;
-+ /* Would a higher bridge on a more southern tile be visible?
-+ * If yes, we need to loop over more rows to possibly find one. */
-+ if (min_visible_height < potential_bridge_height + MAX_TILE_EXTENT_TOP) last_row = false;
-+ } else {
-+ /* Outside of map. If we are on the north border of the map, there may still be a bridge visible,
-+ * so we need to loop over more rows to possibly find one. */
-+ if ((tilecoord.x <= 0 || tilecoord.y <= 0) && min_visible_height < potential_bridge_height + MAX_TILE_EXTENT_TOP) last_row = false;
-+ }
- }
-
- if (tile_visible) {
-@@ -1737,6 +1742,9 @@ void ViewportDoDraw(const Viewport *vp, int left, int top, int right, int bottom
-
- _vd.dpi.dst_ptr = BlitterFactory::GetCurrentBlitter()->MoveTo(old_dpi->dst_ptr, x - old_dpi->left, y - old_dpi->top);
-
-+ /* Определение слоя (который будем рисовать) */
-+ _vd.dpi.layer = calculateLayer(vp);
-+
- ViewportAddLandscape();
- ViewportAddVehicles(&_vd.dpi);
-
-diff --git a/src/viewport_func.h b/src/viewport_func.h
-index 58e1706eb..d8f2036aa 100644
---- a/src/viewport_func.h
-+++ b/src/viewport_func.h
-@@ -31,6 +31,7 @@ bool MarkAllViewportsDirty(int left, int top, int right, int bottom);
-
- bool DoZoomInOutWindow(ZoomStateChange how, Window *w);
- void ZoomInOrOutToCursorWindow(bool in, Window * w);
-+void LayerUpOrDownToCursorWindow(bool in, Window * w);
- Point GetTileZoomCenterWindow(bool in, Window * w);
- void FixTitleGameZoom(int zoom_adjust = 0);
- void HandleZoomMessage(Window *w, const Viewport *vp, byte widget_zoom_in, byte widget_zoom_out);
-diff --git a/src/viewport_gui.cpp b/src/viewport_gui.cpp
-index 5047f04f3..3c02f9ab8 100644
---- a/src/viewport_gui.cpp
-+++ b/src/viewport_gui.cpp
-@@ -14,6 +14,7 @@
- #include "strings_func.h"
- #include "zoom_func.h"
- #include "window_func.h"
-+#include "gfx_func.h"
-
- #include "widgets/viewport_widget.h"
-
-@@ -137,7 +138,11 @@ public:
- void OnMouseWheel(int wheel) override
- {
- if (_settings_client.gui.scrollwheel_scrolling != 2) {
-- ZoomInOrOutToCursorWindow(wheel < 0, this);
-+ if (_ctrl_pressed) {
-+ LayerUpOrDownToCursorWindow(wheel < 0, this);
-+ } else {
-+ ZoomInOrOutToCursorWindow(wheel < 0, this);
-+ }
- }
- }
-
-diff --git a/src/water_cmd.cpp b/src/water_cmd.cpp
-index ba09b415a..a87cf657d 100644
---- a/src/water_cmd.cpp
-+++ b/src/water_cmd.cpp
-@@ -10,6 +10,7 @@
- #include "stdafx.h"
- #include "cmd_helper.h"
- #include "landscape.h"
-+#include "layer_func.h"
- #include "viewport_func.h"
- #include "command_func.h"
- #include "town.h"
-@@ -475,6 +476,11 @@ CommandCost CmdBuildCanal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
- return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
- }
-
-+ /* can't make underground water */
-+ if (IsUnderground(current_tile)) {
-+ return_cmd_error(STR_ERROR_UNDERGROUND_CAN_T_BUILD_UNDER_GROUND);
-+ }
-+
- bool water = IsWaterTile(current_tile);
-
- /* Outside the editor, prevent building canals over your own or OWNER_NONE owned canals */
-@@ -1110,6 +1116,9 @@ void DoFloodTile(TileIndex target)
- {
- assert(!IsTileType(target, MP_WATER));
-
-+ /* Подземная часть карты не заливается */
-+ if (IsUnderground(target)) return;
-+
- bool flooded = false; // Will be set to true if something is changed.
-
- Backup<CompanyID> cur_company(_current_company, OWNER_WATER, FILE_LINE);
-@@ -1268,7 +1277,7 @@ void ConvertGroundTilesIntoWaterTiles()
-
- for (TileIndex tile = 0; tile < MapSize(); ++tile) {
- Slope slope = GetTileSlope(tile, &z);
-- if (IsTileType(tile, MP_CLEAR) && z == 0) {
-+ if (IsTileType(tile, MP_CLEAR) && z == 0 && !IsUnderground(tile)) {
- /* Make both water for tiles at level 0
- * and make shore, as that looks much better
- * during the generation. */
-diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt
-index 5586870a3..c5d57cebe 100644
---- a/src/widgets/CMakeLists.txt
-+++ b/src/widgets/CMakeLists.txt
-@@ -57,6 +57,7 @@ add_files(
- town_widget.h
- transparency_widget.h
- tree_widget.h
-+ underground_widget.h
- vehicle_widget.h
- viewport_widget.h
- waypoint_widget.h
-diff --git a/src/widgets/genworld_widget.h b/src/widgets/genworld_widget.h
-index 6644dc1aa..a059a2953 100644
---- a/src/widgets/genworld_widget.h
-+++ b/src/widgets/genworld_widget.h
-@@ -19,6 +19,7 @@ enum GenerateLandscapeWidgets {
-
- WID_GL_MAPSIZE_X_PULLDOWN, ///< Dropdown 'map X size'.
- WID_GL_MAPSIZE_Y_PULLDOWN, ///< Dropdown 'map Y size'.
-+ WID_GL_LAYER_COUNT_PULLDOWN, ///< Dropdown 'map layer count'.
-
- WID_GL_TOWN_PULLDOWN, ///< Dropdown 'No. of towns'.
- WID_GL_TOWNNAME_DROPDOWN, ///< Dropdown 'Townnames'.
-@@ -74,6 +75,7 @@ enum CreateScenarioWidgets {
- WID_CS_RANDOM_WORLD, ///< Generate random land button
- WID_CS_MAPSIZE_X_PULLDOWN, ///< Pull-down arrow for x map size.
- WID_CS_MAPSIZE_Y_PULLDOWN, ///< Pull-down arrow for y map size.
-+ WID_CS_LAYER_COUNT_PULLDOWN, ///< Pull-down arrow for map layer count.
- WID_CS_START_DATE_DOWN, ///< Decrease start year (start earlier).
- WID_CS_START_DATE_TEXT, ///< Clickable start date value.
- WID_CS_START_DATE_UP, ///< Increase start year (start later).
-diff --git a/src/widgets/toolbar_widget.h b/src/widgets/toolbar_widget.h
-index d68de4970..0b4e53227 100644
---- a/src/widgets/toolbar_widget.h
-+++ b/src/widgets/toolbar_widget.h
-@@ -41,6 +41,7 @@ enum ToolbarNormalWidgets {
- WID_TN_WATER, ///< Water building toolbar.
- WID_TN_AIR, ///< Airport building toolbar.
- WID_TN_LANDSCAPE, ///< Landscaping toolbar.
-+ WID_TN_UNDERGROUND, ///< Landscaping toolbar.
- WID_TN_MUSIC_SOUND, ///< Music/sound configuration menu.
- WID_TN_MESSAGES, ///< Messages menu.
- WID_TN_HELP, ///< Help menu.
-diff --git a/src/widgets/underground_widget.h b/src/widgets/underground_widget.h
-new file mode 100644
-index 000000000..522c9db8b
---- /dev/null
-+++ b/src/widgets/underground_widget.h
-@@ -0,0 +1,21 @@
-+/* $Id: terraform_widget.h 23600 2011-12-19 20:46:17Z truebrain $ */
-+
-+/*
-+ * 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 terraform_widget.h Types related to the terraform widgets. */
-+
-+#ifndef WIDGETS_UNDERGROUND_WIDGET_H
-+#define WIDGETS_UNDERGROUND_WIDGET_H
-+
-+/** Widgets of the #TerraformToolbarWindow class. */
-+enum UndergroundToolbarWidgets {
-+ WID_UT_BUILD_ESCALATOR, ///< Build escalator
-+ WID_UT_DEMOLISH, ///< Demolish aka dynamite button.
-+};
-+
-+#endif /* WIDGETS_UNDERGROUND_WIDGET_H */
-diff --git a/src/window_type.h b/src/window_type.h
-index 6eb9573b6..cfaa1e878 100644
---- a/src/window_type.h
-+++ b/src/window_type.h
-@@ -440,6 +440,12 @@ enum WindowClass {
- */
- WC_SCEN_LAND_GEN,
-
-+ /**
-+ * Underground (in game); %Window numbers:
-+ * - 0 = #UndergroundToolbarWidgets
-+ */
-+ WC_UNDERGROUND,
-+
- /**
- * Generate landscape (newgame); %Window numbers:
- * - GLWM_SCENARIO = #CreateScenarioWidgets