Skip to content

Commit

Permalink
Feature: Selective demolition tool.
Browse files Browse the repository at this point in the history
Idea from OpenTTD#7394.
  • Loading branch information
stormcone committed Dec 16, 2019
1 parent df2a19e commit 97801b1
Show file tree
Hide file tree
Showing 9 changed files with 111 additions and 3 deletions.
7 changes: 7 additions & 0 deletions src/command_type.h
Expand Up @@ -421,6 +421,13 @@ enum CommandPauseLevel {
CMDPL_ALL_ACTIONS, ///< All actions may be executed.
};

/** Demolition modes */
enum DemolitionMode : byte {
DM_ALL, ///< Demolish everything
DM_TREES, ///< Demolish trees
DM_COMPANY_PROPS ///< Demolish company properties
};

/**
* Defines the callback type for all command handler functions.
*
Expand Down
14 changes: 14 additions & 0 deletions src/landscape.cpp
Expand Up @@ -736,6 +736,7 @@ CommandCost CmdLandscapeClear(TileIndex tile, DoCommandFlag flags, uint32 p1, ui
* @param p1 start tile of area dragging
* @param p2 various bitstuffed data.
* bit 0: Whether to use the Orthogonal (0) or Diagonal (1) iterator.
* bit 1-2: Demolition mode.
* @param text unused
* @return the cost of this operation or an error
*/
Expand All @@ -750,10 +751,23 @@ CommandCost CmdClearArea(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32

const Company *c = (flags & (DC_AUTO | DC_BANKRUPT)) ? nullptr : Company::GetIfValid(_current_company);
int limit = (c == nullptr ? INT32_MAX : GB(c->clear_limit, 16, 16));
const DemolitionMode demolition_mode = (DemolitionMode)GB(p2, 1, 2);

TileIterator *iter = HasBit(p2, 0) ? (TileIterator *)new DiagonalTileIterator(tile, p1) : new OrthogonalTileIterator(tile, p1);
for (; *iter != INVALID_TILE; ++(*iter)) {
TileIndex t = *iter;
switch (demolition_mode) {
case DM_ALL: /* Do nothing */
break;
case DM_TREES:
if (GetTileType(t) != MP_TREES) continue;
break;
case DM_COMPANY_PROPS:
if (IsTileType(t, MP_HOUSE) || IsTileType(t, MP_INDUSTRY) || GetTileOwner(t) != _local_company) continue;
break;
default:
return CMD_ERROR;
}
CommandCost ret = DoCommand(t, 0, 0, flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR);
if (ret.Failed()) {
last_error = ret;
Expand Down
4 changes: 4 additions & 0 deletions src/lang/english.txt
Expand Up @@ -250,6 +250,10 @@ STR_TOOLTIP_VSCROLL_BAR_SCROLLS_LIST :{BLACK}Scroll b
STR_TOOLTIP_HSCROLL_BAR_SCROLLS_LIST :{BLACK}Scroll bar - scrolls list left/right
STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC :{BLACK}Demolish buildings etc. on a square of land. Ctrl selects the area diagonally. Shift toggles building/showing cost estimate

STR_DEMOLISH_EVERYTHING_TOOLTIP :{BLACK}Demolish everything
STR_DEMOLISH_TREES_TOOLTIP :{BLACK}Demolish trees
STR_DEMOLISH_COMPANY_PROPERTIES_TOOLTIP :{BLACK}Demolish company properties

# Show engines button
STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN :{BLACK}Show hidden
STR_SHOW_HIDDEN_ENGINES_VEHICLE_ROAD_VEHICLE :{BLACK}Show hidden
Expand Down
4 changes: 4 additions & 0 deletions src/script/api/game/game_window.hpp.sq
Expand Up @@ -99,6 +99,7 @@ void SQGSWindow_Register(Squirrel *engine)
SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_INDUSTRY, "WC_BUILD_INDUSTRY");
SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SELECT_GAME, "WC_SELECT_GAME");
SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SCEN_LAND_GEN, "WC_SCEN_LAND_GEN");
SQGSWindow.DefSQConst(engine, ScriptWindow::WC_DEMOLITION_MODE_SELECTION, "WC_DEMOLITION_MODE_SELECTION");
SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GENERATE_LANDSCAPE, "WC_GENERATE_LANDSCAPE");
SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MODAL_PROGRESS, "WC_MODAL_PROGRESS");
SQGSWindow.DefSQConst(engine, ScriptWindow::WC_NETWORK_WINDOW, "WC_NETWORK_WINDOW");
Expand Down Expand Up @@ -1176,6 +1177,9 @@ void SQGSWindow_Register(Squirrel *engine)
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_DECREASE_SIZE, "WID_ETT_DECREASE_SIZE");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_NEW_SCENARIO, "WID_ETT_NEW_SCENARIO");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_RESET_LANDSCAPE, "WID_ETT_RESET_LANDSCAPE");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DM_ALL, "WID_DM_ALL");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DM_TREES, "WID_DM_TREES");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DM_COMPANY_PROPS, "WID_DM_COMPANY_PROPS");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_CAPTION, "WID_VT_CAPTION");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_ORDER_VIEW, "WID_VT_ORDER_VIEW");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_TIMETABLE_PANEL, "WID_VT_TIMETABLE_PANEL");
Expand Down
13 changes: 13 additions & 0 deletions src/script/api/script_window.hpp
Expand Up @@ -525,6 +525,12 @@ class ScriptWindow : public ScriptObject {
*/
WC_SCEN_LAND_GEN = ::WC_SCEN_LAND_GEN,

/**
* Demolition selection mode; %Window numbers:
* - 0 = #DemolitionModeSelectionWidgets
*/
WC_DEMOLITION_MODE_SELECTION = ::WC_DEMOLITION_MODE_SELECTION,

/**
* Generate landscape (newgame); %Window numbers:
* - GLWM_SCENARIO = #CreateScenarioWidgets
Expand Down Expand Up @@ -2391,6 +2397,13 @@ class ScriptWindow : public ScriptObject {
WID_ETT_RESET_LANDSCAPE = ::WID_ETT_RESET_LANDSCAPE, ///< Button for removing all company-owned property.
};

/** Widgets of the #DemolitionModeSelectionWindow class. */
enum DemolitionModeSelectionWidgets {
WID_DM_ALL = ::WID_DM_ALL, ///< Demolish everything
WID_DM_TREES = ::WID_DM_TREES, ///< Demolish trees
WID_DM_COMPANY_PROPS = ::WID_DM_COMPANY_PROPS, ///< Demolish company properties
};

/* automatically generated from ../../widgets/timetable_widget.h */
/** Widgets of the #TimetableWindow class. */
enum VehicleTimetableWidgets {
Expand Down
2 changes: 2 additions & 0 deletions src/script/api/template/template_window.hpp.sq
Expand Up @@ -221,6 +221,8 @@ namespace SQConvert {
template <> inline int Return<ScriptWindow::TerraformToolbarWidgets>(HSQUIRRELVM vm, ScriptWindow::TerraformToolbarWidgets res) { sq_pushinteger(vm, (int32)res); return 1; }
template <> inline ScriptWindow::EditorTerraformToolbarWidgets GetParam(ForceType<ScriptWindow::EditorTerraformToolbarWidgets>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::EditorTerraformToolbarWidgets)tmp; }
template <> inline int Return<ScriptWindow::EditorTerraformToolbarWidgets>(HSQUIRRELVM vm, ScriptWindow::EditorTerraformToolbarWidgets res) { sq_pushinteger(vm, (int32)res); return 1; }
template <> inline ScriptWindow::DemolitionModeSelectionWidgets GetParam(ForceType<ScriptWindow::DemolitionModeSelectionWidgets>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::DemolitionModeSelectionWidgets)tmp; }
template <> inline int Return<ScriptWindow::DemolitionModeSelectionWidgets>(HSQUIRRELVM vm, ScriptWindow::DemolitionModeSelectionWidgets res) { sq_pushinteger(vm, (int32)res); return 1; }
template <> inline ScriptWindow::VehicleTimetableWidgets GetParam(ForceType<ScriptWindow::VehicleTimetableWidgets>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::VehicleTimetableWidgets)tmp; }
template <> inline int Return<ScriptWindow::VehicleTimetableWidgets>(HSQUIRRELVM vm, ScriptWindow::VehicleTimetableWidgets res) { sq_pushinteger(vm, (int32)res); return 1; }
template <> inline ScriptWindow::ToolbarNormalWidgets GetParam(ForceType<ScriptWindow::ToolbarNormalWidgets>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ToolbarNormalWidgets)tmp; }
Expand Down
57 changes: 54 additions & 3 deletions src/terraform_gui.cpp
Expand Up @@ -38,6 +38,8 @@

