mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2025-12-24 00:03:11 +01:00
Refactor. Split out into multiple functions.
This commit is contained in:
@@ -10,9 +10,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Context.h"
|
||||
#include "../OpenRCT2.h"
|
||||
#include "../interface/Window.h"
|
||||
#include "../localisation/Localisation.h"
|
||||
#include "../localisation/StringIds.h"
|
||||
#include "../management/Finance.h"
|
||||
#include "../ride/RideData.h"
|
||||
#include "../windows/Intent.h"
|
||||
#include "../world/Park.h"
|
||||
@@ -75,29 +77,10 @@ public:
|
||||
return std::make_unique<GameActionResult>(GA_ERROR::DISALLOWED, STR_FORBIDDEN_BY_THE_LOCAL_AUTHORITY);
|
||||
}
|
||||
|
||||
if (_coords.x > gMapSizeMaxXY || _coords.y > gMapSizeMaxXY)
|
||||
rct_string_id errorTitle = CheckParameters();
|
||||
if (errorTitle != STR_NONE)
|
||||
{
|
||||
return std::make_unique<GameActionResult>(GA_ERROR::INVALID_PARAMETERS, STR_OFF_EDGE_OF_MAP);
|
||||
}
|
||||
|
||||
if (_height < MINIMUM_LAND_HEIGHT)
|
||||
{
|
||||
return std::make_unique<GameActionResult>(GA_ERROR::INVALID_PARAMETERS, STR_TOO_LOW);
|
||||
}
|
||||
|
||||
// Divide by 2 and subtract 7 to get the in-game units.
|
||||
if (_height > MAXIMUM_LAND_HEIGHT)
|
||||
{
|
||||
return std::make_unique<GameActionResult>(GA_ERROR::INVALID_PARAMETERS, STR_TOO_HIGH);
|
||||
}
|
||||
else if (_height > MAXIMUM_LAND_HEIGHT - 2 && (_style & 0x1F) != 0)
|
||||
{
|
||||
return std::make_unique<GameActionResult>(GA_ERROR::INVALID_PARAMETERS, STR_TOO_HIGH);
|
||||
}
|
||||
|
||||
if (_height == MAXIMUM_LAND_HEIGHT - 2 && (_style & 0x10))
|
||||
{
|
||||
return std::make_unique<GameActionResult>(GA_ERROR::INVALID_PARAMETERS, STR_TOO_HIGH);
|
||||
return std::make_unique<GameActionResult>(GA_ERROR::DISALLOWED, errorTitle);
|
||||
}
|
||||
|
||||
if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode)
|
||||
@@ -108,146 +91,67 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
money32 cost = MONEY(0, 0);
|
||||
|
||||
money32 cost{};
|
||||
if (!gCheatsDisableClearanceChecks)
|
||||
{
|
||||
// Check for obstructing scenery
|
||||
TileElement* tileElement = map_get_first_element_at(_coords.x / 32, _coords.y / 32);
|
||||
do
|
||||
if (gParkFlags & PARK_FLAGS_FORBID_TREE_REMOVAL)
|
||||
{
|
||||
if (tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY)
|
||||
continue;
|
||||
if (_height > tileElement->clearance_height)
|
||||
continue;
|
||||
if (_height + 4 < tileElement->base_height)
|
||||
continue;
|
||||
rct_scenery_entry* sceneryEntry = tileElement->AsSmallScenery()->GetEntry();
|
||||
if (sceneryEntry->small_scenery.height > 64 && gParkFlags & PARK_FLAGS_FORBID_TREE_REMOVAL)
|
||||
// Check for obstructing large trees
|
||||
TileElement* tileElement = CheckTallTreeObstructions();
|
||||
if (tileElement != nullptr)
|
||||
{
|
||||
map_obstruction_set_error_text(tileElement);
|
||||
return std::make_unique<GameActionResult>(GA_ERROR::DISALLOWED, gGameCommandErrorText);
|
||||
}
|
||||
cost += MONEY(sceneryEntry->small_scenery.removal_price, 0);
|
||||
} while (!(tileElement++)->IsLastForTile());
|
||||
}
|
||||
cost = GetSmallSceneryRemovalCost();
|
||||
}
|
||||
|
||||
// Check for ride support limits
|
||||
if (!gCheatsDisableSupportLimits)
|
||||
{
|
||||
TileElement* tileElement = map_get_first_element_at(_coords.x / 32, _coords.y / 32);
|
||||
do
|
||||
errorTitle = CheckRideSupports();
|
||||
if (errorTitle != STR_NONE)
|
||||
{
|
||||
if (tileElement->GetType() == TILE_ELEMENT_TYPE_TRACK)
|
||||
{
|
||||
ride_id_t rideIndex = tileElement->AsTrack()->GetRideIndex();
|
||||
Ride* ride = get_ride(rideIndex);
|
||||
if (ride != nullptr)
|
||||
{
|
||||
rct_ride_entry* rideEntry = get_ride_entry_by_ride(ride);
|
||||
if (rideEntry != nullptr)
|
||||
{
|
||||
int32_t maxHeight = rideEntry->max_height;
|
||||
if (maxHeight == 0)
|
||||
{
|
||||
maxHeight = RideData5[get_ride(rideIndex)->type].max_height;
|
||||
}
|
||||
int32_t zDelta = tileElement->clearance_height - _height;
|
||||
if (zDelta >= 0 && zDelta / 2 > maxHeight)
|
||||
{
|
||||
return std::make_unique<GameActionResult>(GA_ERROR::DISALLOWED, STR_SUPPORTS_CANT_BE_EXTENDED);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (!(tileElement++)->IsLastForTile());
|
||||
return std::make_unique<GameActionResult>(GA_ERROR::DISALLOWED, errorTitle);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t zCorner = _height; // z position of highest corner of tile
|
||||
TileElement* surfaceElement = map_get_surface_element_at(_coords);
|
||||
if (surfaceElement->AsSurface()->HasTrackThatNeedsWater())
|
||||
TileElement* tileElement = CheckFloatingStructures(surfaceElement, _height);
|
||||
if (tileElement != nullptr)
|
||||
{
|
||||
uint32_t waterHeight = surfaceElement->AsSurface()->GetWaterHeight();
|
||||
if (waterHeight != 0)
|
||||
{
|
||||
if (_style & 0x1F)
|
||||
{
|
||||
zCorner += 2;
|
||||
if (_style & 0x10)
|
||||
{
|
||||
zCorner += 2;
|
||||
}
|
||||
}
|
||||
if (zCorner > waterHeight * 2 - 2)
|
||||
{
|
||||
surfaceElement++;
|
||||
map_obstruction_set_error_text(surfaceElement);
|
||||
return std::make_unique<GameActionResult>(GA_ERROR::DISALLOWED, gGameCommandErrorText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
zCorner = _height;
|
||||
if (_style & 0xF)
|
||||
{
|
||||
zCorner += 2;
|
||||
if (_style & 0x10)
|
||||
{
|
||||
zCorner += 2;
|
||||
}
|
||||
map_obstruction_set_error_text(tileElement);
|
||||
return std::make_unique<GameActionResult>(GA_ERROR::DISALLOWED, gGameCommandErrorText);
|
||||
}
|
||||
|
||||
if (!gCheatsDisableClearanceChecks)
|
||||
{
|
||||
uint8_t zCorner = _height;
|
||||
if (_style & TILE_ELEMENT_SURFACE_RAISED_CORNERS_MASK)
|
||||
{
|
||||
zCorner += 2;
|
||||
if (_style & TILE_ELEMENT_SURFACE_DIAGONAL_FLAG)
|
||||
{
|
||||
zCorner += 2;
|
||||
}
|
||||
}
|
||||
if (!map_can_construct_with_clear_at(
|
||||
_coords.x, _coords.y, _height, zCorner, &map_set_land_height_clear_func, 0xF, 0, nullptr,
|
||||
CREATE_CROSSING_MODE_NONE))
|
||||
{
|
||||
return std::make_unique<GameActionResult>(GA_ERROR::DISALLOWED, STR_NONE);
|
||||
return std::make_unique<GameActionResult>(GA_ERROR::DISALLOWED, gGameCommandErrorText);
|
||||
}
|
||||
|
||||
tileElement = CheckUnremovableObstructions(surfaceElement, zCorner);
|
||||
if (tileElement != nullptr)
|
||||
{
|
||||
map_obstruction_set_error_text(tileElement);
|
||||
return std::make_unique<GameActionResult>(GA_ERROR::DISALLOWED, gGameCommandErrorText);
|
||||
}
|
||||
}
|
||||
|
||||
if (!gCheatsDisableClearanceChecks)
|
||||
{
|
||||
TileElement* tileElement = map_get_first_element_at(_coords.x / 32, _coords.y / 32);
|
||||
do
|
||||
{
|
||||
int32_t elementType = tileElement->GetType();
|
||||
|
||||
if (elementType == TILE_ELEMENT_TYPE_WALL)
|
||||
continue;
|
||||
if (elementType == TILE_ELEMENT_TYPE_SMALL_SCENERY)
|
||||
continue;
|
||||
if (tileElement->flags & 0x10)
|
||||
continue;
|
||||
if (tileElement == surfaceElement)
|
||||
continue;
|
||||
if (tileElement > surfaceElement)
|
||||
{
|
||||
if (zCorner > tileElement->base_height)
|
||||
{
|
||||
map_obstruction_set_error_text(tileElement);
|
||||
return std::make_unique<GameActionResult>(GA_ERROR::DISALLOWED, gGameCommandErrorText);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (_height < tileElement->clearance_height)
|
||||
{
|
||||
map_obstruction_set_error_text(tileElement);
|
||||
return std::make_unique<GameActionResult>(GA_ERROR::DISALLOWED, gGameCommandErrorText);
|
||||
}
|
||||
} while (!(tileElement++)->IsLastForTile());
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < 4; i += 1)
|
||||
{
|
||||
int32_t cornerHeight = tile_element_get_corner_height(surfaceElement, i);
|
||||
cornerHeight -= map_get_corner_height(_height, _style & TILE_ELEMENT_SURFACE_SLOPE_MASK, i);
|
||||
cost += MONEY(abs(cornerHeight) * 5 / 2, 0);
|
||||
}
|
||||
|
||||
auto res = std::make_unique<GameActionResult>();
|
||||
res->Cost = cost;
|
||||
res->Cost = cost + GetSurfaceHeightChangeCost(surfaceElement);
|
||||
res->ExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING;
|
||||
return res;
|
||||
}
|
||||
@@ -255,81 +159,227 @@ public:
|
||||
GameActionResult::Ptr Execute() const override
|
||||
{
|
||||
money32 cost = MONEY(0, 0);
|
||||
footpath_remove_litter(_coords.x, _coords.y, tile_element_height(_coords.x, _coords.y));
|
||||
if (!gCheatsDisableClearanceChecks)
|
||||
wall_remove_at(_coords.x, _coords.y, _height * 8 - 16, _height * 8 + 32);
|
||||
auto surfaceHeight = tile_element_height(_coords.x, _coords.y) & 0xFFFF;
|
||||
footpath_remove_litter(_coords.x, _coords.y, surfaceHeight);
|
||||
|
||||
if (!gCheatsDisableClearanceChecks)
|
||||
{
|
||||
TileElement* tileElement = map_get_first_element_at(_coords.x / 32, _coords.y / 32);
|
||||
do
|
||||
{
|
||||
if (tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY)
|
||||
continue;
|
||||
if (_height > tileElement->clearance_height)
|
||||
continue;
|
||||
if (_height + 4 < tileElement->base_height)
|
||||
continue;
|
||||
rct_scenery_entry* sceneryEntry = tileElement->AsSmallScenery()->GetEntry();
|
||||
if (sceneryEntry->small_scenery.height > 64 && gParkFlags & PARK_FLAGS_FORBID_TREE_REMOVAL)
|
||||
{
|
||||
map_obstruction_set_error_text(tileElement);
|
||||
return std::make_unique<GameActionResult>(GA_ERROR::DISALLOWED, gGameCommandErrorText);
|
||||
}
|
||||
cost += MONEY(sceneryEntry->small_scenery.removal_price, 0);
|
||||
tile_element_remove(tileElement--);
|
||||
} while (!(tileElement++)->IsLastForTile());
|
||||
wall_remove_at(_coords.x, _coords.y, _height * 8 - 16, _height * 8 + 32);
|
||||
cost += GetSmallSceneryRemovalCost();
|
||||
SmallSceneryRemoval();
|
||||
}
|
||||
|
||||
uint8_t zCorner = _height; // z position of highest corner of tile
|
||||
TileElement* surfaceElement = map_get_surface_element_at(_coords);
|
||||
cost += GetSurfaceHeightChangeCost(surfaceElement);
|
||||
SetSurfaceHeight(surfaceElement);
|
||||
|
||||
LocationXYZ16 coord;
|
||||
coord.x = _coords.x + 16;
|
||||
coord.y = _coords.y + 16;
|
||||
coord.z = surfaceHeight;
|
||||
network_set_player_last_action_coord(network_get_player_index(game_command_playerid), coord);
|
||||
|
||||
auto res = std::make_unique<GameActionResult>();
|
||||
res->Position = { _coords.x + 16, _coords.y + 16, surfaceHeight };
|
||||
res->Cost = cost;
|
||||
res->ExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING;
|
||||
return res;
|
||||
}
|
||||
|
||||
private:
|
||||
rct_string_id CheckParameters() const
|
||||
{
|
||||
if (_coords.x > gMapSizeMaxXY || _coords.y > gMapSizeMaxXY)
|
||||
{
|
||||
return STR_OFF_EDGE_OF_MAP;
|
||||
}
|
||||
|
||||
if (_height < MINIMUM_LAND_HEIGHT)
|
||||
{
|
||||
return STR_TOO_LOW;
|
||||
}
|
||||
|
||||
// Divide by 2 and subtract 7 to get the in-game units.
|
||||
if (_height > MAXIMUM_LAND_HEIGHT)
|
||||
{
|
||||
return STR_TOO_HIGH;
|
||||
}
|
||||
else if (_height > MAXIMUM_LAND_HEIGHT - 2 && (_style & TILE_ELEMENT_SURFACE_SLOPE_MASK) != 0)
|
||||
{
|
||||
return STR_TOO_HIGH;
|
||||
}
|
||||
|
||||
if (_height == MAXIMUM_LAND_HEIGHT - 2 && (_style & TILE_ELEMENT_SURFACE_DIAGONAL_FLAG))
|
||||
{
|
||||
return STR_TOO_HIGH;
|
||||
}
|
||||
|
||||
return STR_NONE;
|
||||
}
|
||||
|
||||
TileElement* CheckTallTreeObstructions() const
|
||||
{
|
||||
TileElement* tileElement = map_get_first_element_at(_coords.x / 32, _coords.y / 32);
|
||||
do
|
||||
{
|
||||
if (tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY)
|
||||
continue;
|
||||
if (_height > tileElement->clearance_height)
|
||||
continue;
|
||||
if (_height + 4 < tileElement->base_height)
|
||||
continue;
|
||||
rct_scenery_entry* sceneryEntry = tileElement->AsSmallScenery()->GetEntry();
|
||||
if (sceneryEntry->small_scenery.height > 64)
|
||||
{
|
||||
return tileElement;
|
||||
}
|
||||
} while (!(tileElement++)->IsLastForTile());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
money32 GetSmallSceneryRemovalCost() const
|
||||
{
|
||||
money32 cost{ 0 };
|
||||
TileElement* tileElement = map_get_first_element_at(_coords.x / 32, _coords.y / 32);
|
||||
do
|
||||
{
|
||||
if (tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY)
|
||||
continue;
|
||||
if (_height > tileElement->clearance_height)
|
||||
continue;
|
||||
if (_height + 4 < tileElement->base_height)
|
||||
continue;
|
||||
rct_scenery_entry* sceneryEntry = tileElement->AsSmallScenery()->GetEntry();
|
||||
cost += MONEY(sceneryEntry->small_scenery.removal_price, 0);
|
||||
} while (!(tileElement++)->IsLastForTile());
|
||||
return cost;
|
||||
}
|
||||
|
||||
void SmallSceneryRemoval() const
|
||||
{
|
||||
TileElement* tileElement = map_get_first_element_at(_coords.x / 32, _coords.y / 32);
|
||||
do
|
||||
{
|
||||
if (tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY)
|
||||
continue;
|
||||
if (_height > tileElement->clearance_height)
|
||||
continue;
|
||||
if (_height + 4 < tileElement->base_height)
|
||||
continue;
|
||||
tile_element_remove(tileElement--);
|
||||
} while (!(tileElement++)->IsLastForTile());
|
||||
}
|
||||
|
||||
rct_string_id CheckRideSupports() const
|
||||
{
|
||||
TileElement* tileElement = map_get_first_element_at(_coords.x / 32, _coords.y / 32);
|
||||
do
|
||||
{
|
||||
if (tileElement->GetType() == TILE_ELEMENT_TYPE_TRACK)
|
||||
{
|
||||
ride_id_t rideIndex = tileElement->AsTrack()->GetRideIndex();
|
||||
Ride* ride = get_ride(rideIndex);
|
||||
if (ride != nullptr)
|
||||
{
|
||||
rct_ride_entry* rideEntry = get_ride_entry_by_ride(ride);
|
||||
if (rideEntry != nullptr)
|
||||
{
|
||||
int32_t maxHeight = rideEntry->max_height;
|
||||
if (maxHeight == 0)
|
||||
{
|
||||
maxHeight = RideData5[get_ride(rideIndex)->type].max_height;
|
||||
}
|
||||
int32_t zDelta = tileElement->clearance_height - _height;
|
||||
if (zDelta >= 0 && zDelta / 2 > maxHeight)
|
||||
{
|
||||
return STR_SUPPORTS_CANT_BE_EXTENDED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (!(tileElement++)->IsLastForTile());
|
||||
return STR_NONE;
|
||||
}
|
||||
|
||||
TileElement* CheckFloatingStructures(TileElement * surfaceElement, uint8_t zCorner) const
|
||||
{
|
||||
if (surfaceElement->AsSurface()->HasTrackThatNeedsWater())
|
||||
{
|
||||
uint32_t waterHeight = surfaceElement->AsSurface()->GetWaterHeight();
|
||||
if (waterHeight != 0)
|
||||
{
|
||||
if (_style & 0x1F)
|
||||
if (_style & TILE_ELEMENT_SURFACE_SLOPE_MASK)
|
||||
{
|
||||
zCorner += 2;
|
||||
if (_style & 0x10)
|
||||
if (_style & TILE_ELEMENT_SURFACE_DIAGONAL_FLAG)
|
||||
{
|
||||
zCorner += 2;
|
||||
}
|
||||
}
|
||||
if (zCorner > waterHeight * 2 - 2)
|
||||
{
|
||||
surfaceElement++;
|
||||
map_obstruction_set_error_text(surfaceElement);
|
||||
return std::make_unique<GameActionResult>(GA_ERROR::DISALLOWED, gGameCommandErrorText);
|
||||
return ++surfaceElement;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TileElement* CheckUnremovableObstructions(TileElement * surfaceElement, uint8_t zCorner) const
|
||||
{
|
||||
TileElement* tileElement = map_get_first_element_at(_coords.x / 32, _coords.y / 32);
|
||||
do
|
||||
{
|
||||
int32_t elementType = tileElement->GetType();
|
||||
|
||||
// Wall's and Small Scenery are removed and therefore do not need checked
|
||||
if (elementType == TILE_ELEMENT_TYPE_WALL)
|
||||
continue;
|
||||
if (elementType == TILE_ELEMENT_TYPE_SMALL_SCENERY)
|
||||
continue;
|
||||
if (tileElement->IsGhost())
|
||||
continue;
|
||||
if (tileElement == surfaceElement)
|
||||
continue;
|
||||
if (tileElement > surfaceElement)
|
||||
{
|
||||
if (zCorner > tileElement->base_height)
|
||||
{
|
||||
return tileElement;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (_height < tileElement->clearance_height)
|
||||
{
|
||||
return tileElement;
|
||||
}
|
||||
} while (!(tileElement++)->IsLastForTile());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
money32 GetSurfaceHeightChangeCost(TileElement * surfaceElement) const
|
||||
{
|
||||
money32 cost{ 0 };
|
||||
for (int32_t i = 0; i < 4; i += 1)
|
||||
{
|
||||
int32_t cornerHeight = tile_element_get_corner_height(surfaceElement, i);
|
||||
cornerHeight -= map_get_corner_height(_height, _style & TILE_ELEMENT_SURFACE_SLOPE_MASK, i);
|
||||
cost += MONEY(abs(cornerHeight) * 5 / 2, 0);
|
||||
}
|
||||
return cost;
|
||||
}
|
||||
|
||||
LocationXYZ16 coord;
|
||||
coord.x = _coords.x + 16;
|
||||
coord.y = _coords.y + 16;
|
||||
coord.z = tile_element_height(_coords.x, _coords.y);
|
||||
network_set_player_last_action_coord(network_get_player_index(game_command_playerid), coord);
|
||||
|
||||
surfaceElement = map_get_surface_element_at(_coords);
|
||||
void SetSurfaceHeight(TileElement * surfaceElement) const
|
||||
{
|
||||
surfaceElement->base_height = _height;
|
||||
surfaceElement->clearance_height = _height;
|
||||
surfaceElement->AsSurface()->SetSlope(_style);
|
||||
int32_t waterHeight = surfaceElement->AsSurface()->GetWaterHeight();
|
||||
if (waterHeight != 0 && waterHeight <= _height / 2)
|
||||
{
|
||||
surfaceElement->AsSurface()->SetWaterHeight(0);
|
||||
map_invalidate_tile_full(_coords.x, _coords.y);
|
||||
}
|
||||
|
||||
auto res = std::make_unique<GameActionResult>();
|
||||
res->Cost = cost;
|
||||
res->ExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING;
|
||||
return res;
|
||||
map_invalidate_tile_full(_coords.x, _coords.y);
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user