OpenRCT2/src/openrct2/actions/MazePlaceTrackAction.cpp

192 lines
6.0 KiB
C++

/*****************************************************************************
* Copyright (c) 2014-2020 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 "MazePlaceTrackAction.h"
#include "../management/Finance.h"
#include "../ride/RideData.h"
#include "../ride/TrackData.h"
void MazePlaceTrackAction::AcceptParameters(GameActionParameterVisitor& visitor)
{
visitor.Visit(_loc);
visitor.Visit("ride", _rideIndex);
visitor.Visit("mazeEntry", _mazeEntry);
}
void MazePlaceTrackAction::Serialise(DataSerialiser& stream)
{
GameAction::Serialise(stream);
stream << DS_TAG(_loc) << DS_TAG(_rideIndex) << DS_TAG(_mazeEntry);
}
GameActions::Result::Ptr MazePlaceTrackAction::Query() const
{
auto res = std::make_unique<GameActions::Result>();
res->Position = _loc + CoordsXYZ{ 8, 8, 0 };
res->Expenditure = ExpenditureType::RideConstruction;
res->ErrorTitle = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE;
if (!map_check_free_elements_and_reorganise(1))
{
res->Error = GameActions::Status::NoFreeElements;
res->ErrorMessage = STR_TILE_ELEMENT_LIMIT_REACHED;
return res;
}
if ((_loc.z & 0xF) != 0)
{
res->Error = GameActions::Status::Unknown;
res->ErrorMessage = STR_CONSTRUCTION_ERR_UNKNOWN;
return res;
}
if (!LocationValid(_loc) || (!map_is_location_owned(_loc) && !gCheatsSandboxMode))
{
res->Error = GameActions::Status::NotOwned;
res->ErrorMessage = STR_LAND_NOT_OWNED_BY_PARK;
return res;
}
auto surfaceElement = map_get_surface_element_at(_loc);
if (surfaceElement == nullptr)
{
res->Error = GameActions::Status::Unknown;
res->ErrorMessage = STR_INVALID_SELECTION_OF_OBJECTS;
return res;
}
auto baseHeight = _loc.z;
auto clearanceHeight = _loc.z + MAZE_CLEARANCE_HEIGHT;
auto heightDifference = baseHeight - surfaceElement->GetBaseZ();
if (heightDifference >= 0 && !gCheatsDisableSupportLimits)
{
heightDifference /= COORDS_Z_PER_TINY_Z;
if (heightDifference > RideTypeDescriptors[RIDE_TYPE_MAZE].Heights.MaxHeight)
{
res->Error = GameActions::Status::TooHigh;
res->ErrorMessage = STR_TOO_HIGH_FOR_SUPPORTS;
return res;
}
}
money32 clearCost = 0;
if (!map_can_construct_with_clear_at(
{ _loc.ToTileStart(), baseHeight, clearanceHeight }, &map_place_non_scenery_clear_func, { 0b1111, 0 }, GetFlags(),
&clearCost, CREATE_CROSSING_MODE_NONE))
{
return MakeResult(
GameActions::Status::NoClearance, res->ErrorTitle.GetStringId(), gGameCommandErrorText, gCommonFormatArgs);
}
if (gMapGroundFlags & ELEMENT_IS_UNDERWATER)
{
res->Error = GameActions::Status::NoClearance;
res->ErrorMessage = STR_RIDE_CANT_BUILD_THIS_UNDERWATER;
return res;
}
if (gMapGroundFlags & ELEMENT_IS_UNDERGROUND)
{
res->Error = GameActions::Status::NoClearance;
res->ErrorMessage = STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND;
return res;
}
auto ride = get_ride(_rideIndex);
if (ride == nullptr || ride->type == RIDE_TYPE_NULL)
{
res->Error = GameActions::Status::InvalidParameters;
res->ErrorMessage = STR_INVALID_SELECTION_OF_OBJECTS;
return res;
}
money32 price = (((RideTypeDescriptors[ride->type].BuildCosts.TrackPrice * TrackPricing[TrackElemType::Maze]) >> 16));
res->Cost = clearCost + price / 2 * 10;
return res;
}
GameActions::Result::Ptr MazePlaceTrackAction::Execute() const
{
auto res = std::make_unique<GameActions::Result>();
res->Position = _loc + CoordsXYZ{ 8, 8, 0 };
res->Expenditure = ExpenditureType::RideConstruction;
res->ErrorTitle = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE;
auto ride = get_ride(_rideIndex);
if (ride == nullptr)
{
res->Error = GameActions::Status::InvalidParameters;
res->ErrorMessage = STR_NONE;
return res;
}
if (!map_check_free_elements_and_reorganise(1))
{
res->Error = GameActions::Status::NoFreeElements;
res->ErrorMessage = STR_NONE;
return res;
}
uint32_t flags = GetFlags();
if (!(flags & GAME_COMMAND_FLAG_GHOST))
{
footpath_remove_litter(_loc);
wall_remove_at({ _loc.ToTileStart(), _loc.z, _loc.z + 32 });
}
auto baseHeight = _loc.z;
auto clearanceHeight = _loc.z + MAZE_CLEARANCE_HEIGHT;
money32 clearCost = 0;
if (!map_can_construct_with_clear_at(
{ _loc.ToTileStart(), baseHeight, clearanceHeight }, &map_place_non_scenery_clear_func, { 0b1111, 0 },
GetFlags() | GAME_COMMAND_FLAG_APPLY, &clearCost, CREATE_CROSSING_MODE_NONE))
{
return MakeResult(
GameActions::Status::NoClearance, res->ErrorTitle.GetStringId(), gGameCommandErrorText, gCommonFormatArgs);
}
money32 price = (((RideTypeDescriptors[ride->type].BuildCosts.TrackPrice * TrackPricing[TrackElemType::Maze]) >> 16));
res->Cost = clearCost + price / 2 * 10;
auto startLoc = _loc.ToTileStart();
auto tileElement = tile_element_insert(_loc, 0b1111);
assert(tileElement != nullptr);
tileElement->SetClearanceZ(clearanceHeight);
tileElement->SetType(TILE_ELEMENT_TYPE_TRACK);
tileElement->AsTrack()->SetTrackType(TrackElemType::Maze);
tileElement->AsTrack()->SetRideIndex(_rideIndex);
tileElement->AsTrack()->SetMazeEntry(_mazeEntry);
if (flags & GAME_COMMAND_FLAG_GHOST)
{
tileElement->SetGhost(true);
}
map_invalidate_tile_full(startLoc);
ride->maze_tiles++;
ride->stations[0].SetBaseZ(tileElement->GetBaseZ());
ride->stations[0].Start = { 0, 0 };
if (ride->maze_tiles == 1)
{
ride->overall_view = startLoc;
}
return res;
}