From cbb02ec98a0e74ab6afd61a7148282545b0cde66 Mon Sep 17 00:00:00 2001 From: duncanspumpkin Date: Tue, 26 Feb 2019 13:19:17 +0000 Subject: [PATCH] Use game action for track design. Fix error titles. Add files to xcode project (#20) Finally get the placement code working Use game action for ghosts. Fix basequarter Remove references to old command Fix formating remove unused var Fix clang format --- OpenRCT2.xcodeproj/project.pbxproj | 12 + src/openrct2-ui/windows/TopToolbar.cpp | 102 ++++--- src/openrct2/Game.cpp | 6 +- src/openrct2/Game.h | 2 +- .../actions/SmallSceneryPlaceAction.hpp | 90 +++--- src/openrct2/network/Network.cpp | 1 + src/openrct2/ride/TrackDesign.cpp | 18 +- src/openrct2/world/Map.h | 2 - src/openrct2/world/SmallScenery.cpp | 275 ------------------ 9 files changed, 126 insertions(+), 382 deletions(-) diff --git a/OpenRCT2.xcodeproj/project.pbxproj b/OpenRCT2.xcodeproj/project.pbxproj index fc17170959..465dd48837 100644 --- a/OpenRCT2.xcodeproj/project.pbxproj +++ b/OpenRCT2.xcodeproj/project.pbxproj @@ -24,6 +24,9 @@ 2A1F4FE0221FF4B0003CA045 /* Twitch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F76C840F1EC4E7CC00FA49E2 /* Twitch.cpp */; }; 2A1F4FE1221FF4B0003CA045 /* Audio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F76C83571EC4E7CC00FA49E2 /* Audio.cpp */; }; 2A1F4FE2221FF4B0003CA045 /* macos.mm in Sources */ = {isa = PBXBuildFile; fileRef = F76C845D1EC4E7CC00FA49E2 /* macos.mm */; }; + 2A43D2BA2225B8D900E8F73B /* RideSetVehiclesAction.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 2A43D2B72225B8D900E8F73B /* RideSetVehiclesAction.hpp */; }; + 2A43D2BB2225B8D900E8F73B /* SmallSceneryPlaceAction.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 2A43D2B82225B8D900E8F73B /* SmallSceneryPlaceAction.hpp */; }; + 2A43D2BC2225B8D900E8F73B /* LoadOrQuitAction.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 2A43D2B92225B8D900E8F73B /* LoadOrQuitAction.hpp */; }; 2A5354E922099C4F00A5440F /* Network.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2A5354E822099C4F00A5440F /* Network.cpp */; }; 2A5C1368221E9F9000F8C245 /* TrackRemoveAction.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 2A5C1367221E9F9000F8C245 /* TrackRemoveAction.hpp */; }; 2AA050322209A8E300D3A922 /* StaffSetCostumeAction.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 2AA050302209A8E300D3A922 /* StaffSetCostumeAction.hpp */; }; @@ -622,6 +625,9 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 2A43D2B72225B8D900E8F73B /* RideSetVehiclesAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RideSetVehiclesAction.hpp; sourceTree = ""; }; + 2A43D2B82225B8D900E8F73B /* SmallSceneryPlaceAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SmallSceneryPlaceAction.hpp; sourceTree = ""; }; + 2A43D2B92225B8D900E8F73B /* LoadOrQuitAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LoadOrQuitAction.hpp; sourceTree = ""; }; 2A5354E822099C4F00A5440F /* Network.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Network.cpp; sourceTree = ""; }; 2A5354EA22099C7200A5440F /* CircularBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CircularBuffer.h; sourceTree = ""; }; 2A5354EB22099D7700A5440F /* SignSetStyleAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SignSetStyleAction.hpp; sourceTree = ""; }; @@ -2013,6 +2019,9 @@ isa = PBXGroup; children = ( 2ACBAB162226850A0034FB91 /* RideSetSetting.hpp */, + 2A43D2B92225B8D900E8F73B /* LoadOrQuitAction.hpp */, + 2A43D2B72225B8D900E8F73B /* RideSetVehiclesAction.hpp */, + 2A43D2B82225B8D900E8F73B /* SmallSceneryPlaceAction.hpp */, 2A5C1367221E9F9000F8C245 /* TrackRemoveAction.hpp */, 2AAFD7FF220DD3D2002461A4 /* LandSetHeightAction.hpp */, 2AAFD7FB220DD336002461A4 /* RideSetPriceAction.hpp */, @@ -3332,8 +3341,10 @@ 2AAFD7FE220DD374002461A4 /* PauseToggleAction.hpp in Headers */, C6352B941F477032006CCEE3 /* PlaceParkEntranceAction.hpp in Headers */, C6352B911F477032006CCEE3 /* GameAction.h in Headers */, + 2A43D2BA2225B8D900E8F73B /* RideSetVehiclesAction.hpp in Headers */, 2AA050322209A8E300D3A922 /* StaffSetCostumeAction.hpp in Headers */, C62D838B1FD36D6F008C04F1 /* EditorObjectSelectionSession.h in Headers */, + 2A43D2BC2225B8D900E8F73B /* LoadOrQuitAction.hpp in Headers */, 9344BEF920C1E6180047D165 /* Crypt.h in Headers */, 939A35A220C12FFD00630B3F /* InteractiveConsole.h in Headers */, 2ACBAB172226850A0034FB91 /* RideSetSetting.hpp in Headers */, @@ -3346,6 +3357,7 @@ 2AAFD7FC220DD336002461A4 /* RideSetPriceAction.hpp in Headers */, C67B28162002D67A00109C93 /* Window.h in Headers */, C6352B961F477032006CCEE3 /* RideSetStatus.hpp in Headers */, + 2A43D2BB2225B8D900E8F73B /* SmallSceneryPlaceAction.hpp in Headers */, 2AAFD800220DD3D2002461A4 /* LandSetHeightAction.hpp in Headers */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/src/openrct2-ui/windows/TopToolbar.cpp b/src/openrct2-ui/windows/TopToolbar.cpp index 49e5aaabb9..ec6ce4a1ff 100644 --- a/src/openrct2-ui/windows/TopToolbar.cpp +++ b/src/openrct2-ui/windows/TopToolbar.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -1723,7 +1724,8 @@ static void window_top_toolbar_scenery_tool_down(int16_t x, int16_t y, rct_windo { quantity = 35; } - int32_t successfulPlacements = 0; + + bool forceError = true; for (int32_t q = 0; q < quantity; q++) { int32_t zCoordinate = gSceneryPlaceZ; @@ -1755,58 +1757,61 @@ static void window_top_toolbar_scenery_tool_down(int16_t x, int16_t y, rct_windo zAttemptRange = 20; } - bool success = false; + uint8_t quadrant = parameter_2 & 0xFF; + uint8_t primaryColour = (parameter_2 >> 8) & 0xFF; + uint8_t secondaryColour = (parameter_3 >> 16) & 0xFF; + uint8_t type = (parameter_1 >> 8) & 0xFF; + auto success = GA_ERROR::UNKNOWN; + // Try find a valid z coordinate for (; zAttemptRange != 0; zAttemptRange--) { - int32_t flags = GAME_COMMAND_FLAG_APPLY | (parameter_1 & 0xFF00); - - gDisableErrorWindowSound = true; - gGameCommandErrorTitle = STR_CANT_POSITION_THIS_HERE; - int32_t cost = game_do_command( - cur_grid_x, flags, cur_grid_y, parameter_2, GAME_COMMAND_PLACE_SCENERY, - gSceneryPlaceRotation | (parameter_3 & 0xFFFF0000), gSceneryPlaceZ); - gDisableErrorWindowSound = false; - - if (cost != MONEY32_UNDEFINED) - { - window_close_by_class(WC_ERROR); - audio_play_sound_at_location( - SOUND_PLACE_ITEM, gCommandPosition.x, gCommandPosition.y, gCommandPosition.z); - success = true; - break; - } - - if (gGameCommandErrorText == STR_NOT_ENOUGH_CASH_REQUIRES - || gGameCommandErrorText == STR_CAN_ONLY_BUILD_THIS_ON_WATER) + auto smallSceneryPlaceAction = SmallSceneryPlaceAction( + { cur_grid_x, cur_grid_y, gSceneryPlaceZ, gSceneryPlaceRotation }, quadrant, type, primaryColour, + secondaryColour); + auto res = GameActions::Query(&smallSceneryPlaceAction); + success = res->Error; + if (res->Error == GA_ERROR::OK) { break; } - gSceneryPlaceZ += 8; + if (res->Error == GA_ERROR::INSUFFICIENT_FUNDS) + { + break; + } + if (zAttemptRange != 1) + { + gSceneryPlaceZ += 8; + } } - if (success) + // Actually place + if (success == GA_ERROR::OK || ((q + 1 == quantity) && (forceError == true))) { - successfulPlacements++; - } - else - { - if (gGameCommandErrorText == STR_NOT_ENOUGH_CASH_REQUIRES) + auto smallSceneryPlaceAction = SmallSceneryPlaceAction( + { cur_grid_x, cur_grid_y, gSceneryPlaceZ, gSceneryPlaceRotation }, quadrant, type, primaryColour, + secondaryColour); + + smallSceneryPlaceAction.SetCallback([=](const GameAction* ga, const GameActionResult* result) { + if (result->Error == GA_ERROR::OK) + { + audio_play_sound_at_location( + SOUND_PLACE_ITEM, result->Position.x, result->Position.y, result->Position.z); + } + }); + auto res = GameActions::Execute(&smallSceneryPlaceAction); + if (res->Error == GA_ERROR::OK) + { + forceError = false; + } + + if (res->Error == GA_ERROR::INSUFFICIENT_FUNDS) { break; } } gSceneryPlaceZ = zCoordinate; } - - if (successfulPlacements > 0) - { - window_close_by_class(WC_ERROR); - } - else - { - audio_play_sound_at_location(SOUND_ERROR, gCommandPosition.x, gCommandPosition.y, gCommandPosition.z); - } break; } case SCENERY_TYPE_PATH_ITEM: @@ -2444,16 +2449,22 @@ static money32 try_place_ghost_scenery( switch (scenery_type) { case 0: + { // Small Scenery // 6e252b - cost = game_do_command( - map_tile.x, - parameter_1 | GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_5 - | GAME_COMMAND_FLAG_GHOST, - map_tile.y, parameter_2, GAME_COMMAND_PLACE_SCENERY, parameter_3, gSceneryPlaceZ); + uint8_t quadrant = parameter_2 & 0xFF; + uint8_t primaryColour = (parameter_2 >> 8) & 0xFF; + uint8_t secondaryColour = (parameter_3 >> 16) & 0xFF; + uint8_t type = (parameter_1 >> 8) & 0xFF; + uint8_t rotation = parameter_3 & 0xFF; + auto smallSceneryPlaceAction = SmallSceneryPlaceAction( + { map_tile.x, map_tile.y, gSceneryPlaceZ, rotation }, quadrant, type, primaryColour, secondaryColour); + smallSceneryPlaceAction.SetFlags(GAME_COMMAND_FLAG_GHOST | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED); + auto res = GameActions::Execute(&smallSceneryPlaceAction); - if (cost == MONEY32_UNDEFINED) - return cost; + cost = res->Cost; + if (res->Error != GA_ERROR::OK) + return MONEY32_UNDEFINED; gSceneryGhostPosition.x = map_tile.x; gSceneryGhostPosition.y = map_tile.y; @@ -2476,6 +2487,7 @@ static money32 try_place_ghost_scenery( gSceneryGhostType |= SCENERY_GHOST_FLAG_0; break; + } case 1: // Path Bits // 6e265b diff --git a/src/openrct2/Game.cpp b/src/openrct2/Game.cpp index f84e35faac..9532fb7250 100644 --- a/src/openrct2/Game.cpp +++ b/src/openrct2/Game.cpp @@ -630,8 +630,8 @@ void game_log_multiplayer_command(int command, const int* eax, const int* ebx, c network_append_server_log(log_msg); } else if ( - command == GAME_COMMAND_PLACE_SCENERY || command == GAME_COMMAND_PLACE_WALL - || command == GAME_COMMAND_PLACE_LARGE_SCENERY || command == GAME_COMMAND_PLACE_BANNER) + command == GAME_COMMAND_PLACE_WALL || command == GAME_COMMAND_PLACE_LARGE_SCENERY + || command == GAME_COMMAND_PLACE_BANNER) { uint8_t flags = *ebx & 0xFF; if (flags & GAME_COMMAND_FLAG_GHOST) @@ -1275,7 +1275,7 @@ GAME_COMMAND_POINTER* new_game_command_table[GAME_COMMAND_COUNT] = { game_command_place_ride_entrance_or_exit, game_command_remove_ride_entrance_or_exit, nullptr, - game_command_place_scenery, + nullptr, game_command_set_water_height, game_command_place_footpath, game_command_place_footpath_from_track, diff --git a/src/openrct2/Game.h b/src/openrct2/Game.h index 59edf50241..8d1ed6d0c9 100644 --- a/src/openrct2/Game.h +++ b/src/openrct2/Game.h @@ -33,7 +33,7 @@ enum GAME_COMMAND GAME_COMMAND_PLACE_RIDE_ENTRANCE_OR_EXIT, GAME_COMMAND_REMOVE_RIDE_ENTRANCE_OR_EXIT, GAME_COMMAND_REMOVE_SCENERY, // GA - GAME_COMMAND_PLACE_SCENERY, + GAME_COMMAND_PLACE_SCENERY, // GA GAME_COMMAND_SET_WATER_HEIGHT, GAME_COMMAND_PLACE_PATH, GAME_COMMAND_PLACE_PATH_FROM_TRACK, diff --git a/src/openrct2/actions/SmallSceneryPlaceAction.hpp b/src/openrct2/actions/SmallSceneryPlaceAction.hpp index a8bc1a5fdf..0495f82c38 100644 --- a/src/openrct2/actions/SmallSceneryPlaceAction.hpp +++ b/src/openrct2/actions/SmallSceneryPlaceAction.hpp @@ -18,17 +18,19 @@ #include "../localisation/StringIds.h" #include "../management/Finance.h" #include "../ride/Ride.h" -#include "../world/TileElement.h" +#include "../ride/TrackDesign.h" +#include "../world/MapAnimation.h" #include "../world/Park.h" #include "../world/SmallScenery.h" #include "../world/Sprite.h" +#include "../world/Surface.h" +#include "../world/TileElement.h" #include "GameAction.h" DEFINE_GAME_ACTION(SmallSceneryPlaceAction, GAME_COMMAND_PLACE_SCENERY, GameActionResult) { private: - CoordsXYZ _loc; - uint8_t _rotation; + CoordsXYZD _loc; uint8_t _quadrant; uint8_t _sceneryType; uint8_t _primaryColour; @@ -38,10 +40,8 @@ public: SmallSceneryPlaceAction() = default; SmallSceneryPlaceAction( - CoordsXYZ loc, uint8_t quadrant, uint8_t rotation, uint8_t sceneryType, - uint8_t primaryColour, uint8_t secondaryColour) + CoordsXYZD loc, uint8_t quadrant, uint8_t sceneryType, uint8_t primaryColour, uint8_t secondaryColour) : _loc(loc) - , _rotation(rotation) , _quadrant(quadrant) , _sceneryType(sceneryType) , _primaryColour(primaryColour) @@ -58,7 +58,8 @@ public: { GameAction::Serialise(stream); - stream << DS_TAG(_loc) << DS_TAG(_rotation) << DS_TAG(_quadrant) << DS_TAG(_sceneryType) << DS_TAG(_primaryColour) << DS_TAG(_secondaryColour); + stream << DS_TAG(_loc) << DS_TAG(_quadrant) << DS_TAG(_sceneryType) << DS_TAG(_primaryColour) + << DS_TAG(_secondaryColour); } GameActionResult::Ptr Query() const override @@ -87,18 +88,18 @@ public: if (!map_check_free_elements_and_reorganise(1)) { - return MakeResult(GA_ERROR::NO_FREE_ELEMENTS, STR_NONE); + return MakeResult(GA_ERROR::NO_FREE_ELEMENTS, STR_CANT_POSITION_THIS_HERE); } if (!byte_9D8150 && (_loc.x > gMapSizeMaxXY || _loc.y > gMapSizeMaxXY)) { - return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_NONE); + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE); } rct_scenery_entry* sceneryEntry = get_small_scenery_entry(_sceneryType); if (sceneryEntry == nullptr) { - return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_NONE); + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE); } auto quadrant = _quadrant; @@ -146,7 +147,7 @@ public: if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode && !map_is_location_owned(_loc.x, _loc.y, targetHeight)) { - return MakeResult(GA_ERROR::NOT_OWNED, STR_NONE); + return MakeResult(GA_ERROR::NOT_OWNED, STR_CANT_POSITION_THIS_HERE, STR_LAND_NOT_OWNED_BY_PARK); } TileElement* surfaceElement = map_get_surface_element_at({ _loc.x, _loc.y }); @@ -156,7 +157,7 @@ public: int32_t water_height = (surfaceElement->AsSurface()->GetWaterHeight() * 16) - 1; if (water_height > targetHeight) { - return MakeResult(GA_ERROR::DISALLOWED, STR_CANT_BUILD_THIS_UNDERWATER); + return MakeResult(GA_ERROR::DISALLOWED, STR_CANT_POSITION_THIS_HERE, STR_CANT_BUILD_THIS_UNDERWATER); } } @@ -164,14 +165,14 @@ public: { if (isOnWater) { - return MakeResult(GA_ERROR::DISALLOWED, STR_CAN_ONLY_BUILD_THIS_ON_LAND); + return MakeResult(GA_ERROR::DISALLOWED, STR_CANT_POSITION_THIS_HERE, STR_CAN_ONLY_BUILD_THIS_ON_LAND); } if (surfaceElement != nullptr && surfaceElement->AsSurface()->GetWaterHeight() > 0) { - if ((surfaceElement->AsSurface()->GetWaterHeight() * 16) > targetHeight) + if (static_cast((surfaceElement->AsSurface()->GetWaterHeight() * 16)) > targetHeight) { - return MakeResult(GA_ERROR::DISALLOWED, STR_CAN_ONLY_BUILD_THIS_ON_LAND); + return MakeResult(GA_ERROR::DISALLOWED, STR_CANT_POSITION_THIS_HERE, STR_CAN_ONLY_BUILD_THIS_ON_LAND); } } } @@ -180,7 +181,7 @@ public: && (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_REQUIRE_FLAT_SURFACE)) && !supportsRequired && !isOnWater && surfaceElement != nullptr && (surfaceElement->AsSurface()->GetSlope() != TILE_ELEMENT_SLOPE_FLAT)) { - return MakeResult(GA_ERROR::DISALLOWED, STR_LEVEL_LAND_REQUIRED); + return MakeResult(GA_ERROR::DISALLOWED, STR_CANT_POSITION_THIS_HERE, STR_LEVEL_LAND_REQUIRED); } if (!gCheatsDisableSupportLimits && !(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_STACKABLE)) @@ -192,13 +193,13 @@ public: { if (surfaceElement->AsSurface()->GetWaterHeight() || (surfaceElement->base_height * 8) != targetHeight) { - return MakeResult(GA_ERROR::DISALLOWED, STR_LEVEL_LAND_REQUIRED); + return MakeResult(GA_ERROR::DISALLOWED, STR_CANT_POSITION_THIS_HERE, STR_LEVEL_LAND_REQUIRED); } } } else { - return MakeResult(GA_ERROR::DISALLOWED, STR_CAN_ONLY_BUILD_THIS_ON_LAND); + return MakeResult(GA_ERROR::DISALLOWED, STR_CANT_POSITION_THIS_HERE, STR_CAN_ONLY_BUILD_THIS_ON_LAND); } } @@ -218,41 +219,39 @@ public: { if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_THREE_QUARTERS)) { - quadRotation = ((quadrant ^ 2) + _rotation) & 3; + quadRotation = ((quadrant ^ 2) + _loc.direction) & 3; collisionQuadrants = 0b1011; } else { - quadRotation = (quadrant + _rotation) & 1; + quadRotation = (quadrant + _loc.direction) & 1; collisionQuadrants = 0b1010; } } } else { - quadRotation = ((quadrant ^ 2) + _rotation) & 3; + quadRotation = ((quadrant ^ 2) + _loc.direction) & 3; collisionQuadrants = 0b0011; } uint8_t supports = 0; if (!supportsRequired) { - supports |= 0xF0; + supports = 0b1111; } QuarterTile quarterTile = QuarterTile{ collisionQuadrants, supports }.Rotate(quadRotation); money32 clearCost = 0; - if (!gCheatsDisableClearanceChecks - && !map_can_construct_with_clear_at( - _loc.x, _loc.y, zLow, zHigh, &map_place_scenery_clear_func, quarterTile, GetFlags(), &clearCost, - CREATE_CROSSING_MODE_NONE)) + if (!map_can_construct_with_clear_at( + _loc.x, _loc.y, zLow, zHigh, &map_place_scenery_clear_func, quarterTile, GetFlags(), &clearCost, + CREATE_CROSSING_MODE_NONE)) { - return MakeResult(GA_ERROR::DISALLOWED, STR_NONE, gGameCommandErrorText, gCommonFormatArgs); + return MakeResult(GA_ERROR::DISALLOWED, STR_CANT_POSITION_THIS_HERE, gGameCommandErrorText, gCommonFormatArgs); } gSceneryGroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND); - auto res = MakeResult(); res->ExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING; res->Cost = (sceneryEntry->small_scenery.price * 10) + clearCost; @@ -261,7 +260,6 @@ public: GameActionResult::Ptr Execute() const override { - bool isOnWater = false; bool supportsRequired = false; if (_loc.z != 0) { @@ -286,7 +284,7 @@ public: rct_scenery_entry* sceneryEntry = get_small_scenery_entry(_sceneryType); if (sceneryEntry == nullptr) { - return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_NONE); + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE); } auto quadrant = _quadrant; @@ -320,10 +318,6 @@ public: { // base_height2 is now the water height baseHeight >>= 16; - if (_loc.z == 0) - { - isOnWater = true; - } } auto targetHeight = _loc.z; if (_loc.z == 0) @@ -356,56 +350,54 @@ public: { if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_THREE_QUARTERS)) { - quadRotation = ((quadrant ^ 2) + _rotation) & 3; + quadRotation = ((quadrant ^ 2) + _loc.direction) & 3; collisionQuadrants = 0b1011; } else { - quadRotation = (quadrant + _rotation) & 1; + quadRotation = (quadrant + _loc.direction) & 1; collisionQuadrants = 0b1010; } } } else { - quadRotation = ((quadrant ^ 2) + _rotation) & 3; + quadRotation = ((quadrant ^ 2) + _loc.direction) & 3; collisionQuadrants = 0b0011; } uint8_t supports = 0; if (!supportsRequired) { - supports |= 0xF0; + supports = 0b1111; } QuarterTile quarterTile = QuarterTile{ collisionQuadrants, supports }.Rotate(quadRotation); money32 clearCost = 0; - if (!gCheatsDisableClearanceChecks - && !map_can_construct_with_clear_at( - _loc.x, _loc.y, zLow, zHigh, &map_place_scenery_clear_func, quarterTile, GetFlags(), &clearCost, - CREATE_CROSSING_MODE_NONE)) + if (!map_can_construct_with_clear_at( + _loc.x, _loc.y, zLow, zHigh, &map_place_scenery_clear_func, quarterTile, GetFlags(), &clearCost, + CREATE_CROSSING_MODE_NONE)) { - return MakeResult(GA_ERROR::DISALLOWED, STR_NONE, gGameCommandErrorText, gCommonFormatArgs); + return MakeResult(GA_ERROR::DISALLOWED, STR_CANT_POSITION_THIS_HERE, gGameCommandErrorText, gCommonFormatArgs); } gSceneryGroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND); - auto res = MakeResult(); res->ExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING; res->Cost = (sceneryEntry->small_scenery.price * 10) + clearCost; - TileElement* newElement = tile_element_insert(_loc.x / 32, _loc.y / 32, zLow, collisionQuadrants); + TileElement* newElement = tile_element_insert(_loc.x / 32, _loc.y / 32, zLow, quarterTile.GetBaseQuarterOccupied()); assert(newElement != nullptr); gSceneryTileElement = newElement; newElement->SetType(TILE_ELEMENT_TYPE_SMALL_SCENERY); - newElement->SetDirection(_rotation); + newElement->SetDirection(_loc.direction); SmallSceneryElement* sceneryElement = newElement->AsSmallScenery(); sceneryElement->SetSceneryQuadrant(quadrant); sceneryElement->SetEntryIndex(_sceneryType); sceneryElement->SetAge(0); sceneryElement->SetPrimaryColour(_primaryColour); sceneryElement->SetSecondaryColour(_secondaryColour); - newElement->clearance_height = newElement->base_height + ((sceneryEntry->small_scenery.height + 7) / 8); + sceneryElement->clearance_height = sceneryElement->base_height + ((sceneryEntry->small_scenery.height + 7) / 8); if (supportsRequired) { @@ -414,13 +406,13 @@ public: if (GetFlags() & GAME_COMMAND_FLAG_GHOST) { - newElement->flags |= TILE_ELEMENT_FLAG_GHOST; + sceneryElement->SetGhost(true); } map_invalidate_tile_full(_loc.x, _loc.y); if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_ANIMATED)) { - map_animation_create(2, _loc.x, _loc.y, newElement->base_height); + map_animation_create(2, _loc.x, _loc.y, sceneryElement->base_height); } return res; diff --git a/src/openrct2/network/Network.cpp b/src/openrct2/network/Network.cpp index f4dcbfc01b..f1f3855473 100644 --- a/src/openrct2/network/Network.cpp +++ b/src/openrct2/network/Network.cpp @@ -1958,6 +1958,7 @@ void Network::ProcessGameCommands() if (mode == NETWORK_MODE_SERVER) { + // Note these are currently not reached as both commands are ported to GameActions if (command == GAME_COMMAND_PLACE_SCENERY) { player->LastPlaceSceneryTime = player->LastActionTime; diff --git a/src/openrct2/ride/TrackDesign.cpp b/src/openrct2/ride/TrackDesign.cpp index 63e85c4ec8..1a717d31c1 100644 --- a/src/openrct2/ride/TrackDesign.cpp +++ b/src/openrct2/ride/TrackDesign.cpp @@ -15,6 +15,7 @@ #include "../actions/LargeSceneryRemoveAction.hpp" #include "../actions/RideSetSetting.hpp" #include "../actions/RideSetVehiclesAction.hpp" +#include "../actions/SmallSceneryPlaceAction.hpp" #include "../actions/SmallSceneryRemoveAction.hpp" #include "../actions/TrackPlaceAction.hpp" #include "../actions/TrackRemoveAction.hpp" @@ -932,6 +933,7 @@ static int32_t track_design_place_scenery( switch (entry_type) { case OBJECT_TYPE_SMALL_SCENERY: + { if (mode != 0) { continue; @@ -964,15 +966,17 @@ static int32_t track_design_place_scenery( gGameCommandErrorTitle = STR_CANT_POSITION_THIS_HERE; - cost = game_do_command( - mapCoord.x, flags | (entry_index << 8), mapCoord.y, quadrant | (scenery->primary_colour << 8), - GAME_COMMAND_PLACE_SCENERY, rotation | (scenery->secondary_colour << 16), z); + auto smallSceneryPlace = SmallSceneryPlaceAction( + { mapCoord.x, mapCoord.y, z, rotation }, quadrant, entry_index, scenery->primary_colour, + scenery->secondary_colour); - if (cost == MONEY32_UNDEFINED) - { - cost = 0; - } + smallSceneryPlace.SetFlags(flags); + auto res = flags & GAME_COMMAND_FLAG_APPLY ? GameActions::ExecuteNested(&smallSceneryPlace) + : GameActions::QueryNested(&smallSceneryPlace); + + cost = res->Error == GA_ERROR::OK ? res->Cost : 0; break; + } case OBJECT_TYPE_LARGE_SCENERY: if (mode != 0) { diff --git a/src/openrct2/world/Map.h b/src/openrct2/world/Map.h index 8dc7eefc5c..454774548a 100644 --- a/src/openrct2/world/Map.h +++ b/src/openrct2/world/Map.h @@ -206,8 +206,6 @@ void game_command_set_water_height( int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp); void game_command_place_banner( int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp); -void game_command_place_scenery( - int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp); void game_command_place_wall(int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp); void game_command_place_large_scenery( int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp); diff --git a/src/openrct2/world/SmallScenery.cpp b/src/openrct2/world/SmallScenery.cpp index a54048659f..4ee629a1cf 100644 --- a/src/openrct2/world/SmallScenery.cpp +++ b/src/openrct2/world/SmallScenery.cpp @@ -65,269 +65,6 @@ static money32 SmallScenerySetColour( return 0; } -static money32 SmallSceneryPlace( - int16_t x, int16_t y, uint16_t targetHeight, uint8_t quadrant, uint8_t rotation, uint8_t sceneryType, uint8_t primaryColour, - uint8_t secondaryColour, uint8_t flags) -{ - gCommandExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING; - - money32 clearCost = 0; - bool isOnWater = false; - bool supportsRequired = false; - if (targetHeight != 0) - { - supportsRequired = true; - } - int32_t baseHeight = tile_element_height(x, y); - // If on water - if (baseHeight & 0xFFFF0000) - { - baseHeight >>= 16; - } - gCommandPosition.x = x; - gCommandPosition.y = y; - gCommandPosition.z = baseHeight; - if (targetHeight != 0) - { - baseHeight = targetHeight; - gCommandPosition.z = baseHeight; - } - gCommandPosition.x += 16; - gCommandPosition.y += 16; - - if (game_is_paused() && !gCheatsBuildInPauseMode) - { - gGameCommandErrorText = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; - return MONEY32_UNDEFINED; - } - - if (!map_check_free_elements_and_reorganise(1)) - { - return MONEY32_UNDEFINED; - } - - if (!byte_9D8150 && (x > gMapSizeMaxXY || y > gMapSizeMaxXY)) - { - return MONEY32_UNDEFINED; - } - - rct_scenery_entry* sceneryEntry = get_small_scenery_entry(sceneryType); - if (sceneryEntry == nullptr) - { - return MONEY32_UNDEFINED; - } - - if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE) - || !scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_DIAGONAL)) - { - if (scenery_small_entry_has_flag( - sceneryEntry, SMALL_SCENERY_FLAG_DIAGONAL | SMALL_SCENERY_FLAG_HALF_SPACE | SMALL_SCENERY_FLAG_THREE_QUARTERS)) - { - quadrant = 0; - } - } - - // Check if sub tile height is any different compared to actual surface tile height - int32_t x2 = x; - int32_t y2 = y; - if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE)) - { - x2 += 16; - y2 += 16; - } - else - { - x2 += ScenerySubTileOffsets[quadrant & 3].x - 1; - y2 += ScenerySubTileOffsets[quadrant & 3].y - 1; - } - baseHeight = tile_element_height(x2, y2); - // If on water - if (baseHeight & 0xFFFF0000) - { - // base_height2 is now the water height - baseHeight >>= 16; - if (targetHeight == 0) - { - isOnWater = true; - } - } - if (targetHeight == 0) - { - targetHeight = baseHeight; - } - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode && !map_is_location_owned(x, y, targetHeight)) - { - return MONEY32_UNDEFINED; - } - - if (flags & GAME_COMMAND_FLAG_APPLY && !(flags & GAME_COMMAND_FLAG_GHOST)) - { - footpath_remove_litter(x, y, targetHeight); - if (!gCheatsDisableClearanceChecks && (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_NO_WALLS))) - { - wall_remove_at(x, y, targetHeight, targetHeight + sceneryEntry->small_scenery.height); - } - } - - TileElement* surfaceElement = map_get_surface_element_at({ x, y }); - - if (surfaceElement != nullptr && !gCheatsDisableClearanceChecks && surfaceElement->AsSurface()->GetWaterHeight() > 0) - { - int32_t water_height = (surfaceElement->AsSurface()->GetWaterHeight() * 16) - 1; - if (water_height > targetHeight) - { - gGameCommandErrorText = STR_CANT_BUILD_THIS_UNDERWATER; - return MONEY32_UNDEFINED; - } - } - - if (!gCheatsDisableClearanceChecks && !(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_STACKABLE))) - { - if (isOnWater) - { - gGameCommandErrorText = STR_CAN_ONLY_BUILD_THIS_ON_LAND; - return MONEY32_UNDEFINED; - } - - if (surfaceElement != nullptr && surfaceElement->AsSurface()->GetWaterHeight() > 0) - { - if ((surfaceElement->AsSurface()->GetWaterHeight() * 16) > targetHeight) - { - gGameCommandErrorText = STR_CAN_ONLY_BUILD_THIS_ON_LAND; - return MONEY32_UNDEFINED; - } - } - } - - if (!gCheatsDisableClearanceChecks && (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_REQUIRE_FLAT_SURFACE)) - && !supportsRequired && !isOnWater && surfaceElement != nullptr - && (surfaceElement->AsSurface()->GetSlope() != TILE_ELEMENT_SLOPE_FLAT)) - { - gGameCommandErrorText = STR_LEVEL_LAND_REQUIRED; - return MONEY32_UNDEFINED; - } - - if (!gCheatsDisableSupportLimits && !(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_STACKABLE)) - && supportsRequired) - { - if (!isOnWater) - { - if (surfaceElement != nullptr) - { - if (surfaceElement->AsSurface()->GetWaterHeight() || (surfaceElement->base_height * 8) != targetHeight) - { - gGameCommandErrorText = STR_LEVEL_LAND_REQUIRED; - return MONEY32_UNDEFINED; - } - } - } - else - { - gGameCommandErrorText = STR_CAN_ONLY_BUILD_THIS_ON_LAND; - return MONEY32_UNDEFINED; - } - } - - int32_t zLow = targetHeight / 8; - int32_t zHigh = zLow + ceil2(sceneryEntry->small_scenery.height, 8) / 8; - uint8_t collisionQuadrants = 0b1111; - auto quadRotation{ 0 }; - if (!(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE))) - { - quadRotation = (quadrant ^ 2); - collisionQuadrants = 0b0001; - } - if (!(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_HALF_SPACE))) - { - if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_DIAGONAL) - && scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE)) - { - if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_THREE_QUARTERS)) - { - quadRotation = ((quadrant ^ 2) + rotation) & 3; - collisionQuadrants = 0b1011; - } - else - { - quadRotation = (quadrant + rotation) & 1; - collisionQuadrants = 0b1010; - } - } - } - else - { - quadRotation = ((quadrant ^ 2) + rotation) & 3; - collisionQuadrants = 0b0011; - } - uint8_t supports = 0; - if (!supportsRequired) - { - supports |= 0xF0; - } - - QuarterTile quarterTile = QuarterTile{ collisionQuadrants, supports }.Rotate(quadRotation); - - if (!map_can_construct_with_clear_at( - x, y, zLow, zHigh, &map_place_scenery_clear_func, quarterTile, flags, &clearCost, CREATE_CROSSING_MODE_NONE)) - { - return MONEY32_UNDEFINED; - } - - gSceneryGroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND); - - money32 cost = (sceneryEntry->small_scenery.price * 10) + clearCost; - if (gParkFlags & PARK_FLAGS_NO_MONEY) - { - cost = 0; - } - - if (!(flags & GAME_COMMAND_FLAG_APPLY)) - { - return cost; - } - - if (gGameCommandNestLevel == 1 && !(flags & GAME_COMMAND_FLAG_GHOST)) - { - LocationXYZ16 coord; - coord.x = x + 16; - coord.y = y + 16; - coord.z = tile_element_height(coord.x, coord.y); - network_set_player_last_action_coord(network_get_player_index(game_command_playerid), coord); - } - - TileElement* newElement = tile_element_insert(x / 32, y / 32, zLow, collisionQuadrants); - assert(newElement != nullptr); - gSceneryTileElement = newElement; - newElement->SetType(TILE_ELEMENT_TYPE_SMALL_SCENERY); - newElement->SetDirection(rotation); - SmallSceneryElement* sceneryElement = newElement->AsSmallScenery(); - sceneryElement->SetSceneryQuadrant(quadrant); - sceneryElement->SetEntryIndex(sceneryType); - sceneryElement->SetAge(0); - sceneryElement->SetPrimaryColour(primaryColour); - sceneryElement->SetSecondaryColour(secondaryColour); - newElement->clearance_height = newElement->base_height + ((sceneryEntry->small_scenery.height + 7) / 8); - - if (supportsRequired) - { - sceneryElement->SetNeedsSupports(); - } - - if (flags & GAME_COMMAND_FLAG_GHOST) - { - newElement->SetGhost(true); - } - - map_invalidate_tile_full(x, y); - if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_ANIMATED)) - { - map_animation_create(2, x, y, newElement->base_height); - } - - return cost; -} - /** * * rct2: 0x006E0F26 @@ -412,18 +149,6 @@ int32_t map_place_non_scenery_clear_func(TileElement** tile_element, int32_t x, return 0; } -/** - * - * rct2: 0x006E08F4 - */ -void game_command_place_scenery( - int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, [[maybe_unused]] int32_t* esi, int32_t* edi, int32_t* ebp) -{ - *ebx = SmallSceneryPlace( - *eax & 0xFFFF, *ecx & 0xFFFF, *ebp & 0xFFFF, *edx & 0xFF, *edi & 0xFF, (*ebx >> 8) & 0xFF, (*edx >> 8) & 0xFF, - (*edi >> 16) & 0xFF, *ebx & 0xFF); -} - bool scenery_small_entry_has_flag(const rct_scenery_entry* sceneryEntry, uint32_t flags) { return (bool)(sceneryEntry->small_scenery.flags & flags);