diff options
44 files changed, 1192 insertions, 78 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/source.list b/source.list index 7b31df91b..d50c1ee28 100644 --- a/source.list +++ b/source.list @@ -1197,3 +1197,12 @@ thread/thread.h #else thread/thread_none.cpp #end + +# underground +layer.cpp +underground_gui.cpp +layer_type.h +layer_func.h +layer_gui.h +underground_gui.h +widgets/underground_widget.h 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 |