diff --git a/src/lang/english.txt b/src/lang/english.txt index 80eae3b445..df1a368edc 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -5550,6 +5550,10 @@ STR_ERROR_NAME_MUST_BE_UNIQUE :{WHITE}Name mus STR_ERROR_GENERIC_OBJECT_IN_THE_WAY :{WHITE}{1:STRING} in the way STR_ERROR_NOT_ALLOWED_WHILE_PAUSED :{WHITE}Not allowed while paused +# Clear area query +STR_QUERY_CLEAR_AREA_CAPTION :{WHITE}Clear area +STR_CLEAR_AREA_CONFIRMATION_TEXT :{YELLOW}You are about to destroy an important structure. Are you sure? + # Local authority errors STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS :{WHITE}{TOWN} local authority refuses to allow this STR_ERROR_LOCAL_AUTHORITY_REFUSES_AIRPORT :{WHITE}{TOWN} local authority refuses to allow another airport to be built in this town diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp index 49eb34824b..3cc340d696 100644 --- a/src/misc_gui.cpp +++ b/src/misc_gui.cpp @@ -12,6 +12,8 @@ #include "landscape.h" #include "error.h" #include "gui.h" + +#include #include "command_func.h" #include "company_func.h" #include "town.h" @@ -1230,19 +1232,19 @@ void ShowQueryString(StringID str, StringID caption, uint maxsize, Window *paren * Window used for asking the user a YES/NO question. */ struct QueryWindow : public Window { - QueryCallbackProc *proc; ///< callback function executed on closing of popup. Window* points to parent, bool is true if 'yes' clicked, false otherwise + QueryCallbackProc proc; ///< callback function executed on closing of popup. Window* points to parent, bool is true if 'yes' clicked, false otherwise uint64 params[10]; ///< local copy of #_global_string_params StringID message; ///< message shown for query window StringID caption; ///< title of window - QueryWindow(WindowDesc *desc, StringID caption, StringID message, Window *parent, QueryCallbackProc *callback) : Window(desc) + QueryWindow(WindowDesc *desc, StringID caption, StringID message, Window *parent, QueryCallbackProc callback) : Window(desc) { /* Create a backup of the variadic arguments to strings because it will be * overridden pretty often. We will copy these back for drawing */ CopyOutDParam(this->params, 0, lengthof(this->params)); this->caption = caption; this->message = message; - this->proc = callback; + this->proc = std::move(callback); this->parent = parent; this->InitNested(WN_CONFIRM_POPUP_QUERY); @@ -1299,7 +1301,7 @@ struct QueryWindow : public Window { case WID_Q_YES: { /* in the Generate New World window, clicking 'Yes' causes * DeleteNonVitalWindows() to be called - we shouldn't be in a window then */ - QueryCallbackProc *proc = this->proc; + QueryCallbackProc proc = this->proc; Window *parent = this->parent; /* Prevent the destructor calling the callback function */ this->proc = nullptr; @@ -1364,9 +1366,9 @@ static WindowDesc _query_desc( * @param message string that will be shown for the window * @param parent pointer to parent window, if this pointer is nullptr the parent becomes * the main window WC_MAIN_WINDOW - * @param callback callback function pointer to set in the window descriptor + * @param callback callback function to set in the window descriptor */ -void ShowQuery(StringID caption, StringID message, Window *parent, QueryCallbackProc *callback) +void ShowQuery(StringID caption, StringID message, Window *parent, QueryCallbackProc callback) { if (parent == nullptr) parent = FindWindowById(WC_MAIN_WINDOW, 0); @@ -1374,7 +1376,7 @@ void ShowQuery(StringID caption, StringID message, Window *parent, QueryCallback if (w->window_class != WC_CONFIRM_POPUP_QUERY) continue; const QueryWindow *qw = (const QueryWindow *)w; - if (qw->parent != parent || qw->proc != callback) continue; + if (qw->parent != parent) continue; delete qw; break; diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index 844326775b..e0563c04f0 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -2141,7 +2141,7 @@ public: case WID_CL_MATRIX: { StringID text = STR_NULL; - QueryCallbackProc *callback = nullptr; + QueryCallbackProc callback = nullptr; switch (index) { case DD_CLIENT_ADMIN_KICK: diff --git a/src/terraform_gui.cpp b/src/terraform_gui.cpp index 2db07278b4..17061601f9 100644 --- a/src/terraform_gui.cpp +++ b/src/terraform_gui.cpp @@ -30,6 +30,7 @@ #include "hotkeys.h" #include "engine_base.h" #include "terraform_gui.h" +#include "cheat_func.h" #include "town_gui.h" #include "zoom_func.h" @@ -95,6 +96,30 @@ static void GenerateRockyArea(TileIndex end, TileIndex start) if (success && _settings_client.sound.confirm) SndPlayTileFx(SND_1F_CONSTRUCTION_OTHER, end); } +/** Checks if the area contains any structures that are important enough to query about first */ +static bool IsIndustryOrRailStationInArea(TileIndex start_tile, TileIndex end_tile, bool diagonal) +{ + std::unique_ptr tile_iterator; + + if (diagonal) { + tile_iterator = std::make_unique(end_tile, start_tile); + } else { + tile_iterator = std::make_unique(end_tile, start_tile); + } + + bool destroying_industry_or_station = false; + + for (; *tile_iterator != INVALID_TILE; ++(*tile_iterator)) { + if ((_cheats.magic_bulldozer.value && IsTileType(*tile_iterator, MP_INDUSTRY)) || + IsRailStationTile(*tile_iterator)) { + destroying_industry_or_station = true; + break; + } + } + + return destroying_industry_or_station; +} + /** * A central place to handle all X_AND_Y dragged GUI functions. * @param proc Procedure related to the dragging @@ -114,9 +139,23 @@ 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); + case DDSP_DEMOLISH_AREA: { + const bool should_query_first = IsIndustryOrRailStationInArea(start_tile, end_tile, _ctrl_pressed); + + const auto cmd_clear_area = [=](Window*, bool confirmed) { + if (confirmed) { + DoCommandP(end_tile, start_tile, _ctrl_pressed ? 1 : 0, CMD_CLEAR_AREA | CMD_MSG(STR_ERROR_CAN_T_CLEAR_THIS_AREA), CcPlaySound_EXPLOSION); + } + }; + + if (should_query_first) { + ShowQuery(STR_QUERY_CLEAR_AREA_CAPTION, STR_CLEAR_AREA_CONFIRMATION_TEXT, nullptr, cmd_clear_area); + } else { + cmd_clear_area(nullptr, true); + } + 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); break; diff --git a/src/textbuf_gui.h b/src/textbuf_gui.h index c96f4e2e06..a7a225eb49 100644 --- a/src/textbuf_gui.h +++ b/src/textbuf_gui.h @@ -10,10 +10,13 @@ #ifndef TEXTBUF_GUI_H #define TEXTBUF_GUI_H -#include "window_type.h" #include "string_type.h" #include "strings_type.h" +#include + +struct Window; + /** Flags used in ShowQueryString() call */ enum QueryStringFlags { QSF_NONE = 0, @@ -26,10 +29,10 @@ enum QueryStringFlags { DECLARE_ENUM_AS_BIT_SET(QueryStringFlags) /** Callback procedure for the ShowQuery method. */ -typedef void QueryCallbackProc(Window*, bool); +typedef std::function QueryCallbackProc; void ShowQueryString(StringID str, StringID caption, uint max_len, Window *parent, CharSetFilter afilter, QueryStringFlags flags); -void ShowQuery(StringID caption, StringID message, Window *w, QueryCallbackProc *callback); +void ShowQuery(StringID caption, StringID message, Window *w, QueryCallbackProc callback); /** The number of 'characters' on the on-screen keyboard. */ static const uint OSK_KEYBOARD_ENTRIES = 50;