From 9109ea8eefa791688066eb3cda857eeb706a2e54 Mon Sep 17 00:00:00 2001 From: Erich Eckner Date: Sun, 27 Feb 2022 09:29:15 +0100 Subject: openttd-git: 31316.802ca4e72-4 -> 31416.1c256a4be-1 --- openttd-git/PKGBUILD | 14 +- openttd-git/chunnel-pre.patch | 12 - openttd-git/chunnel-signaltunnel-pre.patch | 22 - openttd-git/chunnel-underground-pre.patch | 22 - openttd-git/chunnel.patch | 1063 -------- openttd-git/signaltunnel.patch | 86 +- openttd-git/sloped-stations.patch | 449 ---- openttd-git/underground.patch | 3664 ---------------------------- 8 files changed, 49 insertions(+), 5283 deletions(-) delete mode 100644 openttd-git/chunnel-pre.patch delete mode 100644 openttd-git/chunnel-signaltunnel-pre.patch delete mode 100644 openttd-git/chunnel-underground-pre.patch delete mode 100644 openttd-git/chunnel.patch delete mode 100644 openttd-git/sloped-stations.patch delete mode 100644 openttd-git/underground.patch (limited to 'openttd-git') 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 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::IsChainInDepot() const - return true; - } - -+/** -+ * Updates vehicle's Z inclination inside a wormhole, where applicable. -+ */ -+template -+void GroundVehicle::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; - /* 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 { - 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 . -+ */ -+ -+/** @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(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 . -+ */ -+ -+/** @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 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(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 : MakeEnumPropsT {}; - -+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 &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 - #include - #include -+#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 . -+ -+ 6464, 4- : -+ 64256, , : -+ -+ 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 . -+ */ -+ -+/** @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 -@@ -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 --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 --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(existing_station, station_to_join, adjacent, ta, st); -+ return FindJoiningBaseStation(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 &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 &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 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 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, &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(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, &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, &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 - 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 . -+ */ -+ -+/** @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(_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(_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(&_underground_desc, 0); -+ return w; -+ } -+ -+ /* Delete the terraform toolbar to place it again. */ -+ CloseWindowById(WC_UNDERGROUND, 0, true); -+ w = AllocateWindowDescFront(&_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 . -+ */ -+ -+/** @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 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 . -+ */ -+ -+/** @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 -- cgit v1.2.3-70-g09d2