1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-31 18:55:23 +01:00

Merge pull request #9109 from tharkne/issue-9053

Fix 9053: Remove gSceneryGroundFlags by returning it within GameActionResult
This commit is contained in:
Duncan
2019-04-22 07:57:26 +01:00
committed by GitHub
6 changed files with 105 additions and 56 deletions

View File

@@ -127,6 +127,8 @@ The following people are not part of the development team, but have been contrib
* Zetao Ye (ZbrettonYe)
* Jordan Arevalos (Jarevalos2017)
* Florian Will (w-flo)
* Trevor Harkness (tharkne)
* Steve Xu (stevexu-umich)
## Toolchain
* (Balletie) - macOS

View File

@@ -2487,7 +2487,7 @@ static money32 try_place_ghost_scenery(
tileElement = gSceneryTileElement;
gSceneryGhostPosition.z = tileElement->base_height;
gSceneryQuadrant = tileElement->AsSmallScenery()->GetSceneryQuadrant();
if (gSceneryGroundFlags & ELEMENT_IS_UNDERGROUND)
if (dynamic_cast<SmallSceneryPlaceActionResult*>(res.get())->GroundFlags & ELEMENT_IS_UNDERGROUND)
{
// Set underground on
viewport_set_visibility(4);
@@ -2582,7 +2582,7 @@ static money32 try_place_ghost_scenery(
tileElement = gSceneryTileElement;
gSceneryGhostPosition.z = tileElement->base_height;
if (gSceneryGroundFlags & ELEMENT_IS_UNDERGROUND)
if (dynamic_cast<LargeSceneryPlaceActionResult*>(res.get())->GroundFlags & ELEMENT_IS_UNDERGROUND)
{
// Set underground on
viewport_set_visibility(4);

View File

@@ -19,7 +19,30 @@
#include "../world/Scenery.h"
#include "GameAction.h"
DEFINE_GAME_ACTION(LargeSceneryPlaceAction, GAME_COMMAND_PLACE_LARGE_SCENERY, GameActionResult)
class LargeSceneryPlaceActionResult final : public GameActionResult
{
public:
LargeSceneryPlaceActionResult()
: GameActionResult(GA_ERROR::OK, STR_CANT_POSITION_THIS_HERE)
{
}
LargeSceneryPlaceActionResult(GA_ERROR error)
: GameActionResult(error, STR_CANT_POSITION_THIS_HERE)
{
}
LargeSceneryPlaceActionResult(GA_ERROR error, rct_string_id message)
: GameActionResult(error, STR_CANT_POSITION_THIS_HERE, message)
{
}
LargeSceneryPlaceActionResult(GA_ERROR error, rct_string_id message, uint8_t* args)
: GameActionResult(error, STR_CANT_POSITION_THIS_HERE, message, args)
{
}
uint8_t GroundFlags{ 0 };
};
DEFINE_GAME_ACTION(LargeSceneryPlaceAction, GAME_COMMAND_PLACE_LARGE_SCENERY, LargeSceneryPlaceActionResult)
{
private:
CoordsXYZD _loc;
@@ -62,15 +85,15 @@ public:
GameActionResult::Ptr Query() const override
{
auto res = MakeResult();
auto res = std::make_unique<LargeSceneryPlaceActionResult>();
res->ErrorTitle = STR_CANT_POSITION_THIS_HERE;
res->ExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING;
int16_t surfaceHeight = tile_element_height(_loc.x, _loc.y) & 0xFFFF;
res->Position.x = _loc.x + 16;
res->Position.y = _loc.y + 16;
res->Position.z = surfaceHeight;
res->GroundFlags = 0;
gSceneryGroundFlags = 0;
money32 supportsCost = 0;
if (_primaryColour > TILE_ELEMENT_COLOUR_MASK || _secondaryColour > TILE_ELEMENT_COLOUR_MASK)
@@ -78,20 +101,20 @@ public:
log_error(
"Invalid game command for scenery placement, primaryColour = %u, secondaryColour = %u", _primaryColour,
_secondaryColour);
return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE);
return std::make_unique<LargeSceneryPlaceActionResult>(GA_ERROR::INVALID_PARAMETERS);
}
if (_sceneryType >= MAX_LARGE_SCENERY_OBJECTS)
{
log_error("Invalid game command for scenery placement, sceneryType = %u", _sceneryType);
return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE);
return std::make_unique<LargeSceneryPlaceActionResult>(GA_ERROR::INVALID_PARAMETERS);
}
rct_scenery_entry* sceneryEntry = get_large_scenery_entry(_sceneryType);
if (sceneryEntry == nullptr)
{
log_error("Invalid game command for scenery placement, sceneryType = %u", _sceneryType);
return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE);
return std::make_unique<LargeSceneryPlaceActionResult>(GA_ERROR::INVALID_PARAMETERS);
}
uint32_t totalNumTiles = GetTotalNumTiles(sceneryEntry->large_scenery.tiles);
@@ -109,20 +132,20 @@ public:
if (_bannerId == BANNER_INDEX_NULL)
{
log_error("Banner Index not specified.");
return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_TOO_MANY_BANNERS_IN_GAME, STR_CANT_POSITION_THIS_HERE);
return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_TOO_MANY_BANNERS_IN_GAME);
}
if (gBanners[_bannerId].type != BANNER_NULL)
{
log_error("No free banners available");
return MakeResult(GA_ERROR::NO_FREE_ELEMENTS, STR_CANT_POSITION_THIS_HERE);
return std::make_unique<LargeSceneryPlaceActionResult>(GA_ERROR::NO_FREE_ELEMENTS);
}
}
if (!map_check_free_elements_and_reorganise(totalNumTiles))
{
log_error("No free map elements available");
return MakeResult(GA_ERROR::NO_FREE_ELEMENTS, STR_CANT_POSITION_THIS_HERE);
return std::make_unique<LargeSceneryPlaceActionResult>(GA_ERROR::NO_FREE_ELEMENTS);
}
uint8_t tileNum = 0;
@@ -144,8 +167,8 @@ public:
curTile.x, curTile.y, zLow, zHigh, &map_place_scenery_clear_func, quarterTile, GetFlags(), &supportsCost,
CREATE_CROSSING_MODE_NONE))
{
return MakeResult(
GA_ERROR::NO_CLEARANCE, STR_CANT_POSITION_THIS_HERE, gGameCommandErrorText, gCommonFormatArgs);
return std::make_unique<LargeSceneryPlaceActionResult>(
GA_ERROR::NO_CLEARANCE, gGameCommandErrorText, gCommonFormatArgs);
}
int32_t tempSceneryGroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND);
@@ -153,25 +176,27 @@ public:
{
if ((gMapGroundFlags & ELEMENT_IS_UNDERWATER) || (gMapGroundFlags & ELEMENT_IS_UNDERGROUND))
{
return MakeResult(GA_ERROR::DISALLOWED, STR_CANT_POSITION_THIS_HERE, STR_CANT_BUILD_THIS_UNDERWATER);
return std::make_unique<LargeSceneryPlaceActionResult>(
GA_ERROR::DISALLOWED, STR_CANT_BUILD_THIS_UNDERWATER);
}
if (gSceneryGroundFlags && !(gSceneryGroundFlags & tempSceneryGroundFlags))
if (res->GroundFlags && !(res->GroundFlags & tempSceneryGroundFlags))
{
return MakeResult(
GA_ERROR::DISALLOWED, STR_CANT_POSITION_THIS_HERE, STR_CANT_BUILD_PARTLY_ABOVE_AND_PARTLY_BELOW_GROUND);
return std::make_unique<LargeSceneryPlaceActionResult>(
GA_ERROR::DISALLOWED, STR_CANT_BUILD_PARTLY_ABOVE_AND_PARTLY_BELOW_GROUND);
}
}
gSceneryGroundFlags = tempSceneryGroundFlags;
res->GroundFlags = tempSceneryGroundFlags;
if (curTile.x >= gMapSizeUnits || curTile.y >= gMapSizeUnits)
{
return MakeResult(GA_ERROR::DISALLOWED, STR_CANT_POSITION_THIS_HERE, STR_OFF_EDGE_OF_MAP);
return std::make_unique<LargeSceneryPlaceActionResult>(GA_ERROR::DISALLOWED, STR_OFF_EDGE_OF_MAP);
}
if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !map_is_location_owned(curTile.x, curTile.y, zLow * 8)
&& !gCheatsSandboxMode)
{
return MakeResult(GA_ERROR::DISALLOWED, STR_CANT_POSITION_THIS_HERE, STR_LAND_NOT_OWNED_BY_PARK);
return std::make_unique<LargeSceneryPlaceActionResult>(GA_ERROR::DISALLOWED, STR_LAND_NOT_OWNED_BY_PARK);
}
}
@@ -184,28 +209,28 @@ public:
GameActionResult::Ptr Execute() const override
{
auto res = MakeResult();
auto res = std::make_unique<LargeSceneryPlaceActionResult>();
res->ErrorTitle = STR_CANT_POSITION_THIS_HERE;
int16_t surfaceHeight = tile_element_height(_loc.x, _loc.y) & 0xFFFF;
res->Position.x = _loc.x + 16;
res->Position.y = _loc.y + 16;
res->Position.z = surfaceHeight;
res->GroundFlags = 0;
gSceneryGroundFlags = 0;
money32 supportsCost = 0;
rct_scenery_entry* sceneryEntry = get_large_scenery_entry(_sceneryType);
if (sceneryEntry == nullptr)
{
log_error("Invalid game command for scenery placement, sceneryType = %u", _sceneryType);
return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE);
return std::make_unique<LargeSceneryPlaceActionResult>(GA_ERROR::INVALID_PARAMETERS);
}
if (sceneryEntry->large_scenery.tiles == nullptr)
{
log_error("Invalid large scenery object, sceneryType = %u", _sceneryType);
return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE);
return std::make_unique<LargeSceneryPlaceActionResult>(GA_ERROR::INVALID_PARAMETERS);
}
uint32_t totalNumTiles = GetTotalNumTiles(sceneryEntry->large_scenery.tiles);
@@ -223,13 +248,13 @@ public:
if (_bannerId == BANNER_INDEX_NULL)
{
log_error("No free banners available");
return MakeResult(GA_ERROR::NO_FREE_ELEMENTS, STR_TOO_MANY_BANNERS_IN_GAME, STR_CANT_POSITION_THIS_HERE);
return MakeResult(GA_ERROR::NO_FREE_ELEMENTS, STR_TOO_MANY_BANNERS_IN_GAME);
}
if (gBanners[_bannerId].type != BANNER_NULL)
{
log_error("No free banners available");
return MakeResult(GA_ERROR::NO_FREE_ELEMENTS, STR_CANT_POSITION_THIS_HERE);
return std::make_unique<LargeSceneryPlaceActionResult>(GA_ERROR::NO_FREE_ELEMENTS);
}
rct_banner* banner = &gBanners[_bannerId];
@@ -252,7 +277,7 @@ public:
if (!map_check_free_elements_and_reorganise(totalNumTiles))
{
log_error("No free map elements available");
return MakeResult(GA_ERROR::NO_FREE_ELEMENTS, STR_CANT_POSITION_THIS_HERE);
return std::make_unique<LargeSceneryPlaceActionResult>(GA_ERROR::NO_FREE_ELEMENTS);
}
uint8_t tileNum = 0;
@@ -274,11 +299,11 @@ public:
curTile.x, curTile.y, zLow, zHigh, &map_place_scenery_clear_func, quarterTile, GetFlags(), &supportsCost,
CREATE_CROSSING_MODE_NONE))
{
return MakeResult(
GA_ERROR::NO_CLEARANCE, STR_CANT_POSITION_THIS_HERE, gGameCommandErrorText, gCommonFormatArgs);
return std::make_unique<LargeSceneryPlaceActionResult>(
GA_ERROR::NO_CLEARANCE, gGameCommandErrorText, gCommonFormatArgs);
}
gSceneryGroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND);
res->GroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND);
if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST))
{
@@ -297,7 +322,7 @@ public:
newTileElement->clearance_height = zHigh;
auto newSceneryElement = newTileElement->AsLargeScenery();
SetNewLargeSceneryElement(*newSceneryElement, tileNum, _bannerId);
SetNewLargeSceneryElement(*newSceneryElement, tileNum);
if (tileNum == 0)
{
@@ -367,7 +392,7 @@ private:
return maxHeight;
}
void SetNewLargeSceneryElement(LargeSceneryElement & sceneryElement, uint8_t tileNum, BannerIndex bannerId) const
void SetNewLargeSceneryElement(LargeSceneryElement & sceneryElement, uint8_t tileNum) const
{
sceneryElement.SetDirection(_loc.direction);
sceneryElement.SetEntryIndex(_sceneryType);
@@ -375,9 +400,9 @@ private:
sceneryElement.SetPrimaryColour(_primaryColour);
sceneryElement.SetSecondaryColour(_secondaryColour);
if (bannerId != BANNER_INDEX_NULL)
if (_bannerId != BANNER_INDEX_NULL)
{
sceneryElement.SetBannerIndex(bannerId);
sceneryElement.SetBannerIndex(_bannerId);
}
if (GetFlags() & GAME_COMMAND_FLAG_GHOST)

View File

@@ -27,7 +27,30 @@
#include "../world/TileElement.h"
#include "GameAction.h"
DEFINE_GAME_ACTION(SmallSceneryPlaceAction, GAME_COMMAND_PLACE_SCENERY, GameActionResult)
class SmallSceneryPlaceActionResult final : public GameActionResult
{
public:
SmallSceneryPlaceActionResult()
: GameActionResult(GA_ERROR::OK, STR_CANT_POSITION_THIS_HERE)
{
}
SmallSceneryPlaceActionResult(GA_ERROR error)
: GameActionResult(error, STR_CANT_POSITION_THIS_HERE)
{
}
SmallSceneryPlaceActionResult(GA_ERROR error, rct_string_id message)
: GameActionResult(error, STR_CANT_POSITION_THIS_HERE, message)
{
}
SmallSceneryPlaceActionResult(GA_ERROR error, rct_string_id message, uint8_t* args)
: GameActionResult(error, STR_CANT_POSITION_THIS_HERE, message, args)
{
}
uint8_t GroundFlags{ 0 };
};
DEFINE_GAME_ACTION(SmallSceneryPlaceAction, GAME_COMMAND_PLACE_SCENERY, SmallSceneryPlaceActionResult)
{
private:
CoordsXYZD _loc;
@@ -81,7 +104,7 @@ public:
{
baseHeight >>= 16;
}
auto res = MakeResult();
auto res = std::make_unique<SmallSceneryPlaceActionResult>();
res->Position.x = _loc.x + 16;
res->Position.y = _loc.y + 16;
res->Position.z = baseHeight;
@@ -93,18 +116,18 @@ public:
if (!map_check_free_elements_and_reorganise(1))
{
return MakeResult(GA_ERROR::NO_FREE_ELEMENTS, STR_CANT_POSITION_THIS_HERE);
return std::make_unique<SmallSceneryPlaceActionResult>(GA_ERROR::NO_FREE_ELEMENTS);
}
if (!byte_9D8150 && (_loc.x > gMapSizeMaxXY || _loc.y > gMapSizeMaxXY))
{
return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE);
return std::make_unique<SmallSceneryPlaceActionResult>(GA_ERROR::INVALID_PARAMETERS);
}
rct_scenery_entry* sceneryEntry = get_small_scenery_entry(_sceneryType);
if (sceneryEntry == nullptr)
{
return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE);
return std::make_unique<SmallSceneryPlaceActionResult>(GA_ERROR::INVALID_PARAMETERS);
}
auto quadrant = _quadrant;
@@ -152,7 +175,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_CANT_POSITION_THIS_HERE, STR_LAND_NOT_OWNED_BY_PARK);
return std::make_unique<SmallSceneryPlaceActionResult>(GA_ERROR::NOT_OWNED, STR_LAND_NOT_OWNED_BY_PARK);
}
TileElement* surfaceElement = map_get_surface_element_at({ _loc.x, _loc.y });
@@ -162,7 +185,7 @@ public:
int32_t water_height = (surfaceElement->AsSurface()->GetWaterHeight() * 16) - 1;
if (water_height > targetHeight)
{
return MakeResult(GA_ERROR::DISALLOWED, STR_CANT_POSITION_THIS_HERE, STR_CANT_BUILD_THIS_UNDERWATER);
return std::make_unique<SmallSceneryPlaceActionResult>(GA_ERROR::DISALLOWED, STR_CANT_BUILD_THIS_UNDERWATER);
}
}
@@ -170,14 +193,15 @@ public:
{
if (isOnWater)
{
return MakeResult(GA_ERROR::DISALLOWED, STR_CANT_POSITION_THIS_HERE, STR_CAN_ONLY_BUILD_THIS_ON_LAND);
return std::make_unique<SmallSceneryPlaceActionResult>(GA_ERROR::DISALLOWED, STR_CAN_ONLY_BUILD_THIS_ON_LAND);
}
if (surfaceElement != nullptr && surfaceElement->AsSurface()->GetWaterHeight() > 0)
{
if (static_cast<int32_t>((surfaceElement->AsSurface()->GetWaterHeight() * 16)) > targetHeight)
{
return MakeResult(GA_ERROR::DISALLOWED, STR_CANT_POSITION_THIS_HERE, STR_CAN_ONLY_BUILD_THIS_ON_LAND);
return std::make_unique<SmallSceneryPlaceActionResult>(
GA_ERROR::DISALLOWED, STR_CAN_ONLY_BUILD_THIS_ON_LAND);
}
}
}
@@ -186,7 +210,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_CANT_POSITION_THIS_HERE, STR_LEVEL_LAND_REQUIRED);
return std::make_unique<SmallSceneryPlaceActionResult>(GA_ERROR::DISALLOWED, STR_LEVEL_LAND_REQUIRED);
}
if (!gCheatsDisableSupportLimits && !(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_STACKABLE))
@@ -198,13 +222,13 @@ public:
{
if (surfaceElement->AsSurface()->GetWaterHeight() || (surfaceElement->base_height * 8) != targetHeight)
{
return MakeResult(GA_ERROR::DISALLOWED, STR_CANT_POSITION_THIS_HERE, STR_LEVEL_LAND_REQUIRED);
return std::make_unique<SmallSceneryPlaceActionResult>(GA_ERROR::DISALLOWED, STR_LEVEL_LAND_REQUIRED);
}
}
}
else
{
return MakeResult(GA_ERROR::DISALLOWED, STR_CANT_POSITION_THIS_HERE, STR_CAN_ONLY_BUILD_THIS_ON_LAND);
return std::make_unique<SmallSceneryPlaceActionResult>(GA_ERROR::DISALLOWED, STR_CAN_ONLY_BUILD_THIS_ON_LAND);
}
}
@@ -252,10 +276,11 @@ public:
_loc.x, _loc.y, zLow, zHigh, &map_place_scenery_clear_func, quarterTile, GetFlags(), &clearCost,
CREATE_CROSSING_MODE_NONE))
{
return MakeResult(GA_ERROR::DISALLOWED, STR_CANT_POSITION_THIS_HERE, gGameCommandErrorText, gCommonFormatArgs);
return std::make_unique<SmallSceneryPlaceActionResult>(
GA_ERROR::DISALLOWED, gGameCommandErrorText, gCommonFormatArgs);
}
gSceneryGroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND);
res->GroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND);
res->ExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING;
res->Cost = (sceneryEntry->small_scenery.price * 10) + clearCost;
@@ -276,7 +301,7 @@ public:
{
baseHeight >>= 16;
}
auto res = MakeResult();
auto res = std::make_unique<SmallSceneryPlaceActionResult>();
res->Position.x = _loc.x + 16;
res->Position.y = _loc.y + 16;
res->Position.z = baseHeight;
@@ -289,7 +314,7 @@ public:
rct_scenery_entry* sceneryEntry = get_small_scenery_entry(_sceneryType);
if (sceneryEntry == nullptr)
{
return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE);
return std::make_unique<SmallSceneryPlaceActionResult>(GA_ERROR::INVALID_PARAMETERS);
}
auto quadrant = _quadrant;
@@ -383,10 +408,11 @@ public:
_loc.x, _loc.y, zLow, zHigh, &map_place_scenery_clear_func, quarterTile, GetFlags() | GAME_COMMAND_FLAG_APPLY,
&clearCost, CREATE_CROSSING_MODE_NONE))
{
return MakeResult(GA_ERROR::DISALLOWED, STR_CANT_POSITION_THIS_HERE, gGameCommandErrorText, gCommonFormatArgs);
return std::make_unique<SmallSceneryPlaceActionResult>(
GA_ERROR::DISALLOWED, gGameCommandErrorText, gCommonFormatArgs);
}
gSceneryGroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND);
res->GroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND);
res->ExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING;
res->Cost = (sceneryEntry->small_scenery.price * 10) + clearCost;

View File

@@ -63,8 +63,6 @@ int16_t gSceneryShiftPressZOffset;
int16_t gSceneryCtrlPressed;
int16_t gSceneryCtrlPressZ;
uint8_t gSceneryGroundFlags;
money32 gClearSceneryCost;
// rct2: 0x009A3E74

View File

@@ -279,8 +279,6 @@ extern int16_t gSceneryShiftPressZOffset;
extern int16_t gSceneryCtrlPressed;
extern int16_t gSceneryCtrlPressZ;
extern uint8_t gSceneryGroundFlags;
extern const LocationXY8 ScenerySubTileOffsets[];
extern money32 gClearSceneryCost;