mirror of https://github.com/OpenRCT2/OpenRCT2.git
Implement ClearAction.
This commit is contained in:
parent
d7096f71cb
commit
b9fd90ffd3
|
@ -57,7 +57,7 @@ private:
|
|||
|
||||
int32_t _lastScreenWidth = 0;
|
||||
int32_t _lastScreenHeight = 0;
|
||||
CoordsXY _viewCentreLocation = {};
|
||||
CoordsXY _viewCentreLocation;
|
||||
|
||||
public:
|
||||
explicit TitleSequencePlayer(IScenarioRepository& scenarioRepository, GameState& gameState)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue