summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/base_station_base.h9
-rw-r--r--src/clear_cmd.cpp24
-rw-r--r--src/console_cmds.cpp2
-rw-r--r--src/genworld_gui.cpp45
-rw-r--r--src/gfx_type.h1
-rw-r--r--src/heightmap.cpp4
-rw-r--r--src/industry_cmd.cpp3
-rw-r--r--src/lang/english.txt39
-rw-r--r--src/lang/russian.txt39
-rw-r--r--src/layer.cpp137
-rw-r--r--src/layer_func.h159
-rw-r--r--src/layer_gui.h17
-rw-r--r--src/layer_type.h22
-rw-r--r--src/main_gui.cpp2
-rw-r--r--src/map.cpp7
-rw-r--r--src/map_func.h2
-rw-r--r--src/misc.cpp3
-rw-r--r--src/rail.h2
-rw-r--r--src/saveload/map_sl.cpp6
-rw-r--r--src/script/api/script_window.hpp2
-rw-r--r--src/settings.cpp1
-rw-r--r--src/settings_type.h3
-rw-r--r--src/station.cpp42
-rw-r--r--src/station_cmd.cpp71
-rw-r--r--src/station_gui.cpp25
-rw-r--r--src/table/settings.ini18
-rw-r--r--src/terraform_cmd.cpp5
-rw-r--r--src/tgp.cpp14
-rw-r--r--src/tile_map.h2
-rw-r--r--src/tilearea_type.h10
-rw-r--r--src/toolbar_gui.cpp51
-rw-r--r--src/town_cmd.cpp6
-rw-r--r--src/tree_cmd.cpp8
-rw-r--r--src/tunnelbridge_cmd.cpp11
-rw-r--r--src/underground_gui.cpp321
-rw-r--r--src/underground_gui.h19
-rw-r--r--src/vehicle.cpp2
-rw-r--r--src/viewport.cpp42
-rw-r--r--src/water_cmd.cpp11
-rw-r--r--src/widgets/genworld_widget.h2
-rw-r--r--src/widgets/underground_widget.h21
-rw-r--r--src/window_type.h6
42 files changed, 1138 insertions, 78 deletions
diff --git a/src/base_station_base.h b/src/base_station_base.h
index cd512c517..3602a56d1 100644
--- a/src/base_station_base.h
+++ b/src/base_station_base.h
@@ -28,6 +28,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
{
@@ -38,7 +45,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 f9eb88df5..0db7590be 100644
--- a/src/clear_cmd.cpp
+++ b/src/clear_cmd.cpp
@@ -14,6 +14,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"
@@ -100,8 +101,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));
@@ -126,6 +147,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);
}
diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp
index d9155a97d..07cca44b7 100644
--- a/src/console_cmds.cpp
+++ b/src/console_cmds.cpp
@@ -27,6 +27,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"
@@ -1061,6 +1062,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/genworld_gui.cpp b/src/genworld_gui.cpp
index b22ba5287..dd1a2cade 100644
--- a/src/genworld_gui.cpp
+++ b/src/genworld_gui.cpp
@@ -18,6 +18,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"
@@ -81,6 +83,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_NUMBER_OF_TOWNS, STR_NULL), SetFill(1, 1),
NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_TERRAIN_TYPE, STR_NULL), SetFill(1, 1),
@@ -97,6 +100,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_TOWN_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),
@@ -201,6 +205,7 @@ static const NWidgetPart _nested_heightmap_load_widgets[] = {
NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_HEIGHTMAP_NAME, 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),
@@ -218,6 +223,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),
@@ -282,11 +288,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 = new DropDownList();
- 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->Append() = item;
@@ -295,6 +301,16 @@ static DropDownList *BuildMapsizeDropDown()
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, 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};
static const StringID _rivers[] = {STR_RIVERS_NONE, STR_RIVERS_FEW, STR_RIVERS_MODERATE, STR_RIVERS_LOT, INVALID_STRING_ID};
@@ -338,6 +354,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_MAX_HEIGHTLEVEL_TEXT: SetDParam(0, _settings_newgame.construction.max_heightlevel); break;
case WID_GL_SNOW_LEVEL_TEXT: SetDParam(0, _settings_newgame.game_creation.snow_line_height); break;
@@ -460,6 +477,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_LEVEL_TEXT:
SetDParamMaxValue(0, MAX_TILE_HEIGHT);
*size = maxdim(*size, GetStringBoundingBox(STR_JUST_INT));
@@ -546,6 +568,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;
@@ -719,6 +745,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_TREE_PULLDOWN: _settings_newgame.game_creation.tree_placer = 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;
@@ -903,6 +930,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;
@@ -936,6 +967,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:
@@ -969,6 +1004,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;
@@ -1031,6 +1070,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();
}
@@ -1086,6 +1126,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 4cfc149a8..c39d428ac 100644
--- a/src/gfx_type.h
+++ b/src/gfx_type.h
@@ -157,6 +157,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 17bdbbf61..6521cee6f 100644
--- a/src/heightmap.cpp
+++ b/src/heightmap.cpp
@@ -16,6 +16,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"
@@ -397,6 +398,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 d918ef16b..f278275fa 100644
--- a/src/industry_cmd.cpp
+++ b/src/industry_cmd.cpp
@@ -14,6 +14,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"
@@ -1399,7 +1400,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);
}
diff --git a/src/lang/english.txt b/src/lang/english.txt
index cb04a5cbd..a2a8645d9 100644
--- a/src/lang/english.txt
+++ b/src/lang/english.txt
@@ -455,6 +455,13 @@ 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
+STR_LANDSCAPING_MENU_SEPARATOR1 :
+STR_LANDSCAPING_MENU_UNDERGROUND :Special constructions
+STR_LANDSCAPING_MENU_SEPARATOR2 :
+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)
############ range ends here
############ range for music menu starts
@@ -5041,3 +5048,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/russian.txt b/src/lang/russian.txt
index 542c1384a..1648e903b 100644
--- a/src/lang/russian.txt
+++ b/src/lang/russian.txt
@@ -581,6 +581,13 @@ STR_AIRCRAFT_MENU_AIRPORT_CONSTRUCTION :Строите
STR_LANDSCAPING_MENU_LANDSCAPING :Ландшафт
STR_LANDSCAPING_MENU_PLANT_TREES :Высадка деревьев
STR_LANDSCAPING_MENU_PLACE_SIGN :Поставить метку
+STR_LANDSCAPING_MENU_SEPARATOR1 :
+STR_LANDSCAPING_MENU_UNDERGROUND :Спец. конструкции
+STR_LANDSCAPING_MENU_SEPARATOR2 :
+STR_LANDSCAPING_MENU_LAYER_1 :Поверхность
+STR_LANDSCAPING_MENU_LAYER_2 :Подземелье (-1)
+STR_LANDSCAPING_MENU_LAYER_3 :Подземелье (-2)
+STR_LANDSCAPING_MENU_LAYER_4 :Подземелье (-3)
############ range ends here
############ range for music menu starts
@@ -5230,3 +5237,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/layer.cpp b/src/layer.cpp
new file mode 100644
index 000000000..b897c45a3
--- /dev/null
+++ b/src/layer.cpp
@@ -0,0 +1,137 @@
+/* $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))
+ 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..250e79a3d
--- /dev/null
+++ b/src/layer_func.h
@@ -0,0 +1,159 @@
+/* $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 FOR_ALL_LAYERS(var) for (uint var = 0; var < LayerCount(); var++)
+
+
+/**
+ * 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;
+}
+
+/**
+ * Get the layer counts
+ * @return the number of layers
+ */
+static inline uint LayerCount()
+{
+ extern uint _layer_count;
+ 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;
+}
+
+/**
+ * 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..303fa32a3
--- /dev/null
+++ b/src/layer_gui.h
@@ -0,0 +1,17 @@
+/* $Id: layer_func.h 2012-09-07 18:11:11 constructor $ */
+
+/*
+* . layer.cpp
+*/
+
+/** @file layer_gui.h Functions for visualisation map with support layers */
+
+#ifndef LAYER_GUI_H
+#define LAYER_GUI_H
+
+#include "layer_func.h"
+#include "viewport_type.h"
+
+uint8 calculateLayer(const ViewPort *vp);
+
+#endif /* LAYER_GUI_H */
diff --git a/src/layer_type.h b/src/layer_type.h
new file mode 100644
index 000000000..53eafdde6
--- /dev/null
+++ b/src/layer_type.h
@@ -0,0 +1,22 @@
+/* $Id: layer_type.h 21493 2012-09-11 2:21:53Z constructor $ */
+
+/*
+ * This file is part of OpenTTD.
+ * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
+ * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** @file layer_type.h Types related to maps. */
+
+#ifndef LAYER_TYPE_H
+#define LAYER_TYPE_H
+
+/** Minimal and maximal layer counts */
+static const uint MIN_LAYER_COUNT_BITS = 0; ///< Minimal size of map is equal to 2 ^ MIN_LAYER_SIZE_BITS
+static const uint MAX_LAYER_COUNT_BITS = 3; ///< Maximal size of map is equal to 2 ^ MAX_LAYER_SIZE_BITS
+static const uint MIN_LAYER_COUNT = 1 << MIN_LAYER_COUNT_BITS; ///< Minimal layer count = 1
+static const uint MAX_LAYER_COUNT = 1 << MAX_LAYER_COUNT_BITS; ///< Maximal layer count = 8
+
+
+#endif /* LAYER_TYPE_H */
diff --git a/src/main_gui.cpp b/src/main_gui.cpp
index 199546d43..4b3dea267 100644
--- a/src/main_gui.cpp
+++ b/src/main_gui.cpp
@@ -107,7 +107,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;
}
diff --git a/src/map.cpp b/src/map.cpp
index 85590c3e8..c7e4f5fbc 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -13,6 +13,7 @@
#include "debug.h"
#include "core/alloc_func.hpp"
#include "water_map.h"
+#include "layer_func.h"
#include "string_func.h"
#include "safeguards.h"
@@ -38,7 +39,7 @@ TileExtended *_me = NULL; ///< 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. */
@@ -49,6 +50,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 %dx%d", size_x, size_y);
_map_log_x = FindFirstBit(size_x);
diff --git a/src/map_func.h b/src/map_func.h
index 21d69b138..08cf12b5f 100644
--- a/src/map_func.h
+++ b/src/map_func.h
@@ -43,7 +43,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.
diff --git a/src/misc.cpp b/src/misc.cpp
index d9d506993..f5184c058 100644
--- a/src/misc.cpp
+++ b/src/misc.cpp
@@ -10,6 +10,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"
@@ -57,7 +58,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;
_fast_forward = 0;
diff --git a/src/rail.h b/src/rail.h
index b7258d301..5ff4bd3a1 100644
--- a/src/rail.h
+++ b/src/rail.h
@@ -150,7 +150,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/saveload/map_sl.cpp b/src/saveload/map_sl.cpp
index 693ddb7ce..e2e9f4877 100644
--- a/src/saveload/map_sl.cpp
+++ b/src/saveload/map_sl.cpp
@@ -11,6 +11,7 @@
#include "../stdafx.h"
#include "../map_func.h"
+#include "../layer_func.h"
#include "../core/bitmath_func.hpp"
#include "../fios.h"
@@ -20,10 +21,12 @@
static uint32 _map_dim_x;
static uint32 _map_dim_y;
+static uint32 _layer_count;
static const SaveLoadGlobVarList _map_dimensions[] = {
SLEG_CONDVAR(_map_dim_x, SLE_UINT32, 6, SL_MAX_VERSION),
SLEG_CONDVAR(_map_dim_y, SLE_UINT32, 6, SL_MAX_VERSION),
+ SLEG_CONDVAR(_layer_count, SLE_UINT32, 6, SL_MAX_VERSION),
SLEG_END()
};
@@ -31,13 +34,14 @@ static void Save_MAPS()
{
_map_dim_x = MapSizeX();
_map_dim_y = MapSizeY();
+ _layer_count = LayerCount();
SlGlobList(_map_dimensions);
}
static void Load_MAPS()
{
SlGlobList(_map_dimensions);
- AllocateMap(_map_dim_x, _map_dim_y);
+ AllocateMap(_map_dim_x, _map_dim_y/_layer_count, _layer_count);
}
static void Check_MAPS()
diff --git a/src/script/api/script_window.hpp b/src/script/api/script_window.hpp
index 9dcf58e05..9585ba365 100644
--- a/src/script/api/script_window.hpp
+++ b/src/script/api/script_window.hpp
@@ -1317,6 +1317,7 @@ public:
WID_GL_MAPSIZE_X_PULLDOWN = ::WID_GL_MAPSIZE_X_PULLDOWN, ///< Dropdown 'map X size'.
WID_GL_MAPSIZE_Y_PULLDOWN = ::WID_GL_MAPSIZE_Y_PULLDOWN, ///< Dropdown 'map Y size'.
+ WID_GL_LAYER_COUNT_PULLDOWN = ::WID_GL_LAYER_COUNT_PULLDOWN, ///< Dropdown 'map layer count'
WID_GL_TOWN_PULLDOWN = ::WID_GL_TOWN_PULLDOWN, ///< Dropdown 'No. of towns'.
WID_GL_INDUSTRY_PULLDOWN = ::WID_GL_INDUSTRY_PULLDOWN, ///< Dropdown 'No. of industries'.
@@ -1365,6 +1366,7 @@ public:
WID_CS_RANDOM_WORLD = ::WID_CS_RANDOM_WORLD, ///< Generate random land button
WID_CS_MAPSIZE_X_PULLDOWN = ::WID_CS_MAPSIZE_X_PULLDOWN, ///< Pull-down arrow for x map size.
WID_CS_MAPSIZE_Y_PULLDOWN = ::WID_CS_MAPSIZE_Y_PULLDOWN, ///< Pull-down arrow for y map size.
+ WID_CS_LAYER_COUNT_PULLDOWN = ::WID_CS_LAYER_COUNT_PULLDOWN, ///< Pull-down arrow for map layer count.
WID_CS_START_DATE_DOWN = ::WID_CS_START_DATE_DOWN, ///< Decrease start year (start earlier).
WID_CS_START_DATE_TEXT = ::WID_CS_START_DATE_TEXT, ///< Clickable start date value.
WID_CS_START_DATE_UP = ::WID_CS_START_DATE_UP, ///< Increase start year (start later).
diff --git a/src/settings.cpp b/src/settings.cpp
index 0dc1e24d4..ea42ae6d0 100644
--- a/src/settings.cpp
+++ b/src/settings.cpp
@@ -32,6 +32,7 @@
#include "command_func.h"
#include "console_func.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 690f6d803..d2022fd89 100644
--- a/src/settings_type.h
+++ b/src/settings_type.h
@@ -147,6 +147,8 @@ struct GUISettings {
uint8 graph_line_thickness; ///< the thickness of the lines in the various graph guis
uint8 osk_activation; ///< Mouse gesture to trigger the OSK.
+ 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.
@@ -286,6 +288,7 @@ struct GameCreationSettings {
Year starting_year; ///< starting 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
diff --git a/src/station.cpp b/src/station.cpp
index f86286f3d..73d9bf1fd 100644
--- a/src/station.cpp
+++ b/src/station.cpp
@@ -13,6 +13,7 @@
#include "company_func.h"
#include "company_base.h"
#include "roadveh.h"
+#include "layer_func.h"
#include "viewport_func.h"
#include "date_func.h"
#include "command_func.h"
@@ -331,8 +332,8 @@ static bool FindIndustryToDeliver(TileIndex ind_tile, void *user_data)
if (riv->industries_near->Contains(ind)) return false;
/* Only process tiles in the station acceptance rectangle */
- int x = TileX(ind_tile);
- int y = TileY(ind_tile);
+ int x = LayerX(ind_tile);
+ int y = LayerY(ind_tile);
if (x < riv->rect.left || x > riv->rect.right || y < riv->rect.top || y > riv->rect.bottom) return false;
/* Include only industries that can accept cargo */
@@ -362,7 +363,8 @@ void Station::RecomputeIndustriesNear()
};
/* Compute maximum extent of acceptance rectangle wrt. station sign */
- TileIndex start_tile = this->xy;
+ /* */
+ TileIndex start_tile = TopTile(this->xy);
uint max_radius = max(
max(DistanceManhattan(start_tile, TileXY(riv.rect.left, riv.rect.top)), DistanceManhattan(start_tile, TileXY(riv.rect.left, riv.rect.bottom))),
max(DistanceManhattan(start_tile, TileXY(riv.rect.right, riv.rect.top)), DistanceManhattan(start_tile, TileXY(riv.rect.right, riv.rect.bottom)))
@@ -397,7 +399,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)
@@ -416,8 +418,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) {
@@ -470,18 +474,25 @@ 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));
- TILE_AREA_LOOP(tile, ta) {
- if (IsTileType(tile, MP_STATION) && GetStationIndex(tile) == st_id) return true;
- }
+ FOR_ALL_LAYERS(layer) {
+ ta.tile += layer * LayerSize();
+ TILE_AREA_LOOP(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
@@ -530,8 +541,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 16f135df2..fa35b2fdf 100644
--- a/src/station_cmd.cpp
+++ b/src/station_cmd.cpp
@@ -13,6 +13,7 @@
#include "aircraft.h"
#include "bridge_map.h"
#include "cmd_helper.h"
+#include "layer_func.h"
#include "viewport_func.h"
#include "command_func.h"
#include "town.h"
@@ -97,23 +98,26 @@ bool IsHangar(TileIndex t)
* @return Succeeded command (if zero or one station found) or failed command (for two or more stations found).
*/
template <class T>
-CommandCost GetStationAround(TileArea ta, StationID closest_station, CompanyID company, T **st)
+CommandCost GetStationAround(TileArea ta, StationID closest_station, CompanyID company, T **st, bool layers=false)
{
ta.tile -= TileDiffXY(1, 1);
ta.w += 2;
ta.h += 2;
/* check around to see if there are any stations there owned by the company */
- TILE_AREA_LOOP(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) {
+ TILE_AREA_LOOP(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) ? NULL : T::Get(closest_station);
return CommandCost();
@@ -1004,11 +1008,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 = min(TileX(cur_ta.tile), TileX(new_ta.tile));
- int y = min(TileY(cur_ta.tile), TileY(new_ta.tile));
- new_ta.w = max(TileX(cur_ta.tile) + cur_ta.w, TileX(new_ta.tile) + new_ta.w) - x;
- new_ta.h = max(TileY(cur_ta.tile) + cur_ta.h, TileY(new_ta.tile) + new_ta.h) - y;
- new_ta.tile = TileXY(x, y);
+ /* , ("") .
+ * */
+ int topx = min(LayerX(cur_ta.tile), LayerX(new_ta.tile));
+ int topy = min(LayerY(cur_ta.tile), LayerY(new_ta.tile));
+ new_ta.w = max(LayerX(cur_ta.tile) + cur_ta.w, LayerX(new_ta.tile) + new_ta.w) - topx;
+ new_ta.h = 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) {
@@ -1080,7 +1086,7 @@ void GetStationLayout(byte *layout, int numtracks, int plat_len, const StationSp
* @return command cost with the error or 'okay'
*/
template <class T, StringID error_message>
-CommandCost FindJoiningBaseStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, T **st)
+CommandCost FindJoiningBaseStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, T **st, bool layers=false)
{
assert(*st == NULL);
bool check_surrounding = true;
@@ -1106,7 +1112,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;
}
@@ -1125,9 +1131,9 @@ CommandCost FindJoiningBaseStation(StationID existing_station, StationID station
* @param st 'return' pointer for the found station
* @return command cost with the error or 'okay'
*/
-static CommandCost FindJoiningStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, Station **st)
+static CommandCost FindJoiningStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, Station **st, bool layers=false)
{
- return FindJoiningBaseStation<Station, STR_ERROR_MUST_REMOVE_RAILWAY_STATION_FIRST>(existing_station, station_to_join, adjacent, ta, st);
+ return FindJoiningBaseStation<Station, STR_ERROR_MUST_REMOVE_RAILWAY_STATION_FIRST>(existing_station, station_to_join, adjacent, ta, st, layers);
}
/**
@@ -1277,8 +1283,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);
@@ -1649,11 +1657,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 */
- TILE_AREA_LOOP(tile, ta) {
+ TILE_AREA_LOOP(top_tile, ta) {
+ TileIndex tile = top_tile + layer * LayerSize();
/* only remove tiles that are actually train station tiles */
if (st->TileBelongsToRailStation(tile)) {
SmallVector<T*, 4> affected_stations; // dummy
@@ -2027,13 +2040,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;
- TILE_AREA_LOOP(cur_tile, roadstop_area) {
+ /* Check all layers */
+ FOR_ALL_LAYERS(layer)
+ TILE_AREA_LOOP(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;
@@ -2217,6 +2238,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);
+ }
CommandCost cost = CheckFlatLand(airport_area, flags);
if (cost.Failed()) return cost;
diff --git a/src/station_gui.cpp b/src/station_gui.cpp
index 3f64b139a..d143d7aa2 100644
--- a/src/station_gui.cpp
+++ b/src/station_gui.cpp
@@ -21,6 +21,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"
@@ -2178,8 +2179,15 @@ static const T *FindStationsNearby(TileArea ta, bool distant_join)
_deleted_stations_nearby.Clear();
/* Check the inside, to return, if we sit on another station */
- TILE_AREA_LOOP(t, ta) {
- if (t < MapSize() && IsTileType(t, MP_STATION) && T::IsValidID(GetStationIndex(t))) return T::GetByTile(t);
+ FOR_ALL_LAYERS(layer) {
+ TILE_AREA_LOOP(tile, ta) {
+ TileIndex t = TopTile(tile) + layer * LayerSize();
+ if (t < MapSize() && IsTileType(t, MP_STATION) && T::IsValidID(GetStationIndex(t)))
+ {
+ if (t == tile) return T::GetByTile(t);
+ AddNearbyStation<T>(t, &ctx);
+ }
+ }
}
/* Look for deleted stations */
@@ -2187,14 +2195,14 @@ static const T *FindStationsNearby(TileArea ta, bool distant_join)
FOR_ALL_BASE_STATIONS(st) {
if (T::IsExpected(st) && !st->IsInUse() && st->owner == _local_company) {
/* Include only within station spread (yes, it is strictly less than) */
- if (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 (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) {
TileAndStation *ts = _deleted_stations_nearby.Append();
ts->tile = st->xy;
ts->station = st->index;
/* Add the station when it's within where we're going to build */
- if (IsInsideBS(TileX(st->xy), TileX(ctx.tile), ctx.w) &&
- IsInsideBS(TileY(st->xy), TileY(ctx.tile), ctx.h)) {
+ if (IsInsideBS(LayerX(st->xy), LayerX(ctx.tile), ctx.w) &&
+ IsInsideBS(LayerY(st->xy), LayerY(ctx.tile), ctx.h)) {
AddNearbyStation<T>(st->xy, &ctx);
}
}
@@ -2207,8 +2215,11 @@ static const T *FindStationsNearby(TileArea ta, bool distant_join)
if (distant_join && min(ta.w, ta.h) >= _settings_game.station.station_spread) return NULL;
uint max_dist = distant_join ? _settings_game.station.station_spread - min(ta.w, ta.h) : 1;
- TileIndex tile = TileAddByDir(ctx.tile, DIR_N);
- CircularTileSearch(&tile, max_dist, ta.w, ta.h, AddNearbyStation<T>, &ctx);
+ FOR_ALL_LAYERS(layer) {
+ ctx.tile = TopTile(ctx.tile) + layer * LayerSize();
+ TileIndex tile = TileAddByDir(ctx.tile, DIR_N);
+ CircularTileSearch(&tile, max_dist, ta.w, ta.h, AddNearbyStation<T>, &ctx);
+ }
return NULL;
}
diff --git a/src/table/settings.ini b/src/table/settings.ini
index c061c394f..d940ca6da 100644
--- a/src/table/settings.ini
+++ b/src/table/settings.ini
@@ -1848,6 +1848,15 @@ min = 500
max = 1000000
cat = SC_EXPERT
+[SDT_VAR]
+base = GameSettings
+var = game_creation.layers
+type = SLE_UINT8
+flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
+def = 1
+min = MIN_LAYER_COUNT_BITS
+max = MAX_LAYER_COUNT_BITS
+
[SDT_BOOL]
base = GameSettings
var = pf.yapf.rail_firstred_twoway_eol
@@ -3143,6 +3152,15 @@ strhelp = STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS_HELPTEXT
strval = STR_JUST_COMMA
proc = RedrawScreen
+[SDTC_VAR]
+var = gui.layer_view_type
+type = SLE_UINT32
+flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
+def = 0
+min = 0
+max = UINT32_MAX
+proc = RedrawScreen
+
; For the dedicated build we'll enable dates in logs by default.
[SDTC_BOOL]
ifdef = DEDICATED
diff --git a/src/terraform_cmd.cpp b/src/terraform_cmd.cpp
index aad982282..ac96a0b63 100644
--- a/src/terraform_cmd.cpp
+++ b/src/terraform_cmd.cpp
@@ -10,6 +10,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"
@@ -253,6 +254,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(tile)) {
int bridge_height = GetBridgeHeight(GetSouthernBridgeEnd(tile));
diff --git a/src/tgp.cpp b/src/tgp.cpp
index 436870b41..a9f43bb77 100644
--- a/src/tgp.cpp
+++ b/src/tgp.cpp
@@ -14,6 +14,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"
@@ -170,6 +171,8 @@ struct HeightMap
int total_size; //< height map total size
int size_x; //< MapSizeX()
int size_y; //< MapSizeY()
+ int map_x; //< MapSizeX()
+ int map_y; //< MapSizeY()
/**
* Height map accessor
@@ -307,8 +310,11 @@ static inline bool AllocHeightMap()
{
height_t *h;
- _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 */
_height_map.total_size = (_height_map.size_x + 1) * (_height_map.size_y + 1);
@@ -995,8 +1001,8 @@ void GenerateTerrainPerlin()
/* First make sure the tiles at the north border are void tiles if needed. */
if (_settings_game.construction.freeform_edges) {
- for (int y = 0; y < _height_map.size_y - 1; y++) MakeVoid(_height_map.size_x * y);
- for (int x = 0; x < _height_map.size_x; x++) MakeVoid(x);
+ for (int y = 0; y < _height_map.map_y - 1; y++) MakeVoid(_height_map.size_x * y);
+ for (int x = 0; x < _height_map.map_x; x++) MakeVoid(x);
}
int max_height = H2I(TGPGetMaxHeight());
diff --git a/src/tile_map.h b/src/tile_map.h
index 7ee5727be..58dff2cb0 100644
--- a/src/tile_map.h
+++ b/src/tile_map.h
@@ -127,7 +127,7 @@ static inline void SetTileType(TileIndex tile, TileType type)
/* VOID tiles (and no others) are exactly allowed at the lower left and right
* edges of the map. If _settings_game.construction.freeform_edges is true,
* the upper edges of the map are also VOID tiles. */
- assert(IsInnerTile(tile) == (type != MP_VOID));
+ assert(IsInnerTile(tile) == (type != MP_VOID)); // was commented in <underground>
SB(_m[tile].type, 4, 4, type);
}
diff --git a/src/tilearea_type.h b/src/tilearea_type.h
index 45bfb3d4c..11094ea17 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 40ac3634f..eceff4e94 100644
--- a/src/toolbar_gui.cpp
+++ b/src/toolbar_gui.cpp
@@ -13,7 +13,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"
@@ -22,6 +25,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"
@@ -968,10 +972,54 @@ static CallBackFunction MenuClickBuildAir(int index)
static CallBackFunction ToolbarForestClick(Window *w)
{
- PopupMainToolbMenu(w, WID_TN_LANDSCAPE, STR_LANDSCAPING_MENU_LANDSCAPING, 3);
+ // :
+ // . 3
+ PopupMainToolbMenu(w, WID_TN_LANDSCAPE, STR_LANDSCAPING_MENU_LANDSCAPING, 10);
return CBF_NONE;
}
+bool ScrollWindowRel(ViewportData *viewport, int dx, int dy)
+{
+ Point pt = RemapCoords(dx, dy, 0);
+
+ viewport->dest_scrollpos_x += pt.x;
+ viewport->dest_scrollpos_y += pt.y;
+ return true;
+}
+
+void SelectLayer(ViewportData *viewport, int layer)
+{
+ if (layer < 0) layer = 0;
+ if (uint(layer) >= LayerCount()) layer = LayerCount() - 1;
+
+ int delta_layer = calculateLayer(viewport) - layer;
+ bool res = ScrollWindowRel(viewport, 0, -delta_layer * LayerSizeY() * TILE_SIZE);
+}
+
+void SelectLayerInMainWindow(int layer)
+{
+ Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
+ SelectLayer(w->viewport, layer);
+ w->InvalidateData();
+}
+
+/**
+ * Handle click on the entry in the underground menu.
+ *
+ * @param index Menu entry clicked.
+ */
+static void ToMenuClickUnderground(int index)
+{
+ switch (index) {
+ case 4: ShowUndergroundToolbar(); break;
+
+ case 6: SelectLayerInMainWindow(index-6); break;
+ case 7: SelectLayerInMainWindow(index-6); break;
+ case 8: SelectLayerInMainWindow(index-6); break;
+ case 9: SelectLayerInMainWindow(index-6); break;
+ }
+}
+
/**
* Handle click on the entry in the landscaping menu.
*
@@ -985,6 +1033,7 @@ static CallBackFunction MenuClickForest(int index)
case 1: ShowBuildTreesToolbar(); break;
case 2: return SelectSignTool();
}
+ ToMenuClickUnderground(index);
return CBF_NONE;
}
diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp
index 927651864..9c542378a 100644
--- a/src/town_cmd.cpp
+++ b/src/town_cmd.cpp
@@ -13,6 +13,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 "cmd_helper.h"
#include "command_func.h"
@@ -2108,6 +2109,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;
+
/* building under a bridge? */
if (IsBridgeAbove(tile)) return false;
@@ -2539,6 +2543,8 @@ CommandCost CmdRenameTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
t->UpdateVirtCoord();
InvalidateWindowData(WC_TOWN_DIRECTORY, 0, 1);
+ InvalidateWindowClassesData(WC_TOWN_VIEW);
+ InvalidateWindowClassesData(WC_INDUSTRY_VIEW);
UpdateAllStationVirtCoords();
}
return CommandCost();
diff --git a/src/tree_cmd.cpp b/src/tree_cmd.cpp
index 7240cf86d..824ec2c2f 100644
--- a/src/tree_cmd.cpp
+++ b/src/tree_cmd.cpp
@@ -13,6 +13,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;
}
@@ -339,6 +341,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;
diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp
index 297a01d30..3a5ae05ad 100644
--- a/src/tunnelbridge_cmd.cpp
+++ b/src/tunnelbridge_cmd.cpp
@@ -15,6 +15,7 @@
#include "stdafx.h"
#include "newgrf_object.h"
+#include "layer_func.h"
#include "viewport_func.h"
#include "cmd_helper.h"
#include "command_func.h"
@@ -277,6 +278,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;
@@ -641,6 +646,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..5c8f37dcc
--- /dev/null
+++ b/src/underground_gui.cpp
@@ -0,0 +1,321 @@
+/* $Id: terraform_gui.cpp 23547 2011-12-16 18:21:13Z truebrain $ */
+
+/*
+ * This file is part of OpenTTD.
+ * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
+ * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** @file terraform_gui.cpp GUI related to terraforming the map. */
+
+#include "stdafx.h"
+#include "clear_map.h"
+#include "company_func.h"
+#include "company_base.h"
+#include "gui.h"
+#include "window_gui.h"
+#include "window_func.h"
+#include "layer_func.h"
+#include "viewport_func.h"
+#include "command_func.h"
+#include "signs_func.h"
+#include "sound_func.h"
+#include "base_station_base.h"
+#include "textbuf_gui.h"
+#include "genworld.h"
+#include "tree_map.h"
+#include "landscape_type.h"
+#include "tilehighlight_func.h"
+#include "strings_func.h"
+#include "newgrf_object.h"
+#include "newgrf_station.h"
+#include "object.h"
+#include "hotkeys.h"
+#include "engine_base.h"
+
+#include "widgets/underground_widget.h"
+
+#include "table/strings.h"
+#include "error.h"
+
+void ShowError(TileIndex tile, CommandCost res, uint32 cmd)
+{
+ int x = TileX(tile) * TILE_SIZE;
+ int y = TileY(tile) * TILE_SIZE;
+ StringID error_part1 = GB(cmd, 16, 16);
+
+ if (IsLocalCompany() && error_part1 != 0) {
+ ShowErrorMessage(error_part1, res.GetErrorMessage(), WL_INFO, x, y, res.GetTextRefStackGRF(), res.GetTextRefStackSize(), res.GetTextRefStack());
+ }
+}
+
+
+/**
+ * Place a escalator.
+ * @param tile Position to place or start dragging a station.
+ */
+static void PlaceUnderground_Escalator(TileIndex tile)
+{
+ RailType railtype = RAILTYPE_RAIL;
+ Axis orientation = AXIS_X;
+ StationClassID station_class = STAT_CLASS_DFLT;
+ byte station_type = 0;
+
+ uint32 p1 = railtype | orientation << 4 | 1 << 8 | 1 << 16 | _ctrl_pressed << 24;
+ uint32 p2 = station_class | station_type << 8 | INVALID_STATION << 16;
+
+ int w = 1;
+ int h = 1;
+
+ uint top_tile = TopTile(tile);
+ uint base_tile = tile;
+ bool from_top = false; //
+
+ if (top_tile == base_tile)
+ {
+ from_top = true;
+ base_tile += LayerSize();
+ };
+
+ uint32 cmdS = CMD_BUILD_RAIL_STATION | CMD_MSG(STR_ERROR_UNDERGROUND_CAN_T_BUILD_PART);
+ uint32 cmdT = CMD_BUILD_RAIL_STATION | CMD_MSG(STR_ERROR_UNDERGROUND_CAN_T_BUILD_TOP_PART);
+ uint32 cmdB = CMD_BUILD_RAIL_STATION | CMD_MSG(STR_ERROR_UNDERGROUND_CAN_T_BUILD_BOTTOM_PART);
+ CommandContainer cmdTop = { top_tile, p1, p2, cmdT, CcStation, "" };
+ CommandContainer cmdBase = { base_tile, p1, p2, cmdB, CcStation, "" };
+
+ DoCommandFlag flags = DC_AUTO | DC_NO_WATER;
+ CommandCost resTop;
+ CommandCost res;
+
+ // :
+ resTop=DoCommand(&cmdTop, flags | DC_QUERY_COST);
+ if (resTop.Failed())
+ {
+ ShowError(tile, resTop, cmdT);
+ return;
+ }
+
+ res=DoCommand(&cmdBase, flags | DC_QUERY_COST);
+ if (res.Failed())
+ {
+ ShowError(tile, res, cmdB);
+ return;
+ }
+
+ res.AddCost(resTop.GetCost());
+ if (_shift_pressed || !CheckCompanyHasMoney(res))
+ {
+ if (res.Failed()) ShowError(tile, res, cmdS);
+ else ShowEstimatedCostOrIncome(res.GetCost(), TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE);
+ return;
+ }
+
+ // .
+ // ,
+ CommandContainer *cmd1 = from_top ? &cmdTop : &cmdBase;
+ CommandContainer *cmd2 = from_top ? &cmdBase : &cmdTop;
+
+ // ( )
+ res=DoCommand(cmd1, flags | DC_EXEC);
+ assert(!res.Failed());
+
+ //
+ StationID station = GetStationIndex(cmd1->tile);
+ cmd2->p2 = station_class | station_type << 8 | station << 16;
+
+ // ( )
+ res=DoCommand(cmd2, flags | DC_EXEC);
+ assert(!res.Failed());
+}
+
+/** Underground toolbar managing class. */
+struct UndergroundToolbarWindow : Window {
+ int last_user_action; ///< Last started user action.
+
+ UndergroundToolbarWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc)
+ {
+ /* This is needed as we like to have the tree available on OnInit. */
+ this->CreateNestedTree(desc);
+ this->FinishInitNested(window_number);
+ this->last_user_action = WIDGET_LIST_END;
+ }
+
+ ~UndergroundToolbarWindow()
+ {
+ }
+
+ virtual void OnInit()
+ {
+ }
+
+ virtual void OnClick(Point pt, int widget, int click_count)
+ {
+ switch (widget) {
+ case WID_UT_BUILD_ESCALATOR: // WID_TT_BUILD_ESCALATOR
+ HandlePlacePushButton(this, WID_UT_BUILD_ESCALATOR, SPR_CURSOR_RAIL_STATION, HT_RECT);
+ this->last_user_action = widget;
+ break;
+
+ case WID_UT_DEMOLISH: // Demolish aka dynamite button
+ HandlePlacePushButton(this, WID_UT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL);
+ this->last_user_action = widget;
+ break;
+
+ default: NOT_REACHED();
+ }
+ }
+
+ virtual void OnTimeout()
+ {
+ }
+
+ virtual void OnPlaceObject(Point pt, TileIndex tile)
+ {
+ switch (this->last_user_action) {
+ case WID_UT_BUILD_ESCALATOR:
+ PlaceUnderground_Escalator(tile);
+ break;
+
+ case WID_UT_DEMOLISH: // Demolish aka dynamite button
+ PlaceProc_DemolishArea(tile);
+ break;
+
+ default: NOT_REACHED();
+ }
+ }
+
+ virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt)
+ {
+ VpSelectTilesWithMethod(pt.x, pt.y, select_method);
+ }
+
+ virtual Point OnInitialPosition(const WindowDesc *desc, int16 sm_width, int16 sm_height, int window_number)
+ {
+ Point pt = GetToolbarAlignedWindowPosition(sm_width);
+ pt.y += sm_height;
+ return pt;
+ }
+
+ virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile)
+ {
+ if (pt.x != -1) {
+ switch (select_proc) {
+ default: NOT_REACHED();
+ case DDSP_DEMOLISH_AREA:
+ GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
+ break;
+ }
+ }
+ }
+
+ virtual void OnPlaceObjectAbort()
+ {
+ DeleteWindowById(WC_BUILD_OBJECT, 0);
+ this->RaiseButtons();
+ }
+
+ static HotkeyList hotkeys;
+};
+
+/**
+ * Handler for global hotkeys of the UndergroundToolbarWindow.
+ * @param hotkey Hotkey
+ * @return ES_HANDLED if hotkey was accepted.
+ */
+static EventState UndergroundToolbarGlobalHotkeys(int hotkey)
+{
+ if (_game_mode != GM_NORMAL) return ES_NOT_HANDLED;
+/* TODO Window *w = ShowAIDebugWindow(INVALID_COMPANY);
+ if (w == NULL) return ES_NOT_HANDLED;
+ return w->OnHotkey(hotkey); */
+}
+
+EventState UndergroundToolbarGlobalHotkeys(uint16 key, uint16 keycode)
+{
+/* int num = CheckHotkeyMatch<UndergroundToolbarWindow>(_underground_hotkeys, keycode, NULL, true);
+ if (num == -1) return ES_NOT_HANDLED;
+ Window *w = ShowUndergroundToolbar(NULL); TODO
+ if (w == NULL) return ES_NOT_HANDLED;
+ return w->OnKeyPress(key, keycode);
+}
+ int num = CheckHotkeyMatch(underground_hotkeys, keycode, this);
+ if (num == -1) return ES_NOT_HANDLED;
+ this->OnClick(Point(), num, 1);
+ return ES_HANDLED;
++static EventState AIDebugGlobalHotkeys(int hotkey)
++{
++ if (_game_mode != GM_NORMAL) return ES_NOT_HANDLED;
++ Window *w = ShowAIDebugWindow(INVALID_COMPANY);
++ if (w == NULL) return ES_NOT_HANDLED;
++ return w->OnHotkey(hotkey);
++}
+-EventState AIDebugGlobalHotkeys(uint16 key, uint16 keycode)
+-{
+- int num = CheckHotkeyMatch<AIDebugWindow>(_aidebug_hotkeys, keycode, NULL, true);
+- if (num == -1) return ES_NOT_HANDLED;
+- Window *w = ShowAIDebugWindow(INVALID_COMPANY);
+- if (w == NULL) return ES_NOT_HANDLED;
+- return w->OnKeyPress(key, keycode);
+-}
+- */
+ return ES_NOT_HANDLED;
+}
+
+static Hotkey underground_hotkeys[] = {
+ Hotkey('D' | WKC_GLOBAL_HOTKEY, "dynamite", WID_UT_DEMOLISH),
+ Hotkey('0', "placeescalator", WID_UT_BUILD_ESCALATOR),
+ HOTKEY_LIST_END
+};
+HotkeyList UndergroundToolbarWindow::hotkeys("undergroundtoolbar", underground_hotkeys, UndergroundToolbarGlobalHotkeys);
+
+static const NWidgetPart _nested_underground_widgets[] = {
+ NWidget(NWID_HORIZONTAL),
+ NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
+ NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_UNDERGROUND_BUILD, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
+ NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN),
+ EndContainer(),
+ NWidget(NWID_HORIZONTAL),
+ NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_UT_BUILD_ESCALATOR),
+ SetFill(0, 1), SetMinimalSize(42, 22), SetDataTip(SPR_IMG_RAIL_STATION, STR_UNDERGROUND_TOOLTIP_ESCALATOR),
+ NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetMinimalSize(64, 22), EndContainer(),
+ NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_UT_DEMOLISH), SetMinimalSize(22, 22),
+ SetFill(0, 1), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC),
+ EndContainer(),
+};
+
+static WindowDesc _underground_desc(
+ WDP_MANUAL, "undergroundtoolbar", 0, 0,
+ WC_UNDERGROUND, WC_NONE,
+ WDF_CONSTRUCTION,
+ _nested_underground_widgets, lengthof(_nested_underground_widgets)
+);
+
+/**
+ * Show the toolbar for terraforming in the game.
+ * @param link The toolbar we might want to link to.
+ * @return The allocated toolbar.
+ */
+Window *ShowUndergroundToolbar(Window *link)
+{
+ if (!Company::IsValidID(_local_company)) return NULL;
+
+ Window *w;
+ if (link == NULL) {
+ w = AllocateWindowDescFront<UndergroundToolbarWindow>(&_underground_desc, 0);
+ return w;
+ }
+
+ /* Delete the terraform toolbar to place it again. */
+ DeleteWindowById(WC_UNDERGROUND, 0, true);
+ w = AllocateWindowDescFront<UndergroundToolbarWindow>(&_underground_desc, 0);
+ /* Align the terraform toolbar under the main toolbar. */
+ w->top -= w->height;
+ w->SetDirty();
+ /* Put the linked toolbar to the left / right of it. */
+ link->left = w->left + (_current_text_dir == TD_RTL ? w->width : -link->width);
+ link->top = w->top;
+ link->SetDirty();
+
+ return w;
+}
diff --git a/src/underground_gui.h b/src/underground_gui.h
new file mode 100644
index 000000000..81b119545
--- /dev/null
+++ b/src/underground_gui.h
@@ -0,0 +1,19 @@
+/* $Id: underground_gui.h 21608 2012-09-08 1:13:14 constructor $ */
+
+/*
+ * This file is part of OpenTTD.
+ * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
+ * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** @file underground_gui.h GUI stuff related to terraforming. */
+
+#ifndef UNDERGROUND_GUI_H
+#define UNDERGROUND_GUI_H
+
+#include "window_type.h"
+
+Window *ShowUndergroundToolbar(Window *link = NULL);
+
+#endif /* UNDERGROUND_GUI_H */
diff --git a/src/vehicle.cpp b/src/vehicle.cpp
index 9015396a8..2f4322d54 100644
--- a/src/vehicle.cpp
+++ b/src/vehicle.cpp
@@ -15,6 +15,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"
@@ -1142,6 +1143,7 @@ void ViewportAddVehicles(DrawPixelInfo *dpi)
const Vehicle *v = _vehicle_viewport_hash[x + y]; // already masked & 0xFFF
while (v != NULL) {
+ if (LayerIndex(v->tile) == dpi->layer)
if (!(v->vehstatus & VS_HIDDEN) &&
l <= v->coord.right &&
t <= v->coord.bottom &&
diff --git a/src/viewport.cpp b/src/viewport.cpp
index 13f87de1d..e33bcb07c 100644
--- a/src/viewport.cpp
+++ b/src/viewport.cpp
@@ -64,6 +64,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"
@@ -1176,24 +1178,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) {
@@ -1569,6 +1574,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/water_cmd.cpp b/src/water_cmd.cpp
index 31dafe57f..c5c7e47f2 100644
--- a/src/water_cmd.cpp
+++ b/src/water_cmd.cpp
@@ -12,6 +12,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"
@@ -416,6 +417,11 @@ CommandCost CmdBuildCanal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
/* can't make water of water! */
if (IsTileType(tile, MP_WATER) && (!IsTileOwner(tile, OWNER_WATER) || wc == WATER_CLASS_SEA)) continue;
+ /* can't make underground water */
+ if (IsUnderground(tile)) {
+ return_cmd_error(STR_ERROR_UNDERGROUND_CAN_T_BUILD_UNDER_GROUND);
+ }
+
bool water = IsWaterTile(tile);
ret = DoCommand(tile, 0, 0, flags | DC_FORCE_CLEAR_TILE, CMD_LANDSCAPE_CLEAR);
if (ret.Failed()) return ret;
@@ -1042,6 +1048,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<CompanyByte> cur_company(_current_company, OWNER_WATER, FILE_LINE);
@@ -1199,7 +1208,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/genworld_widget.h b/src/widgets/genworld_widget.h
index 877efbb92..9766a0640 100644
--- a/src/widgets/genworld_widget.h
+++ b/src/widgets/genworld_widget.h
@@ -21,6 +21,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_INDUSTRY_PULLDOWN, ///< Dropdown 'No. of industries'.
@@ -69,6 +70,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/underground_widget.h b/src/widgets/underground_widget.h
new file mode 100644
index 000000000..522c9db8b
--- /dev/null
+++ b/src/widgets/underground_widget.h
@@ -0,0 +1,21 @@
+/* $Id: terraform_widget.h 23600 2011-12-19 20:46:17Z truebrain $ */
+
+/*
+ * This file is part of OpenTTD.
+ * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
+ * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** @file terraform_widget.h Types related to the terraform widgets. */
+
+#ifndef WIDGETS_UNDERGROUND_WIDGET_H
+#define WIDGETS_UNDERGROUND_WIDGET_H
+
+/** Widgets of the #TerraformToolbarWindow class. */
+enum UndergroundToolbarWidgets {
+ WID_UT_BUILD_ESCALATOR, ///< Build escalator
+ WID_UT_DEMOLISH, ///< Demolish aka dynamite button.
+};
+
+#endif /* WIDGETS_UNDERGROUND_WIDGET_H */
diff --git a/src/window_type.h b/src/window_type.h
index 7185bfcb4..85f54f076 100644
--- a/src/window_type.h
+++ b/src/window_type.h
@@ -444,6 +444,12 @@ enum WindowClass {
WC_SCEN_LAND_GEN,
/**
+ * Underground (in game); %Window numbers:
+ * - 0 = #UndergroundToolbarWidgets
+ */
+ WC_UNDERGROUND,
+
+ /**
* Generate landscape (newgame); %Window numbers:
* - GLWM_SCENARIO = #CreateScenarioWidgets
* - #GenerateLandscapeWindowMode = #GenerateLandscapeWidgets