1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-19 04:53:12 +01:00

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
This commit is contained in:
Duncan
2020-06-16 20:57:11 +01:00
committed by GitHub
parent 0f12382895
commit 50d22ededd
47 changed files with 169 additions and 21 deletions

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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)

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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);
}

View File

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

View File

@@ -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__

View File

@@ -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)
{

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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)
{

View File

@@ -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<LargeSceneryPlaceActionResult>(GA_ERROR::DISALLOWED, STR_OFF_EDGE_OF_MAP);
}

View File

@@ -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)

View File

@@ -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)

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);

View File

@@ -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)
{

View File

@@ -65,7 +65,8 @@ public:
return std::make_unique<GameActionResult>(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<GameActionResult>(
GA_ERROR::INVALID_PARAMETERS, STR_CANT_BUILD_PARK_ENTRANCE_HERE, STR_TOO_CLOSE_TO_EDGE_OF_MAP);

View File

@@ -62,7 +62,7 @@ public:
return std::make_unique<GameActionResult>(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<GameActionResult>(

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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<GameActionResult>();
}

View File

@@ -132,6 +132,11 @@ public:
return std::make_unique<SmallSceneryPlaceActionResult>(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<SmallSceneryPlaceActionResult>(GA_ERROR::INVALID_PARAMETERS);

View File

@@ -56,7 +56,7 @@ public:
{
GameActionResult::Ptr res = std::make_unique<GameActionResult>();
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);
}

View File

@@ -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))

View File

@@ -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)
{

View File

@@ -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))

View File

@@ -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<TileModifyType>(_setting))
{

View File

@@ -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;

View File

@@ -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<TrackPlaceActionResult>(GA_ERROR::DISALLOWED, STR_LAND_NOT_OWNED_BY_PARK);
}

View File

@@ -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;

View File

@@ -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)
{

View File

@@ -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)
{

View File

@@ -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<GameActionResult>(
GA_ERROR::INVALID_PARAMETERS, STR_CANT_REMOVE_THIS, STR_INVALID_SELECTION_OF_OBJECTS);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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))

View File

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

View File

@@ -37,6 +37,7 @@ namespace OpenRCT2::Scripting
NETWORK_JOIN,
NETWORK_LEAVE,
RIDE_RATINGS_CALCULATE,
ACTION_LOCATION,
COUNT,
UNDEFINED = -1,
};