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, };