mirror of https://github.com/OpenRCT2/OpenRCT2.git
Implement game action
This commit is contained in:
parent
736734c065
commit
0070283dc2
|
@ -1278,7 +1278,7 @@ GAME_COMMAND_POINTER* new_game_command_table[GAME_COMMAND_COUNT] = {
|
||||||
nullptr,
|
nullptr,
|
||||||
nullptr,
|
nullptr,
|
||||||
nullptr,
|
nullptr,
|
||||||
game_command_place_footpath_from_track,
|
nullptr,
|
||||||
nullptr,
|
nullptr,
|
||||||
game_command_change_surface_style,
|
game_command_change_surface_style,
|
||||||
nullptr,
|
nullptr,
|
||||||
|
|
|
@ -36,8 +36,8 @@ enum GAME_COMMAND
|
||||||
GAME_COMMAND_PLACE_SCENERY, // GA
|
GAME_COMMAND_PLACE_SCENERY, // GA
|
||||||
GAME_COMMAND_SET_WATER_HEIGHT, // GA
|
GAME_COMMAND_SET_WATER_HEIGHT, // GA
|
||||||
GAME_COMMAND_PLACE_PATH, // GA
|
GAME_COMMAND_PLACE_PATH, // GA
|
||||||
GAME_COMMAND_PLACE_PATH_FROM_TRACK,
|
GAME_COMMAND_PLACE_PATH_FROM_TRACK, // GA
|
||||||
GAME_COMMAND_REMOVE_PATH, // GA
|
GAME_COMMAND_REMOVE_PATH, // GA
|
||||||
GAME_COMMAND_CHANGE_SURFACE_STYLE,
|
GAME_COMMAND_CHANGE_SURFACE_STYLE,
|
||||||
GAME_COMMAND_SET_RIDE_PRICE, // GA
|
GAME_COMMAND_SET_RIDE_PRICE, // GA
|
||||||
GAME_COMMAND_SET_GUEST_NAME, // GA
|
GAME_COMMAND_SET_GUEST_NAME, // GA
|
||||||
|
|
|
@ -0,0 +1,285 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* Copyright (c) 2014-2019 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../Cheats.h"
|
||||||
|
#include "../OpenRCT2.h"
|
||||||
|
#include "../core/MemoryStream.h"
|
||||||
|
#include "../interface/Window.h"
|
||||||
|
#include "../localisation/StringIds.h"
|
||||||
|
#include "../management/Finance.h"
|
||||||
|
#include "../world/Footpath.h"
|
||||||
|
#include "../world/Location.hpp"
|
||||||
|
#include "../world/Park.h"
|
||||||
|
#include "../world/Surface.h"
|
||||||
|
#include "../world/Wall.h"
|
||||||
|
#include "GameAction.h"
|
||||||
|
|
||||||
|
DEFINE_GAME_ACTION(FootpathPlaceFromTrackAction, GAME_COMMAND_PLACE_PATH_FROM_TRACK, GameActionResult)
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
CoordsXYZ _loc;
|
||||||
|
uint8_t _slope;
|
||||||
|
uint8_t _type;
|
||||||
|
uint8_t _edges;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FootpathPlaceFromTrackAction() = default;
|
||||||
|
FootpathPlaceFromTrackAction(CoordsXYZ loc, uint8_t slope, uint8_t type, uint8_t edges)
|
||||||
|
: _loc(loc)
|
||||||
|
, _slope(slope)
|
||||||
|
, _type(type)
|
||||||
|
, _edges(edges)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t GetActionFlags() const override
|
||||||
|
{
|
||||||
|
return GameAction::GetActionFlags();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Serialise(DataSerialiser & stream) override
|
||||||
|
{
|
||||||
|
GameAction::Serialise(stream);
|
||||||
|
|
||||||
|
stream << DS_TAG(_loc) << DS_TAG(_slope) << DS_TAG(_type) << DS_TAG(_edges);
|
||||||
|
}
|
||||||
|
|
||||||
|
GameActionResult::Ptr Query() const override
|
||||||
|
{
|
||||||
|
GameActionResult::Ptr res = std::make_unique<GameActionResult>();
|
||||||
|
res->Cost = 0;
|
||||||
|
res->ExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING;
|
||||||
|
res->Position = _loc;
|
||||||
|
res->Position.x += 16;
|
||||||
|
res->Position.y += 16;
|
||||||
|
|
||||||
|
gFootpathGroundFlags = 0;
|
||||||
|
|
||||||
|
if (map_is_edge({ _loc.x, _loc.y }))
|
||||||
|
{
|
||||||
|
return MakeResult(
|
||||||
|
GA_ERROR::INVALID_PARAMETERS, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_OFF_EDGE_OF_MAP);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode)
|
||||||
|
&& !map_is_location_owned(_loc.x, _loc.y, _loc.z))
|
||||||
|
{
|
||||||
|
return MakeResult(GA_ERROR::DISALLOWED, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_LAND_NOT_OWNED_BY_PARK);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_loc.z / 8 < 2)
|
||||||
|
{
|
||||||
|
return MakeResult(GA_ERROR::DISALLOWED, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_TOO_LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_loc.z / 8 > 248)
|
||||||
|
{
|
||||||
|
return MakeResult(GA_ERROR::DISALLOWED, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_TOO_HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ElementInsertQuery(std::move(res));
|
||||||
|
}
|
||||||
|
|
||||||
|
GameActionResult::Ptr Execute() const override
|
||||||
|
{
|
||||||
|
GameActionResult::Ptr res = std::make_unique<GameActionResult>();
|
||||||
|
res->Cost = 0;
|
||||||
|
res->ExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING;
|
||||||
|
res->Position = _loc;
|
||||||
|
res->Position.x += 16;
|
||||||
|
res->Position.y += 16;
|
||||||
|
|
||||||
|
if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST))
|
||||||
|
{
|
||||||
|
footpath_interrupt_peeps(_loc.x, _loc.y, _loc.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
gFootpathGroundFlags = 0;
|
||||||
|
|
||||||
|
// Force ride construction to recheck area
|
||||||
|
_currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_RECHECK;
|
||||||
|
|
||||||
|
return ElementInsertExecute(std::move(res));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
GameActionResult::Ptr ElementInsertQuery(GameActionResult::Ptr res) const
|
||||||
|
{
|
||||||
|
bool entrancePath = false, entranceIsSamePath = false;
|
||||||
|
|
||||||
|
if (!map_check_free_elements_and_reorganise(1))
|
||||||
|
{
|
||||||
|
return MakeResult(GA_ERROR::NO_FREE_ELEMENTS, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE);
|
||||||
|
}
|
||||||
|
|
||||||
|
res->Cost = MONEY(12, 00);
|
||||||
|
|
||||||
|
QuarterTile quarterTile{ 0b1111, 0 };
|
||||||
|
auto zLow = _loc.z / 8;
|
||||||
|
auto zHigh = zLow + 4;
|
||||||
|
if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED)
|
||||||
|
{
|
||||||
|
quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope & TILE_ELEMENT_DIRECTION_MASK);
|
||||||
|
zHigh += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto entranceElement = map_get_park_entrance_element_at(_loc.x, _loc.y, zLow, false);
|
||||||
|
// Make sure the entrance part is the middle
|
||||||
|
if (entranceElement != nullptr && (entranceElement->GetSequenceIndex()) == 0)
|
||||||
|
{
|
||||||
|
entrancePath = true;
|
||||||
|
// Make the price the same as replacing a path
|
||||||
|
if (entranceElement->GetPathType() == (_type & 0xF))
|
||||||
|
entranceIsSamePath = true;
|
||||||
|
else
|
||||||
|
res->Cost -= MONEY(6, 00);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not attempt to build a crossing with a queue or a sloped.
|
||||||
|
uint8_t crossingMode = (_type & FOOTPATH_ELEMENT_INSERT_QUEUE) || (_slope != TILE_ELEMENT_SLOPE_FLAT)
|
||||||
|
? CREATE_CROSSING_MODE_NONE
|
||||||
|
: CREATE_CROSSING_MODE_PATH_OVER_TRACK;
|
||||||
|
if (!entrancePath
|
||||||
|
&& !map_can_construct_with_clear_at(
|
||||||
|
_loc.x, _loc.y, zLow, zHigh, &map_place_non_scenery_clear_func, quarterTile, GetFlags(), &res->Cost,
|
||||||
|
crossingMode))
|
||||||
|
{
|
||||||
|
return MakeResult(
|
||||||
|
GA_ERROR::NO_CLEARANCE, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, gGameCommandErrorText,
|
||||||
|
gCommonFormatArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
gFootpathGroundFlags = gMapGroundFlags;
|
||||||
|
if (!gCheatsDisableClearanceChecks && (gMapGroundFlags & ELEMENT_IS_UNDERWATER))
|
||||||
|
{
|
||||||
|
return MakeResult(
|
||||||
|
GA_ERROR::DISALLOWED, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_CANT_BUILD_THIS_UNDERWATER);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto tileElement = map_get_surface_element_at({ _loc.x, _loc.y });
|
||||||
|
if (tileElement == nullptr)
|
||||||
|
{
|
||||||
|
return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE);
|
||||||
|
}
|
||||||
|
auto surfaceElement = tileElement->AsSurface();
|
||||||
|
int32_t supportHeight = zLow - surfaceElement->base_height;
|
||||||
|
res->Cost += supportHeight < 0 ? MONEY(20, 00) : (supportHeight / 2) * MONEY(5, 00);
|
||||||
|
|
||||||
|
// Prevent the place sound from being spammed
|
||||||
|
if (entranceIsSamePath)
|
||||||
|
res->Cost = 0;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
GameActionResult::Ptr ElementInsertExecute(GameActionResult::Ptr res) const
|
||||||
|
{
|
||||||
|
bool entrancePath = false, entranceIsSamePath = false;
|
||||||
|
|
||||||
|
if (!(GetFlags() & (GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_GHOST)))
|
||||||
|
{
|
||||||
|
footpath_remove_litter(_loc.x, _loc.y, _loc.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
res->Cost = MONEY(12, 00);
|
||||||
|
|
||||||
|
QuarterTile quarterTile{ 0b1111, 0 };
|
||||||
|
auto zLow = _loc.z / 8;
|
||||||
|
auto zHigh = zLow + 4;
|
||||||
|
if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED)
|
||||||
|
{
|
||||||
|
quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope & TILE_ELEMENT_DIRECTION_MASK);
|
||||||
|
zHigh += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto entranceElement = map_get_park_entrance_element_at(_loc.x, _loc.y, zLow, false);
|
||||||
|
// Make sure the entrance part is the middle
|
||||||
|
if (entranceElement != nullptr && (entranceElement->GetSequenceIndex()) == 0)
|
||||||
|
{
|
||||||
|
entrancePath = true;
|
||||||
|
// Make the price the same as replacing a path
|
||||||
|
if (entranceElement->GetPathType() == (_type & 0xF))
|
||||||
|
entranceIsSamePath = true;
|
||||||
|
else
|
||||||
|
res->Cost -= MONEY(6, 00);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not attempt to build a crossing with a queue or a sloped.
|
||||||
|
uint8_t crossingMode = (_type & FOOTPATH_ELEMENT_INSERT_QUEUE) || (_slope != TILE_ELEMENT_SLOPE_FLAT)
|
||||||
|
? CREATE_CROSSING_MODE_NONE
|
||||||
|
: CREATE_CROSSING_MODE_PATH_OVER_TRACK;
|
||||||
|
if (!entrancePath
|
||||||
|
&& !map_can_construct_with_clear_at(
|
||||||
|
_loc.x, _loc.y, zLow, zHigh, &map_place_non_scenery_clear_func, quarterTile,
|
||||||
|
GAME_COMMAND_FLAG_APPLY | GetFlags(), &res->Cost, crossingMode))
|
||||||
|
{
|
||||||
|
return MakeResult(
|
||||||
|
GA_ERROR::NO_CLEARANCE, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, gGameCommandErrorText,
|
||||||
|
gCommonFormatArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
gFootpathGroundFlags = gMapGroundFlags;
|
||||||
|
|
||||||
|
auto tileElement = map_get_surface_element_at({ _loc.x, _loc.y });
|
||||||
|
if (tileElement == nullptr)
|
||||||
|
{
|
||||||
|
return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE);
|
||||||
|
}
|
||||||
|
auto surfaceElement = tileElement->AsSurface();
|
||||||
|
int32_t supportHeight = zLow - surfaceElement->base_height;
|
||||||
|
res->Cost += supportHeight < 0 ? MONEY(20, 00) : (supportHeight / 2) * MONEY(5, 00);
|
||||||
|
|
||||||
|
if (entrancePath)
|
||||||
|
{
|
||||||
|
if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && !entranceIsSamePath)
|
||||||
|
{
|
||||||
|
// Set the path type but make sure it's not a queue as that will not show up
|
||||||
|
entranceElement->SetPathType(_type & 0x7F);
|
||||||
|
map_invalidate_tile_full(_loc.x, _loc.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tileElement = tile_element_insert(_loc.x / 32, _loc.y / 32, zLow, 0b1111);
|
||||||
|
assert(tileElement != nullptr);
|
||||||
|
tileElement->SetType(TILE_ELEMENT_TYPE_PATH);
|
||||||
|
PathElement* pathElement = tileElement->AsPath();
|
||||||
|
pathElement->clearance_height = zHigh;
|
||||||
|
pathElement->SetPathEntryIndex(_type);
|
||||||
|
pathElement->SetSlopeDirection(_slope & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK);
|
||||||
|
if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED)
|
||||||
|
{
|
||||||
|
pathElement->SetSloped(true);
|
||||||
|
}
|
||||||
|
if (_type & FOOTPATH_ELEMENT_INSERT_QUEUE)
|
||||||
|
{
|
||||||
|
pathElement->SetIsQueue(true);
|
||||||
|
}
|
||||||
|
pathElement->SetAddition(0);
|
||||||
|
pathElement->SetRideIndex(RIDE_ID_NULL);
|
||||||
|
pathElement->SetAdditionStatus(255);
|
||||||
|
pathElement->SetIsBroken(false);
|
||||||
|
pathElement->SetEdges(_edges);
|
||||||
|
pathElement->SetCorners(0);
|
||||||
|
if (GetFlags() & GAME_COMMAND_FLAG_GHOST)
|
||||||
|
{
|
||||||
|
pathElement->SetGhost(true);
|
||||||
|
}
|
||||||
|
map_invalidate_tile_full(_loc.x, _loc.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent the place sound from being spammed
|
||||||
|
if (entranceIsSamePath)
|
||||||
|
res->Cost = 0;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
};
|
|
@ -11,6 +11,7 @@
|
||||||
#include "ClearAction.hpp"
|
#include "ClearAction.hpp"
|
||||||
#include "ClimateSetAction.hpp"
|
#include "ClimateSetAction.hpp"
|
||||||
#include "FootpathPlaceAction.hpp"
|
#include "FootpathPlaceAction.hpp"
|
||||||
|
#include "FootpathPlaceFromTrackAction.hpp"
|
||||||
#include "FootpathRemoveAction.hpp"
|
#include "FootpathRemoveAction.hpp"
|
||||||
#include "FootpathSceneryPlaceAction.hpp"
|
#include "FootpathSceneryPlaceAction.hpp"
|
||||||
#include "FootpathSceneryRemoveAction.hpp"
|
#include "FootpathSceneryRemoveAction.hpp"
|
||||||
|
@ -59,6 +60,7 @@ namespace GameActions
|
||||||
Register<BannerSetNameAction>();
|
Register<BannerSetNameAction>();
|
||||||
Register<ClimateSetAction>();
|
Register<ClimateSetAction>();
|
||||||
Register<FootpathPlaceAction>();
|
Register<FootpathPlaceAction>();
|
||||||
|
Register<FootpathPlaceFromTrackAction>();
|
||||||
Register<FootpathRemoveAction>();
|
Register<FootpathRemoveAction>();
|
||||||
Register<FootpathSceneryPlaceAction>();
|
Register<FootpathSceneryPlaceAction>();
|
||||||
Register<FootpathSceneryRemoveAction>();
|
Register<FootpathSceneryRemoveAction>();
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "../Cheats.h"
|
#include "../Cheats.h"
|
||||||
#include "../Game.h"
|
#include "../Game.h"
|
||||||
#include "../OpenRCT2.h"
|
#include "../OpenRCT2.h"
|
||||||
|
#include "../actions/FootpathPlaceFromTrackAction.hpp"
|
||||||
#include "../actions/LargeSceneryRemoveAction.hpp"
|
#include "../actions/LargeSceneryRemoveAction.hpp"
|
||||||
#include "../actions/RideEntranceExitPlaceAction.hpp"
|
#include "../actions/RideEntranceExitPlaceAction.hpp"
|
||||||
#include "../actions/RideSetSetting.hpp"
|
#include "../actions/RideSetSetting.hpp"
|
||||||
|
@ -1098,15 +1099,15 @@ static int32_t track_design_place_scenery(
|
||||||
flags = 0;
|
flags = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
gGameCommandErrorTitle = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE;
|
uint8_t slope = ((bh >> 5) & 0x3) | ((bh >> 2) & 0x4);
|
||||||
cost = game_do_command(
|
uint8_t edges = bh & 0xF;
|
||||||
mapCoord.x, flags | (bh << 8), mapCoord.y, z | (entry_index << 8),
|
auto footpathPlaceAction = FootpathPlaceFromTrackAction(
|
||||||
GAME_COMMAND_PLACE_PATH_FROM_TRACK, 0, 0);
|
{ mapCoord.x, mapCoord.y, z * 8 }, slope, entry_index, edges);
|
||||||
|
footpathPlaceAction.SetFlags(flags);
|
||||||
if (cost == MONEY32_UNDEFINED)
|
auto res = flags & GAME_COMMAND_FLAG_APPLY ? GameActions::ExecuteNested(&footpathPlaceAction)
|
||||||
{
|
: GameActions::QueryNested(&footpathPlaceAction);
|
||||||
cost = 0;
|
// Ignore failures
|
||||||
}
|
cost = res->Error == GA_ERROR::OK ? res->Cost : 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -124,11 +124,6 @@ TileElement* map_get_footpath_element(int32_t x, int32_t y, int32_t z)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** rct2: 0x0098D7EC */
|
|
||||||
static constexpr const QuarterTile SlopedFootpathQuarterTiles[] = {
|
|
||||||
{ 0b1111, 0b1100 }, { 0b1111, 0b1001 }, { 0b1111, 0b0011 }, { 0b1111, 0b0110 }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* rct2: 0x006BA23E
|
* rct2: 0x006BA23E
|
||||||
|
@ -148,171 +143,6 @@ void remove_banners_at_element(int32_t x, int32_t y, TileElement* tileElement)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static money32 footpath_place_from_track(
|
|
||||||
int32_t type, int32_t x, int32_t y, int32_t z, int32_t slope, int32_t edges, int32_t flags)
|
|
||||||
{
|
|
||||||
TileElement* tileElement;
|
|
||||||
EntranceElement* entranceElement;
|
|
||||||
bool entrancePath = false, entranceIsSamePath = false;
|
|
||||||
|
|
||||||
gCommandExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING;
|
|
||||||
gCommandPosition.x = x + 16;
|
|
||||||
gCommandPosition.y = y + 16;
|
|
||||||
gCommandPosition.z = z * 8;
|
|
||||||
|
|
||||||
if (!(flags & GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED) && game_is_paused() && !gCheatsBuildInPauseMode)
|
|
||||||
{
|
|
||||||
gGameCommandErrorText = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED;
|
|
||||||
return MONEY32_UNDEFINED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((flags & GAME_COMMAND_FLAG_APPLY) && !(flags & GAME_COMMAND_FLAG_GHOST))
|
|
||||||
footpath_interrupt_peeps(x, y, z * 8);
|
|
||||||
|
|
||||||
gFootpathPrice = 0;
|
|
||||||
gFootpathGroundFlags = 0;
|
|
||||||
|
|
||||||
if (!map_is_location_owned(x, y, z * 8) && !gCheatsSandboxMode)
|
|
||||||
{
|
|
||||||
return MONEY32_UNDEFINED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode) && !map_is_location_owned(x, y, z * 8))
|
|
||||||
return MONEY32_UNDEFINED;
|
|
||||||
|
|
||||||
if (z < 2)
|
|
||||||
{
|
|
||||||
gGameCommandErrorText = STR_TOO_LOW;
|
|
||||||
return MONEY32_UNDEFINED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (z > 248)
|
|
||||||
{
|
|
||||||
gGameCommandErrorText = STR_TOO_HIGH;
|
|
||||||
return MONEY32_UNDEFINED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & GAME_COMMAND_FLAG_APPLY)
|
|
||||||
{
|
|
||||||
if (!(flags & (GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_GHOST)))
|
|
||||||
{
|
|
||||||
footpath_remove_litter(x, y, z * 8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gFootpathPrice += 120;
|
|
||||||
QuarterTile quarterTile = { 0b1111, 0 };
|
|
||||||
int32_t zHigh = z + 4;
|
|
||||||
if (slope & TILE_ELEMENT_SLOPE_S_CORNER_UP)
|
|
||||||
{
|
|
||||||
quarterTile = SlopedFootpathQuarterTiles[slope & TILE_ELEMENT_SLOPE_NE_SIDE_UP];
|
|
||||||
zHigh += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
entranceElement = map_get_park_entrance_element_at(x, y, z, false);
|
|
||||||
// Make sure the entrance part is the middle
|
|
||||||
if (entranceElement != nullptr && (entranceElement->GetSequenceIndex()) == 0)
|
|
||||||
{
|
|
||||||
entrancePath = true;
|
|
||||||
// Make the price the same as replacing a path
|
|
||||||
if (entranceElement->GetPathType() == (type & 0xF))
|
|
||||||
entranceIsSamePath = true;
|
|
||||||
else
|
|
||||||
gFootpathPrice -= MONEY(6, 00);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do not attempt to build a crossing with a queue or a sloped.
|
|
||||||
uint8_t crossingMode = (type & FOOTPATH_ELEMENT_INSERT_QUEUE) || (slope != TILE_ELEMENT_SLOPE_FLAT)
|
|
||||||
? CREATE_CROSSING_MODE_NONE
|
|
||||||
: CREATE_CROSSING_MODE_PATH_OVER_TRACK;
|
|
||||||
if (!entrancePath
|
|
||||||
&& !map_can_construct_with_clear_at(
|
|
||||||
x, y, z, zHigh, &map_place_non_scenery_clear_func, quarterTile, flags, &gFootpathPrice, crossingMode))
|
|
||||||
return MONEY32_UNDEFINED;
|
|
||||||
|
|
||||||
gFootpathGroundFlags = gMapGroundFlags;
|
|
||||||
if (!gCheatsDisableClearanceChecks && (gMapGroundFlags & ELEMENT_IS_UNDERWATER))
|
|
||||||
{
|
|
||||||
gGameCommandErrorText = STR_CANT_BUILD_THIS_UNDERWATER;
|
|
||||||
return MONEY32_UNDEFINED;
|
|
||||||
}
|
|
||||||
|
|
||||||
tileElement = map_get_surface_element_at({ x, y });
|
|
||||||
|
|
||||||
int32_t supportHeight = z - tileElement->base_height;
|
|
||||||
gFootpathPrice += supportHeight < 0 ? MONEY(20, 00) : (supportHeight / 2) * MONEY(5, 00);
|
|
||||||
|
|
||||||
if (flags & GAME_COMMAND_FLAG_APPLY)
|
|
||||||
{
|
|
||||||
if (gGameCommandNestLevel == 1 && !(flags & GAME_COMMAND_FLAG_GHOST))
|
|
||||||
{
|
|
||||||
LocationXYZ16 coord;
|
|
||||||
coord.x = x + 16;
|
|
||||||
coord.y = y + 16;
|
|
||||||
coord.z = tile_element_height(coord.x, coord.y);
|
|
||||||
network_set_player_last_action_coord(network_get_player_index(game_command_playerid), coord);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entrancePath)
|
|
||||||
{
|
|
||||||
if (!(flags & GAME_COMMAND_FLAG_GHOST) && !entranceIsSamePath)
|
|
||||||
{
|
|
||||||
// Set the path type but make sure it's not a queue as that will not show up
|
|
||||||
entranceElement->SetPathType(type & 0x7F);
|
|
||||||
map_invalidate_tile_full(x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tileElement = tile_element_insert(x / 32, y / 32, z, 0x0F);
|
|
||||||
assert(tileElement != nullptr);
|
|
||||||
tileElement->SetType(TILE_ELEMENT_TYPE_PATH);
|
|
||||||
PathElement* pathElement = tileElement->AsPath();
|
|
||||||
// This can NEVER happen, but GCC does not want to believe that...
|
|
||||||
if (pathElement == nullptr)
|
|
||||||
{
|
|
||||||
assert(false);
|
|
||||||
return MONEY32_UNDEFINED;
|
|
||||||
}
|
|
||||||
pathElement->clearance_height = z + 4 + ((slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED) ? 2 : 0);
|
|
||||||
pathElement->SetPathEntryIndex(type & 0xF);
|
|
||||||
pathElement->SetSlopeDirection(slope & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK);
|
|
||||||
if (slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED)
|
|
||||||
pathElement->SetSloped(true);
|
|
||||||
if (type & (1 << 7))
|
|
||||||
pathElement->SetIsQueue(true);
|
|
||||||
pathElement->SetAddition(0);
|
|
||||||
pathElement->SetRideIndex(RIDE_ID_NULL);
|
|
||||||
pathElement->SetAdditionStatus(255);
|
|
||||||
pathElement->SetEdges(edges);
|
|
||||||
pathElement->SetCorners(0);
|
|
||||||
pathElement->SetIsBroken(false);
|
|
||||||
if (flags & (1 << 6))
|
|
||||||
pathElement->SetGhost(true);
|
|
||||||
|
|
||||||
map_invalidate_tile_full(x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entranceIsSamePath)
|
|
||||||
gFootpathPrice = 0;
|
|
||||||
|
|
||||||
return gParkFlags & PARK_FLAGS_NO_MONEY ? 0 : gFootpathPrice;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* rct2: 0x006A68AE
|
|
||||||
*/
|
|
||||||
void game_command_place_footpath_from_track(
|
|
||||||
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, [[maybe_unused]] int32_t* esi, [[maybe_unused]] int32_t* edi,
|
|
||||||
[[maybe_unused]] int32_t* ebp)
|
|
||||||
{
|
|
||||||
*ebx = footpath_place_from_track(
|
|
||||||
(*edx >> 8) & 0xFF, *eax & 0xFFFF, *ecx & 0xFFFF, *edx & 0xFF, ((*ebx >> 13) & 0x3) | ((*ebx >> 10) & 0x4),
|
|
||||||
(*ebx >> 8) & 0xF, *ebx & 0xFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
money32 footpath_remove(int32_t x, int32_t y, int32_t z, int32_t flags)
|
money32 footpath_remove(int32_t x, int32_t y, int32_t z, int32_t flags)
|
||||||
{
|
{
|
||||||
auto action = FootpathRemoveAction(x, y, z);
|
auto action = FootpathRemoveAction(x, y, z);
|
||||||
|
|
|
@ -173,8 +173,6 @@ TileElement* map_get_footpath_element(int32_t x, int32_t y, int32_t z);
|
||||||
struct PathElement;
|
struct PathElement;
|
||||||
PathElement* map_get_footpath_element_slope(int32_t x, int32_t y, int32_t z, int32_t slope);
|
PathElement* map_get_footpath_element_slope(int32_t x, int32_t y, int32_t z, int32_t slope);
|
||||||
void footpath_interrupt_peeps(int32_t x, int32_t y, int32_t z);
|
void footpath_interrupt_peeps(int32_t x, int32_t y, int32_t z);
|
||||||
void game_command_place_footpath_from_track(
|
|
||||||
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
|
|
||||||
void game_command_remove_footpath(
|
void game_command_remove_footpath(
|
||||||
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
|
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
|
||||||
money32 footpath_remove(int32_t x, int32_t y, int32_t z, int32_t flags);
|
money32 footpath_remove(int32_t x, int32_t y, int32_t z, int32_t flags);
|
||||||
|
|
Loading…
Reference in New Issue