diff options
43 files changed, 1177 insertions, 74 deletions
diff --git a/layer.txt b/layer.txt new file mode 100644 index 000000000..6a2ad1d5f --- /dev/null +++ b/layer.txt @@ -0,0 +1,45 @@ + +* Генерация карты (расширенная карта) + +ВИЗУАЛИЗАЦИЯ + +* устроить "сдвиг" вьюпорта для выбора слоя +- и ограничение по перемещению ++ каждый вьюпорт -- свой слой + +ЛОГИКА + +подземелье: + недоступность: +* наводнение +* изменение ландшафта +* строительство +* домов +* деревьев +* вода +* фабрик +* мостов +* тоннелей +* аэропортов +* дороги на пересечении слоев +? генератор +? реки, города +* края (независимый подъем, void) + +ограничение активности +синхронизация изменения ландшафта + +ГУИ + +** строительство двухуровневой станции +** работа со станцией (строительство, удаление / блокирование частей / стоимость) +* шаблон меню для управления / строительства + ++ добавить выбор кол-ва слоев +- исправить координаты в "справке по местности" +- подписи, названия станций (на все слои), эффекты (на нужный слой) + +БАГИ ++ удаление станции (вылет) +* не работает расширение подземной станции (при пристройке клеточек - добавляется новая) +- грф. "скачет" (не редактируемая часть станции произвольно меняется, при модификации станции) diff --git a/src/base_station_base.h b/src/base_station_base.h index 40543f1b8..9a5157ca4 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 17711a626..5fc5829f9 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" @@ -99,8 +100,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)); @@ -125,6 +146,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 7f663fe86..63307d17d 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" @@ -1072,6 +1073,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 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 932a6cb87..569282130 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 41ee3ac06..8e37724a2 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" @@ -1447,7 +1448,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 becf8d35c..aeefcb49f 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -478,6 +478,15 @@ 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 + # Music menu ###length 1 STR_TOOLBAR_SOUND_MUSIC :Sound/music @@ -5556,3 +5565,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 534be43c1..c4c113f45 100644 --- a/src/lang/russian.txt +++ b/src/lang/russian.txt @@ -604,6 +604,16 @@ STR_LANDSCAPING_MENU_LANDSCAPING :Ландшаф STR_LANDSCAPING_MENU_PLANT_TREES :Высадка деревьев STR_LANDSCAPING_MENU_PLACE_SIGN :Поставить метку +# Underground menu +###length 7 +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) + # Music menu ###length 1 STR_TOOLBAR_SOUND_MUSIC :Звук/музыка @@ -5780,3 +5790,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..fdf182e1f --- /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..7b791b7e9 --- /dev/null +++ b/src/layer_gui.h @@ -0,0 +1,17 @@ +/* $Id: layer_func.h 2012-09-07 18:11:11 constructor $ */ + +/* +* . layer.cpp +*/ + +/** @file layer_gui.h Functions for visualisation map with support layers */ + +#ifndef LAYER_GUI_H +#define LAYER_GUI_H + +#include "layer_func.h" +#include "viewport_type.h" + +uint8 calculateLayer(const Viewport *vp); + +#endif /* LAYER_GUI_H */ diff --git a/src/layer_type.h b/src/layer_type.h new file mode 100644 index 000000000..53eafdde6 --- /dev/null +++ b/src/layer_type.h @@ -0,0 +1,22 @@ +/* $Id: layer_type.h 21493 2012-09-11 2:21:53Z constructor $ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>. + */ + +/** @file layer_type.h Types related to maps. */ + +#ifndef LAYER_TYPE_H +#define LAYER_TYPE_H + +/** Minimal and maximal layer counts */ +static const uint MIN_LAYER_COUNT_BITS = 0; ///< Minimal size of map is equal to 2 ^ MIN_LAYER_SIZE_BITS +static const uint MAX_LAYER_COUNT_BITS = 3; ///< Maximal size of map is equal to 2 ^ MAX_LAYER_SIZE_BITS +static const uint MIN_LAYER_COUNT = 1 << MIN_LAYER_COUNT_BITS; ///< Minimal layer count = 1 +static const uint MAX_LAYER_COUNT = 1 << MAX_LAYER_COUNT_BITS; ///< Maximal layer count = 8 + + +#endif /* LAYER_TYPE_H */ diff --git a/src/main_gui.cpp b/src/main_gui.cpp index b2c4bfee4..60cadfb31 100644 --- a/src/main_gui.cpp +++ b/src/main_gui.cpp @@ -66,7 +66,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 2a08d656e..e47332c1d 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); diff --git a/src/map_func.h b/src/map_func.h index 34cc5ee0e..e8ab9036e 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. 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/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/saveload/map_sl.cpp b/src/saveload/map_sl.cpp index 07a36d6a3..e85313762 100644 --- a/src/saveload/map_sl.cpp +++ b/src/saveload/map_sl.cpp @@ -13,6 +13,7 @@ #include "compat/map_sl_compat.h" #include "../map_func.h" +#include "../layer_func.h" #include "../core/bitmath_func.hpp" #include "../fios.h" #include <array> @@ -21,10 +22,12 @@ static uint32 _map_dim_x; static uint32 _map_dim_y; +static uint32 _layer_count; 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_6, SL_MAX_VERSION), }; struct MAPSChunkHandler : ChunkHandler { @@ -36,6 +39,7 @@ struct MAPSChunkHandler : ChunkHandler { _map_dim_x = MapSizeX(); _map_dim_y = MapSizeY(); + _layer_count = LayerCount(); SlSetArrayIndex(0); SlGlobList(_map_desc); @@ -49,7 +53,7 @@ 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); + AllocateMap(_map_dim_x, _map_dim_y/_layer_count, _layer_count); } void LoadCheck(size_t) const override 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..a8de1488e 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,18 +569,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)); - for (TileIndex tile : ta) { - if (IsTileType(tile, MP_STATION) && GetStationIndex(tile) == st_id) return true; - } + FOR_ALL_LAYERS(layer) { + 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 @@ -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 5a91fa474..d833b0ef7 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" @@ -104,21 +105,24 @@ bool IsHangar(TileIndex t) * @return Succeeded command (if zero or one station found) or failed command (for two or more stations found). */ template <class T> -CommandCost GetStationAround(TileArea ta, StationID closest_station, CompanyID company, T **st) +CommandCost GetStationAround(TileArea ta, StationID closest_station, CompanyID company, T **st, bool layers=false) { ta.Expand(1); /* check around to see if there are any stations there owned by the company */ - for (TileIndex tile_cur : ta) { - if (IsTileType(tile_cur, MP_STATION)) { - StationID t = GetStationIndex(tile_cur); - if (!T::IsValidID(t) || Station::Get(t)->owner != company) continue; - if (closest_station == INVALID_STATION) { - closest_station = t; - } else if (closest_station != t) { - return_cmd_error(STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING); + FOR_ALL_LAYERS(layer) { + for (TileIndex tile_cur : ta) { + if (IsTileType(tile_cur, MP_STATION)) { + StationID t = GetStationIndex(tile_cur); + if (!T::IsValidID(t) || Station::Get(t)->owner != company) continue; + if (closest_station == INVALID_STATION) { + closest_station = t; + } else if (closest_station != t) { + return_cmd_error(STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING); + } } } + if (!layers) break; } *st = (closest_station == INVALID_STATION) ? nullptr : T::Get(closest_station); return CommandCost(); @@ -1073,11 +1077,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) { @@ -1149,7 +1155,7 @@ void GetStationLayout(byte *layout, uint numtracks, uint plat_len, const Station * @return command cost with the error or 'okay' */ template <class T, StringID error_message> -CommandCost FindJoiningBaseStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, T **st) +CommandCost FindJoiningBaseStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, T **st, bool layers=false) { assert(*st == nullptr); bool check_surrounding = true; @@ -1175,7 +1181,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; } @@ -1194,9 +1200,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); } /** @@ -1332,8 +1338,10 @@ CommandCost CmdBuildRailStation(DoCommandFlag flags, TileIndex tile_org, RailTyp 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); @@ -1711,11 +1719,16 @@ CommandCost RemoveRailStation(T *st, DoCommandFlag flags, Money removal_cost) /* determine width and height of platforms */ TileArea ta = st->train_station; - assert(ta.w != 0 && ta.h != 0); + /* TileArea is top finite area */ + assert(IsTopTile(ta.tile)); + assert(ta.IsFinite()); CommandCost cost(EXPENSES_CONSTRUCTION); + /* Check all layers */ + FOR_ALL_LAYERS(layer) /* clear all areas of the station */ - for (TileIndex tile : ta) { + for (TileIndex top_tile : ta) { + TileIndex tile = top_tile + layer * LayerSize(); /* only remove tiles that are actually train station tiles */ if (st->TileBelongsToRailStation(tile)) { std::vector<T*> affected_stations; // dummy @@ -2060,13 +2073,21 @@ CommandCost CmdRemoveRoadStop(DoCommandFlag flags, TileIndex tile, uint8 width, /* Bankrupting company is not supposed to remove roads, there may be road vehicles. */ if (remove_road && (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) || GetRoadStopType(cur_tile) != stop_type) continue; @@ -2230,6 +2251,10 @@ CommandCost CmdBuildAirport(DoCommandFlag flags, TileIndex tile, byte airport_ty 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 923387821..1816d4c8e 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" @@ -2212,20 +2213,27 @@ static const T *FindStationsNearby(TileArea ta, bool distant_join) _deleted_stations_nearby.clear(); /* Check the inside, to return, if we sit on another station */ - for (TileIndex t : ta) { - if (t < MapSize() && IsTileType(t, MP_STATION) && T::IsValidID(GetStationIndex(t))) return T::GetByTile(t); + FOR_ALL_LAYERS(layer) { + for (TileIndex tile : ta) { + TileIndex t = TopTile(tile) + layer * LayerSize(); + if (t < MapSize() && IsTileType(t, MP_STATION) && T::IsValidID(GetStationIndex(t))) + { + if (t == tile) return T::GetByTile(t); + AddNearbyStation<T>(t, &ctx); + } + } } /* Look for deleted stations */ for (const BaseStation *st : BaseStation::Iterate()) { if (T::IsExpected(st) && !st->IsInUse() && st->owner == _local_company) { /* Include only within station spread (yes, it is strictly less than) */ - if (std::max(DistanceMax(ta.tile, st->xy), DistanceMax(TILE_ADDXY(ta.tile, ta.w - 1, ta.h - 1), st->xy)) < _settings_game.station.station_spread) { + if (std::max(DistanceMax(TopTile(ta.tile), TopTile(st->xy)), DistanceMax(TILE_ADDXY(TopTile(ta.tile), ta.w - 1, ta.h - 1), TopTile(st->xy))) < _settings_game.station.station_spread) { _deleted_stations_nearby.push_back({st->xy, st->index}); /* Add the station when it's within where we're going to build */ - if (IsInsideBS(TileX(st->xy), TileX(ctx.tile), ctx.w) && - IsInsideBS(TileY(st->xy), TileY(ctx.tile), ctx.h)) { + if (IsInsideBS(LayerX(st->xy), LayerX(ctx.tile), ctx.w) && + IsInsideBS(LayerY(st->xy), LayerY(ctx.tile), ctx.h)) { AddNearbyStation<T>(st->xy, &ctx); } } @@ -2238,8 +2246,11 @@ static const T *FindStationsNearby(TileArea ta, bool distant_join) if (distant_join && std::min(ta.w, ta.h) >= _settings_game.station.station_spread) return nullptr; uint max_dist = distant_join ? _settings_game.station.station_spread - std::min(ta.w, ta.h) : 1; - TileIndex tile = TileAddByDir(ctx.tile, DIR_N); - CircularTileSearch(&tile, max_dist, ta.w, ta.h, AddNearbyStation<T>, &ctx); + FOR_ALL_LAYERS(layer) { + ctx.tile = TopTile(ctx.tile) + layer * LayerSize(); + TileIndex tile = TileAddByDir(ctx.tile, DIR_N); + CircularTileSearch(&tile, max_dist, ta.w, ta.h, AddNearbyStation<T>, &ctx); + } return nullptr; } diff --git a/src/table/settings/game_settings.ini b/src/table/settings/game_settings.ini index 79fac7513..f4b7258a0 100644 --- a/src/table/settings/game_settings.ini +++ b/src/table/settings/game_settings.ini @@ -419,3 +419,12 @@ var = gui.sg_new_nonstop from = SLV_22 to = SLV_93 def = false + +[SDT_VAR] +base = GameSettings +var = game_creation.layers +type = SLE_UINT8 +flags = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC +def = 1 +min = MIN_LAYER_COUNT_BITS +max = MAX_LAYER_COUNT_BITS diff --git a/src/table/settings/gui_settings.ini b/src/table/settings/gui_settings.ini index ad18f8318..5b1a63001 100644 --- a/src/table/settings/gui_settings.ini +++ b/src/table/settings/gui_settings.ini @@ -848,3 +848,11 @@ min = 1 max = 65535 cat = SC_EXPERT +[SDTC_VAR] +var = gui.layer_view_type +type = SLE_UINT32 +flags = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC +def = 0 +min = 0 +max = UINT32_MAX +proc = RedrawScreen diff --git a/src/terraform_cmd.cpp b/src/terraform_cmd.cpp index 21df5ccbe..c6c43799a 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" @@ -248,6 +249,10 @@ std::tuple<CommandCost, Money, TileIndex> CmdTerraformLand(DoCommandFlag flags, 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..4bd584539 100644 --- a/src/tile_map.h +++ b/src/tile_map.h @@ -134,7 +134,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 b6af998a7..8a9292ad6 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 13c52f2b4..068a1962e 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" @@ -980,6 +984,48 @@ static CallBackFunction ToolbarForestClick(Window *w) 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. * @@ -993,6 +1039,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 405a83cce..450582941 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" @@ -2328,6 +2329,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; @@ -2761,6 +2765,8 @@ CommandCost CmdRenameTown(DoCommandFlag flags, TownID town_id, const std::string 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 c98758062..bd112f31b 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" @@ -74,7 +75,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; } @@ -392,6 +394,10 @@ CommandCost CmdPlantTree(DoCommandFlag flags, TileIndex tile, TileIndex start_ti CommandCost cost(EXPENSES_OTHER); if (start_tile >= MapSize()) return CMD_ERROR; + + /* tree only top layer */ + if (IsUnderground(start_tile)) 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 543ac8b28..3e2d4206a 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" @@ -303,6 +304,10 @@ CommandCost CmdBuildBridge(DoCommandFlag flags, TileIndex tile_end, TileIndex ti 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; @@ -693,6 +698,12 @@ CommandCost CmdBuildTunnel(DoCommandFlag flags, TileIndex start_tile, TransportT 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..05ac87bab --- /dev/null +++ b/src/underground_gui.cpp @@ -0,0 +1,321 @@ +/* $Id: terraform_gui.cpp 23547 2011-12-16 18:21:13Z truebrain $ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>. + */ + +/** @file terraform_gui.cpp GUI related to terraforming the map. */ + +#include "stdafx.h" +#include "clear_map.h" +#include "company_func.h" +#include "company_base.h" +#include "gui.h" +#include "window_gui.h" +#include "window_func.h" +#include "layer_func.h" +#include "viewport_func.h" +#include "command_func.h" +#include "signs_func.h" +#include "sound_func.h" +#include "base_station_base.h" +#include "textbuf_gui.h" +#include "genworld.h" +#include "tree_map.h" +#include "landscape_type.h" +#include "tilehighlight_func.h" +#include "strings_func.h" +#include "newgrf_object.h" +#include "newgrf_station.h" +#include "object.h" +#include "hotkeys.h" +#include "engine_base.h" + +#include "widgets/underground_widget.h" + +#include "table/strings.h" +#include "error.h" + +void ShowError(TileIndex tile, CommandCost res, uint32 cmd) +{ + int x = TileX(tile) * TILE_SIZE; + int y = TileY(tile) * TILE_SIZE; + StringID error_part1 = GB(cmd, 16, 16); + + if (IsLocalCompany() && error_part1 != 0) { + ShowErrorMessage(error_part1, res.GetErrorMessage(), WL_INFO, x, y, res.GetTextRefStackGRF(), res.GetTextRefStackSize(), res.GetTextRefStack()); + } +} + + +/** + * Place a escalator. + * @param tile Position to place or start dragging a station. + */ +static void PlaceUnderground_Escalator(TileIndex tile) +{ + RailType railtype = RAILTYPE_RAIL; + Axis orientation = AXIS_X; + StationClassID station_class = STAT_CLASS_DFLT; + byte station_type = 0; + + uint32 p1 = railtype | orientation << 4 | 1 << 8 | 1 << 16 | _ctrl_pressed << 24; + uint32 p2 = station_class | station_type << 8 | INVALID_STATION << 16; + + int w = 1; + int h = 1; + + uint top_tile = TopTile(tile); + uint base_tile = tile; + bool from_top = false; // + + if (top_tile == base_tile) + { + from_top = true; + base_tile += LayerSize(); + }; + + uint32 cmdS = CMD_BUILD_RAIL_STATION | CMD_MSG(STR_ERROR_UNDERGROUND_CAN_T_BUILD_PART); + uint32 cmdT = CMD_BUILD_RAIL_STATION | CMD_MSG(STR_ERROR_UNDERGROUND_CAN_T_BUILD_TOP_PART); + uint32 cmdB = CMD_BUILD_RAIL_STATION | CMD_MSG(STR_ERROR_UNDERGROUND_CAN_T_BUILD_BOTTOM_PART); + CommandContainer cmdTop = { top_tile, p1, p2, cmdT, CcStation, "" }; + CommandContainer cmdBase = { base_tile, p1, p2, cmdB, CcStation, "" }; + + DoCommandFlag flags = DC_AUTO | DC_NO_WATER; + CommandCost resTop; + CommandCost res; + + // : + resTop=DoCommand(&cmdTop, flags | DC_QUERY_COST); + if (resTop.Failed()) + { + ShowError(tile, resTop, cmdT); + return; + } + + res=DoCommand(&cmdBase, flags | DC_QUERY_COST); + if (res.Failed()) + { + ShowError(tile, res, cmdB); + return; + } + + res.AddCost(resTop.GetCost()); + if (_shift_pressed || !CheckCompanyHasMoney(res)) + { + if (res.Failed()) ShowError(tile, res, cmdS); + else ShowEstimatedCostOrIncome(res.GetCost(), TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE); + return; + } + + // . + // , + CommandContainer *cmd1 = from_top ? &cmdTop : &cmdBase; + CommandContainer *cmd2 = from_top ? &cmdBase : &cmdTop; + + // ( ) + res=DoCommand(cmd1, flags | DC_EXEC); + assert(!res.Failed()); + + // + StationID station = GetStationIndex(cmd1->tile); + cmd2->p2 = station_class | station_type << 8 | station << 16; + + // ( ) + res=DoCommand(cmd2, flags | DC_EXEC); + assert(!res.Failed()); +} + +/** Underground toolbar managing class. */ +struct UndergroundToolbarWindow : Window { + int last_user_action; ///< Last started user action. + + UndergroundToolbarWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) + { + /* This is needed as we like to have the tree available on OnInit. */ + this->CreateNestedTree(desc); + this->FinishInitNested(window_number); + this->last_user_action = WIDGET_LIST_END; + } + + ~UndergroundToolbarWindow() + { + } + + virtual void OnInit() + { + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_UT_BUILD_ESCALATOR: // WID_TT_BUILD_ESCALATOR + HandlePlacePushButton(this, WID_UT_BUILD_ESCALATOR, SPR_CURSOR_RAIL_STATION, HT_RECT); + this->last_user_action = widget; + break; + + case WID_UT_DEMOLISH: // Demolish aka dynamite button + HandlePlacePushButton(this, WID_UT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL); + this->last_user_action = widget; + break; + + default: NOT_REACHED(); + } + } + + virtual void OnTimeout() + { + } + + virtual void OnPlaceObject(Point pt, TileIndex tile) + { + switch (this->last_user_action) { + case WID_UT_BUILD_ESCALATOR: + PlaceUnderground_Escalator(tile); + break; + + case WID_UT_DEMOLISH: // Demolish aka dynamite button + PlaceProc_DemolishArea(tile); + break; + + default: NOT_REACHED(); + } + } + + virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) + { + VpSelectTilesWithMethod(pt.x, pt.y, select_method); + } + + virtual Point OnInitialPosition(const WindowDesc *desc, int16 sm_width, int16 sm_height, int window_number) + { + Point pt = GetToolbarAlignedWindowPosition(sm_width); + pt.y += sm_height; + return pt; + } + + virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) + { + if (pt.x != -1) { + switch (select_proc) { + default: NOT_REACHED(); + case DDSP_DEMOLISH_AREA: + GUIPlaceProcDragXY(select_proc, start_tile, end_tile); + break; + } + } + } + + virtual void OnPlaceObjectAbort() + { + CloseWindowById(WC_BUILD_OBJECT, 0); + this->RaiseButtons(); + } + + static HotkeyList hotkeys; +}; + +/** + * Handler for global hotkeys of the UndergroundToolbarWindow. + * @param hotkey Hotkey + * @return ES_HANDLED if hotkey was accepted. + */ +static EventState UndergroundToolbarGlobalHotkeys(int hotkey) +{ + if (_game_mode != GM_NORMAL) return ES_NOT_HANDLED; +/* TODO Window *w = ShowAIDebugWindow(INVALID_COMPANY); + if (w == NULL) return ES_NOT_HANDLED; + return w->OnHotkey(hotkey); */ +} + +EventState UndergroundToolbarGlobalHotkeys(uint16 key, uint16 keycode) +{ +/* int num = CheckHotkeyMatch<UndergroundToolbarWindow>(_underground_hotkeys, keycode, NULL, true); + if (num == -1) return ES_NOT_HANDLED; + Window *w = ShowUndergroundToolbar(NULL); TODO + if (w == NULL) return ES_NOT_HANDLED; + return w->OnKeyPress(key, keycode); +} + int num = CheckHotkeyMatch(underground_hotkeys, keycode, this); + if (num == -1) return ES_NOT_HANDLED; + this->OnClick(Point(), num, 1); + return ES_HANDLED; ++static EventState AIDebugGlobalHotkeys(int hotkey) ++{ ++ if (_game_mode != GM_NORMAL) return ES_NOT_HANDLED; ++ Window *w = ShowAIDebugWindow(INVALID_COMPANY); ++ if (w == NULL) return ES_NOT_HANDLED; ++ return w->OnHotkey(hotkey); ++} +-EventState AIDebugGlobalHotkeys(uint16 key, uint16 keycode) +-{ +- int num = CheckHotkeyMatch<AIDebugWindow>(_aidebug_hotkeys, keycode, NULL, true); +- if (num == -1) return ES_NOT_HANDLED; +- Window *w = ShowAIDebugWindow(INVALID_COMPANY); +- if (w == NULL) return ES_NOT_HANDLED; +- return w->OnKeyPress(key, keycode); +-} +- */ + return ES_NOT_HANDLED; +} + +static Hotkey underground_hotkeys[] = { + Hotkey('D' | WKC_GLOBAL_HOTKEY, "dynamite", WID_UT_DEMOLISH), + Hotkey('0', "placeescalator", WID_UT_BUILD_ESCALATOR), + HOTKEY_LIST_END +}; +HotkeyList UndergroundToolbarWindow::hotkeys("undergroundtoolbar", underground_hotkeys, UndergroundToolbarGlobalHotkeys); + +static const NWidgetPart _nested_underground_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), + NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_UNDERGROUND_BUILD, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_UT_BUILD_ESCALATOR), + SetFill(0, 1), SetMinimalSize(42, 22), SetDataTip(SPR_IMG_RAIL_STATION, STR_UNDERGROUND_TOOLTIP_ESCALATOR), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetMinimalSize(64, 22), EndContainer(), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_UT_DEMOLISH), SetMinimalSize(22, 22), + SetFill(0, 1), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC), + EndContainer(), +}; + +static WindowDesc _underground_desc( + WDP_MANUAL, "undergroundtoolbar", 0, 0, + WC_UNDERGROUND, WC_NONE, + WDF_CONSTRUCTION, + _nested_underground_widgets, lengthof(_nested_underground_widgets) +); + +/** + * Show the toolbar for terraforming in the game. + * @param link The toolbar we might want to link to. + * @return The allocated toolbar. + */ +Window *ShowUndergroundToolbar(Window *link) +{ + if (!Company::IsValidID(_local_company)) return NULL; + + Window *w; + if (link == NULL) { + w = AllocateWindowDescFront<UndergroundToolbarWindow>(&_underground_desc, 0); + return w; + } + + /* Delete the terraform toolbar to place it again. */ + CloseWindowById(WC_UNDERGROUND, 0, true); + w = AllocateWindowDescFront<UndergroundToolbarWindow>(&_underground_desc, 0); + /* Align the terraform toolbar under the main toolbar. */ + w->top -= w->height; + w->SetDirty(); + /* Put the linked toolbar to the left / right of it. */ + link->left = w->left + (_current_text_dir == TD_RTL ? w->width : -link->width); + link->top = w->top; + link->SetDirty(); + + return w; +} diff --git a/src/underground_gui.h b/src/underground_gui.h new file mode 100644 index 000000000..81b119545 --- /dev/null +++ b/src/underground_gui.h @@ -0,0 +1,19 @@ +/* $Id: underground_gui.h 21608 2012-09-08 1:13:14 constructor $ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>. + */ + +/** @file underground_gui.h GUI stuff related to terraforming. */ + +#ifndef UNDERGROUND_GUI_H +#define UNDERGROUND_GUI_H + +#include "window_type.h" + +Window *ShowUndergroundToolbar(Window *link = NULL); + +#endif /* UNDERGROUND_GUI_H */ diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 120c4a259..0e338737c 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 69db0aeab..d8fd85b5a 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" @@ -1247,24 +1249,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) { @@ -1738,6 +1743,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 c02a1e9b4..be95c096e 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" @@ -468,6 +469,11 @@ CommandCost CmdBuildCanal(DoCommandFlag flags, TileIndex tile, TileIndex start_t 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 */ @@ -1103,6 +1109,9 @@ void DoFloodTile(TileIndex target) { assert(!IsTileType(target, MP_WATER)); + /* */ + if (IsUnderground(target)) return; + bool flooded = false; // Will be set to true if something is changed. Backup<CompanyID> cur_company(_current_company, OWNER_WATER, FILE_LINE); @@ -1261,7 +1270,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 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/underground_widget.h b/src/widgets/underground_widget.h new file mode 100644 index 000000000..522c9db8b --- /dev/null +++ b/src/widgets/underground_widget.h @@ -0,0 +1,21 @@ +/* $Id: terraform_widget.h 23600 2011-12-19 20:46:17Z truebrain $ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>. + */ + +/** @file terraform_widget.h Types related to the terraform widgets. */ + +#ifndef WIDGETS_UNDERGROUND_WIDGET_H +#define WIDGETS_UNDERGROUND_WIDGET_H + +/** Widgets of the #TerraformToolbarWindow class. */ +enum UndergroundToolbarWidgets { + WID_UT_BUILD_ESCALATOR, ///< Build escalator + WID_UT_DEMOLISH, ///< Demolish aka dynamite button. +}; + +#endif /* WIDGETS_UNDERGROUND_WIDGET_H */ diff --git a/src/window_type.h b/src/window_type.h index 6eb9573b6..cfaa1e878 100644 --- a/src/window_type.h +++ b/src/window_type.h @@ -441,6 +441,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 |