#include "safeguards.h"

DemolitionMode _demolition_mode;

void CcTerraform(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd)
{
if (result.Succeeded()) {
Expand Down Expand Up @@ -94,6 +96,52 @@ static void GenerateRockyArea(TileIndex end, TileIndex start)
if (success && _settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT_OTHER, end);
}

struct DemolitionModeSelectionWindow : public PickerWindowBase {
DemolitionModeSelectionWindow(WindowDesc *desc, Window *parent) : PickerWindowBase(desc, parent)
{
this->InitNested(0);
this->LowerWidget(WID_DM_ALL);
_demolition_mode = DM_ALL;
}

void OnClick(Point pt, int widget, int click_count) override
{
this->RaiseWidget(_demolition_mode + WID_DM_ALL);
_demolition_mode = (DemolitionMode)(widget - WID_DM_ALL);
this->LowerWidget(_demolition_mode + WID_DM_ALL);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
this->SetDirty();
}
};

/** Nested widget definition of the demolition mode selection window */
static const NWidgetPart _nested_demolition_mode_selection_widgets[] = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
NWidget(WWT_PANEL, COLOUR_DARK_GREEN), EndContainer(),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_DM_ALL), SetMinimalSize(22, 22),
SetFill(0, 1), SetDataTip(SPR_IMG_DYNAMITE, STR_DEMOLISH_EVERYTHING_TOOLTIP),
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_DM_TREES), SetMinimalSize(22, 22),
SetFill(0, 1), SetDataTip(SPR_IMG_PLANTTREES, STR_DEMOLISH_TREES_TOOLTIP),
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_DM_COMPANY_PROPS), SetMinimalSize(22, 22),
SetFill(0, 1), SetDataTip(SPR_IMG_SHOW_ROUTES, STR_DEMOLISH_COMPANY_PROPERTIES_TOOLTIP),
EndContainer(),
};

