/* $Id: terraform_gui.cpp 23547 2011-12-16 18:21:13Z truebrain $ */ /* * This file is part of OpenTTD. * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . */ /** @file terraform_gui.cpp GUI related to terraforming the map. */ #include "stdafx.h" #include "clear_map.h" #include "company_func.h" #include "company_base.h" #include "gui.h" #include "window_gui.h" #include "window_func.h" #include "layer_func.h" #include "viewport_func.h" #include "command_func.h" #include "signs_func.h" #include "sound_func.h" #include "base_station_base.h" #include "textbuf_gui.h" #include "genworld.h" #include "tree_map.h" #include "landscape_type.h" #include "tilehighlight_func.h" #include "strings_func.h" #include "newgrf_object.h" #include "newgrf_station.h" #include "object.h" #include "hotkeys.h" #include "engine_base.h" #include "widgets/underground_widget.h" #include "table/strings.h" #include "error.h" void ShowError(TileIndex tile, CommandCost res, uint32 cmd) { int x = TileX(tile) * TILE_SIZE; int y = TileY(tile) * TILE_SIZE; StringID error_part1 = GB(cmd, 16, 16); if (IsLocalCompany() && error_part1 != 0) { ShowErrorMessage(error_part1, res.GetErrorMessage(), WL_INFO, x, y, res.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(const WindowDesc *desc, WindowNumber window_number) : Window() { /* This is needed as we like to have the tree available on OnInit. */ this->CreateNestedTree(desc); this->FinishInitNested(desc, 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 EventState OnKeyPress(uint16 key, uint16 keycode) { int num = CheckHotkeyMatch(underground_hotkeys, keycode, this); if (num == -1) return ES_NOT_HANDLED; this->OnClick(Point(), num, 1); return ES_HANDLED; } 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 Hotkey underground_hotkeys[]; }; Hotkey UndergroundToolbarWindow::underground_hotkeys[] = { Hotkey('D' | WKC_GLOBAL_HOTKEY, "dynamite", WID_UT_DEMOLISH), Hotkey('0', "placeescalator", WID_UT_BUILD_ESCALATOR), HOTKEY_LIST_END(UndergroundToolbarWindow) }; Hotkey *_underground_hotkeys = UndergroundToolbarWindow::underground_hotkeys; 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 const WindowDesc _underground_desc( WDP_MANUAL, 0, 0, WC_UNDERGROUND, WC_NONE, WDF_CONSTRUCTION, _nested_underground_widgets, lengthof(_nested_underground_widgets) ); /** * Show the toolbar for terraforming in the game. * @param link The toolbar we might want to link to. * @return The allocated toolbar. */ Window *ShowUndergroundToolbar(Window *link) { if (!Company::IsValidID(_local_company)) return NULL; Window *w; if (link == NULL) { w = AllocateWindowDescFront(&_underground_desc, 0); return w; } /* Delete the terraform toolbar to place it again. */ DeleteWindowById(WC_UNDERGROUND, 0, true); w = AllocateWindowDescFront(&_underground_desc, 0); /* Align the terraform toolbar under the main toolbar. */ w->top -= w->height; w->SetDirty(); /* Put the linked toolbar to the left / right of it. */ link->left = w->left + (_current_text_dir == TD_RTL ? w->width : -link->width); link->top = w->top; link->SetDirty(); return w; } EventState UndergroundToolbarGlobalHotkeys(uint16 key, uint16 keycode) { int num = CheckHotkeyMatch(_underground_hotkeys, keycode, NULL, true); if (num == -1) return ES_NOT_HANDLED; Window *w = ShowUndergroundToolbar(NULL); if (w == NULL) return ES_NOT_HANDLED; return w->OnKeyPress(key, keycode); }