2017-04-15 12:07:26 +02:00
|
|
|
#pragma region Copyright (c) 2014-2017 OpenRCT2 Developers
|
|
|
|
/*****************************************************************************
|
|
|
|
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
|
|
|
|
*
|
|
|
|
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
|
|
|
|
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
|
|
|
|
*
|
|
|
|
* OpenRCT2 is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* A full copy of the GNU General Public License can be found in licence.txt
|
|
|
|
*****************************************************************************/
|
|
|
|
#pragma endregion
|
|
|
|
|
2017-09-30 23:57:38 +02:00
|
|
|
#pragma once
|
|
|
|
|
2017-04-15 12:07:26 +02:00
|
|
|
#include "../core/MemoryStream.h"
|
2018-01-06 18:32:25 +01:00
|
|
|
#include "../localisation/StringIds.h"
|
2017-08-10 19:22:45 +02:00
|
|
|
#include "../OpenRCT2.h"
|
2017-04-15 12:07:26 +02:00
|
|
|
#include "GameAction.h"
|
|
|
|
|
2017-12-13 13:02:24 +01:00
|
|
|
#include "../Cheats.h"
|
2017-12-14 10:34:12 +01:00
|
|
|
#include "../world/Entrance.h"
|
2017-12-31 21:40:00 +01:00
|
|
|
#include "../world/Park.h"
|
2017-09-30 23:57:38 +02:00
|
|
|
#include "../world/footpath.h"
|
2017-04-15 12:07:26 +02:00
|
|
|
|
2017-10-18 20:57:36 +02:00
|
|
|
struct PlaceParkEntranceAction : public GameActionBase<GAME_COMMAND_PLACE_PARK_ENTRANCE, GameActionResult>
|
2017-04-15 12:07:26 +02:00
|
|
|
{
|
2017-09-04 21:37:58 +02:00
|
|
|
private:
|
|
|
|
sint16 _x;
|
|
|
|
sint16 _y;
|
|
|
|
sint16 _z;
|
|
|
|
uint8 _direction;
|
|
|
|
|
2017-04-15 12:07:26 +02:00
|
|
|
public:
|
2017-09-04 21:37:58 +02:00
|
|
|
PlaceParkEntranceAction() {}
|
|
|
|
PlaceParkEntranceAction(sint16 x, sint16 y, sint16 z, sint16 direction) :
|
|
|
|
_x(x),
|
|
|
|
_y(y),
|
|
|
|
_z(z),
|
|
|
|
_direction(direction)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16 GetActionFlags() const override
|
|
|
|
{
|
|
|
|
return GameActionBase::GetActionFlags() | GA_FLAGS::EDITOR_ONLY;
|
|
|
|
}
|
2017-04-15 12:07:26 +02:00
|
|
|
|
2017-07-21 19:14:38 +02:00
|
|
|
void Serialise(DataSerialiser& stream) override
|
|
|
|
{
|
2017-07-18 16:17:47 +02:00
|
|
|
GameAction::Serialise(stream);
|
|
|
|
|
2017-09-04 21:37:58 +02:00
|
|
|
stream << _x << _y << _z << _direction;
|
2017-07-21 19:14:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
GameActionResult::Ptr Query() const override
|
|
|
|
{
|
|
|
|
if (!(gScreenFlags & SCREEN_FLAGS_EDITOR) && !gCheatsSandboxMode)
|
|
|
|
{
|
2017-10-18 20:57:36 +02:00
|
|
|
return std::make_unique<GameActionResult>(GA_ERROR::NOT_IN_EDITOR_MODE, STR_CANT_BUILD_PARK_ENTRANCE_HERE, STR_NONE);
|
2017-07-21 19:14:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
gCommandExpenditureType = RCT_EXPENDITURE_TYPE_LAND_PURCHASE;
|
|
|
|
|
2017-09-04 21:37:58 +02:00
|
|
|
gCommandPosition.x = _x;
|
|
|
|
gCommandPosition.y = _y;
|
|
|
|
gCommandPosition.z = _z * 16;
|
2017-07-21 19:14:38 +02:00
|
|
|
|
|
|
|
if (!map_check_free_elements_and_reorganise(3))
|
|
|
|
{
|
2017-10-18 20:57:36 +02:00
|
|
|
return std::make_unique<GameActionResult>(GA_ERROR::NO_FREE_ELEMENTS, STR_CANT_BUILD_PARK_ENTRANCE_HERE, STR_NONE);
|
2017-07-21 19:14:38 +02:00
|
|
|
}
|
|
|
|
|
2017-09-04 21:37:58 +02:00
|
|
|
if (_x <= 32 || _y <= 32 || _x >= (gMapSizeUnits - 32) || _y >= (gMapSizeUnits - 32))
|
2017-07-21 19:14:38 +02:00
|
|
|
{
|
2017-10-18 20:57:36 +02:00
|
|
|
return std::make_unique<GameActionResult>(GA_ERROR::INVALID_PARAMETERS, STR_CANT_BUILD_PARK_ENTRANCE_HERE, STR_TOO_CLOSE_TO_EDGE_OF_MAP);
|
2017-07-21 19:14:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
sint8 entranceNum = -1;
|
|
|
|
for (uint8 i = 0; i < MAX_PARK_ENTRANCES; ++i)
|
|
|
|
{
|
2017-10-13 22:23:07 +02:00
|
|
|
if (gParkEntrances[i].x == LOCATION_NULL)
|
2017-07-21 19:14:38 +02:00
|
|
|
{
|
|
|
|
entranceNum = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (entranceNum == -1)
|
|
|
|
{
|
2017-10-18 20:57:36 +02:00
|
|
|
return std::make_unique<GameActionResult>(GA_ERROR::INVALID_PARAMETERS, STR_CANT_BUILD_PARK_ENTRANCE_HERE, STR_ERR_TOO_MANY_PARK_ENTRANCES);
|
2017-07-21 19:14:38 +02:00
|
|
|
}
|
|
|
|
|
2017-09-04 21:37:58 +02:00
|
|
|
sint8 zLow = _z * 2;
|
2017-07-21 19:14:38 +02:00
|
|
|
sint8 zHigh = zLow + 12;
|
2017-10-13 22:23:07 +02:00
|
|
|
LocationXY16 entranceLoc = { _x, _y };
|
2017-07-21 19:14:38 +02:00
|
|
|
for (uint8 index = 0; index < 3; index++)
|
|
|
|
{
|
|
|
|
if (index == 1)
|
|
|
|
{
|
2017-09-04 21:37:58 +02:00
|
|
|
entranceLoc.x += TileDirectionDelta[(_direction - 1) & 0x3].x;
|
|
|
|
entranceLoc.y += TileDirectionDelta[(_direction - 1) & 0x3].y;
|
2017-07-21 19:14:38 +02:00
|
|
|
}
|
|
|
|
else if (index == 2)
|
|
|
|
{
|
2017-09-04 21:37:58 +02:00
|
|
|
entranceLoc.x += TileDirectionDelta[(_direction + 1) & 0x3].x * 2;
|
|
|
|
entranceLoc.y += TileDirectionDelta[(_direction + 1) & 0x3].y * 2;
|
2017-07-21 19:14:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!gCheatsDisableClearanceChecks)
|
|
|
|
{
|
|
|
|
if (!map_can_construct_at(entranceLoc.x, entranceLoc.y, zLow, zHigh, 0xF))
|
|
|
|
{
|
2017-10-18 20:57:36 +02:00
|
|
|
return std::make_unique<GameActionResult>(GA_ERROR::NO_CLEARANCE, STR_CANT_BUILD_PARK_ENTRANCE_HERE, STR_NONE);
|
2017-07-21 19:14:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that entrance element does not already exist at this location
|
2017-10-31 12:57:40 +01:00
|
|
|
rct_tile_element* entranceElement = map_get_park_entrance_element_at(entranceLoc.x, entranceLoc.y, zLow, false);
|
2017-07-21 19:14:38 +02:00
|
|
|
if (entranceElement != NULL)
|
|
|
|
{
|
2017-10-18 20:57:36 +02:00
|
|
|
return std::make_unique<GameActionResult>(GA_ERROR::ITEM_ALREADY_PLACED, STR_CANT_BUILD_PARK_ENTRANCE_HERE, STR_NONE);
|
2017-07-21 19:14:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-18 20:57:36 +02:00
|
|
|
return std::make_unique<GameActionResult>();
|
2017-07-21 19:14:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
GameActionResult::Ptr Execute() const override
|
|
|
|
{
|
2017-07-15 11:24:08 +02:00
|
|
|
uint32 flags = GetFlags();
|
|
|
|
|
2017-07-21 19:14:38 +02:00
|
|
|
gCommandExpenditureType = RCT_EXPENDITURE_TYPE_LAND_PURCHASE;
|
|
|
|
|
2017-09-04 21:37:58 +02:00
|
|
|
gCommandPosition.x = _x;
|
|
|
|
gCommandPosition.y = _y;
|
|
|
|
gCommandPosition.z = _z * 16;
|
2017-07-21 19:14:38 +02:00
|
|
|
|
|
|
|
sint8 entranceNum = -1;
|
|
|
|
for (uint8 i = 0; i < MAX_PARK_ENTRANCES; ++i)
|
|
|
|
{
|
2017-10-13 22:23:07 +02:00
|
|
|
if (gParkEntrances[i].x == LOCATION_NULL)
|
2017-07-21 19:14:38 +02:00
|
|
|
{
|
|
|
|
entranceNum = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Guard::Assert(entranceNum != -1);
|
|
|
|
|
2017-09-04 21:37:58 +02:00
|
|
|
gParkEntrances[entranceNum].x = _x;
|
|
|
|
gParkEntrances[entranceNum].y = _y;
|
|
|
|
gParkEntrances[entranceNum].z = _z * 16;
|
|
|
|
gParkEntrances[entranceNum].direction = _direction;
|
2017-07-21 19:14:38 +02:00
|
|
|
|
2017-09-04 21:37:58 +02:00
|
|
|
sint8 zLow = _z * 2;
|
2017-07-21 19:14:38 +02:00
|
|
|
sint8 zHigh = zLow + 12;
|
2017-10-13 22:23:07 +02:00
|
|
|
LocationXY16 entranceLoc = { _x, _y };
|
2017-07-21 19:14:38 +02:00
|
|
|
for (uint8 index = 0; index < 3; index++)
|
|
|
|
{
|
|
|
|
if (index == 1)
|
|
|
|
{
|
2017-09-04 21:37:58 +02:00
|
|
|
entranceLoc.x += TileDirectionDelta[(_direction - 1) & 0x3].x;
|
|
|
|
entranceLoc.y += TileDirectionDelta[(_direction - 1) & 0x3].y;
|
2017-07-21 19:14:38 +02:00
|
|
|
}
|
|
|
|
else if (index == 2)
|
|
|
|
{
|
2017-09-04 21:37:58 +02:00
|
|
|
entranceLoc.x += TileDirectionDelta[(_direction + 1) & 0x3].x * 2;
|
|
|
|
entranceLoc.y += TileDirectionDelta[(_direction + 1) & 0x3].y * 2;
|
2017-07-21 19:14:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!(flags & GAME_COMMAND_FLAG_GHOST))
|
|
|
|
{
|
2017-10-31 12:57:40 +01:00
|
|
|
rct_tile_element* surfaceElement = map_get_surface_element_at(entranceLoc.x / 32, entranceLoc.y / 32);
|
2017-07-21 19:14:38 +02:00
|
|
|
surfaceElement->properties.surface.ownership = 0;
|
|
|
|
}
|
|
|
|
|
2017-10-31 12:57:40 +01:00
|
|
|
rct_tile_element* newElement = tile_element_insert(entranceLoc.x / 32, entranceLoc.y / 32, zLow, 0xF);
|
2017-07-21 19:14:38 +02:00
|
|
|
Guard::Assert(newElement != NULL);
|
|
|
|
newElement->clearance_height = zHigh;
|
|
|
|
|
|
|
|
if (flags & GAME_COMMAND_FLAG_GHOST)
|
|
|
|
{
|
2017-10-31 12:57:40 +01:00
|
|
|
newElement->flags |= TILE_ELEMENT_FLAG_GHOST;
|
2017-07-21 19:14:38 +02:00
|
|
|
}
|
|
|
|
|
2017-10-31 12:57:40 +01:00
|
|
|
newElement->type = TILE_ELEMENT_TYPE_ENTRANCE;
|
2017-09-04 21:37:58 +02:00
|
|
|
newElement->type |= _direction;
|
2017-07-21 19:14:38 +02:00
|
|
|
newElement->properties.entrance.index = index;
|
|
|
|
newElement->properties.entrance.type = ENTRANCE_TYPE_PARK_ENTRANCE;
|
|
|
|
newElement->properties.entrance.path_type = gFootpathSelectedId;
|
|
|
|
|
|
|
|
if (!(flags & GAME_COMMAND_FLAG_GHOST))
|
|
|
|
{
|
|
|
|
footpath_connect_edges(entranceLoc.x, entranceLoc.y, newElement, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
update_park_fences(entranceLoc.x, entranceLoc.y);
|
|
|
|
update_park_fences(entranceLoc.x - 32, entranceLoc.y);
|
|
|
|
update_park_fences(entranceLoc.x + 32, entranceLoc.y);
|
|
|
|
update_park_fences(entranceLoc.x, entranceLoc.y - 32);
|
|
|
|
update_park_fences(entranceLoc.x, entranceLoc.y + 32);
|
|
|
|
|
|
|
|
map_invalidate_tile(entranceLoc.x, entranceLoc.y, newElement->base_height * 8, newElement->clearance_height * 8);
|
|
|
|
|
|
|
|
if (index == 0)
|
|
|
|
{
|
|
|
|
map_animation_create(MAP_ANIMATION_TYPE_PARK_ENTRANCE, entranceLoc.x, entranceLoc.y, zLow);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-18 20:57:36 +02:00
|
|
|
return std::make_unique<GameActionResult>();
|
2017-07-21 19:14:38 +02:00
|
|
|
}
|
2017-04-15 12:07:26 +02:00
|
|
|
};
|