Implement SceneryRemoveSmallAction.

This commit is contained in:
Matt 2018-12-22 18:11:08 +01:00
parent d4a3feca29
commit b34b09c6bb
9 changed files with 197 additions and 122 deletions

View File

@ -16,6 +16,7 @@
#include <openrct2/Game.h>
#include <openrct2/Input.h>
#include <openrct2/OpenRCT2.h>
#include <openrct2/actions/SceneryRemoveSmallAction.hpp>
#include <openrct2/actions/WallRemoveAction.hpp>
#include <openrct2/localisation/Localisation.h>
#include <openrct2/ride/Ride.h>
@ -465,10 +466,11 @@ int32_t viewport_interaction_right_click(int32_t x, int32_t y)
*/
static void viewport_interaction_remove_scenery(TileElement* tileElement, int32_t x, int32_t y)
{
gGameCommandErrorTitle = STR_CANT_REMOVE_THIS;
game_do_command(
x, (tileElement->AsSmallScenery()->GetSceneryQuadrant() << 8) | GAME_COMMAND_FLAG_APPLY, y,
(tileElement->AsSmallScenery()->GetEntryIndex() << 8) | tileElement->base_height, GAME_COMMAND_REMOVE_SCENERY, 0, 0);
auto removeSceneryAction = SceneryRemoveSmallAction(
x, y, tileElement->base_height, tileElement->AsSmallScenery()->GetSceneryQuadrant(),
tileElement->AsSmallScenery()->GetEntryIndex());
GameActions::Execute(&removeSceneryAction);
}
/**

View File

@ -1469,7 +1469,7 @@ GAME_COMMAND_POINTER* new_game_command_table[GAME_COMMAND_COUNT] = {
game_command_set_ride_setting,
game_command_place_ride_entrance_or_exit,
game_command_remove_ride_entrance_or_exit,
game_command_remove_scenery,
nullptr,
game_command_place_scenery,
game_command_set_water_height,
game_command_place_footpath,

View File

@ -24,6 +24,7 @@
#include "RideSetColourScheme.hpp"
#include "RideSetName.hpp"
#include "RideSetStatus.hpp"
#include "SceneryRemoveSmallAction.hpp"
#include "SetParkEntranceFeeAction.hpp"
#include "SignSetNameAction.hpp"
#include "StaffSetColourAction.hpp"
@ -55,5 +56,6 @@ namespace GameActions
Register<StaffSetColourAction>();
Register<StaffSetNameAction>();
Register<WallRemoveAction>();
Register<SceneryRemoveSmallAction>();
}
} // namespace GameActions

View File

@ -0,0 +1,168 @@
/*****************************************************************************
* Copyright (c) 2014-2018 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 "../Cheats.h"
#include "../OpenRCT2.h"
#include "../common.h"
#include "../core/MemoryStream.h"
#include "../interface/Window.h"
#include "../localisation/Localisation.h"
#include "../localisation/StringIds.h"
#include "../management/Finance.h"
#include "../ride/Ride.h"
#include "../world/Park.h"
#include "../world/SmallScenery.h"
#include "../world/Sprite.h"
#include "GameAction.h"
DEFINE_GAME_ACTION(SceneryRemoveSmallAction, GAME_COMMAND_REMOVE_SCENERY, GameActionResult)
{
private:
int16_t _x;
int16_t _y;
uint8_t _baseHeight;
uint8_t _quadrant;
uint8_t _sceneryType;
public:
SceneryRemoveSmallAction() = default;
SceneryRemoveSmallAction(int16_t x, int16_t y, uint8_t baseHeight, uint8_t quadrant, uint8_t sceneryType)
: _x(x)
, _y(y)
, _baseHeight(baseHeight)
, _quadrant(quadrant)
, _sceneryType(sceneryType)
{
}
uint16_t GetActionFlags() const override
{
return GameAction::GetActionFlags();
}
void Serialise(DataSerialiser & stream) override
{
GameAction::Serialise(stream);
stream << DS_TAG(_x) << DS_TAG(_y) << DS_TAG(_baseHeight) << DS_TAG(_quadrant) << DS_TAG(_sceneryType);
}
GameActionResult::Ptr Query() const override
{
GameActionResult::Ptr res = std::make_unique<GameActionResult>();
if (!map_is_location_valid({ _x, _y }))
{
return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK);
}
rct_scenery_entry* entry = get_small_scenery_entry(_sceneryType);
if (entry == nullptr)
{
return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_REMOVE_THIS, STR_INVALID_SELECTION_OF_OBJECTS);
}
res->Cost = entry->small_scenery.removal_price * 10;
res->ExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING;
res->Position.x = _x;
res->Position.y = _y;
res->Position.z = _baseHeight * 8;
if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !(GetFlags() & GAME_COMMAND_FLAG_GHOST) && !gCheatsSandboxMode)
{
// Check if allowed to remove item
if (gParkFlags & PARK_FLAGS_FORBID_TREE_REMOVAL)
{
if (entry->small_scenery.height > 64)
{
res->Error = GA_ERROR::NO_CLEARANCE;
res->ErrorTitle = STR_CANT_REMOVE_THIS;
res->ErrorMessage = STR_FORBIDDEN_BY_THE_LOCAL_AUTHORITY;
return res;
}
}
// Check if the land is owned
if (!map_is_location_owned(_x, _y, _baseHeight * 8))
{
res->Error = GA_ERROR::NO_CLEARANCE;
res->ErrorTitle = STR_CANT_REMOVE_THIS;
res->ErrorMessage = STR_LAND_NOT_OWNED_BY_PARK;
return res;
}
}
TileElement* tileElement = FindSceneryElement();
if (tileElement == nullptr)
{
res->Cost = 0;
return res;
}
return res;
}
GameActionResult::Ptr Execute() const override
{
GameActionResult::Ptr res = std::make_unique<GameActionResult>();
rct_scenery_entry* entry = get_small_scenery_entry(_sceneryType);
if (entry == nullptr)
{
return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_INVALID_SELECTION_OF_OBJECTS);
}
res->Cost = entry->small_scenery.removal_price * 10;
res->ExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING;
res->Position.x = _x;
res->Position.y = _y;
res->Position.z = _baseHeight * 8;
TileElement* tileElement = FindSceneryElement();
if (tileElement == nullptr)
{
res->Cost = 0;
return res;
}
res->Position.z = tile_element_height(res->Position.x, res->Position.y);
map_invalidate_tile_full(_x, _y);
tile_element_remove(tileElement);
return res;
}
private:
TileElement* FindSceneryElement() const
{
TileElement* tileElement = map_get_first_element_at(_x / 32, _y / 32);
do
{
if (tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY)
continue;
if ((tileElement->AsSmallScenery()->GetSceneryQuadrant()) != _quadrant)
continue;
if (tileElement->base_height != _baseHeight)
continue;
if (tileElement->AsSmallScenery()->GetEntryIndex() != _sceneryType)
continue;
if ((GetFlags() & GAME_COMMAND_FLAG_GHOST) && tileElement->IsGhost() == false)
continue;
return tileElement;
} while (!(tileElement++)->IsLastForTile());
return nullptr;
}
};

View File

@ -12,6 +12,7 @@
#include "../Cheats.h"
#include "../Game.h"
#include "../OpenRCT2.h"
#include "../actions/SceneryRemoveSmallAction.hpp"
#include "../actions/WallRemoveAction.hpp"
#include "../audio/audio.h"
#include "../core/File.h"
@ -828,9 +829,11 @@ static int32_t track_design_place_scenery(
}
z = (scenery->z * 8 + originZ) / 8;
game_do_command(
mapCoord.x, flags | quadrant << 8, mapCoord.y, (entry_index << 8) | z, GAME_COMMAND_REMOVE_SCENERY,
0, 0);
auto removeSceneryAction = SceneryRemoveSmallAction(mapCoord.x, mapCoord.y, z, quadrant, entry_index);
removeSceneryAction.SetFlags(flags);
removeSceneryAction.Execute();
break;
}
case OBJECT_TYPE_LARGE_SCENERY:

View File

@ -15,6 +15,7 @@
#include "../Input.h"
#include "../OpenRCT2.h"
#include "../actions/FootpathRemoveAction.hpp"
#include "../actions/SceneryRemoveSmallAction.hpp"
#include "../actions/WallRemoveAction.hpp"
#include "../audio/audio.h"
#include "../config/Config.h"
@ -1078,17 +1079,17 @@ restart_from_beginning:
case TILE_ELEMENT_TYPE_SMALL_SCENERY:
if (clear & (1 << 0))
{
int32_t eax = x * 32;
int32_t ebx = (tileElement->AsSmallScenery()->GetSceneryQuadrant() << 8) | flags;
int32_t ecx = y * 32;
int32_t edx = (tileElement->AsSmallScenery()->GetEntryIndex() << 8) | (tileElement->base_height);
int32_t edi = 0, ebp = 0;
cost = game_do_command(eax, ebx, ecx, edx, GAME_COMMAND_REMOVE_SCENERY, edi, ebp);
auto removeSceneryAction = SceneryRemoveSmallAction(
x * 32, y * 32, tileElement->base_height, tileElement->AsSmallScenery()->GetSceneryQuadrant(),
tileElement->AsSmallScenery()->GetEntryIndex());
removeSceneryAction.SetFlags(flags);
if (cost == MONEY32_UNDEFINED)
auto res
= ((flags & GAME_COMMAND_FLAG_APPLY) ? removeSceneryAction.Execute() : removeSceneryAction.Query());
if (res->Error != GA_ERROR::OK)
return MONEY32_UNDEFINED;
totalCost += cost;
totalCost += res->Cost;
if (flags & GAME_COMMAND_FLAG_APPLY)
goto restart_from_beginning;

View File

@ -187,8 +187,6 @@ void game_command_set_land_height(
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_land_ownership(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_remove_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_remove_large_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_remove_banner(

View File

@ -12,6 +12,7 @@
#include "../Cheats.h"
#include "../Context.h"
#include "../Game.h"
#include "../actions/SceneryRemoveSmallAction.hpp"
#include "../actions/WallRemoveAction.hpp"
#include "../common.h"
#include "../localisation/Localisation.h"
@ -184,10 +185,10 @@ void scenery_remove_ghost_tool_placement()
if (gSceneryGhostType & SCENERY_GHOST_FLAG_0)
{
gSceneryGhostType &= ~SCENERY_GHOST_FLAG_0;
uint8_t flags = GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_5
| GAME_COMMAND_FLAG_GHOST;
game_do_command(
x, flags | (gSceneryQuadrant << 8), y, z | (gSceneryPlaceObject << 8), GAME_COMMAND_REMOVE_SCENERY, 0, 0);
auto removeSceneryAction = SceneryRemoveSmallAction(x, y, z, gSceneryQuadrant, gSceneryPlaceObject);
removeSceneryAction.SetFlags(GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_5 | GAME_COMMAND_FLAG_GHOST);
removeSceneryAction.Execute();
}
if (gSceneryGhostType & SCENERY_GHOST_FLAG_1)

View File

@ -24,95 +24,6 @@
#include "Scenery.h"
#include "Surface.h"
static money32 SmallSceneryRemove(
int16_t x, int16_t y, uint8_t baseHeight, uint8_t quadrant, uint8_t sceneryType, uint8_t flags)
{
if (!map_is_location_valid({ x, y }))
{
return MONEY32_UNDEFINED;
}
money32 cost;
rct_scenery_entry* entry = get_small_scenery_entry(sceneryType);
if (entry == nullptr)
{
log_warning("Invalid game command for scenery removal, scenery_type = %u", sceneryType);
return MONEY32_UNDEFINED;
}
cost = entry->small_scenery.removal_price * 10;
gCommandExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING;
gCommandPosition.x = x + 16;
gCommandPosition.y = y + 16;
gCommandPosition.z = baseHeight * 8;
if (!(flags & GAME_COMMAND_FLAG_GHOST) && game_is_paused() && !gCheatsBuildInPauseMode)
{
gGameCommandErrorText = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED;
return MONEY32_UNDEFINED;
}
if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !(flags & GAME_COMMAND_FLAG_GHOST) && !gCheatsSandboxMode)
{
// Check if allowed to remove item
if (gParkFlags & PARK_FLAGS_FORBID_TREE_REMOVAL)
{
if (entry->small_scenery.height > 64)
{
gGameCommandErrorText = STR_FORBIDDEN_BY_THE_LOCAL_AUTHORITY;
return MONEY32_UNDEFINED;
}
}
// Check if the land is owned
if (!map_is_location_owned(x, y, gCommandPosition.z))
{
return MONEY32_UNDEFINED;
}
}
bool sceneryFound = false;
TileElement* tileElement = map_get_first_element_at(x / 32, y / 32);
do
{
if (tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY)
continue;
if ((tileElement->AsSmallScenery()->GetSceneryQuadrant()) != quadrant)
continue;
if (tileElement->base_height != baseHeight)
continue;
if (tileElement->AsSmallScenery()->GetEntryIndex() != sceneryType)
continue;
if ((flags & GAME_COMMAND_FLAG_GHOST) && !(tileElement->flags & TILE_ELEMENT_FLAG_GHOST))
continue;
sceneryFound = true;
break;
} while (!(tileElement++)->IsLastForTile());
if (!sceneryFound)
{
return 0;
}
// Remove element
if (flags & GAME_COMMAND_FLAG_APPLY)
{
if (gGameCommandNestLevel == 1 && !(flags & GAME_COMMAND_FLAG_GHOST))
{
LocationXYZ16 coord;
coord.x = x + 16;
coord.y = y + 16;
coord.z = tile_element_height(coord.x, coord.y);
network_set_player_last_action_coord(network_get_player_index(game_command_playerid), coord);
}
map_invalidate_tile_full(x, y);
tile_element_remove(tileElement);
}
return (gParkFlags & PARK_FLAGS_NO_MONEY) ? 0 : cost;
}
static money32 SmallScenerySetColour(
int16_t x, int16_t y, uint8_t baseHeight, uint8_t quadrant, uint8_t sceneryType, uint8_t primaryColour,
uint8_t secondaryColour, uint8_t flags)
@ -412,17 +323,6 @@ static money32 SmallSceneryPlace(
return cost;
}
/**
*
* rct2: 0x006E0E01
*/
void game_command_remove_scenery(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, [[maybe_unused]] int32_t* esi, [[maybe_unused]] int32_t* edi,
[[maybe_unused]] int32_t* ebp)
{
*ebx = SmallSceneryRemove(*eax & 0xFFFF, *ecx & 0xFFFF, *edx & 0xFF, ((*ebx >> 8) & 0xFF), (*edx >> 8) & 0xFF, *ebx & 0xFF);
}
/**
*
* rct2: 0x006E0F26