static WindowDesc _demolition_mode_selection_desc(
WDP_AUTO, nullptr, 0, 0,
WC_DEMOLITION_MODE_SELECTION, WC_SCEN_LAND_GEN,
WDF_CONSTRUCTION,
_nested_demolition_mode_selection_widgets, lengthof(_nested_demolition_mode_selection_widgets)
);

static void ShowDemolitionModeSelectionPicker(Window *parent)
{
new DemolitionModeSelectionWindow(&_demolition_mode_selection_desc, parent);
}

/**
* A central place to handle all X_AND_Y dragged GUI functions.
* @param proc Procedure related to the dragging
Expand All @@ -114,7 +162,7 @@ bool GUIPlaceProcDragXY(ViewportDragDropSelectionProcess proc, TileIndex start_t

switch (proc) {
case DDSP_DEMOLISH_AREA:
DoCommandP(end_tile, start_tile, _ctrl_pressed ? 1 : 0, CMD_CLEAR_AREA | CMD_MSG(STR_ERROR_CAN_T_CLEAR_THIS_AREA), CcPlaySound_EXPLOSION);
DoCommandP(end_tile, start_tile, (_ctrl_pressed ? 1 : 0) | _demolition_mode << 1, CMD_CLEAR_AREA | CMD_MSG(STR_ERROR_CAN_T_CLEAR_THIS_AREA), CcPlaySound_EXPLOSION);
break;
case DDSP_RAISE_AND_LEVEL_AREA:
DoCommandP(end_tile, start_tile, LM_RAISE << 1 | (_ctrl_pressed ? 1 : 0), CMD_LEVEL_LAND | CMD_MSG(STR_ERROR_CAN_T_RAISE_LAND_HERE), CcTerraform);
Expand Down Expand Up @@ -191,8 +239,10 @@ struct TerraformToolbarWindow : Window {
break;

case WID_TT_DEMOLISH: // Demolish aka dynamite button
HandlePlacePushButton(this, WID_TT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL);
this->last_user_action = widget;
if (HandlePlacePushButton(this, WID_TT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL)) {
ShowDemolitionModeSelectionPicker(this);
this->last_user_action = widget;
}
break;

case WID_TT_BUY_LAND: // Buy land button
Expand Down Expand Up @@ -278,6 +328,7 @@ struct TerraformToolbarWindow : Window {
void OnPlaceObjectAbort() override
{
this->RaiseButtons();
DeleteWindowById(WC_DEMOLITION_MODE_SELECTION, 0);
}

static HotkeyList hotkeys;
Expand Down
7 changes: 7 additions & 0 deletions src/widgets/terraform_widget.h
Expand Up @@ -44,4 +44,11 @@ enum EditorTerraformToolbarWidgets {
WID_ETT_RESET_LANDSCAPE, ///< Button for removing all company-owned property.
};

/** Widgets of the #DemolitionModeSelectionWindow class. */
enum DemolitionModeSelectionWidgets {
WID_DM_ALL, ///< Demolish everything
WID_DM_TREES, ///< Demolish trees
WID_DM_COMPANY_PROPS, ///< Demolish company properties
};

#endif /* WIDGETS_TERRAFORM_WIDGET_H */
6 changes: 6 additions & 0 deletions src/window_type.h
Expand Up @@ -441,6 +441,12 @@ enum WindowClass {
*/
WC_SCEN_LAND_GEN,

/**
* Demolition selection mode; %Window numbers:
* - 0 = #DemolitionModeSelectionWidgets
*/
WC_DEMOLITION_MODE_SELECTION,

/**
* Generate landscape (newgame); %Window numbers:
* - GLWM_SCENARIO = #CreateScenarioWidgets
Expand Down

0 comments on commit 97801b1

Please sign in to comment.