diff --git a/src/openrct2-ui/interface/ViewportInteraction.cpp b/src/openrct2-ui/interface/ViewportInteraction.cpp index b0bf8c4fb3..57fb23e329 100644 --- a/src/openrct2-ui/interface/ViewportInteraction.cpp +++ b/src/openrct2-ui/interface/ViewportInteraction.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -507,16 +508,8 @@ static void viewport_interaction_remove_footpath(TileElement* tileElement, int32 */ static void viewport_interaction_remove_footpath_item(TileElement* tileElement, int32_t x, int32_t y) { - int32_t type = tileElement->AsPath()->GetPathEntryIndex(); - if (tileElement->AsPath()->IsQueue()) - type |= 0x80; - - int32_t slopeData = tileElement->AsPath()->GetSlopeDirection(); - if (tileElement->AsPath()->IsSloped()) - slopeData |= FOOTPATH_PROPERTIES_FLAG_IS_SLOPED; - - gGameCommandErrorTitle = STR_CANT_REMOVE_THIS; - game_do_command(x, (slopeData << 8) | 1, y, (type << 8) | tileElement->base_height, GAME_COMMAND_PLACE_PATH, 0, 0); + auto footpathSceneryRemoveAction = FootpathSceneryRemoveAction({x, y, tileElement->base_height * 8}); + GameActions::Execute(&footpathSceneryRemoveAction); } /** diff --git a/src/openrct2/Game.h b/src/openrct2/Game.h index 3d210d9289..4ad216a95c 100644 --- a/src/openrct2/Game.h +++ b/src/openrct2/Game.h @@ -94,6 +94,8 @@ enum GAME_COMMAND GAME_COMMAND_SET_CLIMATE, // GA GAME_COMMAND_SET_COLOUR_SCHEME, // GA GAME_COMMAND_SET_STAFF_COSTUME, // GA + GAME_COMMAND_PLACE_FOOTPATH_SCENERY, // GA + GAME_COMMAND_REMOVE_FOOTPATH_SCENERY, // GA GAME_COMMAND_COUNT, }; diff --git a/src/openrct2/actions/FootpathSceneryPlaceAction.hpp b/src/openrct2/actions/FootpathSceneryPlaceAction.hpp new file mode 100644 index 0000000000..1c76b5f365 --- /dev/null +++ b/src/openrct2/actions/FootpathSceneryPlaceAction.hpp @@ -0,0 +1,64 @@ +/***************************************************************************** + * 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 "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../world/Footpath.h" +#include "../world/Location.hpp" +#include "../world/Park.h" +#include "../world/Wall.h" +#include "GameAction.h" + +DEFINE_GAME_ACTION(FootpathSceneryPlaceAction, GAME_COMMAND_PLACE_FOOTPATH_SCENERY, GameActionResult) +{ +private: + int32_t _x; + int32_t _y; + int32_t _z; + +public: + FootpathSceneryPlaceAction() = default; + FootpathSceneryPlaceAction(int32_t x, int32_t y, int32_t z) + : _x(x) + , _y(y) + , _z(z) + { + } + + 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(_z); + } + + GameActionResult::Ptr Query() const override + { + GameActionResult::Ptr res = std::make_unique(); + + return res; + } + + GameActionResult::Ptr Execute() const override + { + GameActionResult::Ptr res = std::make_unique(); + return res; + } +}; diff --git a/src/openrct2/actions/FootpathSceneryRemoveAction.hpp b/src/openrct2/actions/FootpathSceneryRemoveAction.hpp new file mode 100644 index 0000000000..b810f830e6 --- /dev/null +++ b/src/openrct2/actions/FootpathSceneryRemoveAction.hpp @@ -0,0 +1,105 @@ +/***************************************************************************** + * 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 "../core/MemoryStream.h" +#include "../interface/Window.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../world/Footpath.h" +#include "../world/Location.hpp" +#include "../world/Park.h" +#include "../world/Wall.h" +#include "GameAction.h" + +DEFINE_GAME_ACTION(FootpathSceneryRemoveAction, GAME_COMMAND_REMOVE_FOOTPATH_SCENERY, GameActionResult) +{ +private: + CoordsXYZ _loc; + +public: + FootpathSceneryRemoveAction() = default; + FootpathSceneryRemoveAction(CoordsXYZ loc) + : _loc(loc) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override + { + GameAction::Serialise(stream); + + stream << DS_TAG(_loc); + } + + GameActionResult::Ptr Query() const override + { + if (!map_is_location_valid({_loc.x, _loc.y})) + { + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_REMOVE_THIS, STR_OFF_EDGE_OF_MAP); + } + + if (!((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode) + && !map_is_location_owned(_loc.x, _loc.y, _loc.z / 8)) + { + return MakeResult(GA_ERROR::DISALLOWED, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + + if (_loc.z / 8 < 2) + { + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_REMOVE_THIS, STR_TOO_LOW); + } + + if (_loc.z / 8 > 248) + { + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_REMOVE_THIS, STR_TOO_HIGH); + } + + auto tileElement = map_get_footpath_element(_loc.x / 32, _loc.y / 32, _loc.z / 8); + auto pathElement = tileElement->AsPath(); + + if (pathElement == nullptr) + { + log_error("Could not find path element."); + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_REMOVE_THIS); + } + auto res = MakeResult(); + res->Cost = MONEY(0, 0); + return res; + } + + GameActionResult::Ptr Execute() const override + { + auto tileElement = map_get_footpath_element(_loc.x / 32, _loc.y / 32, _loc.z / 8); + auto pathElement = tileElement->AsPath(); + + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + footpath_interrupt_peeps(_loc.x, _loc.y, _loc.z); + } + + if (pathElement == nullptr) + { + log_error("Could not find path element."); + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_REMOVE_THIS); + } + + pathElement->SetAddition(0); + auto res = MakeResult(); + res->Cost = MONEY(0, 0); + return res; + } +}; diff --git a/src/openrct2/actions/GameActionRegistration.cpp b/src/openrct2/actions/GameActionRegistration.cpp index f99e9a3e07..24ffea581e 100644 --- a/src/openrct2/actions/GameActionRegistration.cpp +++ b/src/openrct2/actions/GameActionRegistration.cpp @@ -11,6 +11,8 @@ #include "ClearAction.hpp" #include "ClimateSetAction.hpp" #include "FootpathRemoveAction.hpp" +#include "FootpathSceneryPlaceAction.hpp" +#include "FootpathSceneryRemoveAction.hpp" #include "GameAction.h" #include "GuestSetNameAction.hpp" #include "LandSetHeightAction.hpp" @@ -56,6 +58,8 @@ namespace GameActions Register(); Register(); Register(); + Register(); + Register(); Register(); Register(); Register(); diff --git a/src/openrct2/core/DataSerialiserTraits.h b/src/openrct2/core/DataSerialiserTraits.h index e415f18bab..99c71baddb 100644 --- a/src/openrct2/core/DataSerialiserTraits.h +++ b/src/openrct2/core/DataSerialiserTraits.h @@ -343,6 +343,32 @@ template<> struct DataSerializerTraits } }; +template<> struct DataSerializerTraits +{ + static void encode(IStream* stream, const CoordsXYZ& coord) + { + stream->WriteValue(ByteSwapBE(coord.x)); + stream->WriteValue(ByteSwapBE(coord.y)); + stream->WriteValue(ByteSwapBE(coord.z)); + } + + static void decode(IStream* stream, CoordsXYZ& coord) + { + auto x = ByteSwapBE(stream->ReadValue()); + auto y = ByteSwapBE(stream->ReadValue()); + auto z = ByteSwapBE(stream->ReadValue()); + coord = CoordsXYZ{ x, y, z }; + } + + static void log(IStream* stream, const CoordsXYZ& coord) + { + char msg[128] = {}; + snprintf( + msg, sizeof(msg), "CoordsXYZ(x = %d, y = %d, z = %d)", coord.x, coord.y, coord.z); + stream->Write(msg, strlen(msg)); + } +}; + template<> struct DataSerializerTraits { static void encode(IStream* stream, const CoordsXYZD& coord) diff --git a/src/openrct2/world/Scenery.cpp b/src/openrct2/world/Scenery.cpp index 6aed6e3766..914d5018c2 100644 --- a/src/openrct2/world/Scenery.cpp +++ b/src/openrct2/world/Scenery.cpp @@ -14,6 +14,7 @@ #include "../Game.h" #include "../actions/LargeSceneryRemoveAction.hpp" #include "../actions/SmallSceneryRemoveAction.hpp" +#include "../actions/FootpathSceneryRemoveAction.hpp" #include "../actions/WallRemoveAction.hpp" #include "../common.h" #include "../localisation/Localisation.h" @@ -205,9 +206,9 @@ void scenery_remove_ghost_tool_placement() if (tileElement->base_height != z) continue; - game_do_command( - x, 233 | (gSceneryPlacePathSlope << 8), y, z | (gSceneryPlacePathType << 8), GAME_COMMAND_PLACE_PATH, - gSceneryGhostPathObjectType & 0xFFFF0000, 0); + auto footpathSceneryRemoveAction = FootpathSceneryRemoveAction({x, y, z * 8}); + footpathSceneryRemoveAction.SetFlags(GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_GHOST); + GameActions::Execute(&footpathSceneryRemoveAction); break; } while (!(tileElement++)->IsLastForTile()); }