From 510d71ab68513d6ecebae2b6d92597ca6cca22ca Mon Sep 17 00:00:00 2001 From: duncanspumpkin Date: Fri, 1 Mar 2019 10:53:52 +0000 Subject: [PATCH] Add FootpathSceneryPlaceAction --- src/openrct2-ui/windows/TopToolbar.cpp | 58 ++++--- .../actions/FootpathSceneryPlaceAction.hpp | 163 ++++++++++++++++-- .../actions/FootpathSceneryRemoveAction.hpp | 10 ++ src/openrct2/network/NetworkAction.cpp | 2 + src/openrct2/world/Footpath.cpp | 82 +-------- 5 files changed, 200 insertions(+), 115 deletions(-) diff --git a/src/openrct2-ui/windows/TopToolbar.cpp b/src/openrct2-ui/windows/TopToolbar.cpp index ec6ce4a1ff..d28c609c2c 100644 --- a/src/openrct2-ui/windows/TopToolbar.cpp +++ b/src/openrct2-ui/windows/TopToolbar.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -1816,14 +1817,18 @@ static void window_top_toolbar_scenery_tool_down(int16_t x, int16_t y, rct_windo } case SCENERY_TYPE_PATH_ITEM: { - int32_t flags = GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_PATH_SCENERY | (parameter_1 & 0xFF00); + auto pathItemType = parameter_3 & 0xFF; + int32_t z = (parameter_2 & 0xFF) * 8; + auto footpathSceneryPlaceAction = FootpathSceneryPlaceAction({ gridX, gridY, z }, pathItemType); - gGameCommandErrorTitle = STR_CANT_POSITION_THIS_HERE; - int32_t cost = game_do_command(gridX, flags, gridY, parameter_2, GAME_COMMAND_PLACE_PATH, parameter_3, 0); - if (cost != MONEY32_UNDEFINED) - { - audio_play_sound_at_location(SOUND_PLACE_ITEM, gCommandPosition.x, gCommandPosition.y, gCommandPosition.z); - } + footpathSceneryPlaceAction.SetCallback([](const GameAction* ga, const GameActionResult* result) { + if (result->Error != GA_ERROR::OK) + { + return; + } + audio_play_sound_at_location(SOUND_PLACE_ITEM, result->Position.x, result->Position.y, result->Position.z); + }); + auto res = GameActions::Execute(&footpathSceneryPlaceAction); break; } case SCENERY_TYPE_WALL: @@ -2489,27 +2494,32 @@ static money32 try_place_ghost_scenery( break; } case 1: + { // Path Bits // 6e265b - cost = game_do_command( - map_tile.x, - (parameter_1 & 0xFF00) - | (GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_5 - | GAME_COMMAND_FLAG_GHOST | GAME_COMMAND_FLAG_PATH_SCENERY), - map_tile.y, parameter_2, GAME_COMMAND_PLACE_PATH, parameter_3, 0); + auto pathItemType = parameter_3 & 0xFF; + int32_t z = (parameter_2 & 0xFF) * 8; + auto footpathSceneryPlaceAction = FootpathSceneryPlaceAction({ map_tile.x, map_tile.y, z }, pathItemType); + footpathSceneryPlaceAction.SetFlags(GAME_COMMAND_FLAG_GHOST | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED); + footpathSceneryPlaceAction.SetCallback([=](const GameAction* ga, const GameActionResult* result) { + if (result->Error != GA_ERROR::OK) + { + return; + } + gSceneryGhostPosition.x = map_tile.x; + gSceneryGhostPosition.y = map_tile.y; + gSceneryGhostPosition.z = (parameter_2 & 0xFF); + gSceneryPlacePathSlope = ((parameter_1 >> 8) & 0xFF); + gSceneryPlacePathType = ((parameter_2 >> 8) & 0xFF); + gSceneryGhostPathObjectType = parameter_3; - if (cost == MONEY32_UNDEFINED) - return cost; - - gSceneryGhostPosition.x = map_tile.x; - gSceneryGhostPosition.y = map_tile.y; - gSceneryGhostPosition.z = (parameter_2 & 0xFF); - gSceneryPlacePathSlope = ((parameter_1 >> 8) & 0xFF); - gSceneryPlacePathType = ((parameter_2 >> 8) & 0xFF); - gSceneryGhostPathObjectType = parameter_3; - - gSceneryGhostType |= SCENERY_GHOST_FLAG_1; + gSceneryGhostType |= SCENERY_GHOST_FLAG_1; + }); + auto res = GameActions::Execute(&footpathSceneryPlaceAction); + if (res->Error != GA_ERROR::OK) + return MONEY32_UNDEFINED; break; + } case 2: // Walls // 6e26b0 diff --git a/src/openrct2/actions/FootpathSceneryPlaceAction.hpp b/src/openrct2/actions/FootpathSceneryPlaceAction.hpp index 1c76b5f365..3afff671b6 100644 --- a/src/openrct2/actions/FootpathSceneryPlaceAction.hpp +++ b/src/openrct2/actions/FootpathSceneryPlaceAction.hpp @@ -24,16 +24,14 @@ DEFINE_GAME_ACTION(FootpathSceneryPlaceAction, GAME_COMMAND_PLACE_FOOTPATH_SCENERY, GameActionResult) { private: - int32_t _x; - int32_t _y; - int32_t _z; + CoordsXYZ _loc; + uint8_t _pathItemType; public: FootpathSceneryPlaceAction() = default; - FootpathSceneryPlaceAction(int32_t x, int32_t y, int32_t z) - : _x(x) - , _y(y) - , _z(z) + FootpathSceneryPlaceAction(CoordsXYZ loc, uint8_t pathItemType) + : _loc(loc) + , _pathItemType(pathItemType) { } @@ -46,19 +44,164 @@ public: { GameAction::Serialise(stream); - stream << DS_TAG(_x) << DS_TAG(_y) << DS_TAG(_z); + stream << DS_TAG(_loc) << DS_TAG(_pathItemType); } GameActionResult::Ptr Query() const override { - GameActionResult::Ptr res = std::make_unique(); + auto res = MakeResult(); + res->ExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING; + res->Position = _loc; + if (!map_is_location_valid({ _loc.x, _loc.y })) + { + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE, 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_POSITION_THIS_HERE, STR_LAND_NOT_OWNED_BY_PARK); + } + + if (_loc.z / 8 < 2) + { + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE, STR_TOO_LOW); + } + + if (_loc.z / 8 > 248) + { + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE, 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_POSITION_THIS_HERE); + } + + // No change + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && pathElement->GetAddition() == _pathItemType + && !(pathElement->IsBroken())) + { + if (GetFlags() & GAME_COMMAND_FLAG_4) + return MakeResult(GA_ERROR::UNKNOWN, STR_CANT_POSITION_THIS_HERE); + + return res; + } + + if (_pathItemType != 0) + { + rct_scenery_entry* sceneryEntry = get_footpath_item_entry(_pathItemType - 1); + if (sceneryEntry == nullptr) + { + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE); + } + uint16_t sceneryFlags = sceneryEntry->path_bit.flags; + + if ((sceneryFlags & PATH_BIT_FLAG_DONT_ALLOW_ON_SLOPE) && pathElement->IsSloped()) + { + return MakeResult( + GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE, STR_CANT_BUILD_THIS_ON_SLOPED_FOOTPATH); + } + + if ((sceneryFlags & PATH_BIT_FLAG_DONT_ALLOW_ON_QUEUE) && pathElement->IsQueue()) + { + return MakeResult( + GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE, STR_CANNOT_PLACE_THESE_ON_QUEUE_LINE_AREA); + } + + if (!(sceneryFlags & (PATH_BIT_FLAG_JUMPING_FOUNTAIN_WATER | PATH_BIT_FLAG_JUMPING_FOUNTAIN_SNOW)) + && (pathElement->GetEdges()) == 0x0F) + { + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE); + } + + if ((sceneryFlags & PATH_BIT_FLAG_IS_QUEUE_SCREEN) && !pathElement->IsQueue()) + { + return MakeResult( + GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE, STR_CAN_ONLY_PLACE_THESE_ON_QUEUE_AREA); + } + + res->Cost = sceneryEntry->path_bit.price; + } + + if (GetFlags() & GAME_COMMAND_FLAG_4) + return MakeResult(GA_ERROR::UNKNOWN, STR_CANT_POSITION_THIS_HERE); + + // Should place a ghost? + if (GetFlags() & GAME_COMMAND_FLAG_GHOST) + { + // Check if there is something on the path already + if (pathElement->HasAddition()) + { + return MakeResult(GA_ERROR::ITEM_ALREADY_PLACED, STR_CANT_POSITION_THIS_HERE); + } + } return res; } GameActionResult::Ptr Execute() const override { - GameActionResult::Ptr res = std::make_unique(); + auto res = MakeResult(); + res->Position = _loc; + res->ExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING; + + 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_POSITION_THIS_HERE); + } + + // No change + if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && pathElement->GetAddition() == _pathItemType + && !(pathElement->IsBroken()) && !pathElement->AdditionIsGhost()) + { + return res; + } + + if (_pathItemType != 0) + { + rct_scenery_entry* sceneryEntry = get_footpath_item_entry(_pathItemType - 1); + if (sceneryEntry == nullptr) + { + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE); + } + + res->Cost = sceneryEntry->path_bit.price; + } + + if (GetFlags() & GAME_COMMAND_FLAG_GHOST) + { + pathElement->SetAdditionIsGhost(true); + } + else + { + footpath_interrupt_peeps(_loc.x, _loc.y, _loc.z); + } + + if ((_pathItemType != 0 && !(GetFlags() & GAME_COMMAND_FLAG_GHOST)) + || (_pathItemType == 0 && pathElement->AdditionIsGhost())) + { + pathElement->SetAdditionIsGhost(false); + } + + pathElement->SetAddition(_pathItemType); + pathElement->SetIsBroken(false); + if (_pathItemType != 0) + { + rct_scenery_entry* scenery_entry = get_footpath_item_entry(_pathItemType - 1); + if (scenery_entry != nullptr && scenery_entry->path_bit.flags & PATH_BIT_FLAG_IS_BIN) + { + pathElement->SetAdditionStatus(255); + } + } + map_invalidate_tile_full(_loc.x, _loc.y); return res; } }; diff --git a/src/openrct2/actions/FootpathSceneryRemoveAction.hpp b/src/openrct2/actions/FootpathSceneryRemoveAction.hpp index b810f830e6..5c64b0318e 100644 --- a/src/openrct2/actions/FootpathSceneryRemoveAction.hpp +++ b/src/openrct2/actions/FootpathSceneryRemoveAction.hpp @@ -76,7 +76,14 @@ public: log_error("Could not find path element."); return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_REMOVE_THIS); } + + if (!pathElement->AdditionIsGhost() && (GetFlags() & GAME_COMMAND_FLAG_GHOST)) + { + log_error("Tried to remove non ghost during ghost removal."); + return MakeResult(GA_ERROR::DISALLOWED, STR_CANT_REMOVE_THIS); + } auto res = MakeResult(); + res->Position = _loc; res->Cost = MONEY(0, 0); return res; } @@ -98,7 +105,10 @@ public: } pathElement->SetAddition(0); + map_invalidate_tile_full(_loc.x, _loc.y); + auto res = MakeResult(); + res->Position = _loc; res->Cost = MONEY(0, 0); return res; } diff --git a/src/openrct2/network/NetworkAction.cpp b/src/openrct2/network/NetworkAction.cpp index f89ac947a0..af28b7e488 100644 --- a/src/openrct2/network/NetworkAction.cpp +++ b/src/openrct2/network/NetworkAction.cpp @@ -153,6 +153,8 @@ const std::array NetworkActions::Action GAME_COMMAND_PLACE_PATH, GAME_COMMAND_PLACE_PATH_FROM_TRACK, GAME_COMMAND_REMOVE_PATH, + GAME_COMMAND_PLACE_FOOTPATH_SCENERY, + GAME_COMMAND_REMOVE_FOOTPATH_SCENERY, }, }, NetworkAction{ diff --git a/src/openrct2/world/Footpath.cpp b/src/openrct2/world/Footpath.cpp index 6b4c100d4c..31d155d839 100644 --- a/src/openrct2/world/Footpath.cpp +++ b/src/openrct2/world/Footpath.cpp @@ -324,87 +324,7 @@ static money32 footpath_element_update( } else if (pathItemType != 0) { - if (!(flags & GAME_COMMAND_FLAG_GHOST) && tileElement->AsPath()->GetAddition() == pathItemType - && !(tileElement->AsPath()->IsBroken())) - { - if (flags & GAME_COMMAND_FLAG_4) - return MONEY32_UNDEFINED; - - return gParkFlags & PARK_FLAGS_NO_MONEY ? 0 : gFootpathPrice; - } - - if (pathItemType != 0) - { - rct_scenery_entry* scenery_entry = get_footpath_item_entry(pathItemType - 1); - uint16_t unk6 = scenery_entry->path_bit.flags; - - if ((unk6 & PATH_BIT_FLAG_DONT_ALLOW_ON_SLOPE) && tileElement->AsPath()->IsSloped()) - { - gGameCommandErrorText = STR_CANT_BUILD_THIS_ON_SLOPED_FOOTPATH; - return MONEY32_UNDEFINED; - } - - if ((unk6 & PATH_BIT_FLAG_DONT_ALLOW_ON_QUEUE) && tileElement->AsPath()->IsQueue()) - { - gGameCommandErrorText = STR_CANNOT_PLACE_THESE_ON_QUEUE_LINE_AREA; - return MONEY32_UNDEFINED; - } - - if (!(unk6 & (PATH_BIT_FLAG_JUMPING_FOUNTAIN_WATER | PATH_BIT_FLAG_JUMPING_FOUNTAIN_SNOW)) - && (tileElement->AsPath()->GetEdges()) == 0x0F) - { - gGameCommandErrorText = STR_NONE; - return MONEY32_UNDEFINED; - } - - if ((unk6 & PATH_BIT_FLAG_IS_QUEUE_SCREEN) && !tileElement->AsPath()->IsQueue()) - { - gGameCommandErrorText = STR_CAN_ONLY_PLACE_THESE_ON_QUEUE_AREA; - return MONEY32_UNDEFINED; - } - - gFootpathPrice += scenery_entry->path_bit.price; - } - - if (flags & GAME_COMMAND_FLAG_4) - return MONEY32_UNDEFINED; - - // Should place a ghost? - if (flags & GAME_COMMAND_FLAG_GHOST) - { - // Check if there is something on the path already - if (tileElement->AsPath()->HasAddition()) - { - gGameCommandErrorText = STR_NONE; - return MONEY32_UNDEFINED; - } - - // There is nothing yet - check if we should place a ghost - if (flags & GAME_COMMAND_FLAG_APPLY) - tileElement->AsPath()->SetAdditionIsGhost(true); - } - - if (!(flags & GAME_COMMAND_FLAG_APPLY)) - return gParkFlags & PARK_FLAGS_NO_MONEY ? 0 : gFootpathPrice; - - if ((pathItemType != 0 && !(flags & GAME_COMMAND_FLAG_GHOST)) - || (pathItemType == 0 && tileElement->AsPath()->AdditionIsGhost())) - { - tileElement->AsPath()->SetAdditionIsGhost(false); - } - - tileElement->AsPath()->SetAddition(pathItemType); - tileElement->AsPath()->SetIsBroken(false); - if (pathItemType != 0) - { - rct_scenery_entry* scenery_entry = get_footpath_item_entry(pathItemType - 1); - if (scenery_entry != nullptr && scenery_entry->path_bit.flags & PATH_BIT_FLAG_IS_BIN) - { - tileElement->AsPath()->SetAdditionStatus(255); - } - } - map_invalidate_tile_full(x, y); - return gParkFlags & PARK_FLAGS_NO_MONEY ? 0 : gFootpathPrice; + Guard::Assert(false, "No longer in use. Use FootpathScenery{Place/Remove}Action."); } if (flags & GAME_COMMAND_FLAG_4)