OpenRCT2/src/openrct2/actions/WaterSetHeightAction.cpp

166 lines
4.7 KiB
C++

/*****************************************************************************
* Copyright (c) 2014-2024 OpenRCT2 developers
*
* For a complete list of all authors, please refer to contributors.md
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include "WaterSetHeightAction.h"
#include "../GameState.h"
#include "../OpenRCT2.h"
#include "../management/Finance.h"
#include "../world/ConstructionClearance.h"
#include "../world/Park.h"
#include "../world/Surface.h"
using namespace OpenRCT2;
WaterSetHeightAction::WaterSetHeightAction(const CoordsXY& coords, uint8_t height)
: _coords(coords)
, _height(height)
{
}
void WaterSetHeightAction::AcceptParameters(GameActionParameterVisitor& visitor)
{
visitor.Visit(_coords);
visitor.Visit("height", _height);
}
uint16_t WaterSetHeightAction::GetActionFlags() const
{
return GameAction::GetActionFlags();
}
void WaterSetHeightAction::Serialise(DataSerialiser& stream)
{
GameAction::Serialise(stream);
stream << DS_TAG(_coords) << DS_TAG(_height);
}
GameActions::Result WaterSetHeightAction::Query() const
{
auto res = GameActions::Result();
res.Expenditure = ExpenditureType::Landscaping;
res.Position = { _coords, _height * COORDS_Z_STEP };
if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !GetGameState().Cheats.SandboxMode
&& GetGameState().Park.Flags & PARK_FLAGS_FORBID_LANDSCAPE_CHANGES)
{
return GameActions::Result(GameActions::Status::Disallowed, STR_NONE, STR_FORBIDDEN_BY_THE_LOCAL_AUTHORITY);
}
StringId errorMsg = CheckParameters();
if (errorMsg != STR_NONE)
{
return GameActions::Result(GameActions::Status::InvalidParameters, STR_NONE, errorMsg);
}
if (!LocationValid(_coords))
{
return GameActions::Result(GameActions::Status::NotOwned, STR_NONE, STR_LAND_NOT_OWNED_BY_PARK);
}
if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !GetGameState().Cheats.SandboxMode)
{
if (!MapIsLocationInPark(_coords))
{
return GameActions::Result(GameActions::Status::Disallowed, STR_NONE, STR_LAND_NOT_OWNED_BY_PARK);
}
}
SurfaceElement* surfaceElement = MapGetSurfaceElementAt(_coords);
if (surfaceElement == nullptr)
{
LOG_ERROR("No surface element at: x %u, y %u", _coords.x, _coords.y);
return GameActions::Result(
GameActions::Status::InvalidParameters, STR_ERR_INVALID_PARAMETER, STR_ERR_SURFACE_ELEMENT_NOT_FOUND);
}
int32_t zHigh = surfaceElement->GetBaseZ();
int32_t zLow = _height * COORDS_Z_STEP;
if (surfaceElement->GetWaterHeight() > 0)
{
zHigh = surfaceElement->GetWaterHeight();
}
if (zLow > zHigh)
{
int32_t temp = zHigh;
zHigh = zLow;
zLow = temp;
}
if (auto res2 = MapCanConstructAt({ _coords, zLow, zHigh }, { 0b1111, 0b1111 }); res2.Error != GameActions::Status::Ok)
{
return res2;
}
if (surfaceElement->HasTrackThatNeedsWater())
{
return GameActions::Result(
GameActions::Status::Disallowed, STR_ERR_INVALID_PARAMETER, STR_ERR_TRACK_ON_THIS_TILE_NEEDS_WATER);
}
res.Cost = 250;
return res;
}
GameActions::Result WaterSetHeightAction::Execute() const
{
auto res = GameActions::Result();
res.Expenditure = ExpenditureType::Landscaping;
res.Position = { _coords, _height * COORDS_Z_STEP };
int32_t surfaceHeight = TileElementHeight(_coords);
FootpathRemoveLitter({ _coords, surfaceHeight });
if (!GetGameState().Cheats.DisableClearanceChecks)
WallRemoveAtZ({ _coords, surfaceHeight });
SurfaceElement* surfaceElement = MapGetSurfaceElementAt(_coords);
if (surfaceElement == nullptr)
{
LOG_ERROR("No surface element at: x %u, y %u", _coords.x, _coords.y);
return GameActions::Result(
GameActions::Status::InvalidParameters, STR_ERR_INVALID_PARAMETER, STR_ERR_SURFACE_ELEMENT_NOT_FOUND);
}
if (_height > surfaceElement->BaseHeight)
{
surfaceElement->SetWaterHeight(_height * COORDS_Z_STEP);
}
else
{
surfaceElement->SetWaterHeight(0);
}
MapInvalidateTileFull(_coords);
res.Cost = 250;
return res;
}
StringId WaterSetHeightAction::CheckParameters() const
{
auto mapSizeMax = GetMapSizeMaxXY();
if (_coords.x > mapSizeMax.x || _coords.y > mapSizeMax.y)
{
return STR_OFF_EDGE_OF_MAP;
}
if (_height < kMinimumWaterHeight)
{
return STR_TOO_LOW;
}
if (_height > kMaximumWaterHeight)
{
return STR_TOO_HIGH;
}
return STR_NONE;
}