diff --git a/src/openrct2-ui/windows/TileInspector.cpp b/src/openrct2-ui/windows/TileInspector.cpp index 69b79b6755..49832fcb9a 100644 --- a/src/openrct2-ui/windows/TileInspector.cpp +++ b/src/openrct2-ui/windows/TileInspector.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -29,7 +30,6 @@ #include #include #include -#include // clang-format off static constexpr const rct_string_id TerrainTypeStringIds[] = { @@ -619,25 +619,25 @@ static void window_tile_inspector_load_tile(rct_window* w, TileElement* elementT static void window_tile_inspector_insert_corrupt_element(int32_t elementIndex) { openrct2_assert(elementIndex >= 0 && elementIndex < windowTileInspectorElementCount, "elementIndex out of range"); - game_do_command( - TILE_INSPECTOR_ANY_INSERT_CORRUPT, GAME_COMMAND_FLAG_APPLY, windowTileInspectorTileX | (windowTileInspectorTileY << 8), - elementIndex, GAME_COMMAND_MODIFY_TILE, 0, 0); + auto modifyTile = TileModifyAction( + { windowTileInspectorToolMapX, windowTileInspectorToolMapY }, TileModifyType::AnyInsertCorrupt, elementIndex); + GameActions::Execute(&modifyTile); } static void window_tile_inspector_remove_element(int32_t elementIndex) { openrct2_assert(elementIndex >= 0 && elementIndex < windowTileInspectorElementCount, "elementIndex out of range"); - game_do_command( - TILE_INSPECTOR_ANY_REMOVE, GAME_COMMAND_FLAG_APPLY, windowTileInspectorTileX | (windowTileInspectorTileY << 8), - elementIndex, GAME_COMMAND_MODIFY_TILE, 0, 0); + auto modifyTile = TileModifyAction( + { windowTileInspectorToolMapX, windowTileInspectorToolMapY }, TileModifyType::AnyRemove, elementIndex); + GameActions::Execute(&modifyTile); } static void window_tile_inspector_rotate_element(int32_t elementIndex) { openrct2_assert(elementIndex >= 0 && elementIndex < windowTileInspectorElementCount, "elementIndex out of range"); - game_do_command( - TILE_INSPECTOR_ANY_ROTATE, GAME_COMMAND_FLAG_APPLY, windowTileInspectorTileX | (windowTileInspectorTileY << 8), - elementIndex, GAME_COMMAND_MODIFY_TILE, 0, 0); + auto modifyTile = TileModifyAction( + { windowTileInspectorToolMapX, windowTileInspectorToolMapY }, TileModifyType::AnyRotate, elementIndex); + GameActions::Execute(&modifyTile); } // Swap element with its parent @@ -645,17 +645,16 @@ static void window_tile_inspector_swap_elements(int16_t first, int16_t second) { openrct2_assert(first >= 0 && first < windowTileInspectorElementCount, "first out of range"); openrct2_assert(second >= 0 && second < windowTileInspectorElementCount, "second out of range"); - game_do_command( - TILE_INSPECTOR_ANY_SWAP, GAME_COMMAND_FLAG_APPLY, windowTileInspectorTileX | (windowTileInspectorTileY << 8), first, - GAME_COMMAND_MODIFY_TILE, second, 0); + auto modifyTile = TileModifyAction( + { windowTileInspectorToolMapX, windowTileInspectorToolMapY }, TileModifyType::AnySwap, first, second); + GameActions::Execute(&modifyTile); } static void window_tile_inspector_sort_elements() { openrct2_assert(windowTileInspectorTileSelected, "No tile selected"); - game_do_command( - TILE_INSPECTOR_ANY_SORT, GAME_COMMAND_FLAG_APPLY, windowTileInspectorTileX | (windowTileInspectorTileY << 8), 0, - GAME_COMMAND_MODIFY_TILE, 0, 0); + auto modifyTile = TileModifyAction({ windowTileInspectorToolMapX, windowTileInspectorToolMapY }, TileModifyType::AnySort); + GameActions::Execute(&modifyTile); } static void window_tile_inspector_copy_element(rct_window* w) @@ -672,127 +671,130 @@ static void window_tile_inspector_paste_element(rct_window* w) int32_t data[2]; std::memcpy(&data[0], &tileInspectorCopiedElement, 8); assert_struct_size(data, sizeof(tileInspectorCopiedElement)); - - game_do_command( - TILE_INSPECTOR_ANY_PASTE, GAME_COMMAND_FLAG_APPLY, windowTileInspectorTileX | (windowTileInspectorTileY << 8), data[0], - GAME_COMMAND_MODIFY_TILE, data[1], 0); + auto modifyTile = TileModifyAction( + { windowTileInspectorToolMapX, windowTileInspectorToolMapY }, TileModifyType::AnyPaste, 0, 0, + tileInspectorCopiedElement); + GameActions::Execute(&modifyTile); } static void window_tile_inspector_base_height_offset(int16_t elementIndex, int8_t heightOffset) { - game_do_command( - TILE_INSPECTOR_ANY_BASE_HEIGHT_OFFSET, GAME_COMMAND_FLAG_APPLY, - windowTileInspectorTileX | (windowTileInspectorTileY << 8), elementIndex, GAME_COMMAND_MODIFY_TILE, heightOffset, 0); + auto modifyTile = TileModifyAction( + { windowTileInspectorToolMapX, windowTileInspectorToolMapY }, TileModifyType::AnyBaseHeightOffset, elementIndex, + heightOffset); + GameActions::Execute(&modifyTile); } static void window_tile_inspector_surface_show_park_fences(bool showFences) { - game_do_command( - TILE_INSPECTOR_SURFACE_SHOW_PARK_FENCES, GAME_COMMAND_FLAG_APPLY, - windowTileInspectorTileX | (windowTileInspectorTileY << 8), showFences, GAME_COMMAND_MODIFY_TILE, 0, 0); + auto modifyTile = TileModifyAction( + { windowTileInspectorToolMapX, windowTileInspectorToolMapY }, TileModifyType::SurfaceShowParkFences, showFences); + GameActions::Execute(&modifyTile); } static void window_tile_inspector_surface_toggle_corner(int32_t cornerIndex) { - game_do_command( - TILE_INSPECTOR_SURFACE_TOGGLE_CORNER, GAME_COMMAND_FLAG_APPLY, - windowTileInspectorTileX | (windowTileInspectorTileY << 8), cornerIndex, GAME_COMMAND_MODIFY_TILE, 0, 0); + auto modifyTile = TileModifyAction( + { windowTileInspectorToolMapX, windowTileInspectorToolMapY }, TileModifyType::SurfaceToggleCorner, cornerIndex); + GameActions::Execute(&modifyTile); } static void window_tile_inspector_surface_toggle_diagonal() { - game_do_command( - TILE_INSPECTOR_SURFACE_TOGGLE_DIAGONAL, GAME_COMMAND_FLAG_APPLY, - windowTileInspectorTileX | (windowTileInspectorTileY << 8), 0, GAME_COMMAND_MODIFY_TILE, 0, 0); + auto modifyTile = TileModifyAction( + { windowTileInspectorToolMapX, windowTileInspectorToolMapY }, TileModifyType::SurfaceToggleDiagonal); + GameActions::Execute(&modifyTile); } static void window_tile_inspector_path_set_sloped(int32_t elementIndex, bool sloped) { - game_do_command( - TILE_INSPECTOR_PATH_SET_SLOPE, GAME_COMMAND_FLAG_APPLY, windowTileInspectorTileX | (windowTileInspectorTileY << 8), - elementIndex, GAME_COMMAND_MODIFY_TILE, sloped, 0); + auto modifyTile = TileModifyAction( + { windowTileInspectorToolMapX, windowTileInspectorToolMapY }, TileModifyType::PathSetSlope, elementIndex, sloped); + GameActions::Execute(&modifyTile); } static void window_tile_inspector_path_set_broken(int32_t elementIndex, bool broken) { - game_do_command( - TILE_INSPECTOR_PATH_SET_BROKEN, GAME_COMMAND_FLAG_APPLY, windowTileInspectorTileX | (windowTileInspectorTileY << 8), - elementIndex, GAME_COMMAND_MODIFY_TILE, broken, 0); + auto modifyTile = TileModifyAction( + { windowTileInspectorToolMapX, windowTileInspectorToolMapY }, TileModifyType::PathSetBroken, elementIndex, broken); + GameActions::Execute(&modifyTile); } static void window_tile_inspector_path_toggle_edge(int32_t elementIndex, int32_t cornerIndex) { openrct2_assert(elementIndex >= 0 && elementIndex < windowTileInspectorElementCount, "elementIndex out of range"); openrct2_assert(cornerIndex >= 0 && cornerIndex < 8, "cornerIndex out of range"); - game_do_command( - TILE_INSPECTOR_PATH_TOGGLE_EDGE, GAME_COMMAND_FLAG_APPLY, windowTileInspectorTileX | (windowTileInspectorTileY << 8), - elementIndex, GAME_COMMAND_MODIFY_TILE, cornerIndex, 0); + auto modifyTile = TileModifyAction( + { windowTileInspectorToolMapX, windowTileInspectorToolMapY }, TileModifyType::PathToggleEdge, elementIndex, + cornerIndex); + GameActions::Execute(&modifyTile); } static void window_tile_inspector_entrance_make_usable(int32_t elementIndex) { Guard::ArgumentInRange(elementIndex, 0, windowTileInspectorElementCount - 1); - game_do_command( - TILE_INSPECTOR_ENTRANCE_MAKE_USABLE, GAME_COMMAND_FLAG_APPLY, - windowTileInspectorTileX | (windowTileInspectorTileY << 8), elementIndex, GAME_COMMAND_MODIFY_TILE, 0, 0); + auto modifyTile = TileModifyAction( + { windowTileInspectorToolMapX, windowTileInspectorToolMapY }, TileModifyType::EntranceMakeUsable, elementIndex); + GameActions::Execute(&modifyTile); } static void window_tile_inspector_wall_set_slope(int32_t elementIndex, int32_t slopeValue) { // Make sure only the correct bits are set openrct2_assert((slopeValue & 3) == slopeValue, "slopeValue doesn't match its mask"); - - game_do_command( - TILE_INSPECTOR_WALL_SET_SLOPE, GAME_COMMAND_FLAG_APPLY, windowTileInspectorTileX | (windowTileInspectorTileY << 8), - elementIndex, GAME_COMMAND_MODIFY_TILE, slopeValue, 0); + auto modifyTile = TileModifyAction( + { windowTileInspectorToolMapX, windowTileInspectorToolMapY }, TileModifyType::WallSetSlope, elementIndex, slopeValue); + GameActions::Execute(&modifyTile); } static void window_tile_inspector_track_block_height_offset(int32_t elementIndex, int8_t heightOffset) { - game_do_command( - TILE_INSPECTOR_TRACK_BASE_HEIGHT_OFFSET, GAME_COMMAND_FLAG_APPLY, - windowTileInspectorTileX | (windowTileInspectorTileY << 8), elementIndex, GAME_COMMAND_MODIFY_TILE, heightOffset, 0); + auto modifyTile = TileModifyAction( + { windowTileInspectorToolMapX, windowTileInspectorToolMapY }, TileModifyType::TrackBaseHeightOffset, elementIndex, + heightOffset); + GameActions::Execute(&modifyTile); } static void window_tile_inspector_track_block_set_lift(int32_t elementIndex, bool entireTrackBlock, bool chain) { - game_do_command( - TILE_INSPECTOR_TRACK_SET_CHAIN, GAME_COMMAND_FLAG_APPLY, windowTileInspectorTileX | (windowTileInspectorTileY << 8), - elementIndex, GAME_COMMAND_MODIFY_TILE, entireTrackBlock, chain); + auto modifyTile = TileModifyAction( + { windowTileInspectorToolMapX, windowTileInspectorToolMapY }, + entireTrackBlock ? TileModifyType::TrackSetChainBlock : TileModifyType::TrackSetChain, elementIndex, chain); + GameActions::Execute(&modifyTile); } static void window_tile_inspector_track_set_block_brake(int32_t elementIndex, bool blockBrake) { - game_do_command( - TILE_INSPECTOR_TRACK_SET_BLOCK_BRAKE, GAME_COMMAND_FLAG_APPLY, - windowTileInspectorTileX | (windowTileInspectorTileY << 8), elementIndex, GAME_COMMAND_MODIFY_TILE, blockBrake, 0); + auto modifyTile = TileModifyAction( + { windowTileInspectorToolMapX, windowTileInspectorToolMapY }, TileModifyType::TrackSetBlockBrake, elementIndex, + blockBrake); + GameActions::Execute(&modifyTile); } static void window_tile_inspector_track_set_indestructible(int32_t elementIndex, bool isIndestructible) { - game_do_command( - TILE_INSPECTOR_TRACK_SET_INDESTRUCTIBLE, GAME_COMMAND_FLAG_APPLY, - windowTileInspectorTileX | (windowTileInspectorTileY << 8), elementIndex, GAME_COMMAND_MODIFY_TILE, isIndestructible, - 0); + auto modifyTile = TileModifyAction( + { windowTileInspectorToolMapX, windowTileInspectorToolMapY }, TileModifyType::TrackSetIndestructible, elementIndex, + isIndestructible); + GameActions::Execute(&modifyTile); } static void window_tile_inspector_quarter_tile_set(int32_t elementIndex, const int32_t quarterIndex) { // quarterIndex is widget index relative to WIDX_SCENERY_CHECK_QUARTER_N, so a value from 0-3 openrct2_assert(quarterIndex >= 0 && quarterIndex < 4, "quarterIndex out of range"); - - game_do_command( - TILE_INSPECTOR_SCENERY_SET_QUARTER_LOCATION, GAME_COMMAND_FLAG_APPLY, - windowTileInspectorTileX | (windowTileInspectorTileY << 8), elementIndex, GAME_COMMAND_MODIFY_TILE, - (quarterIndex - get_current_rotation()) & 3, 0); + auto modifyTile = TileModifyAction( + { windowTileInspectorToolMapX, windowTileInspectorToolMapY }, TileModifyType::ScenerySetQuarterLocation, elementIndex, + (quarterIndex - get_current_rotation()) & 3); + GameActions::Execute(&modifyTile); } static void window_tile_inspector_toggle_quadrant_collosion(int32_t elementIndex, const int32_t quadrantIndex) { - game_do_command( - TILE_INSPECTOR_SCENERY_SET_QUARTER_COLLISION, GAME_COMMAND_FLAG_APPLY, - windowTileInspectorTileX | (windowTileInspectorTileY << 8), elementIndex, GAME_COMMAND_MODIFY_TILE, - (quadrantIndex + 2 - get_current_rotation()) & 3, 0); + auto modifyTile = TileModifyAction( + { windowTileInspectorToolMapX, windowTileInspectorToolMapY }, TileModifyType::ScenerySetQuarterCollision, elementIndex, + (quadrantIndex + 2 - get_current_rotation()) & 3); + GameActions::Execute(&modifyTile); } static void window_tile_inspector_banner_toggle_block(int32_t elementIndex, int32_t edgeIndex) @@ -801,17 +803,17 @@ static void window_tile_inspector_banner_toggle_block(int32_t elementIndex, int3 // Make edgeIndex abstract edgeIndex = (edgeIndex - get_current_rotation()) & 3; - - game_do_command( - TILE_INSPECTOR_BANNER_TOGGLE_BLOCKING_EDGE, GAME_COMMAND_FLAG_APPLY, - windowTileInspectorTileX | (windowTileInspectorTileY << 8), elementIndex, GAME_COMMAND_MODIFY_TILE, edgeIndex, 0); + auto modifyTile = TileModifyAction( + { windowTileInspectorToolMapX, windowTileInspectorToolMapY }, TileModifyType::BannerToggleBlockingEdge, elementIndex, + edgeIndex); + GameActions::Execute(&modifyTile); } static void window_tile_inspector_clamp_corrupt(int32_t elementIndex) { - game_do_command( - TILE_INSPECTOR_CORRUPT_CLAMP, GAME_COMMAND_FLAG_APPLY, windowTileInspectorTileX | (windowTileInspectorTileY << 8), - elementIndex, GAME_COMMAND_MODIFY_TILE, 0, 0); + auto modifyTile = TileModifyAction( + { windowTileInspectorToolMapX, windowTileInspectorToolMapY }, TileModifyType::CorruptClamp, elementIndex); + GameActions::Execute(&modifyTile); } static void window_tile_inspector_mouseup(rct_window* w, rct_widgetindex widgetIndex) diff --git a/src/openrct2/Game.cpp b/src/openrct2/Game.cpp index f24cd83a6f..90f388f0f5 100644 --- a/src/openrct2/Game.cpp +++ b/src/openrct2/Game.cpp @@ -1225,7 +1225,7 @@ GAME_COMMAND_POINTER* new_game_command_table[GAME_COMMAND_COUNT] = { game_command_pickup_guest, game_command_pickup_staff, nullptr, - game_command_modify_tile, + nullptr, nullptr, NULL, }; diff --git a/src/openrct2/Game.h b/src/openrct2/Game.h index d9885993c3..d29f0f06b3 100644 --- a/src/openrct2/Game.h +++ b/src/openrct2/Game.h @@ -87,8 +87,8 @@ enum GAME_COMMAND GAME_COMMAND_CHEAT, // GA GAME_COMMAND_PICKUP_GUEST, GAME_COMMAND_PICKUP_STAFF, - GAME_COMMAND_BALLOON_PRESS, // GA - GAME_COMMAND_MODIFY_TILE, + GAME_COMMAND_BALLOON_PRESS, // GA + GAME_COMMAND_MODIFY_TILE, // GA GAME_COMMAND_EDIT_SCENARIO_OPTIONS, // GA GAME_COMMAND_PLACE_PEEP_SPAWN, // GA, TODO: refactor to separate array for just game actions GAME_COMMAND_SET_CLIMATE, // GA diff --git a/src/openrct2/ReplayManager.cpp b/src/openrct2/ReplayManager.cpp index 157be538b0..eb4ec432bf 100644 --- a/src/openrct2/ReplayManager.cpp +++ b/src/openrct2/ReplayManager.cpp @@ -19,6 +19,7 @@ #include "actions/RideEntranceExitPlaceAction.hpp" #include "actions/RideSetSetting.hpp" #include "actions/SetCheatAction.hpp" +#include "actions/TileModifyAction.hpp" #include "actions/TrackPlaceAction.hpp" #include "config/Config.h" #include "core/DataSerialiser.h" @@ -537,6 +538,28 @@ namespace OpenRCT2 result.action->SetFlags(command.ebx & 0xFF); break; } + case GAME_COMMAND_MODIFY_TILE: + { + int32_t param1 = command.edx; + int32_t param2 = command.edi; + CoordsXY loc = { static_cast((command.ecx & 0xFF) * 32), + static_cast(((command.ecx >> 8) & 0xFF) * 32) }; + TileModifyType type = static_cast(command.eax & 0xFF); + + if (type == TileModifyType::AnyPaste) + { + TileElement copiedElement{}; + uint32_t data[2] = { command.edx, command.edi }; + std::memcpy(&copiedElement, &data[0], 8); + result.action = std::make_unique(loc, type, 0, 0, copiedElement); + } + else + { + result.action = std::make_unique(loc, type, param1, param2); + } + result.action->SetFlags(command.ebx & 0xFF); + break; + } default: throw std::runtime_error("Deprecated game command requires replay translation."); } diff --git a/src/openrct2/actions/GameActionRegistration.cpp b/src/openrct2/actions/GameActionRegistration.cpp index 4bbbabdbcd..25f0601b9a 100644 --- a/src/openrct2/actions/GameActionRegistration.cpp +++ b/src/openrct2/actions/GameActionRegistration.cpp @@ -74,6 +74,7 @@ #include "StaffSetOrdersAction.hpp" #include "StaffSetPatrolAreaAction.hpp" #include "SurfaceSetStyleAction.hpp" +#include "TileModifyAction.hpp" #include "TrackPlaceAction.hpp" #include "TrackRemoveAction.hpp" #include "TrackSetBrakeSpeedAction.hpp" @@ -151,6 +152,7 @@ namespace GameActions Register(); Register(); Register(); + Register(); Register(); Register(); Register(); diff --git a/src/openrct2/actions/TileModifyAction.hpp b/src/openrct2/actions/TileModifyAction.hpp new file mode 100644 index 0000000000..ef063b3856 --- /dev/null +++ b/src/openrct2/actions/TileModifyAction.hpp @@ -0,0 +1,262 @@ +/***************************************************************************** + * 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 "../world/TileInspector.h" +#include "GameAction.h" + +enum class TileModifyType : uint8_t +{ + AnyRemove, + AnySwap, + AnyInsertCorrupt, + AnyRotate, + AnyPaste, + AnySort, + AnyBaseHeightOffset, + SurfaceShowParkFences, + SurfaceToggleCorner, + SurfaceToggleDiagonal, + PathSetSlope, + PathSetBroken, + PathToggleEdge, + EntranceMakeUsable, + WallSetSlope, + TrackBaseHeightOffset, + TrackSetChain, + TrackSetChainBlock, + TrackSetBlockBrake, + TrackSetIndestructible, + ScenerySetQuarterLocation, + ScenerySetQuarterCollision, + BannerToggleBlockingEdge, + CorruptClamp, + Count, +}; + +DEFINE_GAME_ACTION(TileModifyAction, GAME_COMMAND_MODIFY_TILE, GameActionResult) +{ +private: + CoordsXY _loc; + uint8_t _setting{ 0 }; + uint32_t _value1{ 0 }; + uint32_t _value2{ 0 }; + TileElement _pasteElement{}; + +public: + TileModifyAction() + { + } + TileModifyAction( + CoordsXY loc, TileModifyType setting, uint32_t value1 = 0, uint32_t value2 = 0, TileElement pasteElement = {}) + : _loc(loc) + , _setting(static_cast(setting)) + , _value1(value1) + , _value2(value2) + , _pasteElement(pasteElement) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GA_FLAGS::ALLOW_WHILE_PAUSED; + } + + void Serialise(DataSerialiser & stream) override + { + GameAction::Serialise(stream); + + stream << DS_TAG(_loc) << DS_TAG(_setting) << DS_TAG(_value1) << DS_TAG(_value2) << DS_TAG(_pasteElement); + } + + GameActionResult::Ptr Query() const override + { + return QueryExecute(false); + } + + GameActionResult::Ptr Execute() const override + { + return QueryExecute(true); + } + +private: + GameActionResult::Ptr QueryExecute(bool isExecuting) const + { + auto res = MakeResult(); + switch (static_cast(_setting)) + { + case TileModifyType::AnyRemove: + { + const auto elementIndex = _value1; + res = tile_inspector_remove_element_at(_loc, elementIndex, isExecuting); + break; + } + case TileModifyType::AnySwap: + { + const auto firstIndex = _value1; + const auto secondIndex = _value2; + res = tile_inspector_swap_elements_at(_loc, firstIndex, secondIndex, isExecuting); + break; + } + case TileModifyType::AnyInsertCorrupt: + { + const auto elementIndex = _value1; + res = tile_inspector_insert_corrupt_at(_loc, elementIndex, isExecuting); + break; + } + case TileModifyType::AnyRotate: + { + const auto elementIndex = _value1; + res = tile_inspector_rotate_element_at(_loc, elementIndex, isExecuting); + break; + } + case TileModifyType::AnyPaste: + { + res = tile_inspector_paste_element_at(_loc, _pasteElement, isExecuting); + break; + } + case TileModifyType::AnySort: + { + res = tile_inspector_sort_elements_at(_loc, isExecuting); + break; + } + case TileModifyType::AnyBaseHeightOffset: + { + const auto elementIndex = _value1; + const auto heightOffset = _value2; + res = tile_inspector_any_base_height_offset(_loc, elementIndex, heightOffset, isExecuting); + break; + } + case TileModifyType::SurfaceShowParkFences: + { + const bool showFences = _value1; + res = tile_inspector_surface_show_park_fences(_loc, showFences, isExecuting); + break; + } + case TileModifyType::SurfaceToggleCorner: + { + const auto cornerIndex = _value1; + res = tile_inspector_surface_toggle_corner(_loc, cornerIndex, isExecuting); + break; + } + case TileModifyType::SurfaceToggleDiagonal: + { + res = tile_inspector_surface_toggle_diagonal(_loc, isExecuting); + break; + } + case TileModifyType::PathSetSlope: + { + const auto elementIndex = _value1; + const bool sloped = _value2; + res = tile_inspector_path_set_sloped(_loc, elementIndex, sloped, isExecuting); + break; + } + case TileModifyType::PathSetBroken: + { + const auto elementIndex = _value1; + const bool broken = _value2; + res = tile_inspector_path_set_broken(_loc, elementIndex, broken, isExecuting); + break; + } + case TileModifyType::PathToggleEdge: + { + const auto elementIndex = _value1; + const auto edgeIndex = _value2; + res = tile_inspector_path_toggle_edge(_loc, elementIndex, edgeIndex, isExecuting); + break; + } + case TileModifyType::EntranceMakeUsable: + { + const auto elementIndex = _value1; + res = tile_inspector_entrance_make_usable(_loc, elementIndex, isExecuting); + break; + } + case TileModifyType::WallSetSlope: + { + const auto elementIndex = _value1; + const auto slopeValue = _value2; + res = tile_inspector_wall_set_slope(_loc, elementIndex, slopeValue, isExecuting); + break; + } + case TileModifyType::TrackBaseHeightOffset: + { + const auto elementIndex = _value1; + const auto heightOffset = _value2; + res = tile_inspector_track_base_height_offset(_loc, elementIndex, heightOffset, isExecuting); + break; + } + case TileModifyType::TrackSetChainBlock: + { + const auto elementIndex = _value1; + const bool setChain = _value2; + res = tile_inspector_track_set_chain(_loc, elementIndex, true, setChain, isExecuting); + break; + } + case TileModifyType::TrackSetChain: + { + const auto elementIndex = _value1; + const bool setChain = _value2; + res = tile_inspector_track_set_chain(_loc, elementIndex, false, setChain, isExecuting); + break; + } + case TileModifyType::TrackSetBlockBrake: + { + const auto elementIndex = _value1; + const bool blockBrake = _value2; + res = tile_inspector_track_set_block_brake(_loc, elementIndex, blockBrake, isExecuting); + break; + } + case TileModifyType::TrackSetIndestructible: + { + const auto elementIndex = _value1; + const bool isIndestructible = _value2; + res = tile_inspector_track_set_indestructible(_loc, elementIndex, isIndestructible, isExecuting); + break; + } + case TileModifyType::ScenerySetQuarterLocation: + { + const auto elementIndex = _value1; + const auto quarterIndex = _value2; + res = tile_inspector_scenery_set_quarter_location(_loc, elementIndex, quarterIndex, isExecuting); + break; + } + case TileModifyType::ScenerySetQuarterCollision: + { + const auto elementIndex = _value1; + const auto quarterIndex = _value2; + res = tile_inspector_scenery_set_quarter_collision(_loc, elementIndex, quarterIndex, isExecuting); + break; + } + case TileModifyType::BannerToggleBlockingEdge: + { + const auto elementIndex = _value1; + const auto edgeIndex = _value2; + res = tile_inspector_banner_toggle_blocking_edge(_loc, elementIndex, edgeIndex, isExecuting); + break; + } + case TileModifyType::CorruptClamp: + { + const auto elementIndex = _value1; + res = tile_inspector_corrupt_clamp(_loc, elementIndex, isExecuting); + break; + } + default: + log_error("invalid instruction"); + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_NONE); + break; + } + + res->Position.x = _loc.x; + res->Position.y = _loc.y; + res->Position.z = tile_element_height(_loc.x, _loc.y); + + return res; + } +}; diff --git a/src/openrct2/core/DataSerialiserTraits.h b/src/openrct2/core/DataSerialiserTraits.h index fe69c07e84..7d16b0c847 100644 --- a/src/openrct2/core/DataSerialiserTraits.h +++ b/src/openrct2/core/DataSerialiserTraits.h @@ -16,6 +16,7 @@ #include "../network/network.h" #include "../ride/Ride.h" #include "../world/Location.hpp" +#include "../world/TileElement.h" #include "DataSerialiserTag.h" #include "Endianness.h" #include "MemoryStream.h" @@ -381,6 +382,40 @@ template<> struct DataSerializerTraits } }; +template<> struct DataSerializerTraits +{ + static void encode(IStream* stream, const TileElement& tileElement) + { + stream->WriteValue(tileElement.type); + stream->WriteValue(tileElement.flags); + stream->WriteValue(tileElement.base_height); + stream->WriteValue(tileElement.clearance_height); + for (int i = 0; i < 4; ++i) + { + stream->WriteValue(tileElement.pad_04[i]); + } + } + static void decode(IStream* stream, TileElement& tileElement) + { + tileElement.type = stream->ReadValue(); + tileElement.flags = stream->ReadValue(); + tileElement.base_height = stream->ReadValue(); + tileElement.clearance_height = stream->ReadValue(); + for (int i = 0; i < 4; ++i) + { + tileElement.pad_04[i] = stream->ReadValue(); + } + } + static void log(IStream* stream, const TileElement& tileElement) + { + char msg[128] = {}; + snprintf( + msg, sizeof(msg), "TileElement(type = %u, flags = %u, base_height = %u)", tileElement.type, tileElement.flags, + tileElement.base_height); + stream->Write(msg, strlen(msg)); + } +}; + template<> struct DataSerializerTraits { static void encode(IStream* stream, const CoordsXY& coords) diff --git a/src/openrct2/network/Network.cpp b/src/openrct2/network/Network.cpp index 927e2a5858..aa1f25d998 100644 --- a/src/openrct2/network/Network.cpp +++ b/src/openrct2/network/Network.cpp @@ -33,7 +33,7 @@ // This string specifies which version of network stream current build uses. // It is used for making sure only compatible builds get connected, even within // single OpenRCT2 version. -#define NETWORK_STREAM_VERSION "40" +#define NETWORK_STREAM_VERSION "41" #define NETWORK_STREAM_ID OPENRCT2_VERSION "-" NETWORK_STREAM_VERSION static Peep* _pickup_peep = nullptr; diff --git a/src/openrct2/world/Map.cpp b/src/openrct2/world/Map.cpp index 115395cd1b..f778a907cd 100644 --- a/src/openrct2/world/Map.cpp +++ b/src/openrct2/world/Map.cpp @@ -2245,186 +2245,6 @@ void map_clear_all_elements() } } -void game_command_modify_tile( - int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, [[maybe_unused]] int32_t* esi, int32_t* edi, int32_t* ebp) -{ - const int32_t flags = *ebx; - const int32_t x = *ecx & 0xFF; - const int32_t y = (*ecx >> 8) & 0xFF; - const TILE_INSPECTOR_INSTRUCTION_TYPE instruction = static_cast(*eax); - - switch (instruction) - { - case TILE_INSPECTOR_ANY_REMOVE: - { - const int16_t elementIndex = *edx; - *ebx = tile_inspector_remove_element_at(x, y, elementIndex, flags); - break; - } - case TILE_INSPECTOR_ANY_SWAP: - { - const int32_t firstIndex = *edx; - const int32_t secondIndex = *edi; - *ebx = tile_inspector_swap_elements_at(x, y, firstIndex, secondIndex, flags); - break; - } - case TILE_INSPECTOR_ANY_INSERT_CORRUPT: - { - const int16_t elementIndex = *edx; - *ebx = tile_inspector_insert_corrupt_at(x, y, elementIndex, flags); - break; - } - case TILE_INSPECTOR_ANY_ROTATE: - { - const int16_t elementIndex = *edx; - *ebx = tile_inspector_rotate_element_at(x, y, elementIndex, flags); - break; - } - case TILE_INSPECTOR_ANY_PASTE: - { - TileElement elementToPaste; - const int32_t data[] = { *edx, *edi }; - assert_struct_size(data, sizeof(elementToPaste)); - std::memcpy(&elementToPaste, data, 8); - *ebx = tile_inspector_paste_element_at(x, y, elementToPaste, flags); - break; - } - case TILE_INSPECTOR_ANY_SORT: - { - *ebx = tile_inspector_sort_elements_at(x, y, flags); - break; - } - case TILE_INSPECTOR_ANY_BASE_HEIGHT_OFFSET: - { - const int16_t elementIndex = *edx; - const int8_t heightOffset = *edi; - *ebx = tile_inspector_any_base_height_offset(x, y, elementIndex, heightOffset, flags); - break; - } - case TILE_INSPECTOR_SURFACE_SHOW_PARK_FENCES: - { - const bool showFences = *edx; - *ebx = tile_inspector_surface_show_park_fences(x, y, showFences, flags); - break; - } - case TILE_INSPECTOR_SURFACE_TOGGLE_CORNER: - { - const int32_t cornerIndex = *edx; - *ebx = tile_inspector_surface_toggle_corner(x, y, cornerIndex, flags); - break; - } - case TILE_INSPECTOR_SURFACE_TOGGLE_DIAGONAL: - { - *ebx = tile_inspector_surface_toggle_diagonal(x, y, flags); - break; - } - case TILE_INSPECTOR_PATH_SET_SLOPE: - { - const int32_t elementIndex = *edx; - const bool sloped = *edi; - *ebx = tile_inspector_path_set_sloped(x, y, elementIndex, sloped, flags); - break; - } - case TILE_INSPECTOR_PATH_SET_BROKEN: - { - const int32_t elementIndex = *edx; - const bool broken = *edi; - *ebx = tile_inspector_path_set_broken(x, y, elementIndex, broken, flags); - break; - } - case TILE_INSPECTOR_PATH_TOGGLE_EDGE: - { - const int32_t elementIndex = *edx; - const int32_t edgeIndex = *edi; - *ebx = tile_inspector_path_toggle_edge(x, y, elementIndex, edgeIndex, flags); - break; - } - case TILE_INSPECTOR_ENTRANCE_MAKE_USABLE: - { - const int32_t elementIndex = *edx; - *ebx = tile_inspector_entrance_make_usable(x, y, elementIndex, flags); - break; - } - case TILE_INSPECTOR_WALL_SET_SLOPE: - { - const int32_t elementIndex = *edx; - const int32_t slopeValue = *edi; - *ebx = tile_inspector_wall_set_slope(x, y, elementIndex, slopeValue, flags); - break; - } - case TILE_INSPECTOR_TRACK_BASE_HEIGHT_OFFSET: - { - const int32_t elementIndex = *edx; - const int8_t heightOffset = *edi; - *ebx = tile_inspector_track_base_height_offset(x, y, elementIndex, heightOffset, flags); - break; - } - case TILE_INSPECTOR_TRACK_SET_CHAIN: - { - const int32_t elementIndex = *edx; - const bool entireTrackBlock = *edi; - const bool setChain = *ebp; - *ebx = tile_inspector_track_set_chain(x, y, elementIndex, entireTrackBlock, setChain, flags); - break; - } - case TILE_INSPECTOR_TRACK_SET_BLOCK_BRAKE: - { - const int32_t elementIndex = *edx; - const bool blockBrake = *edi; - *ebx = tile_inspector_track_set_block_brake(x, y, elementIndex, blockBrake, flags); - break; - } - case TILE_INSPECTOR_TRACK_SET_INDESTRUCTIBLE: - { - const int32_t elementIndex = *edx; - const bool isIndestructible = *edi; - *ebx = tile_inspector_track_set_indestructible(x, y, elementIndex, isIndestructible, flags); - break; - } - case TILE_INSPECTOR_SCENERY_SET_QUARTER_LOCATION: - { - const int32_t elementIndex = *edx; - const int32_t quarterIndex = *edi; - *ebx = tile_inspector_scenery_set_quarter_location(x, y, elementIndex, quarterIndex, flags); - break; - } - case TILE_INSPECTOR_SCENERY_SET_QUARTER_COLLISION: - { - const int32_t elementIndex = *edx; - const int32_t quarterIndex = *edi; - *ebx = tile_inspector_scenery_set_quarter_collision(x, y, elementIndex, quarterIndex, flags); - break; - } - case TILE_INSPECTOR_BANNER_TOGGLE_BLOCKING_EDGE: - { - const int32_t elementIndex = *edx; - const int32_t edgeIndex = *edi; - *ebx = tile_inspector_banner_toggle_blocking_edge(x, y, elementIndex, edgeIndex, flags); - break; - } - case TILE_INSPECTOR_CORRUPT_CLAMP: - { - const int32_t elementIndex = *edx; - *ebx = tile_inspector_corrupt_clamp(x, y, elementIndex, flags); - break; - } - default: - log_error("invalid instruction"); - *ebx = MONEY32_UNDEFINED; - break; - } - - if (flags & GAME_COMMAND_FLAG_APPLY && gGameCommandNestLevel == 1 && !(flags & GAME_COMMAND_FLAG_GHOST) - && *ebx != MONEY32_UNDEFINED) - { - LocationXYZ16 coord; - coord.x = (x << 5) + 16; - coord.y = (y << 5) + 16; - coord.z = tile_element_height(coord.x, coord.y); - network_set_player_last_action_coord(network_get_player_index(game_command_playerid), coord); - } -} - /** * Gets the track element at x, y, z. * @param x x units, not tiles. diff --git a/src/openrct2/world/Map.h b/src/openrct2/world/Map.h index b50068d3cd..bf54aa9a46 100644 --- a/src/openrct2/world/Map.h +++ b/src/openrct2/world/Map.h @@ -187,8 +187,6 @@ int32_t map_can_construct_at(int32_t x, int32_t y, int32_t zLow, int32_t zHigh, void rotate_map_coordinates(int16_t* x, int16_t* y, int32_t rotation); LocationXY16 coordinate_3d_to_2d(const LocationXYZ16* coordinate_3d, int32_t rotation); -void game_command_modify_tile(int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp); - struct tile_element_iterator { int32_t x; diff --git a/src/openrct2/world/TileInspector.cpp b/src/openrct2/world/TileInspector.cpp index a8266a0cc6..5278f341ef 100644 --- a/src/openrct2/world/TileInspector.cpp +++ b/src/openrct2/world/TileInspector.cpp @@ -11,6 +11,7 @@ #include "../Context.h" #include "../Game.h" +#include "../actions/GameAction.h" #include "../common.h" #include "../core/Guard.hpp" #include "../interface/Window.h" @@ -34,10 +35,10 @@ uint32_t windowTileInspectorTileY; int32_t windowTileInspectorElementCount = 0; int32_t windowTileInspectorSelectedIndex; -static bool map_swap_elements_at(int32_t x, int32_t y, int16_t first, int16_t second) +static bool map_swap_elements_at(CoordsXY loc, int16_t first, int16_t second) { - TileElement* const firstElement = map_get_nth_element_at(x, y, first); - TileElement* const secondElement = map_get_nth_element_at(x, y, second); + TileElement* const firstElement = map_get_nth_element_at(loc.x / 32, loc.y / 32, first); + TileElement* const secondElement = map_get_nth_element_at(loc.x / 32, loc.y / 32, second); if (firstElement == nullptr) { @@ -77,28 +78,29 @@ static bool map_swap_elements_at(int32_t x, int32_t y, int16_t first, int16_t se * @param elementIndex The nth element on this tile * Returns 0 on success, MONEY_UNDEFINED otherwise. */ -int32_t tile_inspector_insert_corrupt_at(int32_t x, int32_t y, int16_t elementIndex, int32_t flags) +GameActionResult::Ptr tile_inspector_insert_corrupt_at(CoordsXY loc, int16_t elementIndex, bool isExecuting) { // Make sure there is enough space for the new element if (!map_check_free_elements_and_reorganise(1)) - return MONEY32_UNDEFINED; + return std::make_unique(GA_ERROR::NO_FREE_ELEMENTS, STR_NONE); - if (flags & GAME_COMMAND_FLAG_APPLY) + if (isExecuting) { // Create new corrupt element - TileElement* corruptElement = tile_element_insert(x, y, -1, 0); // Ugly hack: -1 guarantees this to be placed first + TileElement* corruptElement = tile_element_insert( + loc.x / 32, loc.y / 32, -1, 0); // Ugly hack: -1 guarantees this to be placed first if (corruptElement == nullptr) { log_warning("Failed to insert corrupt element."); - return MONEY32_UNDEFINED; + return std::make_unique(GA_ERROR::UNKNOWN, STR_NONE); } corruptElement->SetType(TILE_ELEMENT_TYPE_CORRUPT); // Set the base height to be the same as the selected element - TileElement* const selectedElement = map_get_nth_element_at(x, y, elementIndex + 1); + TileElement* const selectedElement = map_get_nth_element_at(loc.x / 32, loc.y / 32, elementIndex + 1); if (!selectedElement) { - return MONEY32_UNDEFINED; + return std::make_unique(GA_ERROR::UNKNOWN, STR_NONE); } corruptElement->base_height = corruptElement->clearance_height = selectedElement->base_height; @@ -106,7 +108,7 @@ int32_t tile_inspector_insert_corrupt_at(int32_t x, int32_t y, int16_t elementIn // this way it's placed under the selected element, even when there are multiple elements with the same base height for (int16_t i = 0; i < elementIndex; i++) { - if (!map_swap_elements_at(x, y, i, i + 1)) + if (!map_swap_elements_at(loc, i, i + 1)) { // don't return error here, we've already inserted an element // and moved it as far as we could, the only sensible thing left @@ -115,12 +117,12 @@ int32_t tile_inspector_insert_corrupt_at(int32_t x, int32_t y, int16_t elementIn } } - map_invalidate_tile_full(x << 5, y << 5); + map_invalidate_tile_full(loc.x, loc.y); // Update the tile inspector's list for everyone who has the tile selected rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX - && (uint32_t)y == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && (uint32_t)(loc.x / 32) == windowTileInspectorTileX + && (uint32_t)(loc.y / 32) == windowTileInspectorTileY) { windowTileInspectorElementCount++; @@ -135,7 +137,7 @@ int32_t tile_inspector_insert_corrupt_at(int32_t x, int32_t y, int16_t elementIn } // Nothing went wrong - return 0; + return std::make_unique(); } /** @@ -144,23 +146,23 @@ int32_t tile_inspector_insert_corrupt_at(int32_t x, int32_t y, int16_t elementIn * @param y The y coordinate of the tile * @param elementIndex The nth element on this tile */ -int32_t tile_inspector_remove_element_at(int32_t x, int32_t y, int16_t elementIndex, int32_t flags) +GameActionResult::Ptr tile_inspector_remove_element_at(CoordsXY loc, int16_t elementIndex, bool isExecuting) { - if (flags & GAME_COMMAND_FLAG_APPLY) + if (isExecuting) { // Forcefully remove the element - TileElement* const tileElement = map_get_nth_element_at(x, y, elementIndex); + TileElement* const tileElement = map_get_nth_element_at(loc.x / 32, loc.y / 32, elementIndex); if (!tileElement) { - return MONEY32_UNDEFINED; + return std::make_unique(GA_ERROR::UNKNOWN, STR_NONE); } tile_element_remove(tileElement); - map_invalidate_tile_full(x << 5, y << 5); + map_invalidate_tile_full(loc.x, loc.y); // Update the window rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX - && (uint32_t)y == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && (uint32_t)(loc.x / 32) == windowTileInspectorTileX + && (uint32_t)(loc.y / 32) == windowTileInspectorTileY) { windowTileInspectorElementCount--; @@ -177,23 +179,23 @@ int32_t tile_inspector_remove_element_at(int32_t x, int32_t y, int16_t elementIn } } - return 0; + return std::make_unique(); } -int32_t tile_inspector_swap_elements_at(int32_t x, int32_t y, int16_t first, int16_t second, int32_t flags) +GameActionResult::Ptr tile_inspector_swap_elements_at(CoordsXY loc, int16_t first, int16_t second, bool isExecuting) { - if (flags & GAME_COMMAND_FLAG_APPLY) + if (isExecuting) { - if (!map_swap_elements_at(x, y, first, second)) + if (!map_swap_elements_at(loc, first, second)) { - return MONEY32_UNDEFINED; + return std::make_unique(GA_ERROR::UNKNOWN, STR_NONE); } - map_invalidate_tile_full(x << 5, y << 5); + map_invalidate_tile_full(loc.x, loc.y); // Update the window rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX - && (uint32_t)y == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && (uint32_t)(loc.x / 32) == windowTileInspectorTileX + && (uint32_t)(loc.y / 32) == windowTileInspectorTileY) { // If one of them was selected, update selected list item if (windowTileInspectorSelectedIndex == first) @@ -205,19 +207,19 @@ int32_t tile_inspector_swap_elements_at(int32_t x, int32_t y, int16_t first, int } } - return 0; + return std::make_unique(); } -int32_t tile_inspector_rotate_element_at(int32_t x, int32_t y, int32_t elementIndex, int32_t flags) +GameActionResult::Ptr tile_inspector_rotate_element_at(CoordsXY loc, int32_t elementIndex, bool isExecuting) { - if (flags & GAME_COMMAND_FLAG_APPLY) + if (isExecuting) { uint8_t newRotation, pathEdges, pathCorners; - TileElement* const tileElement = map_get_nth_element_at(x, y, elementIndex); + TileElement* const tileElement = map_get_nth_element_at(loc.x / 32, loc.y / 32, elementIndex); if (!tileElement) { - return MONEY32_UNDEFINED; + return std::make_unique(GA_ERROR::UNKNOWN, STR_NONE); } switch (tileElement->GetType()) { @@ -247,11 +249,12 @@ int32_t tile_inspector_rotate_element_at(int32_t x, int32_t y, int32_t elementIn uint8_t z = tileElement->base_height; // Make sure this is the correct entrance or exit - if (entranceType == ENTRANCE_TYPE_RIDE_ENTRANCE && entrance.x == x && entrance.y == y && entrance.z == z) + if (entranceType == ENTRANCE_TYPE_RIDE_ENTRANCE && entrance.x == loc.x / 32 && entrance.y == loc.y / 32 + && entrance.z == z) { ride_set_entrance_location(ride, stationIndex, { entrance.x, entrance.y, entrance.z, newRotation }); } - else if (entranceType == ENTRANCE_TYPE_RIDE_EXIT && exit.x == x && exit.y == y && exit.z == z) + else if (entranceType == ENTRANCE_TYPE_RIDE_EXIT && exit.x == loc.x / 32 && exit.y == loc.y / 32 && exit.z == z) { ride_set_exit_location(ride, stationIndex, { exit.x, exit.y, exit.z, newRotation }); } @@ -273,41 +276,41 @@ int32_t tile_inspector_rotate_element_at(int32_t x, int32_t y, int32_t elementIn } } - map_invalidate_tile_full(x << 5, y << 5); + map_invalidate_tile_full(loc.x, loc.y); - if ((uint32_t)x == windowTileInspectorTileX && (uint32_t)y == windowTileInspectorTileY) + if ((uint32_t)(loc.x / 32) == windowTileInspectorTileX && (uint32_t)(loc.y / 32) == windowTileInspectorTileY) { window_invalidate_by_class(WC_TILE_INSPECTOR); } } - return 0; + return std::make_unique(); } -int32_t tile_inspector_paste_element_at(int32_t x, int32_t y, TileElement element, int32_t flags) +GameActionResult::Ptr tile_inspector_paste_element_at(CoordsXY loc, TileElement element, bool isExecuting) { // Make sure there is enough space for the new element if (!map_check_free_elements_and_reorganise(1)) { - return MONEY32_UNDEFINED; + return std::make_unique(GA_ERROR::NO_FREE_ELEMENTS, STR_NONE); } - if (flags & GAME_COMMAND_FLAG_APPLY) + if (isExecuting) { // Check if the element to be pasted refers to a banner index BannerIndex bannerIndex = tile_element_get_banner_index(&element); if (bannerIndex != BANNER_INDEX_NULL) { // The element to be pasted refers to a banner index - make a copy of it - BannerIndex newBannerIndex = create_new_banner(flags); + BannerIndex newBannerIndex = create_new_banner(GAME_COMMAND_FLAG_APPLY); if (newBannerIndex == BANNER_INDEX_NULL) { - return MONEY32_UNDEFINED; + return std::make_unique(GA_ERROR::UNKNOWN, STR_NONE); } rct_banner& newBanner = gBanners[newBannerIndex]; newBanner = gBanners[bannerIndex]; - newBanner.x = x; - newBanner.y = y; + newBanner.x = loc.x / 32; + newBanner.y = loc.y / 32; // Use the new banner index tile_element_set_banner_index(&element, newBannerIndex); @@ -321,13 +324,13 @@ int32_t tile_inspector_paste_element_at(int32_t x, int32_t y, TileElement elemen rct_string_id newStringIdx = user_string_allocate(USER_STRING_DUPLICATION_PERMITTED, buffer); if (newStringIdx == 0) { - return MONEY32_UNDEFINED; + return std::make_unique(GA_ERROR::NO_FREE_ELEMENTS, STR_NONE); } gBanners[newBannerIndex].string_idx = newStringIdx; } } - TileElement* const pastedElement = tile_element_insert(x, y, element.base_height, 0); + TileElement* const pastedElement = tile_element_insert(loc.x / 32, loc.y / 32, element.base_height, 0); bool lastForTile = pastedElement->IsLastForTile(); *pastedElement = element; @@ -337,16 +340,16 @@ int32_t tile_inspector_paste_element_at(int32_t x, int32_t y, TileElement elemen pastedElement->flags |= TILE_ELEMENT_FLAG_LAST_TILE; } - map_invalidate_tile_full(x << 5, y << 5); + map_invalidate_tile_full(loc.x, loc.y); rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX - && (uint32_t)y == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && (uint32_t)(loc.x / 32) == windowTileInspectorTileX + && (uint32_t)(loc.y / 32) == windowTileInspectorTileY) { windowTileInspectorElementCount++; // Select new element if there was none selected already - int16_t newIndex = (int16_t)(pastedElement - map_get_first_element_at(x, y)); + int16_t newIndex = (int16_t)(pastedElement - map_get_first_element_at(loc.x / 32, loc.y / 32)); if (windowTileInspectorSelectedIndex == -1) windowTileInspectorSelectedIndex = newIndex; else if (windowTileInspectorSelectedIndex >= newIndex) @@ -356,14 +359,14 @@ int32_t tile_inspector_paste_element_at(int32_t x, int32_t y, TileElement elemen } } - return 0; + return std::make_unique(); } -int32_t tile_inspector_sort_elements_at(int32_t x, int32_t y, int32_t flags) +GameActionResult::Ptr tile_inspector_sort_elements_at(CoordsXY loc, bool isExecuting) { - if (flags & GAME_COMMAND_FLAG_APPLY) + if (isExecuting) { - const TileElement* const firstElement = map_get_first_element_at(x, y); + const TileElement* const firstElement = map_get_first_element_at(loc.x / 32, loc.y / 32); // Count elements on tile int32_t numElement = 0; @@ -387,7 +390,7 @@ int32_t tile_inspector_sort_elements_at(int32_t x, int32_t y, int32_t flags) || (otherElement->base_height == currentElement->base_height && otherElement->clearance_height > currentElement->clearance_height))) { - if (!map_swap_elements_at(x, y, currentId - 1, currentId)) + if (!map_swap_elements_at(loc, currentId - 1, currentId)) { // don't return error here, we've already ran some actions // and moved things as far as we could, the only sensible @@ -401,35 +404,36 @@ int32_t tile_inspector_sort_elements_at(int32_t x, int32_t y, int32_t flags) } } - map_invalidate_tile_full(x << 5, y << 5); + map_invalidate_tile_full(loc.x, loc.y); // Deselect tile for clients who had it selected rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX - && (uint32_t)y == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && (uint32_t)(loc.x / 32) == windowTileInspectorTileX + && (uint32_t)(loc.y / 32) == windowTileInspectorTileY) { windowTileInspectorSelectedIndex = -1; window_invalidate(tileInspectorWindow); } } - return 0; + return std::make_unique(); } -int32_t tile_inspector_any_base_height_offset(int32_t x, int32_t y, int16_t elementIndex, int8_t heightOffset, int32_t flags) +GameActionResult::Ptr tile_inspector_any_base_height_offset( + CoordsXY loc, int16_t elementIndex, int8_t heightOffset, bool isExecuting) { - TileElement* const tileElement = map_get_nth_element_at(x, y, elementIndex); + TileElement* const tileElement = map_get_nth_element_at(loc.x / 32, loc.y / 32, elementIndex); if (tileElement == nullptr) - return MONEY32_UNDEFINED; + return std::make_unique(GA_ERROR::UNKNOWN, STR_NONE); int16_t newBaseHeight = (int16_t)tileElement->base_height + heightOffset; int16_t newClearanceHeight = (int16_t)tileElement->clearance_height + heightOffset; if (newBaseHeight < 0 || newBaseHeight > 0xff || newClearanceHeight < 0 || newClearanceHeight > 0xff) { - return MONEY32_UNDEFINED; + return std::make_unique(GA_ERROR::UNKNOWN, STR_NONE); } - if (flags & GAME_COMMAND_FLAG_APPLY) + if (isExecuting) { if (tileElement->GetType() == TILE_ELEMENT_TYPE_ENTRANCE) { @@ -444,10 +448,11 @@ int32_t tile_inspector_any_base_height_offset(int32_t x, int32_t y, int16_t elem uint8_t z = tileElement->base_height; // Make sure this is the correct entrance or exit - if (entranceType == ENTRANCE_TYPE_RIDE_ENTRANCE && entrance.x == x && entrance.y == y && entrance.z == z) + if (entranceType == ENTRANCE_TYPE_RIDE_ENTRANCE && entrance.x == loc.x / 32 && entrance.y == loc.y / 32 + && entrance.z == z) ride_set_entrance_location( ride, entranceIndex, { entrance.x, entrance.y, z + heightOffset, entrance.direction }); - else if (entranceType == ENTRANCE_TYPE_RIDE_EXIT && exit.x == x && exit.y == y && exit.z == z) + else if (entranceType == ENTRANCE_TYPE_RIDE_EXIT && exit.x == loc.x / 32 && exit.y == loc.y / 32 && exit.z == z) ride_set_exit_location(ride, entranceIndex, { exit.x, exit.y, z + heightOffset, exit.direction }); } } @@ -455,56 +460,56 @@ int32_t tile_inspector_any_base_height_offset(int32_t x, int32_t y, int16_t elem tileElement->base_height += heightOffset; tileElement->clearance_height += heightOffset; - map_invalidate_tile_full(x << 5, y << 5); + map_invalidate_tile_full(loc.x, loc.y); rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX - && (uint32_t)y == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && (uint32_t)(loc.x / 32) == windowTileInspectorTileX + && (uint32_t)(loc.y / 32) == windowTileInspectorTileY) { window_invalidate(tileInspectorWindow); } } - return 0; + return std::make_unique(); } -int32_t tile_inspector_surface_show_park_fences(int32_t x, int32_t y, bool showFences, int32_t flags) +GameActionResult::Ptr tile_inspector_surface_show_park_fences(CoordsXY loc, bool showFences, bool isExecuting) { - TileElement* const surfaceelement = map_get_surface_element_at(x, y); + TileElement* const surfaceelement = map_get_surface_element_at(loc); // No surface element on tile if (surfaceelement == nullptr) - return MONEY32_UNDEFINED; + return std::make_unique(GA_ERROR::UNKNOWN, STR_NONE); - if (flags & GAME_COMMAND_FLAG_APPLY) + if (isExecuting) { if (!showFences) surfaceelement->AsSurface()->SetParkFences(0); else - update_park_fences({ x << 5, y << 5 }); + update_park_fences(loc); - map_invalidate_tile_full(x << 5, y << 5); + map_invalidate_tile_full(loc.x, loc.y); rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX - && (uint32_t)y == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && (uint32_t)(loc.x / 32) == windowTileInspectorTileX + && (uint32_t)(loc.y / 32) == windowTileInspectorTileY) { window_invalidate(tileInspectorWindow); } } - return 0; + return std::make_unique(); } -int32_t tile_inspector_surface_toggle_corner(int32_t x, int32_t y, int32_t cornerIndex, int32_t flags) +GameActionResult::Ptr tile_inspector_surface_toggle_corner(CoordsXY loc, int32_t cornerIndex, bool isExecuting) { - TileElement* const surfaceElement = map_get_surface_element_at(x, y); + TileElement* const surfaceElement = map_get_surface_element_at(loc); // No surface element on tile if (surfaceElement == nullptr) - return MONEY32_UNDEFINED; + return std::make_unique(GA_ERROR::UNKNOWN, STR_NONE); - if (flags & GAME_COMMAND_FLAG_APPLY) + if (isExecuting) { const uint8_t originalSlope = surfaceElement->AsSurface()->GetSlope(); const bool diagonal = (originalSlope & TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT) >> 4; @@ -550,28 +555,28 @@ int32_t tile_inspector_surface_toggle_corner(int32_t x, int32_t y, int32_t corne surfaceElement->clearance_height = surfaceElement->base_height + (diagonal ? 2 : 0); } - map_invalidate_tile_full(x << 5, y << 5); + map_invalidate_tile_full(loc.x, loc.y); rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX - && (uint32_t)y == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && (uint32_t)(loc.x / 32) == windowTileInspectorTileX + && (uint32_t)(loc.y / 32) == windowTileInspectorTileY) { window_invalidate(tileInspectorWindow); } } - return 0; + return std::make_unique(); } -int32_t tile_inspector_surface_toggle_diagonal(int32_t x, int32_t y, int32_t flags) +GameActionResult::Ptr tile_inspector_surface_toggle_diagonal(CoordsXY loc, bool isExecuting) { - TileElement* const surfaceElement = map_get_surface_element_at(x, y); + TileElement* const surfaceElement = map_get_surface_element_at(loc); // No surface element on tile if (surfaceElement == nullptr) - return MONEY32_UNDEFINED; + return std::make_unique(GA_ERROR::UNKNOWN, STR_NONE); - if (flags & GAME_COMMAND_FLAG_APPLY) + if (isExecuting) { uint8_t newSlope = surfaceElement->AsSurface()->GetSlope() ^ TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT; surfaceElement->AsSurface()->SetSlope(newSlope); @@ -588,105 +593,105 @@ int32_t tile_inspector_surface_toggle_diagonal(int32_t x, int32_t y, int32_t fla surfaceElement->clearance_height = surfaceElement->base_height; } - map_invalidate_tile_full(x << 5, y << 5); + map_invalidate_tile_full(loc.x, loc.y); rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX - && (uint32_t)y == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && (uint32_t)(loc.x / 32) == windowTileInspectorTileX + && (uint32_t)(loc.y / 32) == windowTileInspectorTileY) { window_invalidate(tileInspectorWindow); } } - return 0; + return std::make_unique(); } -int32_t tile_inspector_path_set_sloped(int32_t x, int32_t y, int32_t elementIndex, bool sloped, int32_t flags) +GameActionResult::Ptr tile_inspector_path_set_sloped(CoordsXY loc, int32_t elementIndex, bool sloped, bool isExecuting) { - TileElement* const pathElement = map_get_nth_element_at(x, y, elementIndex); + TileElement* const pathElement = map_get_nth_element_at(loc.x / 32, loc.y / 32, elementIndex); if (pathElement == nullptr || pathElement->GetType() != TILE_ELEMENT_TYPE_PATH) - return MONEY32_UNDEFINED; + return std::make_unique(GA_ERROR::UNKNOWN, STR_NONE); - if (flags & GAME_COMMAND_FLAG_APPLY) + if (isExecuting) { pathElement->AsPath()->SetSloped(sloped); - map_invalidate_tile_full(x << 5, y << 5); + map_invalidate_tile_full(loc.x, loc.y); rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX - && (uint32_t)y == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && (uint32_t)(loc.x / 32) == windowTileInspectorTileX + && (uint32_t)(loc.y / 32) == windowTileInspectorTileY) { window_invalidate(tileInspectorWindow); } } - return 0; + return std::make_unique(); } -int32_t tile_inspector_path_set_broken(int32_t x, int32_t y, int32_t elementIndex, bool broken, int32_t flags) +GameActionResult::Ptr tile_inspector_path_set_broken(CoordsXY loc, int32_t elementIndex, bool broken, bool isExecuting) { - TileElement* const pathElement = map_get_nth_element_at(x, y, elementIndex); + TileElement* const pathElement = map_get_nth_element_at(loc.x / 32, loc.y / 32, elementIndex); if (pathElement == nullptr || pathElement->GetType() != TILE_ELEMENT_TYPE_PATH) - return MONEY32_UNDEFINED; + return std::make_unique(GA_ERROR::UNKNOWN, STR_NONE); - if (flags & GAME_COMMAND_FLAG_APPLY) + if (isExecuting) { pathElement->AsPath()->SetIsBroken(broken); - map_invalidate_tile_full(x << 5, y << 5); + map_invalidate_tile_full(loc.x, loc.y); rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX - && (uint32_t)y == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && (uint32_t)(loc.x / 32) == windowTileInspectorTileX + && (uint32_t)(loc.y / 32) == windowTileInspectorTileY) { window_invalidate(tileInspectorWindow); } } - return 0; + return std::make_unique(); } -int32_t tile_inspector_path_toggle_edge(int32_t x, int32_t y, int32_t elementIndex, int32_t edgeIndex, int32_t flags) +GameActionResult::Ptr tile_inspector_path_toggle_edge(CoordsXY loc, int32_t elementIndex, int32_t edgeIndex, bool isExecuting) { - TileElement* const pathElement = map_get_nth_element_at(x, y, elementIndex); + TileElement* const pathElement = map_get_nth_element_at(loc.x / 32, loc.y / 32, elementIndex); if (pathElement == nullptr || pathElement->GetType() != TILE_ELEMENT_TYPE_PATH) - return MONEY32_UNDEFINED; + return std::make_unique(GA_ERROR::UNKNOWN, STR_NONE); - if (flags & GAME_COMMAND_FLAG_APPLY) + if (isExecuting) { uint8_t newEdges = pathElement->AsPath()->GetEdgesAndCorners() ^ (1 << edgeIndex); pathElement->AsPath()->SetEdgesAndCorners(newEdges); - map_invalidate_tile_full(x << 5, y << 5); + map_invalidate_tile_full(loc.x, loc.y); rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX - && (uint32_t)y == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && (uint32_t)(loc.x / 32) == windowTileInspectorTileX + && (uint32_t)(loc.y / 32) == windowTileInspectorTileY) { window_invalidate(tileInspectorWindow); } } - return 0; + return std::make_unique(); } -int32_t tile_inspector_entrance_make_usable(int32_t x, int32_t y, int32_t elementIndex, int32_t flags) +GameActionResult::Ptr tile_inspector_entrance_make_usable(CoordsXY loc, int32_t elementIndex, bool isExecuting) { - TileElement* const entranceElement = map_get_nth_element_at(x, y, elementIndex); + TileElement* const entranceElement = map_get_nth_element_at(loc.x / 32, loc.y / 32, elementIndex); if (entranceElement == nullptr || entranceElement->GetType() != TILE_ELEMENT_TYPE_ENTRANCE) - return MONEY32_UNDEFINED; + return std::make_unique(GA_ERROR::UNKNOWN, STR_NONE); Ride* ride = get_ride(entranceElement->AsEntrance()->GetRideIndex()); if (ride == nullptr) - return MONEY32_UNDEFINED; + return std::make_unique(GA_ERROR::UNKNOWN, STR_NONE); - if (flags & GAME_COMMAND_FLAG_APPLY) + if (isExecuting) { uint8_t stationIndex = entranceElement->AsEntrance()->GetStationIndex(); @@ -694,67 +699,70 @@ int32_t tile_inspector_entrance_make_usable(int32_t x, int32_t y, int32_t elemen { case ENTRANCE_TYPE_RIDE_ENTRANCE: ride_set_entrance_location( - ride, stationIndex, { x, y, entranceElement->base_height, (uint8_t)entranceElement->GetDirection() }); + ride, stationIndex, + { loc.x / 32, loc.y / 32, entranceElement->base_height, (uint8_t)entranceElement->GetDirection() }); break; case ENTRANCE_TYPE_RIDE_EXIT: ride_set_exit_location( - ride, stationIndex, { x, y, entranceElement->base_height, (uint8_t)entranceElement->GetDirection() }); + ride, stationIndex, + { loc.x / 32, loc.y / 32, entranceElement->base_height, (uint8_t)entranceElement->GetDirection() }); break; } rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX - && (uint32_t)y == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && (uint32_t)(loc.x / 32) == windowTileInspectorTileX + && (uint32_t)(loc.y / 32) == windowTileInspectorTileY) { window_invalidate(tileInspectorWindow); } } - return 0; + return std::make_unique(); } -int32_t tile_inspector_wall_set_slope(int32_t x, int32_t y, int32_t elementIndex, int32_t slopeValue, int32_t flags) +GameActionResult::Ptr tile_inspector_wall_set_slope(CoordsXY loc, int32_t elementIndex, int32_t slopeValue, bool isExecuting) { - TileElement* const wallElement = map_get_nth_element_at(x, y, elementIndex); + TileElement* const wallElement = map_get_nth_element_at(loc.x / 32, loc.y / 32, elementIndex); if (wallElement == nullptr || wallElement->GetType() != TILE_ELEMENT_TYPE_WALL) - return MONEY32_UNDEFINED; + return std::make_unique(GA_ERROR::UNKNOWN, STR_NONE); - if (flags & GAME_COMMAND_FLAG_APPLY) + if (isExecuting) { // Set new slope value wallElement->AsWall()->SetSlope(slopeValue); - map_invalidate_tile_full(x << 5, y << 5); + map_invalidate_tile_full(loc.x, loc.y); rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX - && (uint32_t)y == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && (uint32_t)(loc.x / 32) == windowTileInspectorTileX + && (uint32_t)(loc.y / 32) == windowTileInspectorTileY) { window_invalidate(tileInspectorWindow); } } - return 0; + return std::make_unique(); } // Changes the height of all track elements that belong to the same track piece // Broxzier: Copied from track_remove and stripped of unneeded code, but I think this should be smaller -int32_t tile_inspector_track_base_height_offset(int32_t x, int32_t y, int32_t elementIndex, int8_t offset, int32_t flags) +GameActionResult::Ptr tile_inspector_track_base_height_offset( + CoordsXY loc, int32_t elementIndex, int8_t offset, bool isExecuting) { - TileElement* const trackElement = map_get_nth_element_at(x, y, elementIndex); + TileElement* const trackElement = map_get_nth_element_at(loc.x / 32, loc.y / 32, elementIndex); if (offset == 0) - return 0; + return std::make_unique(); if (trackElement == nullptr || trackElement->GetType() != TILE_ELEMENT_TYPE_TRACK) - return MONEY32_UNDEFINED; + return std::make_unique(GA_ERROR::UNKNOWN, STR_NONE); - if (flags & GAME_COMMAND_FLAG_APPLY) + if (isExecuting) { uint8_t type = trackElement->AsTrack()->GetTrackType(); - int16_t originX = x << 5; - int16_t originY = y << 5; + int16_t originX = loc.x; + int16_t originY = loc.y; int16_t originZ = trackElement->base_height * 8; uint8_t rotation = trackElement->GetDirection(); ride_id_t rideIndex = trackElement->AsTrack()->GetRideIndex(); @@ -809,7 +817,7 @@ int32_t tile_inspector_track_base_height_offset(int32_t x, int32_t y, int32_t el if (!found) { log_error("Track map element part not found!"); - return MONEY32_UNDEFINED; + return std::make_unique(GA_ERROR::UNKNOWN, STR_NONE); } // track_remove returns here on failure, not sure when this would ever be hit. Only thing I can think of is for when @@ -827,20 +835,20 @@ int32_t tile_inspector_track_base_height_offset(int32_t x, int32_t y, int32_t el // TODO: Only invalidate when one of the affected tiles is selected window_invalidate_by_class(WC_TILE_INSPECTOR); - return 0; + return std::make_unique(); } // Sets chainlift, optionally for an entire track block // Broxzier: Basically a copy of the above function, with just two different lines... should probably be combined somehow -int32_t tile_inspector_track_set_chain( - int32_t x, int32_t y, int32_t elementIndex, bool entireTrackBlock, bool setChain, int32_t flags) +GameActionResult::Ptr tile_inspector_track_set_chain( + CoordsXY loc, int32_t elementIndex, bool entireTrackBlock, bool setChain, bool isExecuting) { - TileElement* const trackElement = map_get_nth_element_at(x, y, elementIndex); + TileElement* const trackElement = map_get_nth_element_at(loc.x / 32, loc.y / 32, elementIndex); if (trackElement == nullptr || trackElement->GetType() != TILE_ELEMENT_TYPE_TRACK) - return MONEY32_UNDEFINED; + return std::make_unique(GA_ERROR::UNKNOWN, STR_NONE); - if (flags & GAME_COMMAND_FLAG_APPLY) + if (isExecuting) { if (!entireTrackBlock) { @@ -850,12 +858,12 @@ int32_t tile_inspector_track_set_chain( trackElement->AsTrack()->SetHasChain(setChain); } - return 0; + return std::make_unique(); } uint8_t type = trackElement->AsTrack()->GetTrackType(); - int16_t originX = x << 5; - int16_t originY = y << 5; + int16_t originX = loc.x; + int16_t originY = loc.y; int16_t originZ = trackElement->base_height * 8; uint8_t rotation = trackElement->GetDirection(); ride_id_t rideIndex = trackElement->AsTrack()->GetRideIndex(); @@ -910,7 +918,7 @@ int32_t tile_inspector_track_set_chain( if (!found) { log_error("Track map element part not found!"); - return MONEY32_UNDEFINED; + return std::make_unique(GA_ERROR::UNKNOWN, STR_NONE); } // track_remove returns here on failure, not sure when this would ever be hit. Only thing I can think of is for when @@ -930,67 +938,68 @@ int32_t tile_inspector_track_set_chain( // TODO: Only invalidate when one of the affected tiles is selected window_invalidate_by_class(WC_TILE_INSPECTOR); - return 0; + return std::make_unique(); } -int32_t tile_inspector_track_set_block_brake(int32_t x, int32_t y, int32_t elementIndex, bool blockBrake, int32_t flags) +GameActionResult::Ptr tile_inspector_track_set_block_brake( + CoordsXY loc, int32_t elementIndex, bool blockBrake, bool isExecuting) { - TileElement* const trackElement = map_get_nth_element_at(x, y, elementIndex); + TileElement* const trackElement = map_get_nth_element_at(loc.x / 32, loc.y / 32, elementIndex); if (trackElement == nullptr || trackElement->GetType() != TILE_ELEMENT_TYPE_TRACK) - return MONEY32_UNDEFINED; + return std::make_unique(GA_ERROR::UNKNOWN, STR_NONE); - if (flags & GAME_COMMAND_FLAG_APPLY) + if (isExecuting) { trackElement->AsTrack()->SetBlockBrakeClosed(blockBrake); - map_invalidate_tile_full(x << 5, y << 5); + map_invalidate_tile_full(loc.x, loc.y); rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX - && (uint32_t)y == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && (uint32_t)(loc.x / 32) == windowTileInspectorTileX + && (uint32_t)(loc.y / 32) == windowTileInspectorTileY) { window_invalidate(tileInspectorWindow); } } - return 0; + return std::make_unique(); } -int32_t tile_inspector_track_set_indestructible( - int32_t x, int32_t y, int32_t elementIndex, bool isIndestructible, int32_t flags) +GameActionResult::Ptr tile_inspector_track_set_indestructible( + CoordsXY loc, int32_t elementIndex, bool isIndestructible, bool isExecuting) { - TileElement* const trackElement = map_get_nth_element_at(x, y, elementIndex); + TileElement* const trackElement = map_get_nth_element_at(loc.x / 32, loc.y / 32, elementIndex); if (trackElement == nullptr || trackElement->GetType() != TILE_ELEMENT_TYPE_TRACK) - return MONEY32_UNDEFINED; + return std::make_unique(GA_ERROR::UNKNOWN, STR_NONE); - if (flags & GAME_COMMAND_FLAG_APPLY) + if (isExecuting) { trackElement->AsTrack()->SetIsIndestructible(isIndestructible); - map_invalidate_tile_full(x << 5, y << 5); + map_invalidate_tile_full(loc.x, loc.y); rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX - && (uint32_t)y == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && (uint32_t)(loc.x / 32) == windowTileInspectorTileX + && (uint32_t)(loc.y / 32) == windowTileInspectorTileY) { window_invalidate(tileInspectorWindow); } } - return 0; + return std::make_unique(); } -int32_t tile_inspector_scenery_set_quarter_location( - int32_t x, int32_t y, int32_t elementIndex, int32_t quarterIndex, int32_t flags) +GameActionResult::Ptr tile_inspector_scenery_set_quarter_location( + CoordsXY loc, int32_t elementIndex, int32_t quarterIndex, bool isExecuting) { - TileElement* const tileElement = map_get_nth_element_at(x, y, elementIndex); + TileElement* const tileElement = map_get_nth_element_at(loc.x / 32, loc.y / 32, elementIndex); if (tileElement == nullptr || tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY) - return MONEY32_UNDEFINED; + return std::make_unique(GA_ERROR::UNKNOWN, STR_NONE); - if (flags & GAME_COMMAND_FLAG_APPLY) + if (isExecuting) { // Set quadrant index tileElement->AsSmallScenery()->SetSceneryQuadrant(quarterIndex); @@ -999,80 +1008,81 @@ int32_t tile_inspector_scenery_set_quarter_location( tileElement->flags &= 0xF0; tileElement->flags |= 1 << ((quarterIndex + 2) & 3); - map_invalidate_tile_full(x << 5, y << 5); - if ((uint32_t)x == windowTileInspectorTileX && (uint32_t)y == windowTileInspectorTileY) + map_invalidate_tile_full(loc.x, loc.y); + if ((uint32_t)(loc.x / 32) == windowTileInspectorTileX && (uint32_t)(loc.y / 32) == windowTileInspectorTileY) { window_invalidate_by_class(WC_TILE_INSPECTOR); } } - return 0; + return std::make_unique(); } -int32_t tile_inspector_scenery_set_quarter_collision( - int32_t x, int32_t y, int32_t elementIndex, int32_t quarterIndex, int32_t flags) +GameActionResult::Ptr tile_inspector_scenery_set_quarter_collision( + CoordsXY loc, int32_t elementIndex, int32_t quarterIndex, bool isExecuting) { - TileElement* const tileElement = map_get_nth_element_at(x, y, elementIndex); + TileElement* const tileElement = map_get_nth_element_at(loc.x / 32, loc.y / 32, elementIndex); if (tileElement == nullptr || tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY) - return MONEY32_UNDEFINED; + return std::make_unique(GA_ERROR::UNKNOWN, STR_NONE); - if (flags & GAME_COMMAND_FLAG_APPLY) + if (isExecuting) { tileElement->flags ^= 1 << quarterIndex; - map_invalidate_tile_full(x << 5, y << 5); - if ((uint32_t)x == windowTileInspectorTileX && (uint32_t)y == windowTileInspectorTileY) + map_invalidate_tile_full(loc.x, loc.y); + if ((uint32_t)(loc.x / 32) == windowTileInspectorTileX && (uint32_t)(loc.y / 32) == windowTileInspectorTileY) { window_invalidate_by_class(WC_TILE_INSPECTOR); } } - return 0; + return std::make_unique(); } -int32_t tile_inspector_banner_toggle_blocking_edge(int32_t x, int32_t y, int32_t elementIndex, int32_t edgeIndex, int32_t flags) +GameActionResult::Ptr tile_inspector_banner_toggle_blocking_edge( + CoordsXY loc, int32_t elementIndex, int32_t edgeIndex, bool isExecuting) { - TileElement* const bannerElement = map_get_nth_element_at(x, y, elementIndex); + TileElement* const bannerElement = map_get_nth_element_at(loc.x / 32, loc.y / 32, elementIndex); if (bannerElement == nullptr || bannerElement->GetType() != TILE_ELEMENT_TYPE_BANNER) - return MONEY32_UNDEFINED; + return std::make_unique(GA_ERROR::UNKNOWN, STR_NONE); - if (flags & GAME_COMMAND_FLAG_APPLY) + if (isExecuting) { uint8_t edges = bannerElement->AsBanner()->GetAllowedEdges(); edges ^= (1 << edgeIndex); bannerElement->AsBanner()->SetAllowedEdges(edges); - if ((uint32_t)x == windowTileInspectorTileX && (uint32_t)y == windowTileInspectorTileY) + if ((uint32_t)(loc.x / 32) == windowTileInspectorTileX && (uint32_t)(loc.y / 32) == windowTileInspectorTileY) { window_invalidate_by_class(WC_TILE_INSPECTOR); } } - return 0; + return std::make_unique(); } -int32_t tile_inspector_corrupt_clamp(int32_t x, int32_t y, int32_t elementIndex, int32_t flags) +GameActionResult::Ptr tile_inspector_corrupt_clamp(CoordsXY loc, int32_t elementIndex, bool isExecuting) { - TileElement* const corruptElement = map_get_nth_element_at(x, y, elementIndex); + TileElement* const corruptElement = map_get_nth_element_at(loc.x / 32, loc.y / 32, elementIndex); if (corruptElement == nullptr || corruptElement->GetType() != TILE_ELEMENT_TYPE_CORRUPT) - return MONEY32_UNDEFINED; + return std::make_unique(GA_ERROR::UNKNOWN, STR_NONE); if (corruptElement->IsLastForTile()) - return MONEY32_UNDEFINED; + return std::make_unique(GA_ERROR::UNKNOWN, STR_NONE); - if (flags & GAME_COMMAND_FLAG_APPLY) + if (isExecuting) { TileElement* const nextElement = corruptElement + 1; corruptElement->base_height = corruptElement->clearance_height = nextElement->base_height; - if ((uint32_t)x == windowTileInspectorTileX && (uint32_t)y == windowTileInspectorTileY) + if ((uint32_t)(loc.x / 32) == windowTileInspectorTileX && (uint32_t)(loc.y / 32) == windowTileInspectorTileY) { window_invalidate_by_class(WC_TILE_INSPECTOR); } } - return 0; + return std::make_unique(); } diff --git a/src/openrct2/world/TileInspector.h b/src/openrct2/world/TileInspector.h index 90262a2959..05a24484c9 100644 --- a/src/openrct2/world/TileInspector.h +++ b/src/openrct2/world/TileInspector.h @@ -26,58 +26,35 @@ enum TILE_INSPECTOR_ELEMENT_TYPE TILE_INSPECTOR_ELEMENT_CORRUPT, }; -enum TILE_INSPECTOR_INSTRUCTION_TYPE -{ - TILE_INSPECTOR_ANY_REMOVE, - TILE_INSPECTOR_ANY_SWAP, - TILE_INSPECTOR_ANY_INSERT_CORRUPT, - TILE_INSPECTOR_ANY_ROTATE, - TILE_INSPECTOR_ANY_PASTE, - TILE_INSPECTOR_ANY_SORT, - TILE_INSPECTOR_ANY_BASE_HEIGHT_OFFSET, - TILE_INSPECTOR_SURFACE_SHOW_PARK_FENCES, - TILE_INSPECTOR_SURFACE_TOGGLE_CORNER, - TILE_INSPECTOR_SURFACE_TOGGLE_DIAGONAL, - TILE_INSPECTOR_PATH_SET_SLOPE, - TILE_INSPECTOR_PATH_SET_BROKEN, - TILE_INSPECTOR_PATH_TOGGLE_EDGE, - TILE_INSPECTOR_ENTRANCE_MAKE_USABLE, - TILE_INSPECTOR_WALL_SET_SLOPE, - TILE_INSPECTOR_TRACK_BASE_HEIGHT_OFFSET, - TILE_INSPECTOR_TRACK_SET_CHAIN, - TILE_INSPECTOR_SCENERY_SET_QUARTER_LOCATION, - TILE_INSPECTOR_SCENERY_SET_QUARTER_COLLISION, - TILE_INSPECTOR_BANNER_TOGGLE_BLOCKING_EDGE, - TILE_INSPECTOR_CORRUPT_CLAMP, - TILE_INSPECTOR_TRACK_SET_BLOCK_BRAKE, - TILE_INSPECTOR_TRACK_SET_INDESTRUCTIBLE, -}; - -int32_t tile_inspector_insert_corrupt_at(int32_t x, int32_t y, int16_t elementIndex, int32_t flags); -int32_t tile_inspector_remove_element_at(int32_t x, int32_t y, int16_t elementIndex, int32_t flags); -int32_t tile_inspector_swap_elements_at(int32_t x, int32_t y, int16_t first, int16_t second, int32_t flags); -int32_t tile_inspector_rotate_element_at(int32_t x, int32_t y, int32_t elementIndex, int32_t flags); -int32_t tile_inspector_paste_element_at(int32_t x, int32_t y, TileElement element, int32_t flags); -int32_t tile_inspector_sort_elements_at(int32_t x, int32_t y, int32_t flags); -int32_t tile_inspector_any_base_height_offset(int32_t x, int32_t y, int16_t elementIndex, int8_t heightOffset, int32_t flags); -int32_t tile_inspector_surface_show_park_fences(int32_t x, int32_t y, bool enabled, int32_t flags); -int32_t tile_inspector_surface_toggle_corner(int32_t x, int32_t y, int32_t cornerIndex, int32_t flags); -int32_t tile_inspector_surface_toggle_diagonal(int32_t x, int32_t y, int32_t flags); -int32_t tile_inspector_path_set_sloped(int32_t x, int32_t y, int32_t elementIndex, bool sloped, int32_t flags); -int32_t tile_inspector_path_set_broken(int32_t x, int32_t y, int32_t elementIndex, bool broken, int32_t flags); -int32_t tile_inspector_path_toggle_edge(int32_t x, int32_t y, int32_t elementIndex, int32_t cornerIndex, int32_t flags); -int32_t tile_inspector_entrance_make_usable(int32_t x, int32_t y, int32_t elementIndex, int32_t flags); -int32_t tile_inspector_wall_set_slope(int32_t x, int32_t y, int32_t elementIndex, int32_t slopeValue, int32_t flags); -int32_t tile_inspector_track_base_height_offset(int32_t x, int32_t y, int32_t elementIndex, int8_t offset, int32_t flags); -int32_t tile_inspector_track_set_block_brake(int32_t x, int32_t y, int32_t elementIndex, bool blockBrake, int32_t flags); -int32_t tile_inspector_track_set_indestructible( - int32_t x, int32_t y, int32_t elementIndex, bool isIndestructible, int32_t flags); -int32_t tile_inspector_track_set_chain( - int32_t x, int32_t y, int32_t elementIndex, bool entireTrackBlock, bool setChain, int32_t flags); -int32_t tile_inspector_scenery_set_quarter_location( - int32_t x, int32_t y, int32_t elementIndex, int32_t quarterIndex, int32_t flags); -int32_t tile_inspector_scenery_set_quarter_collision( - int32_t x, int32_t y, int32_t elementIndex, int32_t quarterIndex, int32_t flags); -int32_t tile_inspector_banner_toggle_blocking_edge( - int32_t x, int32_t y, int32_t elementIndex, int32_t edgeIndex, int32_t flags); -int32_t tile_inspector_corrupt_clamp(int32_t x, int32_t y, int32_t elementIndex, int32_t flags); +class GameActionResult; +using GameActionResultPtr = std::unique_ptr; +GameActionResultPtr tile_inspector_insert_corrupt_at(CoordsXY loc, int16_t elementIndex, bool isExecuting); +GameActionResultPtr tile_inspector_remove_element_at(CoordsXY loc, int16_t elementIndex, bool isExecuting); +GameActionResultPtr tile_inspector_swap_elements_at(CoordsXY loc, int16_t first, int16_t second, bool isExecuting); +GameActionResultPtr tile_inspector_rotate_element_at(CoordsXY loc, int32_t elementIndex, bool isExecuting); +GameActionResultPtr tile_inspector_paste_element_at(CoordsXY loc, TileElement element, bool isExecuting); +GameActionResultPtr tile_inspector_sort_elements_at(CoordsXY loc, bool isExecuting); +GameActionResultPtr tile_inspector_any_base_height_offset( + CoordsXY loc, int16_t elementIndex, int8_t heightOffset, bool isExecuting); +GameActionResultPtr tile_inspector_surface_show_park_fences(CoordsXY loc, bool enabled, bool isExecuting); +GameActionResultPtr tile_inspector_surface_toggle_corner(CoordsXY loc, int32_t cornerIndex, bool isExecuting); +GameActionResultPtr tile_inspector_surface_toggle_diagonal(CoordsXY loc, bool isExecuting); +GameActionResultPtr tile_inspector_path_set_sloped(CoordsXY loc, int32_t elementIndex, bool sloped, bool isExecuting); +GameActionResultPtr tile_inspector_path_set_broken(CoordsXY loc, int32_t elementIndex, bool broken, bool isExecuting); +GameActionResultPtr tile_inspector_path_toggle_edge(CoordsXY loc, int32_t elementIndex, int32_t cornerIndex, bool isExecuting); +GameActionResultPtr tile_inspector_entrance_make_usable(CoordsXY loc, int32_t elementIndex, bool isExecuting); +GameActionResultPtr tile_inspector_wall_set_slope(CoordsXY loc, int32_t elementIndex, int32_t slopeValue, bool isExecuting); +GameActionResultPtr tile_inspector_track_base_height_offset( + CoordsXY loc, int32_t elementIndex, int8_t offset, bool isExecuting); +GameActionResultPtr tile_inspector_track_set_block_brake(CoordsXY loc, int32_t elementIndex, bool blockBrake, bool isExecuting); +GameActionResultPtr tile_inspector_track_set_indestructible( + CoordsXY loc, int32_t elementIndex, bool isIndestructible, bool isExecuting); +GameActionResultPtr tile_inspector_track_set_chain( + CoordsXY loc, int32_t elementIndex, bool entireTrackBlock, bool setChain, bool isExecuting); +GameActionResultPtr tile_inspector_scenery_set_quarter_location( + CoordsXY loc, int32_t elementIndex, int32_t quarterIndex, bool isExecuting); +GameActionResultPtr tile_inspector_scenery_set_quarter_collision( + CoordsXY loc, int32_t elementIndex, int32_t quarterIndex, bool isExecuting); +GameActionResultPtr tile_inspector_banner_toggle_blocking_edge( + CoordsXY loc, int32_t elementIndex, int32_t edgeIndex, bool isExecuting); +GameActionResultPtr tile_inspector_corrupt_clamp(CoordsXY loc, int32_t elementIndex, bool isExecuting);