Implement ClearAction.

This commit is contained in:
IntelOrca 2019-01-02 12:59:37 +01:00 committed by Matt
parent d7096f71cb
commit b9fd90ffd3
13 changed files with 393 additions and 241 deletions

View File

@ -57,7 +57,7 @@ private:
int32_t _lastScreenWidth = 0;
int32_t _lastScreenHeight = 0;
CoordsXY _viewCentreLocation = {};
CoordsXY _viewCentreLocation;
public:
explicit TitleSequencePlayer(IScenarioRepository& scenarioRepository, GameState& gameState)

View File

@ -25,6 +25,7 @@
#include <openrct2/Input.h>
#include <openrct2/OpenRCT2.h>
#include <openrct2/ParkImporter.h>
#include <openrct2/actions/ClearAction.hpp>
#include <openrct2/audio/audio.h>
#include <openrct2/config/Config.h>
#include <openrct2/interface/InteractiveConsole.h>
@ -292,6 +293,8 @@ static void toggle_water_window(rct_window* topToolbar, rct_widgetindex widgetIn
static money32 selection_lower_land(uint8_t flags);
static money32 selection_raise_land(uint8_t flags);
static ClearAction GetClearAction();
static bool _menuDropdownIncludesTwitch;
static uint8_t _unkF64F0E;
static int16_t _unkF64F0A;
@ -1940,18 +1943,13 @@ static void top_toolbar_tool_update_scenery_clear(int16_t x, int16_t y)
if (!state_changed)
return;
int32_t eax = gMapSelectPositionA.x;
int32_t ecx = gMapSelectPositionA.y;
int32_t edi = gMapSelectPositionB.x;
int32_t ebp = gMapSelectPositionB.y;
int32_t clear = (gClearSmallScenery << 0) | (gClearLargeScenery << 1) | (gClearFootpath << 2);
money32 cost = game_do_command(eax, 0, ecx, clear, GAME_COMMAND_CLEAR_SCENERY, edi, ebp);
auto action = GetClearAction();
auto result = GameActions::Query(&action);
auto cost = (result->Error == GA_ERROR::OK ? result->Cost : MONEY32_UNDEFINED);
if (gClearSceneryCost != cost)
{
gClearSceneryCost = cost;
window_invalidate_by_class(WC_CLEAR_SCENERY);
return;
}
}
@ -2815,16 +2813,12 @@ static void window_top_toolbar_tool_down(rct_window* w, rct_widgetindex widgetIn
switch (widgetIndex)
{
case WIDX_CLEAR_SCENERY:
if (!(gMapSelectFlags & MAP_SELECT_FLAG_ENABLE))
break;
gGameCommandErrorTitle = STR_UNABLE_TO_REMOVE_ALL_SCENERY_FROM_HERE;
game_do_command(
gMapSelectPositionA.x, 1, gMapSelectPositionA.y,
((gClearSmallScenery ? 1 : 0) | (gClearLargeScenery ? 1 : 0) << 1 | (gClearFootpath ? 1 : 0) << 2),
GAME_COMMAND_CLEAR_SCENERY, gMapSelectPositionB.x, gMapSelectPositionB.y);
gCurrentToolId = TOOL_CROSSHAIR;
if (gMapSelectFlags & MAP_SELECT_FLAG_ENABLE)
{
auto action = GetClearAction();
GameActions::Execute(&action);
gCurrentToolId = TOOL_CROSSHAIR;
}
break;
case WIDX_LAND:
if (gMapSelectFlags & MAP_SELECT_FLAG_ENABLE)
@ -3008,19 +3002,12 @@ static void window_top_toolbar_tool_drag(rct_window* w, rct_widgetindex widgetIn
switch (widgetIndex)
{
case WIDX_CLEAR_SCENERY:
if (window_find_by_class(WC_ERROR) != nullptr)
break;
if (!(gMapSelectFlags & MAP_SELECT_FLAG_ENABLE))
break;
gGameCommandErrorTitle = STR_UNABLE_TO_REMOVE_ALL_SCENERY_FROM_HERE;
game_do_command(
gMapSelectPositionA.x, 1, gMapSelectPositionA.y,
((gClearSmallScenery ? 1 : 0) | (gClearLargeScenery ? 1 : 0) << 1 | (gClearFootpath ? 1 : 0) << 2),
GAME_COMMAND_CLEAR_SCENERY, gMapSelectPositionB.x, gMapSelectPositionB.y);
gCurrentToolId = TOOL_CROSSHAIR;
if (window_find_by_class(WC_ERROR) == nullptr && (gMapSelectFlags & MAP_SELECT_FLAG_ENABLE))
{
auto action = GetClearAction();
GameActions::Execute(&action);
gCurrentToolId = TOOL_CROSSHAIR;
}
break;
case WIDX_LAND:
// Custom setting to only change land style instead of raising or lowering land
@ -3539,3 +3526,19 @@ bool water_tool_is_active()
return false;
return true;
}
static ClearAction GetClearAction()
{
auto range = MapRange(gMapSelectPositionA.x, gMapSelectPositionA.y, gMapSelectPositionB.x, gMapSelectPositionB.y);
ClearableItems itemsToClear = 0;
if (gClearSmallScenery)
itemsToClear |= CLEARABLE_ITEMS::SCENERY_SMALL;
if (gClearLargeScenery)
itemsToClear |= CLEARABLE_ITEMS::SCENERY_LARGE;
if (gClearFootpath)
itemsToClear |= CLEARABLE_ITEMS::SCENERY_FOOTPATH;
return ClearAction(range, itemsToClear);
}

View File

@ -1513,7 +1513,7 @@ GAME_COMMAND_POINTER* new_game_command_table[GAME_COMMAND_COUNT] = {
game_command_set_large_scenery_colour,
game_command_set_banner_colour,
game_command_set_land_ownership,
game_command_clear_scenery,
nullptr,
nullptr,
nullptr,
game_command_set_banner_style,

View File

@ -32,7 +32,7 @@ enum GAME_COMMAND
GAME_COMMAND_SET_RIDE_SETTING,
GAME_COMMAND_PLACE_RIDE_ENTRANCE_OR_EXIT,
GAME_COMMAND_REMOVE_RIDE_ENTRANCE_OR_EXIT,
GAME_COMMAND_REMOVE_SCENERY,
GAME_COMMAND_REMOVE_SCENERY, // GA
GAME_COMMAND_PLACE_SCENERY,
GAME_COMMAND_SET_WATER_HEIGHT,
GAME_COMMAND_PLACE_PATH,
@ -63,7 +63,7 @@ enum GAME_COMMAND
GAME_COMMAND_PLACE_WALL,
GAME_COMMAND_REMOVE_WALL, // GA
GAME_COMMAND_PLACE_LARGE_SCENERY,
GAME_COMMAND_REMOVE_LARGE_SCENERY,
GAME_COMMAND_REMOVE_LARGE_SCENERY, // GA
GAME_COMMAND_SET_CURRENT_LOAN, // GA
GAME_COMMAND_SET_RESEARCH_FUNDING, // GA
GAME_COMMAND_PLACE_TRACK_DESIGN,
@ -76,7 +76,7 @@ enum GAME_COMMAND
GAME_COMMAND_SET_LARGE_SCENERY_COLOUR,
GAME_COMMAND_SET_BANNER_COLOUR,
GAME_COMMAND_SET_LAND_OWNERSHIP,
GAME_COMMAND_CLEAR_SCENERY,
GAME_COMMAND_CLEAR_SCENERY, // GA
GAME_COMMAND_SET_BANNER_NAME, // GA
GAME_COMMAND_SET_SIGN_NAME, // GA
GAME_COMMAND_SET_BANNER_STYLE,

View File

@ -0,0 +1,247 @@
/*****************************************************************************
* Copyright (c) 2014-2019 OpenRCT2 developers
*
* For a complete list of all authors, please refer to contributors.md
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#pragma once
#include "../Context.h"
#include "../core/MemoryStream.h"
#include "../drawing/Drawing.h"
#include "../localisation/StringIds.h"
#include "../management/Finance.h"
#include "../world/LargeScenery.h"
#include "../world/Location.hpp"
#include "../world/Map.h"
#include "FootpathRemoveAction.hpp"
#include "GameAction.h"
#include "SceneryRemoveLargeAction.hpp"
#include "SceneryRemoveSmallAction.hpp"
#include "WallRemoveAction.hpp"
#include <algorithm>
using namespace OpenRCT2;
using ClearableItems = uint8_t;
namespace CLEARABLE_ITEMS
{
constexpr ClearableItems SCENERY_SMALL = 1 << 0;
constexpr ClearableItems SCENERY_LARGE = 1 << 1;
constexpr ClearableItems SCENERY_FOOTPATH = 1 << 2;
} // namespace CLEARABLE_ITEMS
DEFINE_GAME_ACTION(ClearAction, GAME_COMMAND_CLEAR_SCENERY, GameActionResult)
{
private:
MapRange _range;
ClearableItems _itemsToClear;
public:
ClearAction()
{
}
ClearAction(MapRange range, ClearableItems itemsToClear)
: _range(range)
, _itemsToClear(itemsToClear)
{
}
void Serialise(DataSerialiser & stream) override
{
GameAction::Serialise(stream);
stream << DS_TAG(_range) << DS_TAG(_itemsToClear);
}
GameActionResult::Ptr Query() const override
{
return QueryExecute(false);
}
GameActionResult::Ptr Execute() const override
{
return QueryExecute(true);
}
private:
GameActionResult::Ptr CreateResult() const
{
auto result = MakeResult();
result->ErrorTitle = STR_UNABLE_TO_REMOVE_ALL_SCENERY_FROM_HERE;
result->ExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING;
auto x = (_range.GetLeft() + _range.GetRight()) / 2 + 16;
auto y = (_range.GetTop() + _range.GetBottom()) / 2 + 16;
auto z = tile_element_height(x, y);
result->Position = CoordsXYZ(x, y, z);
return result;
}
GameActionResult::Ptr QueryExecute(bool executing) const
{
auto result = CreateResult();
auto noValidTiles = true;
auto error = GA_ERROR::OK;
rct_string_id errorMessage = STR_NONE;
money32 totalCost = 0;
auto x0 = std::max(_range.GetLeft(), 32);
auto y0 = std::max(_range.GetTop(), 32);
auto x1 = std::min(_range.GetRight(), (int32_t)gMapSizeMaxXY);
auto y1 = std::min(_range.GetBottom(), (int32_t)gMapSizeMaxXY);
for (int32_t y = y0; y <= y1; y += 32)
{
for (int32_t x = x0; x <= x1; x += 32)
{
if (MapCanClearAt(x, y))
{
auto cost = ClearSceneryFromTile(x / 32, y / 32, executing);
if (cost != MONEY32_UNDEFINED)
{
noValidTiles = false;
totalCost += cost;
}
}
else
{
error = GA_ERROR::NOT_OWNED;
errorMessage = STR_LAND_NOT_OWNED_BY_PARK;
}
}
}
if (_itemsToClear & CLEARABLE_ITEMS::SCENERY_LARGE)
{
ResetClearLargeSceneryFlag();
}
if (noValidTiles)
{
result->Error = error;
result->ErrorMessage = errorMessage;
}
result->Cost = totalCost;
return result;
}
money32 ClearSceneryFromTile(int32_t x, int32_t y, bool executing) const
{
// Pass down all flags.
TileElement* tileElement = nullptr;
money32 totalCost = 0;
bool tileEdited;
do
{
tileEdited = false;
tileElement = map_get_first_element_at(x, y);
do
{
auto type = tileElement->GetType();
switch (type)
{
case TILE_ELEMENT_TYPE_PATH:
if (_itemsToClear & CLEARABLE_ITEMS::SCENERY_FOOTPATH)
{
auto footpathRemoveAction = FootpathRemoveAction(x * 32, y * 32, tileElement->base_height);
footpathRemoveAction.SetFlags(GetFlags());
auto res = executing ? footpathRemoveAction.Execute() : footpathRemoveAction.Query();
if (res->Error != GA_ERROR::OK)
return MONEY32_UNDEFINED;
totalCost += res->Cost;
tileEdited = executing;
}
break;
case TILE_ELEMENT_TYPE_SMALL_SCENERY:
if (_itemsToClear & CLEARABLE_ITEMS::SCENERY_SMALL)
{
auto removeSceneryAction = SceneryRemoveSmallAction(
x * 32, y * 32, tileElement->base_height, tileElement->AsSmallScenery()->GetSceneryQuadrant(),
tileElement->AsSmallScenery()->GetEntryIndex());
removeSceneryAction.SetFlags(GetFlags());
auto res = executing ? removeSceneryAction.Execute() : removeSceneryAction.Query();
if (res->Error != GA_ERROR::OK)
return MONEY32_UNDEFINED;
totalCost += res->Cost;
tileEdited = executing;
}
break;
case TILE_ELEMENT_TYPE_WALL:
if (_itemsToClear & CLEARABLE_ITEMS::SCENERY_SMALL)
{
TileCoordsXYZD wallLocation = { x, y, tileElement->base_height, tileElement->GetDirection() };
auto wallRemoveAction = WallRemoveAction(wallLocation);
wallRemoveAction.SetFlags(GetFlags());
auto res = executing ? wallRemoveAction.Execute() : wallRemoveAction.Query();
if (res->Error != GA_ERROR::OK)
return MONEY32_UNDEFINED;
totalCost += res->Cost;
tileEdited = executing;
}
break;
case TILE_ELEMENT_TYPE_LARGE_SCENERY:
if (_itemsToClear & CLEARABLE_ITEMS::SCENERY_LARGE)
{
auto removeSceneryAction = SceneryRemoveLargeAction(
x * 32, y * 32, tileElement->base_height, tileElement->GetDirection(),
tileElement->AsLargeScenery()->GetSequenceIndex());
removeSceneryAction.SetFlags(GetFlags() | GAME_COMMAND_FLAG_PATH_SCENERY);
auto res = executing ? removeSceneryAction.Execute() : removeSceneryAction.Query();
if (res->Error != GA_ERROR::OK)
return MONEY32_UNDEFINED;
totalCost += res->Cost;
tileEdited = executing;
}
break;
}
} while (!tileEdited && !(tileElement++)->IsLastForTile());
} while (tileEdited);
return totalCost;
}
/**
* Function to clear the flag that is set to prevent cost duplication
* when using the clear scenery tool with large scenery.
*/
static void ResetClearLargeSceneryFlag()
{
// TODO: Improve efficiency of this
for (int32_t y = 0; y < MAXIMUM_MAP_SIZE_TECHNICAL; y++)
{
for (int32_t x = 0; x < MAXIMUM_MAP_SIZE_TECHNICAL; x++)
{
auto tileElement = map_get_first_element_at(x, y);
do
{
if (tileElement->GetType() == TILE_ELEMENT_TYPE_LARGE_SCENERY)
{
tileElement->flags &= ~(1 << 6);
}
} while (!(tileElement++)->IsLastForTile());
}
}
}
static bool MapCanClearAt(int32_t x, int32_t y)
{
return (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode || map_is_location_owned_or_has_rights(x, y);
}
};

View File

@ -8,6 +8,7 @@
*****************************************************************************/
#include "BannerSetNameAction.hpp"
#include "ClearAction.hpp"
#include "ClimateSetAction.hpp"
#include "FootpathRemoveAction.hpp"
#include "GameAction.h"
@ -59,5 +60,6 @@ namespace GameActions
Register<WallRemoveAction>();
Register<SceneryRemoveSmallAction>();
Register<SceneryRemoveLargeAction>();
Register<ClearAction>();
}
} // namespace GameActions

View File

@ -146,6 +146,9 @@ private:
TileElement* FindSceneryElement() const
{
TileElement* tileElement = map_get_first_element_at(_x / 32, _y / 32);
if (!tileElement)
return nullptr;
do
{
if (tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY)

View File

@ -99,6 +99,9 @@ private:
TileElement* GetFirstWallElementAt(const TileCoordsXYZD& location, bool isGhost) const
{
TileElement* tileElement = map_get_first_element_at(location.x, location.y);
if (!tileElement)
return nullptr;
do
{
if (tileElement->GetType() != TILE_ELEMENT_TYPE_WALL)

View File

@ -14,6 +14,7 @@
#include "../network/NetworkTypes.h"
#include "../network/network.h"
#include "../ride/Ride.h"
#include "../world/Location.hpp"
#include "DataSerialiserTag.h"
#include "Endianness.h"
#include "MemoryStream.h"
@ -292,3 +293,31 @@ template<typename _Ty, size_t _Size> struct DataSerializerTraits<std::array<_Ty,
stream->Write("}", 1);
}
};
template<> struct DataSerializerTraits<MapRange>
{
static void encode(IStream* stream, const MapRange& v)
{
stream->WriteValue(ByteSwapBE(v.LeftTop.x));
stream->WriteValue(ByteSwapBE(v.LeftTop.y));
stream->WriteValue(ByteSwapBE(v.RightBottom.x));
stream->WriteValue(ByteSwapBE(v.RightBottom.y));
}
static void decode(IStream* stream, MapRange& v)
{
auto l = ByteSwapBE(stream->ReadValue<int32_t>());
auto t = ByteSwapBE(stream->ReadValue<int32_t>());
auto r = ByteSwapBE(stream->ReadValue<int32_t>());
auto b = ByteSwapBE(stream->ReadValue<int32_t>());
v = MapRange(l, t, r, b);
}
static void log(IStream* stream, const MapRange& v)
{
char coords[128] = {};
snprintf(
coords, sizeof(coords), "MapRange(l = %d, t = %d, r = %d, b = %d)", v.LeftTop.x, v.LeftTop.y, v.RightBottom.x,
v.RightBottom.y);
stream->Write(coords, strlen(coords));
}
};

View File

@ -290,10 +290,10 @@ static void virtual_floor_get_tile_properties(
void virtual_floor_paint(paint_session* session)
{
static constexpr const CoordsXY scenery_half_tile_offsets[4] = {
{ -32, 0 },
{ 0, 32 },
{ 32, 0 },
{ 0, -32 },
CoordsXY{ -32, 0 },
CoordsXY{ 0, 32 },
CoordsXY{ 32, 0 },
CoordsXY{ 0, -32 },
};
if (_virtualFloorHeight < MINIMUM_LAND_HEIGHT)

View File

@ -11,6 +11,8 @@
#include "../common.h"
#include <algorithm>
#define LOCATION_NULL ((int16_t)(uint16_t)0x8000)
#define RCT_XY8_UNDEFINED 0xFFFF
#define MakeXY16(x, y) \
@ -59,7 +61,15 @@ constexpr int32_t COORDS_NULL = -1;
*/
struct CoordsXY
{
int32_t x, y;
int32_t x = 0;
int32_t y = 0;
CoordsXY() = default;
constexpr CoordsXY(int32_t _x, int32_t _y)
: x(_x)
, y(_y)
{
}
};
struct TileCoordsXY
@ -86,7 +96,17 @@ struct TileCoordsXY
struct CoordsXYZ
{
int32_t x, y, z;
int32_t x = 0;
int32_t y = 0;
int32_t z = 0;
CoordsXYZ() = default;
constexpr CoordsXYZ(int32_t _x, int32_t _y, int32_t _z)
: x(_x)
, y(_y)
, z(_z)
{
}
};
struct TileCoordsXYZ
@ -150,3 +170,47 @@ struct TileCoordsXYZD
return x == COORDS_NULL;
};
};
/**
* Represents a rectangular range of the map using regular coordinates (32 per tile).
*/
struct MapRange
{
CoordsXY LeftTop;
CoordsXY RightBottom;
int32_t GetLeft() const
{
return LeftTop.x;
}
int32_t GetTop() const
{
return LeftTop.y;
}
int32_t GetRight() const
{
return RightBottom.x;
}
int32_t GetBottom() const
{
return RightBottom.y;
}
MapRange()
: MapRange(0, 0, 0, 0)
{
}
MapRange(int32_t left, int32_t top, int32_t right, int32_t bottom)
: LeftTop(left, top)
, RightBottom(right, bottom)
{
}
MapRange Normalise() const
{
auto result = MapRange(
std::min(GetLeft(), GetRight()), std::min(GetTop(), GetBottom()), std::max(GetLeft(), GetRight()),
std::max(GetTop(), GetBottom()));
return result;
}
};

View File

@ -873,203 +873,6 @@ void game_command_set_large_scenery_colour(
*ebx = 0;
}
// This will cause clear scenery to remove paths
// This should be a flag for the game command which can be set via a checkbox on the clear scenery window.
// #define CLEAR_SCENERY_REMOVES_PATHS
/**
*
* rct2: 0x0068DFE4
*/
static money32 map_clear_scenery_from_tile(int32_t x, int32_t y, int32_t clear, int32_t flags)
{
int32_t type;
money32 totalCost;
TileElement* tileElement;
totalCost = 0;
restart_from_beginning:
tileElement = map_get_first_element_at(x, y);
do
{
type = tileElement->GetType();
switch (type)
{
case TILE_ELEMENT_TYPE_PATH:
if (clear & (1 << 2))
{
auto footpathRemoveAction = FootpathRemoveAction(x * 32, y * 32, tileElement->base_height);
footpathRemoveAction.SetFlags(flags);
auto res
= ((flags & GAME_COMMAND_FLAG_APPLY) ? footpathRemoveAction.Execute() : footpathRemoveAction.Query());
if (res->Error == GA_ERROR::OK)
{
totalCost += res->Cost;
}
else
{
return MONEY32_UNDEFINED;
}
if (flags & GAME_COMMAND_FLAG_APPLY)
goto restart_from_beginning;
}
break;
case TILE_ELEMENT_TYPE_SMALL_SCENERY:
if (clear & (1 << 0))
{
auto removeSceneryAction = SceneryRemoveSmallAction(
x * 32, y * 32, tileElement->base_height, tileElement->AsSmallScenery()->GetSceneryQuadrant(),
tileElement->AsSmallScenery()->GetEntryIndex());
removeSceneryAction.SetFlags(flags);
auto res
= ((flags & GAME_COMMAND_FLAG_APPLY) ? removeSceneryAction.Execute() : removeSceneryAction.Query());
if (res->Error != GA_ERROR::OK)
return MONEY32_UNDEFINED;
totalCost += res->Cost;
if (flags & GAME_COMMAND_FLAG_APPLY)
goto restart_from_beginning;
}
break;
case TILE_ELEMENT_TYPE_WALL:
if (clear & (1 << 0))
{
// NOTE: We execute the game action directly as this function is already called from such.
TileCoordsXYZD wallLocation = { x, y, tileElement->base_height, tileElement->GetDirection() };
auto wallRemoveAction = WallRemoveAction(wallLocation);
wallRemoveAction.SetFlags(flags);
auto res = ((flags & GAME_COMMAND_FLAG_APPLY) ? wallRemoveAction.Execute() : wallRemoveAction.Query());
if (res->Error == GA_ERROR::OK)
{
totalCost += res->Cost;
}
}
break;
case TILE_ELEMENT_TYPE_LARGE_SCENERY:
if (clear & (1 << 1))
{
auto removeSceneryAction = SceneryRemoveLargeAction(
x * 32, y * 32, tileElement->base_height, tileElement->GetDirection(),
tileElement->AsLargeScenery()->GetSequenceIndex());
removeSceneryAction.SetFlags(flags | GAME_COMMAND_FLAG_PATH_SCENERY);
auto res
= ((flags & GAME_COMMAND_FLAG_APPLY) ? removeSceneryAction.Execute() : removeSceneryAction.Query());
if (res->Error != GA_ERROR::OK)
return MONEY32_UNDEFINED;
totalCost += res->Cost;
if (flags & GAME_COMMAND_FLAG_APPLY)
goto restart_from_beginning;
}
break;
}
} while (!(tileElement++)->IsLastForTile());
return totalCost;
}
/**
* Function to clear the flag that is set to prevent cost duplication
* when using the clear scenery tool with large scenery.
*/
static void map_reset_clear_large_scenery_flag()
{
TileElement* tileElement;
// TODO: Improve efficiency of this
for (int32_t y = 0; y < MAXIMUM_MAP_SIZE_TECHNICAL; y++)
{
for (int32_t x = 0; x < MAXIMUM_MAP_SIZE_TECHNICAL; x++)
{
tileElement = map_get_first_element_at(x, y);
do
{
if (tileElement->GetType() == TILE_ELEMENT_TYPE_LARGE_SCENERY)
{
tileElement->flags &= ~(1 << 6);
}
} while (!(tileElement++)->IsLastForTile());
}
}
}
money32 map_clear_scenery(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t clear, int32_t flags)
{
int32_t x, y, z;
money32 totalCost, cost;
bool noValidTiles;
gCommandExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING;
x = (x0 + x1) / 2 + 16;
y = (y0 + y1) / 2 + 16;
z = tile_element_height(x, y);
gCommandPosition.x = x;
gCommandPosition.y = y;
gCommandPosition.z = z;
x0 = std::max(x0, 32);
y0 = std::max(y0, 32);
x1 = std::min(x1, (int32_t)gMapSizeMaxXY);
y1 = std::min(y1, (int32_t)gMapSizeMaxXY);
noValidTiles = true;
totalCost = 0;
for (y = y0; y <= y1; y += 32)
{
for (x = x0; x <= x1; x += 32)
{
if ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode
|| map_is_location_owned_or_has_rights(x, y))
{
cost = map_clear_scenery_from_tile(x / 32, y / 32, clear, flags);
if (cost != MONEY32_UNDEFINED)
{
noValidTiles = false;
totalCost += cost;
}
}
else
{
gGameCommandErrorText = STR_LAND_NOT_OWNED_BY_PARK;
}
}
}
if (gGameCommandNestLevel == 1 && flags & GAME_COMMAND_FLAG_APPLY)
{
LocationXYZ16 coord;
coord.x = ((x0 + x1) / 2) + 16;
coord.y = ((y0 + y1) / 2) + 16;
coord.z = tile_element_height(coord.x, coord.y);
network_set_player_last_action_coord(network_get_player_index(game_command_playerid), coord);
}
if (clear & (1 << 1))
{
map_reset_clear_large_scenery_flag();
}
return noValidTiles ? MONEY32_UNDEFINED : totalCost;
}
/**
*
* rct2: 0x0068DF91
*/
void game_command_clear_scenery(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, [[maybe_unused]] int32_t* esi, int32_t* edi, int32_t* ebp)
{
*ebx = map_clear_scenery(
(int16_t)(*eax & 0xFFFF), (int16_t)(*ecx & 0xFFFF), (int16_t)(*edi & 0xFFFF), (int16_t)(*ebp & 0xFFFF), *edx,
*ebx & 0xFF);
}
/**
*
* rct2: 0x00663CCD

View File

@ -197,8 +197,6 @@ void game_command_set_large_scenery_colour(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_set_banner_colour(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_clear_scenery(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_change_surface_style(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_raise_land(int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);