From 50d22ededddc51f7766b47ccf5e00e566455dd67 Mon Sep 17 00:00:00 2001 From: Duncan Date: Tue, 16 Jun 2020 20:57:11 +0100 Subject: [PATCH] Create a hookable location checking function for actions (#11860) * Create a hookable location checking function for actions * Add location valid to a number of game actions Actually pass the coordinates to the script Use LocationValid on further game actions Add further actions to the LocationValid. Update api Update remaining actions to use LocationValid * Fix bug with peep pickup Adjust api --- distribution/openrct2.d.ts | 12 +++++- src/openrct2/actions/BannerPlaceAction.hpp | 2 +- src/openrct2/actions/BannerRemoveAction.hpp | 2 +- .../actions/BannerSetColourAction.hpp | 2 +- src/openrct2/actions/ClearAction.hpp | 2 +- src/openrct2/actions/FootpathPlaceAction.hpp | 2 +- .../actions/FootpathPlaceFromTrackAction.hpp | 2 +- src/openrct2/actions/FootpathRemoveAction.hpp | 5 +++ .../actions/FootpathSceneryPlaceAction.hpp | 2 +- .../actions/FootpathSceneryRemoveAction.hpp | 2 +- src/openrct2/actions/GameAction.cpp | 37 ++++++++++++++++++- src/openrct2/actions/GameAction.h | 2 + src/openrct2/actions/LandBuyRightsAction.hpp | 2 + src/openrct2/actions/LandLowerAction.hpp | 2 + src/openrct2/actions/LandRaiseAction.hpp | 2 + src/openrct2/actions/LandSetHeightAction.hpp | 5 +++ src/openrct2/actions/LandSetRightsAction.hpp | 2 + .../actions/LargeSceneryPlaceAction.hpp | 2 +- .../actions/LargeSceneryRemoveAction.hpp | 4 ++ .../actions/LargeScenerySetColourAction.hpp | 5 +++ src/openrct2/actions/MazePlaceTrackAction.hpp | 2 +- src/openrct2/actions/MazeSetTrackAction.hpp | 2 +- .../actions/ParkEntranceRemoveAction.hpp | 2 +- src/openrct2/actions/PeepPickupAction.hpp | 5 +++ .../actions/PlaceParkEntranceAction.hpp | 3 +- src/openrct2/actions/PlacePeepSpawnAction.hpp | 2 +- .../actions/RideEntranceExitPlaceAction.hpp | 2 +- .../actions/RideEntranceExitRemoveAction.hpp | 5 +++ src/openrct2/actions/RideSetColourScheme.hpp | 4 ++ .../actions/SmallSceneryPlaceAction.hpp | 5 +++ .../actions/SmallSceneryRemoveAction.hpp | 2 +- .../actions/SmallScenerySetColourAction.hpp | 5 +++ .../actions/StaffSetPatrolAreaAction.hpp | 5 +++ .../actions/SurfaceSetStyleAction.hpp | 3 ++ src/openrct2/actions/TileModifyAction.hpp | 4 ++ src/openrct2/actions/TrackDesignAction.cpp | 5 +++ src/openrct2/actions/TrackPlaceAction.hpp | 2 +- src/openrct2/actions/TrackRemoveAction.hpp | 4 ++ .../actions/TrackSetBrakeSpeedAction.hpp | 5 +++ src/openrct2/actions/WallPlaceAction.hpp | 5 +++ src/openrct2/actions/WallRemoveAction.hpp | 2 +- src/openrct2/actions/WallSetColourAction.hpp | 5 +++ src/openrct2/actions/WaterLowerAction.hpp | 3 ++ src/openrct2/actions/WaterRaiseAction.hpp | 3 ++ src/openrct2/actions/WaterSetHeightAction.hpp | 5 +++ src/openrct2/scripting/HookEngine.cpp | 3 +- src/openrct2/scripting/HookEngine.h | 1 + 47 files changed, 169 insertions(+), 21 deletions(-) diff --git a/distribution/openrct2.d.ts b/distribution/openrct2.d.ts index c174afa86e..e1445b311b 100644 --- a/distribution/openrct2.d.ts +++ b/distribution/openrct2.d.ts @@ -224,6 +224,7 @@ declare global { subscribe(hook: "network.join", callback: (e: NetworkEventArgs) => void): IDisposable; subscribe(hook: "network.leave", callback: (e: NetworkEventArgs) => void): IDisposable; subscribe(hook: "ride.ratings.calculate", callback: (e: RideRatingsCalculateArgs) => void): IDisposable; + subscribe(hook: "action.location", callback: (e: ActionLocationArgs) => void): IDisposable; } interface Configuration { @@ -289,7 +290,7 @@ declare global { type HookType = "interval.tick" | "interval.day" | "network.chat" | "network.action" | "network.join" | "network.leave" | - "ride.ratings.calculate"; + "ride.ratings.calculate" | "action.location"; type ExpenditureType = "ride_construction" | @@ -350,6 +351,15 @@ declare global { nausea: number; } + interface ActionLocationArgs { + readonly x: number; + readonly y: number; + readonly player: number; + readonly type: number; + readonly isClientOnly: boolean; + result: boolean; + } + /** * APIs for the in-game date. */ diff --git a/src/openrct2/actions/BannerPlaceAction.hpp b/src/openrct2/actions/BannerPlaceAction.hpp index 5778d4b6b5..c0d7ea2b64 100644 --- a/src/openrct2/actions/BannerPlaceAction.hpp +++ b/src/openrct2/actions/BannerPlaceAction.hpp @@ -60,7 +60,7 @@ public: return MakeResult(GA_ERROR::NO_FREE_ELEMENTS, STR_CANT_POSITION_THIS_HERE); } - if (!map_is_location_valid(_loc)) + if (!LocationValid(_loc)) { return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE); } diff --git a/src/openrct2/actions/BannerRemoveAction.hpp b/src/openrct2/actions/BannerRemoveAction.hpp index 3cd4ab457f..1040cacfd5 100644 --- a/src/openrct2/actions/BannerRemoveAction.hpp +++ b/src/openrct2/actions/BannerRemoveAction.hpp @@ -48,7 +48,7 @@ public: res->Position.z = _loc.z; res->ErrorTitle = STR_CANT_REMOVE_THIS; - if (!map_can_build_at({ _loc.x, _loc.y, _loc.z - 16 })) + if (!LocationValid(_loc) || !map_can_build_at({ _loc.x, _loc.y, _loc.z - 16 })) { return MakeResult(GA_ERROR::NOT_OWNED, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); } diff --git a/src/openrct2/actions/BannerSetColourAction.hpp b/src/openrct2/actions/BannerSetColourAction.hpp index bbb003388d..23d160ab5f 100644 --- a/src/openrct2/actions/BannerSetColourAction.hpp +++ b/src/openrct2/actions/BannerSetColourAction.hpp @@ -62,7 +62,7 @@ private: res->Position.z = _loc.z; res->ErrorTitle = STR_CANT_REPAINT_THIS; - if (_loc.x < 0 || _loc.y < 0 || _loc.x > gMapSizeMaxXY || _loc.y > gMapSizeMaxXY) + if (!LocationValid(_loc)) { log_error("Invalid x / y coordinates: x = %d, y = %d", _loc.x, _loc.y); return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_REPAINT_THIS); diff --git a/src/openrct2/actions/ClearAction.hpp b/src/openrct2/actions/ClearAction.hpp index 0c8d0b738d..02be1299de 100644 --- a/src/openrct2/actions/ClearAction.hpp +++ b/src/openrct2/actions/ClearAction.hpp @@ -102,7 +102,7 @@ private: { for (int32_t x = x0; x <= x1; x += COORDS_XY_STEP) { - if (MapCanClearAt({ x, y })) + if (LocationValid({ x, y }) && MapCanClearAt({ x, y })) { auto cost = ClearSceneryFromTile({ x, y }, executing); if (cost != MONEY32_UNDEFINED) diff --git a/src/openrct2/actions/FootpathPlaceAction.hpp b/src/openrct2/actions/FootpathPlaceAction.hpp index 5cb4e0feba..3eac3aa8d9 100644 --- a/src/openrct2/actions/FootpathPlaceAction.hpp +++ b/src/openrct2/actions/FootpathPlaceAction.hpp @@ -62,7 +62,7 @@ public: gFootpathGroundFlags = 0; - if (map_is_edge(_loc)) + if (!LocationValid(_loc) || map_is_edge(_loc)) { return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_BUILD_FOOTPATH_HERE, STR_OFF_EDGE_OF_MAP); } diff --git a/src/openrct2/actions/FootpathPlaceFromTrackAction.hpp b/src/openrct2/actions/FootpathPlaceFromTrackAction.hpp index e8383cbf56..b7c143840e 100644 --- a/src/openrct2/actions/FootpathPlaceFromTrackAction.hpp +++ b/src/openrct2/actions/FootpathPlaceFromTrackAction.hpp @@ -61,7 +61,7 @@ public: gFootpathGroundFlags = 0; - if (map_is_edge(_loc)) + if (!LocationValid(_loc) || map_is_edge(_loc)) { return MakeResult( GA_ERROR::INVALID_PARAMETERS, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_OFF_EDGE_OF_MAP); diff --git a/src/openrct2/actions/FootpathRemoveAction.hpp b/src/openrct2/actions/FootpathRemoveAction.hpp index ff81c53463..c357436856 100644 --- a/src/openrct2/actions/FootpathRemoveAction.hpp +++ b/src/openrct2/actions/FootpathRemoveAction.hpp @@ -53,6 +53,11 @@ public: res->Expenditure = ExpenditureType::Landscaping; res->Position = { _loc.x + 16, _loc.y + 16, _loc.z }; + if (!LocationValid(_loc)) + { + return MakeResult(GA_ERROR::NOT_OWNED, STR_CANT_REMOVE_FOOTPATH_FROM_HERE, STR_LAND_NOT_OWNED_BY_PARK); + } + if (!((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode) && !map_is_location_owned(_loc)) { return MakeResult(GA_ERROR::NOT_OWNED, STR_CANT_REMOVE_FOOTPATH_FROM_HERE, STR_LAND_NOT_OWNED_BY_PARK); diff --git a/src/openrct2/actions/FootpathSceneryPlaceAction.hpp b/src/openrct2/actions/FootpathSceneryPlaceAction.hpp index 8cca6354cf..d5450cb115 100644 --- a/src/openrct2/actions/FootpathSceneryPlaceAction.hpp +++ b/src/openrct2/actions/FootpathSceneryPlaceAction.hpp @@ -53,7 +53,7 @@ public: auto res = MakeResult(); res->Expenditure = ExpenditureType::Landscaping; res->Position = _loc; - if (!map_is_location_valid(_loc)) + if (!LocationValid(_loc)) { return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE, STR_OFF_EDGE_OF_MAP); } diff --git a/src/openrct2/actions/FootpathSceneryRemoveAction.hpp b/src/openrct2/actions/FootpathSceneryRemoveAction.hpp index f8d554b733..d16fc42352 100644 --- a/src/openrct2/actions/FootpathSceneryRemoveAction.hpp +++ b/src/openrct2/actions/FootpathSceneryRemoveAction.hpp @@ -47,7 +47,7 @@ public: GameActionResult::Ptr Query() const override { - if (!map_is_location_valid(_loc)) + if (!LocationValid(_loc)) { return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_REMOVE_THIS, STR_OFF_EDGE_OF_MAP); } diff --git a/src/openrct2/actions/GameAction.cpp b/src/openrct2/actions/GameAction.cpp index 05252c4b38..a083174c2a 100644 --- a/src/openrct2/actions/GameAction.cpp +++ b/src/openrct2/actions/GameAction.cpp @@ -18,6 +18,8 @@ #include "../network/network.h" #include "../platform/platform.h" #include "../scenario/Scenario.h" +#include "../scripting/Duktape.hpp" +#include "../scripting/HookEngine.h" #include "../scripting/ScriptEngine.h" #include "../ui/UiContext.h" #include "../ui/WindowManager.h" @@ -552,5 +554,38 @@ namespace GameActions { return ExecuteInternal(action, false); } - } // namespace GameActions + +bool GameAction::LocationValid(const CoordsXY& coords) const +{ + auto result = map_is_location_valid(coords); + if (!result) + return false; +#ifdef ENABLE_SCRIPTING + auto& hookEngine = GetContext()->GetScriptEngine().GetHookEngine(); + if (hookEngine.HasSubscriptions(OpenRCT2::Scripting::HOOK_TYPE::ACTION_LOCATION)) + { + auto ctx = GetContext()->GetScriptEngine().GetContext(); + + // Create event args object + auto obj = OpenRCT2::Scripting::DukObject(ctx); + obj.Set("x", coords.x); + obj.Set("y", coords.y); + obj.Set("player", _playerId); + obj.Set("type", _type); + + auto flags = GetActionFlags(); + obj.Set("isClientOnly", (flags & GA_FLAGS::CLIENT_ONLY) != 0); + obj.Set("result", true); + + // Call the subscriptions + auto e = obj.Take(); + hookEngine.Call(OpenRCT2::Scripting::HOOK_TYPE::ACTION_LOCATION, e, true); + + auto scriptResult = OpenRCT2::Scripting::AsOrDefault(e["result"], true); + + return scriptResult; + } +#endif + return true; +} diff --git a/src/openrct2/actions/GameAction.h b/src/openrct2/actions/GameAction.h index 3a86c08890..12f8548041 100644 --- a/src/openrct2/actions/GameAction.h +++ b/src/openrct2/actions/GameAction.h @@ -314,6 +314,8 @@ public: * Apply the game action and change the game state. */ virtual GameActionResult::Ptr Execute() const abstract; + + bool LocationValid(const CoordsXY& coords) const; }; #ifdef __WARN_SUGGEST_FINAL_METHODS__ diff --git a/src/openrct2/actions/LandBuyRightsAction.hpp b/src/openrct2/actions/LandBuyRightsAction.hpp index ee6e80398b..7db220655a 100644 --- a/src/openrct2/actions/LandBuyRightsAction.hpp +++ b/src/openrct2/actions/LandBuyRightsAction.hpp @@ -103,6 +103,8 @@ private: { for (auto x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) { + if (!LocationValid({ x, y })) + continue; auto result = map_buy_land_rights_for_tile({ x, y }, isExecuting); if (result->Error == GA_ERROR::OK) { diff --git a/src/openrct2/actions/LandLowerAction.hpp b/src/openrct2/actions/LandLowerAction.hpp index 3372151ecb..6b91344b66 100644 --- a/src/openrct2/actions/LandLowerAction.hpp +++ b/src/openrct2/actions/LandLowerAction.hpp @@ -98,6 +98,8 @@ private: { for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) { + if (!LocationValid({ x, y })) + continue; auto* surfaceElement = map_get_surface_element_at(CoordsXY{ x, y }); if (surfaceElement == nullptr) continue; diff --git a/src/openrct2/actions/LandRaiseAction.hpp b/src/openrct2/actions/LandRaiseAction.hpp index 11742d12a8..a5a68e6d21 100644 --- a/src/openrct2/actions/LandRaiseAction.hpp +++ b/src/openrct2/actions/LandRaiseAction.hpp @@ -99,6 +99,8 @@ private: { for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) { + if (!LocationValid({ x, y })) + continue; auto* surfaceElement = map_get_surface_element_at(CoordsXY{ x, y }); if (surfaceElement == nullptr) continue; diff --git a/src/openrct2/actions/LandSetHeightAction.hpp b/src/openrct2/actions/LandSetHeightAction.hpp index f1a0549f47..b4f6ef85c0 100644 --- a/src/openrct2/actions/LandSetHeightAction.hpp +++ b/src/openrct2/actions/LandSetHeightAction.hpp @@ -186,6 +186,11 @@ public: private: rct_string_id CheckParameters() const { + if (!LocationValid(_coords)) + { + return STR_OFF_EDGE_OF_MAP; + } + if (_coords.x > gMapSizeMaxXY || _coords.y > gMapSizeMaxXY) { return STR_OFF_EDGE_OF_MAP; diff --git a/src/openrct2/actions/LandSetRightsAction.hpp b/src/openrct2/actions/LandSetRightsAction.hpp index ec1c87c188..4a29bddb3a 100644 --- a/src/openrct2/actions/LandSetRightsAction.hpp +++ b/src/openrct2/actions/LandSetRightsAction.hpp @@ -112,6 +112,8 @@ private: { for (auto x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) { + if (!LocationValid({ x, y })) + continue; auto result = map_buy_land_rights_for_tile({ x, y }, isExecuting); if (result->Error == GA_ERROR::OK) { diff --git a/src/openrct2/actions/LargeSceneryPlaceAction.hpp b/src/openrct2/actions/LargeSceneryPlaceAction.hpp index 38eb61090a..80c80a568d 100644 --- a/src/openrct2/actions/LargeSceneryPlaceAction.hpp +++ b/src/openrct2/actions/LargeSceneryPlaceAction.hpp @@ -188,7 +188,7 @@ public: res->GroundFlags = tempSceneryGroundFlags; - if (curTile.x >= gMapSizeUnits || curTile.y >= gMapSizeUnits) + if (!LocationValid(curTile) || curTile.x >= gMapSizeUnits || curTile.y >= gMapSizeUnits) { return std::make_unique(GA_ERROR::DISALLOWED, STR_OFF_EDGE_OF_MAP); } diff --git a/src/openrct2/actions/LargeSceneryRemoveAction.hpp b/src/openrct2/actions/LargeSceneryRemoveAction.hpp index 483fe8c451..6fb3c71e6e 100644 --- a/src/openrct2/actions/LargeSceneryRemoveAction.hpp +++ b/src/openrct2/actions/LargeSceneryRemoveAction.hpp @@ -97,6 +97,10 @@ public: } } + if (!LocationValid(currentTile)) + { + return MakeResult(GA_ERROR::NO_CLEARANCE, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } // Prevent duplicate costs when using the clear scenery tool that overlaps multiple large // scenery tile elements. if (flags & GAME_COMMAND_FLAG_PATH_SCENERY) diff --git a/src/openrct2/actions/LargeScenerySetColourAction.hpp b/src/openrct2/actions/LargeScenerySetColourAction.hpp index a0ae590598..2ec2a3acbd 100644 --- a/src/openrct2/actions/LargeScenerySetColourAction.hpp +++ b/src/openrct2/actions/LargeScenerySetColourAction.hpp @@ -129,6 +129,11 @@ private: } } + if (!LocationValid(currentTile)) + { + return MakeResult(GA_ERROR::NOT_OWNED, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + auto tileElement = map_get_large_scenery_segment({ currentTile.x, currentTile.y, _loc.z, _loc.direction }, i); if (tileElement == nullptr) diff --git a/src/openrct2/actions/MazePlaceTrackAction.hpp b/src/openrct2/actions/MazePlaceTrackAction.hpp index 72e7ed0195..54b0f71ea9 100644 --- a/src/openrct2/actions/MazePlaceTrackAction.hpp +++ b/src/openrct2/actions/MazePlaceTrackAction.hpp @@ -63,7 +63,7 @@ public: return res; } - if (!map_is_location_owned(_loc) && !gCheatsSandboxMode) + if (!LocationValid(_loc) || (!map_is_location_owned(_loc) && !gCheatsSandboxMode)) { res->Error = GA_ERROR::NOT_OWNED; res->ErrorMessage = STR_LAND_NOT_OWNED_BY_PARK; diff --git a/src/openrct2/actions/MazeSetTrackAction.hpp b/src/openrct2/actions/MazeSetTrackAction.hpp index 04781fff7f..c875208764 100644 --- a/src/openrct2/actions/MazeSetTrackAction.hpp +++ b/src/openrct2/actions/MazeSetTrackAction.hpp @@ -101,7 +101,7 @@ public: return res; } - if (!map_is_location_owned(_loc) && !gCheatsSandboxMode) + if (!LocationValid(_loc) || (!map_is_location_owned(_loc) && !gCheatsSandboxMode)) { res->Error = GA_ERROR::NOT_OWNED; res->ErrorMessage = STR_LAND_NOT_OWNED_BY_PARK; diff --git a/src/openrct2/actions/ParkEntranceRemoveAction.hpp b/src/openrct2/actions/ParkEntranceRemoveAction.hpp index fbedfddbd5..f5e526b411 100644 --- a/src/openrct2/actions/ParkEntranceRemoveAction.hpp +++ b/src/openrct2/actions/ParkEntranceRemoveAction.hpp @@ -53,7 +53,7 @@ public: res->ErrorTitle = STR_CANT_REMOVE_THIS; auto entranceIndex = park_entrance_get_index(_loc); - if (entranceIndex == -1) + if (!LocationValid(_loc) || entranceIndex == -1) { log_error("Could not find entrance at x = %d, y = %d, z = %d", _loc.x, _loc.y, _loc.z); return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_REMOVE_THIS); diff --git a/src/openrct2/actions/PeepPickupAction.hpp b/src/openrct2/actions/PeepPickupAction.hpp index fcc6de1bc2..474e52e367 100644 --- a/src/openrct2/actions/PeepPickupAction.hpp +++ b/src/openrct2/actions/PeepPickupAction.hpp @@ -60,6 +60,11 @@ public: return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_ERR_CANT_PLACE_PERSON_HERE); } + if (!_loc.isNull() && !LocationValid(_loc)) + { + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_ERR_CANT_PLACE_PERSON_HERE); + } + Peep* const peep = GET_PEEP(_spriteId); if (!peep || peep->sprite_identifier != SPRITE_IDENTIFIER_PEEP) { diff --git a/src/openrct2/actions/PlaceParkEntranceAction.hpp b/src/openrct2/actions/PlaceParkEntranceAction.hpp index 026fc2c221..f9a766fa24 100644 --- a/src/openrct2/actions/PlaceParkEntranceAction.hpp +++ b/src/openrct2/actions/PlaceParkEntranceAction.hpp @@ -65,7 +65,8 @@ public: return std::make_unique(GA_ERROR::NO_FREE_ELEMENTS, STR_CANT_BUILD_PARK_ENTRANCE_HERE, STR_NONE); } - if (_loc.x <= 32 || _loc.y <= 32 || _loc.x >= (gMapSizeUnits - 32) || _loc.y >= (gMapSizeUnits - 32)) + if (!LocationValid(_loc) || _loc.x <= 32 || _loc.y <= 32 || _loc.x >= (gMapSizeUnits - 32) + || _loc.y >= (gMapSizeUnits - 32)) { return std::make_unique( GA_ERROR::INVALID_PARAMETERS, STR_CANT_BUILD_PARK_ENTRANCE_HERE, STR_TOO_CLOSE_TO_EDGE_OF_MAP); diff --git a/src/openrct2/actions/PlacePeepSpawnAction.hpp b/src/openrct2/actions/PlacePeepSpawnAction.hpp index 091de8c06b..7678a925dc 100644 --- a/src/openrct2/actions/PlacePeepSpawnAction.hpp +++ b/src/openrct2/actions/PlacePeepSpawnAction.hpp @@ -62,7 +62,7 @@ public: return std::make_unique(GA_ERROR::NO_FREE_ELEMENTS, STR_ERR_CANT_PLACE_PEEP_SPAWN_HERE, STR_NONE); } - if (_location.x <= 16 || _location.y <= 16 || _location.x >= (gMapSizeUnits - 16) + if (!LocationValid(_location) || _location.x <= 16 || _location.y <= 16 || _location.x >= (gMapSizeUnits - 16) || _location.y >= (gMapSizeUnits - 16)) { return std::make_unique( diff --git a/src/openrct2/actions/RideEntranceExitPlaceAction.hpp b/src/openrct2/actions/RideEntranceExitPlaceAction.hpp index 9f45b6849d..0667425bdb 100644 --- a/src/openrct2/actions/RideEntranceExitPlaceAction.hpp +++ b/src/openrct2/actions/RideEntranceExitPlaceAction.hpp @@ -109,7 +109,7 @@ public: } auto z = ride->stations[_stationNum].GetBaseZ(); - if (!gCheatsSandboxMode && !map_is_location_owned({ _loc, z })) + if (!LocationValid(_loc) || (!gCheatsSandboxMode && !map_is_location_owned({ _loc, z }))) { return MakeResult(GA_ERROR::NOT_OWNED, errorTitle); } diff --git a/src/openrct2/actions/RideEntranceExitRemoveAction.hpp b/src/openrct2/actions/RideEntranceExitRemoveAction.hpp index 4e5082e6a1..ec8ffee017 100644 --- a/src/openrct2/actions/RideEntranceExitRemoveAction.hpp +++ b/src/openrct2/actions/RideEntranceExitRemoveAction.hpp @@ -72,6 +72,11 @@ public: return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_NOT_ALLOWED_TO_MODIFY_STATION); } + if (!LocationValid(_loc)) + { + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_LAND_NOT_OWNED_BY_PARK); + } + bool found = false; TileElement* tileElement = map_get_first_element_at(_loc); diff --git a/src/openrct2/actions/RideSetColourScheme.hpp b/src/openrct2/actions/RideSetColourScheme.hpp index ac0c798b4a..21233738ef 100644 --- a/src/openrct2/actions/RideSetColourScheme.hpp +++ b/src/openrct2/actions/RideSetColourScheme.hpp @@ -58,6 +58,10 @@ public: GameActionResult::Ptr Query() const override { + if (!LocationValid(_loc)) + { + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_LAND_NOT_OWNED_BY_PARK); + } return std::make_unique(); } diff --git a/src/openrct2/actions/SmallSceneryPlaceAction.hpp b/src/openrct2/actions/SmallSceneryPlaceAction.hpp index 51039faf1a..ca406c9cf8 100644 --- a/src/openrct2/actions/SmallSceneryPlaceAction.hpp +++ b/src/openrct2/actions/SmallSceneryPlaceAction.hpp @@ -132,6 +132,11 @@ public: return std::make_unique(GA_ERROR::NO_FREE_ELEMENTS); } + if (!LocationValid(_loc)) + { + return MakeResult(GA_ERROR::INVALID_PARAMETERS); + } + if (!byte_9D8150 && (_loc.x > gMapSizeMaxXY || _loc.y > gMapSizeMaxXY)) { return std::make_unique(GA_ERROR::INVALID_PARAMETERS); diff --git a/src/openrct2/actions/SmallSceneryRemoveAction.hpp b/src/openrct2/actions/SmallSceneryRemoveAction.hpp index 2a6ef4ba6b..00adefd637 100644 --- a/src/openrct2/actions/SmallSceneryRemoveAction.hpp +++ b/src/openrct2/actions/SmallSceneryRemoveAction.hpp @@ -56,7 +56,7 @@ public: { GameActionResult::Ptr res = std::make_unique(); - if (!map_is_location_valid(_loc)) + if (!LocationValid(_loc)) { return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); } diff --git a/src/openrct2/actions/SmallScenerySetColourAction.hpp b/src/openrct2/actions/SmallScenerySetColourAction.hpp index 60720bfa3a..491bf143d4 100644 --- a/src/openrct2/actions/SmallScenerySetColourAction.hpp +++ b/src/openrct2/actions/SmallScenerySetColourAction.hpp @@ -82,6 +82,11 @@ private: res->Position.z = _loc.z; res->ErrorTitle = STR_CANT_REPAINT_THIS; + if (!LocationValid(_loc)) + { + return MakeResult(GA_ERROR::NOT_OWNED, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) { if (!map_is_location_owned(_loc)) diff --git a/src/openrct2/actions/StaffSetPatrolAreaAction.hpp b/src/openrct2/actions/StaffSetPatrolAreaAction.hpp index 6a80804e6b..083ea79bd7 100644 --- a/src/openrct2/actions/StaffSetPatrolAreaAction.hpp +++ b/src/openrct2/actions/StaffSetPatrolAreaAction.hpp @@ -50,6 +50,11 @@ public: return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_NONE); } + if (!LocationValid(_loc)) + { + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_NONE); + } + auto peep = GET_PEEP(_spriteId); if (peep == nullptr || peep->sprite_identifier != SPRITE_IDENTIFIER_PEEP || peep->AssignedPeepType != PEEP_TYPE_STAFF) { diff --git a/src/openrct2/actions/SurfaceSetStyleAction.hpp b/src/openrct2/actions/SurfaceSetStyleAction.hpp index 0381bef854..670a935c13 100644 --- a/src/openrct2/actions/SurfaceSetStyleAction.hpp +++ b/src/openrct2/actions/SurfaceSetStyleAction.hpp @@ -119,6 +119,9 @@ public: { for (coords.y = validRange.GetTop(); coords.y <= validRange.GetBottom(); coords.y += COORDS_XY_STEP) { + if (!LocationValid(coords)) + continue; + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) { if (!map_is_location_in_park(coords)) diff --git a/src/openrct2/actions/TileModifyAction.hpp b/src/openrct2/actions/TileModifyAction.hpp index 6954645362..53b228bf6d 100644 --- a/src/openrct2/actions/TileModifyAction.hpp +++ b/src/openrct2/actions/TileModifyAction.hpp @@ -90,6 +90,10 @@ public: private: GameActionResult::Ptr QueryExecute(bool isExecuting) const { + if (!LocationValid(_loc)) + { + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_LAND_NOT_OWNED_BY_PARK); + } auto res = MakeResult(); switch (static_cast(_setting)) { diff --git a/src/openrct2/actions/TrackDesignAction.cpp b/src/openrct2/actions/TrackDesignAction.cpp index 68081d55ef..4dd265efd4 100644 --- a/src/openrct2/actions/TrackDesignAction.cpp +++ b/src/openrct2/actions/TrackDesignAction.cpp @@ -37,6 +37,11 @@ GameActionResult::Ptr TrackDesignAction::Query() const res->Expenditure = ExpenditureType::RideConstruction; _currentTrackPieceDirection = _loc.direction; + if (!LocationValid(_loc)) + { + return MakeResult(GA_ERROR::INVALID_PARAMETERS); + } + const rct_object_entry* rideEntryObject = &_td.vehicle_object; uint8_t entryType; diff --git a/src/openrct2/actions/TrackPlaceAction.hpp b/src/openrct2/actions/TrackPlaceAction.hpp index 3ae2c9f327..a42aaeeff5 100644 --- a/src/openrct2/actions/TrackPlaceAction.hpp +++ b/src/openrct2/actions/TrackPlaceAction.hpp @@ -182,7 +182,7 @@ public: auto rotatedTrack = CoordsXYZ{ CoordsXY{ trackBlock->x, trackBlock->y }.Rotate(_origin.direction), 0 }; auto tileCoords = CoordsXYZ{ _origin.x, _origin.y, _origin.z } + rotatedTrack; - if (!map_is_location_owned(tileCoords) && !gCheatsSandboxMode) + if (!LocationValid(tileCoords) || (!map_is_location_owned(tileCoords) && !gCheatsSandboxMode)) { return std::make_unique(GA_ERROR::DISALLOWED, STR_LAND_NOT_OWNED_BY_PARK); } diff --git a/src/openrct2/actions/TrackRemoveAction.hpp b/src/openrct2/actions/TrackRemoveAction.hpp index 6778d51c10..11bb62b852 100644 --- a/src/openrct2/actions/TrackRemoveAction.hpp +++ b/src/openrct2/actions/TrackRemoveAction.hpp @@ -161,6 +161,10 @@ public: rotatedTrack = CoordsXYZ{ CoordsXY{ trackBlock->x, trackBlock->y }.Rotate(startLoc.direction), trackBlock->z }; auto mapLoc = CoordsXYZ{ startLoc.x, startLoc.y, startLoc.z } + rotatedTrack; + if (!LocationValid(mapLoc)) + { + return MakeResult(GA_ERROR::NOT_OWNED, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } map_invalidate_tile_full(mapLoc); found = false; diff --git a/src/openrct2/actions/TrackSetBrakeSpeedAction.hpp b/src/openrct2/actions/TrackSetBrakeSpeedAction.hpp index c7bb3a5b55..be97a68a85 100644 --- a/src/openrct2/actions/TrackSetBrakeSpeedAction.hpp +++ b/src/openrct2/actions/TrackSetBrakeSpeedAction.hpp @@ -66,6 +66,11 @@ private: res->Position.y += 16; res->Expenditure = ExpenditureType::RideConstruction; + if (!LocationValid(_loc)) + { + return MakeResult(GA_ERROR::NOT_OWNED, STR_NONE); + } + TileElement* tileElement = map_get_track_element_at_of_type(_loc, _trackType); if (tileElement == nullptr) { diff --git a/src/openrct2/actions/WallPlaceAction.hpp b/src/openrct2/actions/WallPlaceAction.hpp index b6e7c51553..fb7a68e897 100644 --- a/src/openrct2/actions/WallPlaceAction.hpp +++ b/src/openrct2/actions/WallPlaceAction.hpp @@ -112,6 +112,11 @@ public: res->Position.z = tile_element_height(res->Position); } + if (!LocationValid(_loc)) + { + return MakeResult(GA_ERROR::NOT_OWNED); + } + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !(GetFlags() & GAME_COMMAND_FLAG_PATH_SCENERY) && !gCheatsSandboxMode) { diff --git a/src/openrct2/actions/WallRemoveAction.hpp b/src/openrct2/actions/WallRemoveAction.hpp index a68b561a4c..f474525126 100644 --- a/src/openrct2/actions/WallRemoveAction.hpp +++ b/src/openrct2/actions/WallRemoveAction.hpp @@ -44,7 +44,7 @@ public: res->Cost = 0; res->Expenditure = ExpenditureType::Landscaping; - if (!map_is_location_valid(_loc)) + if (!LocationValid(_loc)) { return std::make_unique( GA_ERROR::INVALID_PARAMETERS, STR_CANT_REMOVE_THIS, STR_INVALID_SELECTION_OF_OBJECTS); diff --git a/src/openrct2/actions/WallSetColourAction.hpp b/src/openrct2/actions/WallSetColourAction.hpp index 473e9ed143..9ac7ac3d25 100644 --- a/src/openrct2/actions/WallSetColourAction.hpp +++ b/src/openrct2/actions/WallSetColourAction.hpp @@ -65,6 +65,11 @@ public: res->Expenditure = ExpenditureType::Landscaping; + if (!LocationValid(_loc)) + { + return MakeResult(GA_ERROR::NOT_OWNED, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); + } + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !map_is_location_in_park(_loc) && !gCheatsSandboxMode) { return MakeResult(GA_ERROR::NOT_OWNED, STR_CANT_REPAINT_THIS, STR_LAND_NOT_OWNED_BY_PARK); diff --git a/src/openrct2/actions/WaterLowerAction.hpp b/src/openrct2/actions/WaterLowerAction.hpp index e2875323c8..62ef98e9cc 100644 --- a/src/openrct2/actions/WaterLowerAction.hpp +++ b/src/openrct2/actions/WaterLowerAction.hpp @@ -79,6 +79,9 @@ private: { for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) { + if (!LocationValid({ x, y })) + continue; + auto* surfaceElement = map_get_surface_element_at(CoordsXY{ x, y }); if (surfaceElement == nullptr) continue; diff --git a/src/openrct2/actions/WaterRaiseAction.hpp b/src/openrct2/actions/WaterRaiseAction.hpp index 9e80f02137..7b607a7a66 100644 --- a/src/openrct2/actions/WaterRaiseAction.hpp +++ b/src/openrct2/actions/WaterRaiseAction.hpp @@ -80,6 +80,9 @@ private: { for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP) { + if (!LocationValid({ x, y })) + continue; + auto surfaceElement = map_get_surface_element_at(CoordsXY{ x, y }); if (surfaceElement == nullptr) continue; diff --git a/src/openrct2/actions/WaterSetHeightAction.hpp b/src/openrct2/actions/WaterSetHeightAction.hpp index 81f209bb57..85d00605b1 100644 --- a/src/openrct2/actions/WaterSetHeightAction.hpp +++ b/src/openrct2/actions/WaterSetHeightAction.hpp @@ -61,6 +61,11 @@ public: return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_NONE, errorMsg); } + if (!LocationValid(_coords)) + { + return MakeResult(GA_ERROR::NOT_OWNED, STR_NONE, STR_LAND_NOT_OWNED_BY_PARK); + } + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) { if (!map_is_location_in_park(_coords)) diff --git a/src/openrct2/scripting/HookEngine.cpp b/src/openrct2/scripting/HookEngine.cpp index c3dd601a54..fde3968bf1 100644 --- a/src/openrct2/scripting/HookEngine.cpp +++ b/src/openrct2/scripting/HookEngine.cpp @@ -28,7 +28,8 @@ HOOK_TYPE OpenRCT2::Scripting::GetHookType(const std::string& name) { "network.authenticate", HOOK_TYPE::NETWORK_AUTHENTICATE }, { "network.join", HOOK_TYPE::NETWORK_JOIN }, { "network.leave", HOOK_TYPE::NETWORK_LEAVE }, - { "ride.ratings.calculate", HOOK_TYPE::RIDE_RATINGS_CALCULATE } }); + { "ride.ratings.calculate", HOOK_TYPE::RIDE_RATINGS_CALCULATE }, + { "action.location", HOOK_TYPE::ACTION_LOCATION } }); auto result = LookupTable.find(name); return (result != LookupTable.end()) ? result->second : HOOK_TYPE::UNDEFINED; } diff --git a/src/openrct2/scripting/HookEngine.h b/src/openrct2/scripting/HookEngine.h index 9b504d2cc4..7323737e24 100644 --- a/src/openrct2/scripting/HookEngine.h +++ b/src/openrct2/scripting/HookEngine.h @@ -37,6 +37,7 @@ namespace OpenRCT2::Scripting NETWORK_JOIN, NETWORK_LEAVE, RIDE_RATINGS_CALCULATE, + ACTION_LOCATION, COUNT, UNDEFINED = -1, };