Query before destroying important structures (rail stations and industries)

Prior to this change, the use of NewObjects often lead to the problem of players trying to clear those and accidentally destroying a rail station or (when using magic bulldozer) an industry. This action cannot be undone.

This change shows a query making sure the player actually wants to destroy the station or industry.

NOTE: The switch to a std::function no longer allows for the inequality check in ShowQuery in misc_gui. If this was required a different solution has to be found.
This commit is contained in:
Andreas Schmitt
2021-06-11 18:10:46 +02:00
parent a7d8c6fe0c
commit 184ade43eb
5 changed files with 61 additions and 13 deletions

View File

@@ -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<TileIterator> tile_iterator;
if (diagonal) {
tile_iterator = std::make_unique<DiagonalTileIterator>(end_tile, start_tile);
} else {
tile_iterator = std::make_unique<OrthogonalTileIterator>(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;