/* $Id: terraform_gui.cpp 23547 2011-12-16 18:21:13Z truebrain $ */
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see .
*/
/** @file terraform_gui.cpp GUI related to terraforming the map. */
#include "stdafx.h"
#include "clear_map.h"
#include "company_func.h"
#include "company_base.h"
#include "gui.h"
#include "window_gui.h"
#include "window_func.h"
#include "layer_func.h"
#include "viewport_func.h"
#include "command_func.h"
#include "signs_func.h"
#include "sound_func.h"
#include "base_station_base.h"
#include "textbuf_gui.h"
#include "genworld.h"
#include "tree_map.h"
#include "landscape_type.h"
#include "tilehighlight_func.h"
#include "strings_func.h"
#include "newgrf_object.h"
#include "newgrf_station.h"
#include "object.h"
#include "hotkeys.h"
#include "engine_base.h"
#include "widgets/underground_widget.h"
#include "table/strings.h"
#include "error.h"
void ShowError(TileIndex tile, CommandCost res, uint32 cmd)
{
int x = TileX(tile) * TILE_SIZE;
int y = TileY(tile) * TILE_SIZE;
StringID error_part1 = GB(cmd, 16, 16);
if (IsLocalCompany() && error_part1 != 0) {
ShowErrorMessage(error_part1, res.GetErrorMessage(), WL_INFO, x, y, res.GetTextRefStackGRF(), res.GetTextRefStackSize(), res.GetTextRefStack());
}
}
/**
* Place a escalator.
* @param tile Position to place or start dragging a station.
*/
static void PlaceUnderground_Escalator(TileIndex tile)
{
RailType railtype = RAILTYPE_RAIL;
Axis orientation = AXIS_X;
StationClassID station_class = STAT_CLASS_DFLT;
byte station_type = 0;
uint32 p1 = railtype | orientation << 4 | 1 << 8 | 1 << 16 | _ctrl_pressed << 24;
uint32 p2 = station_class | station_type << 8 | INVALID_STATION << 16;
int w = 1;
int h = 1;
uint top_tile = TopTile(tile);
uint base_tile = tile;
bool from_top = false; // Строим от верхнего слоя
if (top_tile == base_tile)
{
from_top = true;
base_tile += LayerSize();
};
uint32 cmdS = CMD_BUILD_RAIL_STATION | CMD_MSG(STR_ERROR_UNDERGROUND_CAN_T_BUILD_PART);
uint32 cmdT = CMD_BUILD_RAIL_STATION | CMD_MSG(STR_ERROR_UNDERGROUND_CAN_T_BUILD_TOP_PART);
uint32 cmdB = CMD_BUILD_RAIL_STATION | CMD_MSG(STR_ERROR_UNDERGROUND_CAN_T_BUILD_BOTTOM_PART);
CommandContainer cmdTop = { top_tile, p1, p2, cmdT, CcStation, "" };
CommandContainer cmdBase = { base_tile, p1, p2, cmdB, CcStation, "" };
DoCommandFlag flags = DC_AUTO | DC_NO_WATER;
CommandCost resTop;
CommandCost res;
// Проверяем возможность постройки верха и низа:
resTop=DoCommand(&cmdTop, flags | DC_QUERY_COST);
if (resTop.Failed())
{
ShowError(tile, resTop, cmdT);
return;
}
res=DoCommand(&cmdBase, flags | DC_QUERY_COST);
if (res.Failed())
{
ShowError(tile, res, cmdB);
return;
}
res.AddCost(resTop.GetCost());
if (_shift_pressed || !CheckCompanyHasMoney(res))
{
if (res.Failed()) ShowError(tile, res, cmdS);
else ShowEstimatedCostOrIncome(res.GetCost(), TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE);
return;
}
// Станции могут быть сверху и снизу.
// Чтобы не было конфликта, нужно строить от активного слоя
CommandContainer *cmd1 = from_top ? &cmdTop : &cmdBase;
CommandContainer *cmd2 = from_top ? &cmdBase : &cmdTop;
// Строим уровень (в активном слое)
res=DoCommand(cmd1, flags | DC_EXEC);
assert(!res.Failed());
// Уточняем параметры
StationID station = GetStationIndex(cmd1->tile);
cmd2->p2 = station_class | station_type << 8 | station << 16;
// Строим уровень (в другом слое)
res=DoCommand(cmd2, flags | DC_EXEC);
assert(!res.Failed());
}
/** Underground toolbar managing class. */
struct UndergroundToolbarWindow : Window {
int last_user_action; ///< Last started user action.
UndergroundToolbarWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc)
{
/* This is needed as we like to have the tree available on OnInit. */
this->CreateNestedTree(desc);
this->FinishInitNested(window_number);
this->last_user_action = WIDGET_LIST_END;
}
~UndergroundToolbarWindow()
{
}
virtual void OnInit()
{
}
virtual void OnClick(Point pt, int widget, int click_count)
{
switch (widget) {
case WID_UT_BUILD_ESCALATOR: // WID_TT_BUILD_ESCALATOR
HandlePlacePushButton(this, WID_UT_BUILD_ESCALATOR, SPR_CURSOR_RAIL_STATION, HT_RECT);
this->last_user_action = widget;
break;
case WID_UT_DEMOLISH: // Demolish aka dynamite button
HandlePlacePushButton(this, WID_UT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL);
this->last_user_action = widget;
break;
default: NOT_REACHED();
}
}
virtual void OnTimeout()
{
}
virtual void OnPlaceObject(Point pt, TileIndex tile)
{
switch (this->last_user_action) {
case WID_UT_BUILD_ESCALATOR:
PlaceUnderground_Escalator(tile);
break;
case WID_UT_DEMOLISH: // Demolish aka dynamite button
PlaceProc_DemolishArea(tile);
break;
default: NOT_REACHED();
}
}
virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt)
{
VpSelectTilesWithMethod(pt.x, pt.y, select_method);
}
virtual Point OnInitialPosition(const WindowDesc *desc, int16 sm_width, int16 sm_height, int window_number)
{
Point pt = GetToolbarAlignedWindowPosition(sm_width);
pt.y += sm_height;
return pt;
}
virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile)
{
if (pt.x != -1) {
switch (select_proc) {
default: NOT_REACHED();
case DDSP_DEMOLISH_AREA:
GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
break;
}
}
}
virtual void OnPlaceObjectAbort()
{
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(_underground_hotkeys, keycode, NULL, true);
if (num == -1) return ES_NOT_HANDLED;
Window *w = ShowUndergroundToolbar(NULL); TODO
if (w == NULL) return ES_NOT_HANDLED;
return w->OnKeyPress(key, keycode);
}
int num = CheckHotkeyMatch(underground_hotkeys, keycode, this);
if (num == -1) return ES_NOT_HANDLED;
this->OnClick(Point(), num, 1);
return ES_HANDLED;
+static EventState AIDebugGlobalHotkeys(int hotkey)
+{
+ if (_game_mode != GM_NORMAL) return ES_NOT_HANDLED;
+ Window *w = ShowAIDebugWindow(INVALID_COMPANY);
+ if (w == NULL) return ES_NOT_HANDLED;
+ return w->OnHotkey(hotkey);
+}
-EventState AIDebugGlobalHotkeys(uint16 key, uint16 keycode)
-{
- int num = CheckHotkeyMatch(_aidebug_hotkeys, keycode, NULL, true);
- if (num == -1) return ES_NOT_HANDLED;
- Window *w = ShowAIDebugWindow(INVALID_COMPANY);
- if (w == NULL) return ES_NOT_HANDLED;
- return w->OnKeyPress(key, keycode);
-}
- */
return ES_NOT_HANDLED;
}
static Hotkey underground_hotkeys[] = {
Hotkey('D' | WKC_GLOBAL_HOTKEY, "dynamite", WID_UT_DEMOLISH),
Hotkey('0', "placeescalator", WID_UT_BUILD_ESCALATOR),
HOTKEY_LIST_END
};
HotkeyList UndergroundToolbarWindow::hotkeys("undergroundtoolbar", underground_hotkeys, UndergroundToolbarGlobalHotkeys);
static const NWidgetPart _nested_underground_widgets[] = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_UNDERGROUND_BUILD, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_UT_BUILD_ESCALATOR),
SetFill(0, 1), SetMinimalSize(42, 22), SetDataTip(SPR_IMG_RAIL_STATION, STR_UNDERGROUND_TOOLTIP_ESCALATOR),
NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetMinimalSize(64, 22), EndContainer(),
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_UT_DEMOLISH), SetMinimalSize(22, 22),
SetFill(0, 1), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC),
EndContainer(),
};
static WindowDesc _underground_desc(
WDP_MANUAL, "undergroundtoolbar", 0, 0,
WC_UNDERGROUND, WC_NONE,
WDF_CONSTRUCTION,
_nested_underground_widgets, lengthof(_nested_underground_widgets)
);
/**
* Show the toolbar for terraforming in the game.
* @param link The toolbar we might want to link to.
* @return The allocated toolbar.
*/
Window *ShowUndergroundToolbar(Window *link)
{
if (!Company::IsValidID(_local_company)) return NULL;
Window *w;
if (link == NULL) {
w = AllocateWindowDescFront(&_underground_desc, 0);
return w;
}
/* Delete the terraform toolbar to place it again. */
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;
}