mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2025-12-23 07:43:01 +01:00
Move Footpath game actions into GameActions namespace
This commit is contained in:
@@ -662,7 +662,8 @@ namespace OpenRCT2::Ui
|
||||
*/
|
||||
static void ViewportInteractionRemovePathAddition(const PathElement& pathElement, const CoordsXY& mapCoords)
|
||||
{
|
||||
auto footpathAdditionRemoveAction = FootpathAdditionRemoveAction({ mapCoords.x, mapCoords.y, pathElement.GetBaseZ() });
|
||||
auto footpathAdditionRemoveAction = GameActions::FootpathAdditionRemoveAction(
|
||||
{ mapCoords.x, mapCoords.y, pathElement.GetBaseZ() });
|
||||
GameActions::Execute(&footpathAdditionRemoveAction);
|
||||
}
|
||||
|
||||
|
||||
@@ -1145,7 +1145,7 @@ namespace OpenRCT2::Ui::Windows
|
||||
auto selectedType = gFootpathSelection.GetSelectedSurface();
|
||||
PathConstructFlags constructFlags = FootpathCreateConstructFlags(selectedType);
|
||||
|
||||
auto footpathPlaceAction = FootpathPlaceAction(
|
||||
auto footpathPlaceAction = GameActions::FootpathPlaceAction(
|
||||
{ *mapPos, baseZ }, slope, selectedType, gFootpathSelection.Railings, kInvalidDirection, constructFlags);
|
||||
footpathPlaceAction.SetCallback([this](const GameAction* ga, const GameActions::Result* result) {
|
||||
if (result->Error == GameActions::Status::Ok)
|
||||
@@ -1237,7 +1237,7 @@ namespace OpenRCT2::Ui::Windows
|
||||
|
||||
PathConstructFlags constructFlags = FootpathCreateConstructFlags(type);
|
||||
|
||||
auto footpathPlaceAction = FootpathPlaceAction(
|
||||
auto footpathPlaceAction = GameActions::FootpathPlaceAction(
|
||||
footpathLoc, slope, type, gFootpathSelection.Railings, _footpathConstructDirection, constructFlags);
|
||||
|
||||
footpathPlaceAction.SetCallback([footpathLoc](const GameAction* ga, const GameActions::Result* result) {
|
||||
@@ -1756,7 +1756,7 @@ namespace OpenRCT2::Ui::Windows
|
||||
|
||||
FootpathRemoveProvisional();
|
||||
|
||||
auto footpathPlaceAction = FootpathPlaceAction(
|
||||
auto footpathPlaceAction = GameActions::FootpathPlaceAction(
|
||||
footpathLoc, slope, type, railingsType, kInvalidDirection, constructFlags);
|
||||
footpathPlaceAction.SetFlags(GAME_COMMAND_FLAG_GHOST | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED);
|
||||
auto res = GameActions::Execute(&footpathPlaceAction);
|
||||
|
||||
@@ -2131,7 +2131,7 @@ namespace OpenRCT2::Ui::Windows
|
||||
SceneryRemoveGhostToolPlacement();
|
||||
|
||||
// 6e265b
|
||||
auto footpathAdditionPlaceAction = FootpathAdditionPlaceAction(loc, entryIndex);
|
||||
auto footpathAdditionPlaceAction = GameActions::FootpathAdditionPlaceAction(loc, entryIndex);
|
||||
footpathAdditionPlaceAction.SetFlags(GAME_COMMAND_FLAG_GHOST | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED);
|
||||
footpathAdditionPlaceAction.SetCallback([=](const GameAction* ga, const GameActions::Result* result) {
|
||||
if (result->Error != GameActions::Status::Ok)
|
||||
@@ -3093,7 +3093,8 @@ namespace OpenRCT2::Ui::Windows
|
||||
if (gridPos.IsNull())
|
||||
return;
|
||||
|
||||
auto footpathAdditionPlaceAction = FootpathAdditionPlaceAction({ gridPos, z }, selectedScenery);
|
||||
auto footpathAdditionPlaceAction = GameActions::FootpathAdditionPlaceAction(
|
||||
{ gridPos, z }, selectedScenery);
|
||||
|
||||
footpathAdditionPlaceAction.SetCallback([](const GameAction* ga, const GameActions::Result* result) {
|
||||
if (result->Error != GameActions::Status::Ok)
|
||||
|
||||
@@ -13,51 +13,52 @@
|
||||
#include "../Context.h"
|
||||
#include "../scripting/ScriptEngine.h"
|
||||
|
||||
using namespace OpenRCT2;
|
||||
|
||||
CustomAction::CustomAction(const std::string& id, const std::string& json, const std::string& pluginName)
|
||||
: _id(id)
|
||||
, _json(json)
|
||||
, _pluginName(pluginName)
|
||||
namespace OpenRCT2::GameActions
|
||||
{
|
||||
}
|
||||
CustomAction::CustomAction(const std::string& id, const std::string& json, const std::string& pluginName)
|
||||
: _id(id)
|
||||
, _json(json)
|
||||
, _pluginName(pluginName)
|
||||
{
|
||||
}
|
||||
|
||||
std::string CustomAction::GetId() const
|
||||
{
|
||||
return _id;
|
||||
}
|
||||
std::string CustomAction::GetId() const
|
||||
{
|
||||
return _id;
|
||||
}
|
||||
|
||||
std::string CustomAction::GetJson() const
|
||||
{
|
||||
return _json;
|
||||
}
|
||||
std::string CustomAction::GetJson() const
|
||||
{
|
||||
return _json;
|
||||
}
|
||||
|
||||
std::string CustomAction::GetPluginName() const
|
||||
{
|
||||
return _pluginName;
|
||||
}
|
||||
std::string CustomAction::GetPluginName() const
|
||||
{
|
||||
return _pluginName;
|
||||
}
|
||||
|
||||
uint16_t CustomAction::GetActionFlags() const
|
||||
{
|
||||
return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused;
|
||||
}
|
||||
uint16_t CustomAction::GetActionFlags() const
|
||||
{
|
||||
return GameAction::GetActionFlags() | Flags::AllowWhilePaused;
|
||||
}
|
||||
|
||||
void CustomAction::Serialise(DataSerialiser& stream)
|
||||
{
|
||||
GameAction::Serialise(stream);
|
||||
stream << DS_TAG(_id) << DS_TAG(_json);
|
||||
}
|
||||
void CustomAction::Serialise(DataSerialiser& stream)
|
||||
{
|
||||
GameAction::Serialise(stream);
|
||||
stream << DS_TAG(_id) << DS_TAG(_json);
|
||||
}
|
||||
|
||||
GameActions::Result CustomAction::Query() const
|
||||
{
|
||||
auto& scriptingEngine = OpenRCT2::GetContext()->GetScriptEngine();
|
||||
return scriptingEngine.QueryOrExecuteCustomGameAction(*this, false);
|
||||
}
|
||||
Result CustomAction::Query() const
|
||||
{
|
||||
auto& scriptingEngine = GetContext()->GetScriptEngine();
|
||||
return scriptingEngine.QueryOrExecuteCustomGameAction(*this, false);
|
||||
}
|
||||
|
||||
GameActions::Result CustomAction::Execute() const
|
||||
{
|
||||
auto& scriptingEngine = OpenRCT2::GetContext()->GetScriptEngine();
|
||||
return scriptingEngine.QueryOrExecuteCustomGameAction(*this, true);
|
||||
}
|
||||
Result CustomAction::Execute() const
|
||||
{
|
||||
auto& scriptingEngine = GetContext()->GetScriptEngine();
|
||||
return scriptingEngine.QueryOrExecuteCustomGameAction(*this, true);
|
||||
}
|
||||
} // namespace OpenRCT2::GameActions
|
||||
|
||||
#endif
|
||||
|
||||
@@ -13,26 +13,29 @@
|
||||
|
||||
#include "GameAction.h"
|
||||
|
||||
class CustomAction final : public GameActionBase<GameCommand::Custom>
|
||||
namespace OpenRCT2::GameActions
|
||||
{
|
||||
private:
|
||||
std::string _id;
|
||||
std::string _json;
|
||||
std::string _pluginName;
|
||||
class CustomAction final : public GameActionBase<GameCommand::Custom>
|
||||
{
|
||||
private:
|
||||
std::string _id;
|
||||
std::string _json;
|
||||
std::string _pluginName;
|
||||
|
||||
public:
|
||||
CustomAction() = default;
|
||||
CustomAction(const std::string& id, const std::string& json, const std::string& pluginName);
|
||||
public:
|
||||
CustomAction() = default;
|
||||
CustomAction(const std::string& id, const std::string& json, const std::string& pluginName);
|
||||
|
||||
std::string GetId() const;
|
||||
std::string GetJson() const;
|
||||
std::string GetPluginName() const;
|
||||
std::string GetId() const;
|
||||
std::string GetJson() const;
|
||||
std::string GetPluginName() const;
|
||||
|
||||
uint16_t GetActionFlags() const override;
|
||||
uint16_t GetActionFlags() const override;
|
||||
|
||||
void Serialise(DataSerialiser& stream) override;
|
||||
OpenRCT2::GameActions::Result Query() const override;
|
||||
OpenRCT2::GameActions::Result Execute() const override;
|
||||
};
|
||||
void Serialise(DataSerialiser& stream) override;
|
||||
Result Query() const override;
|
||||
Result Execute() const override;
|
||||
};
|
||||
} // namespace OpenRCT2::GameActions
|
||||
|
||||
#endif
|
||||
|
||||
@@ -24,177 +24,169 @@
|
||||
#include "../world/Scenery.h"
|
||||
#include "../world/tile_element/PathElement.h"
|
||||
|
||||
using namespace OpenRCT2;
|
||||
|
||||
FootpathAdditionPlaceAction::FootpathAdditionPlaceAction(const CoordsXYZ& loc, ObjectEntryIndex pathItemType)
|
||||
: _loc(loc)
|
||||
, _entryIndex(pathItemType)
|
||||
namespace OpenRCT2::GameActions
|
||||
{
|
||||
}
|
||||
|
||||
void FootpathAdditionPlaceAction::AcceptParameters(GameActionParameterVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(_loc);
|
||||
visitor.Visit("object", _entryIndex);
|
||||
}
|
||||
|
||||
uint16_t FootpathAdditionPlaceAction::GetActionFlags() const
|
||||
{
|
||||
return GameAction::GetActionFlags();
|
||||
}
|
||||
|
||||
void FootpathAdditionPlaceAction::Serialise(DataSerialiser& stream)
|
||||
{
|
||||
GameAction::Serialise(stream);
|
||||
|
||||
stream << DS_TAG(_loc) << DS_TAG(_entryIndex);
|
||||
}
|
||||
|
||||
GameActions::Result FootpathAdditionPlaceAction::Query() const
|
||||
{
|
||||
auto res = GameActions::Result();
|
||||
res.Expenditure = ExpenditureType::landscaping;
|
||||
res.Position = _loc;
|
||||
if (!LocationValid(_loc))
|
||||
FootpathAdditionPlaceAction::FootpathAdditionPlaceAction(const CoordsXYZ& loc, ObjectEntryIndex pathItemType)
|
||||
: _loc(loc)
|
||||
, _entryIndex(pathItemType)
|
||||
{
|
||||
return GameActions::Result(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_OFF_EDGE_OF_MAP);
|
||||
}
|
||||
|
||||
if (!(gLegacyScene == LegacyScene::scenarioEditor || getGameState().cheats.sandboxMode) && !MapIsLocationOwned(_loc))
|
||||
void FootpathAdditionPlaceAction::AcceptParameters(GameActionParameterVisitor& visitor)
|
||||
{
|
||||
return GameActions::Result(GameActions::Status::Disallowed, STR_CANT_POSITION_THIS_HERE, STR_LAND_NOT_OWNED_BY_PARK);
|
||||
visitor.Visit(_loc);
|
||||
visitor.Visit("object", _entryIndex);
|
||||
}
|
||||
|
||||
if (_loc.z < kFootpathMinHeight)
|
||||
uint16_t FootpathAdditionPlaceAction::GetActionFlags() const
|
||||
{
|
||||
return GameActions::Result(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_TOO_LOW);
|
||||
return GameAction::GetActionFlags();
|
||||
}
|
||||
|
||||
if (_loc.z > kFootpathMaxHeight)
|
||||
void FootpathAdditionPlaceAction::Serialise(DataSerialiser& stream)
|
||||
{
|
||||
return GameActions::Result(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_TOO_HIGH);
|
||||
GameAction::Serialise(stream);
|
||||
|
||||
stream << DS_TAG(_loc) << DS_TAG(_entryIndex);
|
||||
}
|
||||
|
||||
auto tileElement = MapGetFootpathElement(_loc);
|
||||
if (tileElement == nullptr)
|
||||
Result FootpathAdditionPlaceAction::Query() const
|
||||
{
|
||||
LOG_ERROR("No path element at x = %d, y = %d, z = %d", _loc.x, _loc.y, _loc.z);
|
||||
return GameActions::Result(
|
||||
GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_ERR_PATH_ELEMENT_NOT_FOUND);
|
||||
}
|
||||
|
||||
auto pathElement = tileElement->AsPath();
|
||||
if (pathElement->IsLevelCrossing(_loc))
|
||||
{
|
||||
return GameActions::Result(
|
||||
GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE,
|
||||
STR_CANNOT_BUILD_PATH_ADDITIONS_ON_LEVEL_CROSSINGS);
|
||||
}
|
||||
|
||||
// No change
|
||||
if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && pathElement->GetAdditionEntryIndex() == _entryIndex
|
||||
&& !(pathElement->IsBroken()))
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
auto* pathAdditionEntry = ObjectManager::GetObjectEntry<PathAdditionEntry>(_entryIndex);
|
||||
if (pathAdditionEntry == nullptr)
|
||||
{
|
||||
LOG_ERROR("Unknown footpath addition entry for entryIndex %d", _entryIndex);
|
||||
return GameActions::Result(
|
||||
GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_UNKNOWN_OBJECT_TYPE);
|
||||
}
|
||||
uint16_t sceneryFlags = pathAdditionEntry->flags;
|
||||
|
||||
if ((sceneryFlags & PATH_ADDITION_FLAG_DONT_ALLOW_ON_SLOPE) && pathElement->IsSloped())
|
||||
{
|
||||
return GameActions::Result(
|
||||
GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_CANT_BUILD_THIS_ON_SLOPED_FOOTPATH);
|
||||
}
|
||||
|
||||
if ((sceneryFlags & PATH_ADDITION_FLAG_DONT_ALLOW_ON_QUEUE) && pathElement->IsQueue())
|
||||
{
|
||||
return GameActions::Result(
|
||||
GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_CANNOT_PLACE_THESE_ON_QUEUE_LINE_AREA);
|
||||
}
|
||||
|
||||
if (!(sceneryFlags & (PATH_ADDITION_FLAG_JUMPING_FOUNTAIN_WATER | PATH_ADDITION_FLAG_JUMPING_FOUNTAIN_SNOW))
|
||||
&& (pathElement->GetEdges()) == 0x0F)
|
||||
{
|
||||
return GameActions::Result(
|
||||
GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_CAN_ONLY_BE_PLACED_ON_PATH_EDGES);
|
||||
}
|
||||
|
||||
if ((sceneryFlags & PATH_ADDITION_FLAG_IS_QUEUE_SCREEN) && !pathElement->IsQueue())
|
||||
{
|
||||
return GameActions::Result(
|
||||
GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_CAN_ONLY_PLACE_THESE_ON_QUEUE_AREA);
|
||||
}
|
||||
|
||||
res.Cost = pathAdditionEntry->price;
|
||||
|
||||
// Should place a ghost?
|
||||
if (GetFlags() & GAME_COMMAND_FLAG_GHOST)
|
||||
{
|
||||
// Check if there is something on the path already
|
||||
if (pathElement->HasAddition())
|
||||
auto res = Result();
|
||||
res.Expenditure = ExpenditureType::landscaping;
|
||||
res.Position = _loc;
|
||||
if (!LocationValid(_loc))
|
||||
{
|
||||
return GameActions::Result(GameActions::Status::ItemAlreadyPlaced, STR_CANT_POSITION_THIS_HERE, kStringIdNone);
|
||||
return Result(Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_OFF_EDGE_OF_MAP);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
GameActions::Result FootpathAdditionPlaceAction::Execute() const
|
||||
{
|
||||
auto res = GameActions::Result();
|
||||
res.Position = _loc;
|
||||
res.Expenditure = ExpenditureType::landscaping;
|
||||
if (!(gLegacyScene == LegacyScene::scenarioEditor || getGameState().cheats.sandboxMode) && !MapIsLocationOwned(_loc))
|
||||
{
|
||||
return Result(Status::Disallowed, STR_CANT_POSITION_THIS_HERE, STR_LAND_NOT_OWNED_BY_PARK);
|
||||
}
|
||||
|
||||
auto tileElement = MapGetFootpathElement(_loc);
|
||||
auto pathElement = tileElement->AsPath();
|
||||
if (_loc.z < kFootpathMinHeight)
|
||||
{
|
||||
return Result(Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_TOO_LOW);
|
||||
}
|
||||
|
||||
if (pathElement == nullptr)
|
||||
{
|
||||
LOG_ERROR("No path element at x = %d, y = %d, z = %d", _loc.x, _loc.y, _loc.z);
|
||||
return GameActions::Result(
|
||||
GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_ERR_PATH_ELEMENT_NOT_FOUND);
|
||||
}
|
||||
if (_loc.z > kFootpathMaxHeight)
|
||||
{
|
||||
return Result(Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_TOO_HIGH);
|
||||
}
|
||||
|
||||
// No change
|
||||
if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && pathElement->GetAdditionEntryIndex() == _entryIndex
|
||||
&& !(pathElement->IsBroken()) && !pathElement->AdditionIsGhost())
|
||||
{
|
||||
auto tileElement = MapGetFootpathElement(_loc);
|
||||
if (tileElement == nullptr)
|
||||
{
|
||||
LOG_ERROR("No path element at x = %d, y = %d, z = %d", _loc.x, _loc.y, _loc.z);
|
||||
return Result(Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_ERR_PATH_ELEMENT_NOT_FOUND);
|
||||
}
|
||||
|
||||
auto pathElement = tileElement->AsPath();
|
||||
if (pathElement->IsLevelCrossing(_loc))
|
||||
{
|
||||
return Result(
|
||||
Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_CANNOT_BUILD_PATH_ADDITIONS_ON_LEVEL_CROSSINGS);
|
||||
}
|
||||
|
||||
// No change
|
||||
if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && pathElement->GetAdditionEntryIndex() == _entryIndex
|
||||
&& !(pathElement->IsBroken()))
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
auto* pathAdditionEntry = ObjectManager::GetObjectEntry<PathAdditionEntry>(_entryIndex);
|
||||
if (pathAdditionEntry == nullptr)
|
||||
{
|
||||
LOG_ERROR("Unknown footpath addition entry for entryIndex %d", _entryIndex);
|
||||
return Result(Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_UNKNOWN_OBJECT_TYPE);
|
||||
}
|
||||
uint16_t sceneryFlags = pathAdditionEntry->flags;
|
||||
|
||||
if ((sceneryFlags & PATH_ADDITION_FLAG_DONT_ALLOW_ON_SLOPE) && pathElement->IsSloped())
|
||||
{
|
||||
return Result(Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_CANT_BUILD_THIS_ON_SLOPED_FOOTPATH);
|
||||
}
|
||||
|
||||
if ((sceneryFlags & PATH_ADDITION_FLAG_DONT_ALLOW_ON_QUEUE) && pathElement->IsQueue())
|
||||
{
|
||||
return Result(Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_CANNOT_PLACE_THESE_ON_QUEUE_LINE_AREA);
|
||||
}
|
||||
|
||||
if (!(sceneryFlags & (PATH_ADDITION_FLAG_JUMPING_FOUNTAIN_WATER | PATH_ADDITION_FLAG_JUMPING_FOUNTAIN_SNOW))
|
||||
&& (pathElement->GetEdges()) == 0x0F)
|
||||
{
|
||||
return Result(Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_CAN_ONLY_BE_PLACED_ON_PATH_EDGES);
|
||||
}
|
||||
|
||||
if ((sceneryFlags & PATH_ADDITION_FLAG_IS_QUEUE_SCREEN) && !pathElement->IsQueue())
|
||||
{
|
||||
return Result(Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_CAN_ONLY_PLACE_THESE_ON_QUEUE_AREA);
|
||||
}
|
||||
|
||||
res.Cost = pathAdditionEntry->price;
|
||||
|
||||
// Should place a ghost?
|
||||
if (GetFlags() & GAME_COMMAND_FLAG_GHOST)
|
||||
{
|
||||
// Check if there is something on the path already
|
||||
if (pathElement->HasAddition())
|
||||
{
|
||||
return Result(Status::ItemAlreadyPlaced, STR_CANT_POSITION_THIS_HERE, kStringIdNone);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
auto* pathAdditionEntry = OpenRCT2::ObjectManager::GetObjectEntry<PathAdditionEntry>(_entryIndex);
|
||||
if (pathAdditionEntry == nullptr)
|
||||
Result FootpathAdditionPlaceAction::Execute() const
|
||||
{
|
||||
LOG_ERROR("Unknown footpath addition entry for entryIndex %d", _entryIndex);
|
||||
return GameActions::Result(
|
||||
GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_UNKNOWN_OBJECT_TYPE);
|
||||
}
|
||||
auto res = Result();
|
||||
res.Position = _loc;
|
||||
res.Expenditure = ExpenditureType::landscaping;
|
||||
|
||||
res.Cost = pathAdditionEntry->price;
|
||||
auto tileElement = MapGetFootpathElement(_loc);
|
||||
auto pathElement = tileElement->AsPath();
|
||||
|
||||
if (GetFlags() & GAME_COMMAND_FLAG_GHOST)
|
||||
{
|
||||
pathElement->SetAdditionIsGhost(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
FootpathInterruptPeeps(_loc);
|
||||
pathElement->SetAdditionIsGhost(false);
|
||||
}
|
||||
if (pathElement == nullptr)
|
||||
{
|
||||
LOG_ERROR("No path element at x = %d, y = %d, z = %d", _loc.x, _loc.y, _loc.z);
|
||||
return Result(Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_ERR_PATH_ELEMENT_NOT_FOUND);
|
||||
}
|
||||
|
||||
pathElement->SetAdditionEntryIndex(_entryIndex);
|
||||
pathElement->SetIsBroken(false);
|
||||
if (pathAdditionEntry->flags & PATH_ADDITION_FLAG_IS_BIN)
|
||||
{
|
||||
pathElement->SetAdditionStatus(255);
|
||||
// No change
|
||||
if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && pathElement->GetAdditionEntryIndex() == _entryIndex
|
||||
&& !(pathElement->IsBroken()) && !pathElement->AdditionIsGhost())
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
auto* pathAdditionEntry = OpenRCT2::ObjectManager::GetObjectEntry<PathAdditionEntry>(_entryIndex);
|
||||
if (pathAdditionEntry == nullptr)
|
||||
{
|
||||
LOG_ERROR("Unknown footpath addition entry for entryIndex %d", _entryIndex);
|
||||
return Result(Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE, STR_UNKNOWN_OBJECT_TYPE);
|
||||
}
|
||||
|
||||
res.Cost = pathAdditionEntry->price;
|
||||
|
||||
if (GetFlags() & GAME_COMMAND_FLAG_GHOST)
|
||||
{
|
||||
pathElement->SetAdditionIsGhost(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
FootpathInterruptPeeps(_loc);
|
||||
pathElement->SetAdditionIsGhost(false);
|
||||
}
|
||||
|
||||
pathElement->SetAdditionEntryIndex(_entryIndex);
|
||||
pathElement->SetIsBroken(false);
|
||||
if (pathAdditionEntry->flags & PATH_ADDITION_FLAG_IS_BIN)
|
||||
{
|
||||
pathElement->SetAdditionStatus(255);
|
||||
}
|
||||
MapInvalidateTileFull(_loc);
|
||||
return res;
|
||||
}
|
||||
MapInvalidateTileFull(_loc);
|
||||
return res;
|
||||
}
|
||||
} // namespace OpenRCT2::GameActions
|
||||
|
||||
@@ -11,21 +11,24 @@
|
||||
|
||||
#include "GameAction.h"
|
||||
|
||||
class FootpathAdditionPlaceAction final : public GameActionBase<GameCommand::PlaceFootpathAddition>
|
||||
namespace OpenRCT2::GameActions
|
||||
{
|
||||
private:
|
||||
CoordsXYZ _loc;
|
||||
OpenRCT2::ObjectEntryIndex _entryIndex{};
|
||||
class FootpathAdditionPlaceAction final : public GameActionBase<GameCommand::PlaceFootpathAddition>
|
||||
{
|
||||
private:
|
||||
CoordsXYZ _loc;
|
||||
ObjectEntryIndex _entryIndex{};
|
||||
|
||||
public:
|
||||
FootpathAdditionPlaceAction() = default;
|
||||
FootpathAdditionPlaceAction(const CoordsXYZ& loc, OpenRCT2::ObjectEntryIndex pathItemType);
|
||||
public:
|
||||
FootpathAdditionPlaceAction() = default;
|
||||
FootpathAdditionPlaceAction(const CoordsXYZ& loc, ObjectEntryIndex pathItemType);
|
||||
|
||||
void AcceptParameters(GameActionParameterVisitor& visitor) override;
|
||||
void AcceptParameters(GameActionParameterVisitor& visitor) override;
|
||||
|
||||
uint16_t GetActionFlags() const override;
|
||||
uint16_t GetActionFlags() const override;
|
||||
|
||||
void Serialise(DataSerialiser& stream) override;
|
||||
OpenRCT2::GameActions::Result Query() const override;
|
||||
OpenRCT2::GameActions::Result Execute() const override;
|
||||
};
|
||||
void Serialise(DataSerialiser& stream) override;
|
||||
Result Query() const override;
|
||||
Result Execute() const override;
|
||||
};
|
||||
} // namespace OpenRCT2::GameActions
|
||||
|
||||
@@ -21,99 +21,97 @@
|
||||
#include "../world/Park.h"
|
||||
#include "../world/tile_element/PathElement.h"
|
||||
|
||||
using namespace OpenRCT2;
|
||||
|
||||
FootpathAdditionRemoveAction::FootpathAdditionRemoveAction(const CoordsXYZ& loc)
|
||||
: _loc(loc)
|
||||
namespace OpenRCT2::GameActions
|
||||
{
|
||||
}
|
||||
|
||||
void FootpathAdditionRemoveAction::AcceptParameters(GameActionParameterVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(_loc);
|
||||
}
|
||||
|
||||
uint16_t FootpathAdditionRemoveAction::GetActionFlags() const
|
||||
{
|
||||
return GameAction::GetActionFlags();
|
||||
}
|
||||
|
||||
void FootpathAdditionRemoveAction::Serialise(DataSerialiser& stream)
|
||||
{
|
||||
GameAction::Serialise(stream);
|
||||
|
||||
stream << DS_TAG(_loc);
|
||||
}
|
||||
|
||||
GameActions::Result FootpathAdditionRemoveAction::Query() const
|
||||
{
|
||||
if (!LocationValid(_loc))
|
||||
FootpathAdditionRemoveAction::FootpathAdditionRemoveAction(const CoordsXYZ& loc)
|
||||
: _loc(loc)
|
||||
{
|
||||
return GameActions::Result(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_OFF_EDGE_OF_MAP);
|
||||
}
|
||||
|
||||
if (!(gLegacyScene == LegacyScene::scenarioEditor || getGameState().cheats.sandboxMode) && !MapIsLocationOwned(_loc))
|
||||
void FootpathAdditionRemoveAction::AcceptParameters(GameActionParameterVisitor& visitor)
|
||||
{
|
||||
return GameActions::Result(GameActions::Status::Disallowed, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK);
|
||||
visitor.Visit(_loc);
|
||||
}
|
||||
|
||||
if (_loc.z < kFootpathMinHeight)
|
||||
uint16_t FootpathAdditionRemoveAction::GetActionFlags() const
|
||||
{
|
||||
return GameActions::Result(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_TOO_LOW);
|
||||
return GameAction::GetActionFlags();
|
||||
}
|
||||
|
||||
if (_loc.z > kFootpathMaxHeight)
|
||||
void FootpathAdditionRemoveAction::Serialise(DataSerialiser& stream)
|
||||
{
|
||||
return GameActions::Result(GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_TOO_HIGH);
|
||||
GameAction::Serialise(stream);
|
||||
|
||||
stream << DS_TAG(_loc);
|
||||
}
|
||||
|
||||
auto tileElement = MapGetFootpathElement(_loc);
|
||||
if (tileElement == nullptr)
|
||||
Result FootpathAdditionRemoveAction::Query() const
|
||||
{
|
||||
LOG_ERROR("No path element at x = %d, y = %d, z = %d", _loc.x, _loc.y, _loc.z);
|
||||
return GameActions::Result(
|
||||
GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_ERR_PATH_ELEMENT_NOT_FOUND);
|
||||
if (!LocationValid(_loc))
|
||||
{
|
||||
return Result(Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_OFF_EDGE_OF_MAP);
|
||||
}
|
||||
|
||||
if (!(gLegacyScene == LegacyScene::scenarioEditor || getGameState().cheats.sandboxMode) && !MapIsLocationOwned(_loc))
|
||||
{
|
||||
return Result(Status::Disallowed, STR_CANT_REMOVE_THIS, STR_LAND_NOT_OWNED_BY_PARK);
|
||||
}
|
||||
|
||||
if (_loc.z < kFootpathMinHeight)
|
||||
{
|
||||
return Result(Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_TOO_LOW);
|
||||
}
|
||||
|
||||
if (_loc.z > kFootpathMaxHeight)
|
||||
{
|
||||
return Result(Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_TOO_HIGH);
|
||||
}
|
||||
|
||||
auto tileElement = MapGetFootpathElement(_loc);
|
||||
if (tileElement == nullptr)
|
||||
{
|
||||
LOG_ERROR("No path element at x = %d, y = %d, z = %d", _loc.x, _loc.y, _loc.z);
|
||||
return Result(Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_ERR_PATH_ELEMENT_NOT_FOUND);
|
||||
}
|
||||
|
||||
auto pathElement = tileElement->AsPath();
|
||||
if (pathElement == nullptr)
|
||||
{
|
||||
LOG_ERROR("No path element at x = %d, y = %d, z = %d", _loc.x, _loc.y, _loc.z);
|
||||
return Result(Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_ERR_PATH_ELEMENT_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (!pathElement->AdditionIsGhost() && (GetFlags() & GAME_COMMAND_FLAG_GHOST))
|
||||
{
|
||||
LOG_WARNING("Tried to remove non ghost during ghost removal.");
|
||||
return Result(Status::Disallowed, STR_CANT_REMOVE_THIS, kStringIdNone);
|
||||
}
|
||||
auto res = Result();
|
||||
res.Position = _loc;
|
||||
res.Cost = 0.00_GBP;
|
||||
return res;
|
||||
}
|
||||
|
||||
auto pathElement = tileElement->AsPath();
|
||||
if (pathElement == nullptr)
|
||||
Result FootpathAdditionRemoveAction::Execute() const
|
||||
{
|
||||
LOG_ERROR("No path element at x = %d, y = %d, z = %d", _loc.x, _loc.y, _loc.z);
|
||||
return GameActions::Result(
|
||||
GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_ERR_PATH_ELEMENT_NOT_FOUND);
|
||||
auto* pathElement = MapGetFootpathElement(_loc);
|
||||
if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST))
|
||||
{
|
||||
FootpathInterruptPeeps(_loc);
|
||||
}
|
||||
|
||||
if (pathElement == nullptr)
|
||||
{
|
||||
LOG_ERROR("No path element at x = %d, y = %d, z = %d", _loc.x, _loc.y, _loc.z);
|
||||
return Result(Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_ERR_PATH_ELEMENT_NOT_FOUND);
|
||||
}
|
||||
|
||||
pathElement->SetAddition(0);
|
||||
MapInvalidateTileFull(_loc);
|
||||
|
||||
auto res = Result();
|
||||
res.Position = _loc;
|
||||
res.Cost = 0.00_GBP;
|
||||
return res;
|
||||
}
|
||||
|
||||
if (!pathElement->AdditionIsGhost() && (GetFlags() & GAME_COMMAND_FLAG_GHOST))
|
||||
{
|
||||
LOG_WARNING("Tried to remove non ghost during ghost removal.");
|
||||
return GameActions::Result(GameActions::Status::Disallowed, STR_CANT_REMOVE_THIS, kStringIdNone);
|
||||
}
|
||||
auto res = GameActions::Result();
|
||||
res.Position = _loc;
|
||||
res.Cost = 0.00_GBP;
|
||||
return res;
|
||||
}
|
||||
|
||||
GameActions::Result FootpathAdditionRemoveAction::Execute() const
|
||||
{
|
||||
auto* pathElement = MapGetFootpathElement(_loc);
|
||||
if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST))
|
||||
{
|
||||
FootpathInterruptPeeps(_loc);
|
||||
}
|
||||
|
||||
if (pathElement == nullptr)
|
||||
{
|
||||
LOG_ERROR("No path element at x = %d, y = %d, z = %d", _loc.x, _loc.y, _loc.z);
|
||||
return GameActions::Result(
|
||||
GameActions::Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_ERR_PATH_ELEMENT_NOT_FOUND);
|
||||
}
|
||||
|
||||
pathElement->SetAddition(0);
|
||||
MapInvalidateTileFull(_loc);
|
||||
|
||||
auto res = GameActions::Result();
|
||||
res.Position = _loc;
|
||||
res.Cost = 0.00_GBP;
|
||||
return res;
|
||||
}
|
||||
} // namespace OpenRCT2::GameActions
|
||||
|
||||
@@ -11,20 +11,23 @@
|
||||
|
||||
#include "GameAction.h"
|
||||
|
||||
class FootpathAdditionRemoveAction final : public GameActionBase<GameCommand::RemoveFootpathAddition>
|
||||
namespace OpenRCT2::GameActions
|
||||
{
|
||||
private:
|
||||
CoordsXYZ _loc;
|
||||
class FootpathAdditionRemoveAction final : public GameActionBase<GameCommand::RemoveFootpathAddition>
|
||||
{
|
||||
private:
|
||||
CoordsXYZ _loc;
|
||||
|
||||
public:
|
||||
FootpathAdditionRemoveAction() = default;
|
||||
FootpathAdditionRemoveAction(const CoordsXYZ& loc);
|
||||
public:
|
||||
FootpathAdditionRemoveAction() = default;
|
||||
FootpathAdditionRemoveAction(const CoordsXYZ& loc);
|
||||
|
||||
void AcceptParameters(GameActionParameterVisitor& visitor) override;
|
||||
void AcceptParameters(GameActionParameterVisitor& visitor) override;
|
||||
|
||||
uint16_t GetActionFlags() const override;
|
||||
uint16_t GetActionFlags() const override;
|
||||
|
||||
void Serialise(DataSerialiser& stream) override;
|
||||
OpenRCT2::GameActions::Result Query() const override;
|
||||
OpenRCT2::GameActions::Result Execute() const override;
|
||||
};
|
||||
void Serialise(DataSerialiser& stream) override;
|
||||
Result Query() const override;
|
||||
Result Execute() const override;
|
||||
};
|
||||
} // namespace OpenRCT2::GameActions
|
||||
|
||||
@@ -26,295 +26,291 @@
|
||||
#include "../world/tile_element/Slope.h"
|
||||
#include "../world/tile_element/SurfaceElement.h"
|
||||
|
||||
using namespace OpenRCT2;
|
||||
|
||||
FootpathLayoutPlaceAction::FootpathLayoutPlaceAction(
|
||||
const CoordsXYZ& loc, uint8_t slope, ObjectEntryIndex type, ObjectEntryIndex railingsType, uint8_t edges,
|
||||
PathConstructFlags constructFlags)
|
||||
: _loc(loc)
|
||||
, _slope(slope)
|
||||
, _type(type)
|
||||
, _railingsType(railingsType)
|
||||
, _edges(edges)
|
||||
, _constructFlags(constructFlags)
|
||||
namespace OpenRCT2::GameActions
|
||||
{
|
||||
}
|
||||
|
||||
void FootpathLayoutPlaceAction::Serialise(DataSerialiser& stream)
|
||||
{
|
||||
GameAction::Serialise(stream);
|
||||
|
||||
stream << DS_TAG(_loc) << DS_TAG(_slope) << DS_TAG(_type) << DS_TAG(_railingsType) << DS_TAG(_edges)
|
||||
<< DS_TAG(_constructFlags);
|
||||
}
|
||||
|
||||
void FootpathLayoutPlaceAction::AcceptParameters(GameActionParameterVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(_loc);
|
||||
visitor.Visit("slope", _slope);
|
||||
visitor.Visit("object", _type);
|
||||
visitor.Visit("railingsObject", _railingsType);
|
||||
visitor.Visit("edges", _edges);
|
||||
visitor.Visit("constructFlags", _constructFlags);
|
||||
}
|
||||
|
||||
uint16_t FootpathLayoutPlaceAction::GetActionFlags() const
|
||||
{
|
||||
return GameAction::GetActionFlags();
|
||||
}
|
||||
|
||||
GameActions::Result FootpathLayoutPlaceAction::Query() const
|
||||
{
|
||||
auto res = GameActions::Result();
|
||||
res.Cost = 0;
|
||||
res.Expenditure = ExpenditureType::landscaping;
|
||||
res.Position = _loc.ToTileCentre();
|
||||
|
||||
gFootpathGroundFlags = 0;
|
||||
|
||||
if (!LocationValid(_loc) || MapIsEdge(_loc))
|
||||
FootpathLayoutPlaceAction::FootpathLayoutPlaceAction(
|
||||
const CoordsXYZ& loc, uint8_t slope, ObjectEntryIndex type, ObjectEntryIndex railingsType, uint8_t edges,
|
||||
PathConstructFlags constructFlags)
|
||||
: _loc(loc)
|
||||
, _slope(slope)
|
||||
, _type(type)
|
||||
, _railingsType(railingsType)
|
||||
, _edges(edges)
|
||||
, _constructFlags(constructFlags)
|
||||
{
|
||||
return GameActions::Result(
|
||||
GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_OFF_EDGE_OF_MAP);
|
||||
}
|
||||
|
||||
if (!(gLegacyScene == LegacyScene::scenarioEditor || getGameState().cheats.sandboxMode) && !MapIsLocationOwned(_loc))
|
||||
void FootpathLayoutPlaceAction::Serialise(DataSerialiser& stream)
|
||||
{
|
||||
return GameActions::Result(
|
||||
GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_LAND_NOT_OWNED_BY_PARK);
|
||||
GameAction::Serialise(stream);
|
||||
|
||||
stream << DS_TAG(_loc) << DS_TAG(_slope) << DS_TAG(_type) << DS_TAG(_railingsType) << DS_TAG(_edges)
|
||||
<< DS_TAG(_constructFlags);
|
||||
}
|
||||
|
||||
if (_loc.z < kFootpathMinHeight)
|
||||
void FootpathLayoutPlaceAction::AcceptParameters(GameActionParameterVisitor& visitor)
|
||||
{
|
||||
return GameActions::Result(
|
||||
GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_TOO_LOW);
|
||||
visitor.Visit(_loc);
|
||||
visitor.Visit("slope", _slope);
|
||||
visitor.Visit("object", _type);
|
||||
visitor.Visit("railingsObject", _railingsType);
|
||||
visitor.Visit("edges", _edges);
|
||||
visitor.Visit("constructFlags", _constructFlags);
|
||||
}
|
||||
|
||||
if (_loc.z > kFootpathMaxHeight)
|
||||
uint16_t FootpathLayoutPlaceAction::GetActionFlags() const
|
||||
{
|
||||
return GameActions::Result(
|
||||
GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_TOO_HIGH);
|
||||
return GameAction::GetActionFlags();
|
||||
}
|
||||
|
||||
return ElementInsertQuery(std::move(res));
|
||||
}
|
||||
|
||||
GameActions::Result FootpathLayoutPlaceAction::Execute() const
|
||||
{
|
||||
auto res = GameActions::Result();
|
||||
res.Cost = 0;
|
||||
res.Expenditure = ExpenditureType::landscaping;
|
||||
res.Position = _loc.ToTileCentre();
|
||||
|
||||
if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST))
|
||||
Result FootpathLayoutPlaceAction::Query() const
|
||||
{
|
||||
FootpathInterruptPeeps(_loc);
|
||||
}
|
||||
|
||||
gFootpathGroundFlags = 0;
|
||||
|
||||
// Force ride construction to recheck area
|
||||
_currentTrackSelectionFlags.set(TrackSelectionFlag::recheck);
|
||||
|
||||
return ElementInsertExecute(std::move(res));
|
||||
}
|
||||
|
||||
GameActions::Result FootpathLayoutPlaceAction::ElementInsertQuery(GameActions::Result res) const
|
||||
{
|
||||
bool entrancePath = false, entranceIsSamePath = false;
|
||||
|
||||
if (!MapCheckCapacityAndReorganise(_loc))
|
||||
{
|
||||
return GameActions::Result(
|
||||
GameActions::Status::NoFreeElements, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE,
|
||||
STR_TILE_ELEMENT_LIMIT_REACHED);
|
||||
}
|
||||
|
||||
res.Cost = 12.00_GBP;
|
||||
|
||||
QuarterTile quarterTile{ 0b1111, 0 };
|
||||
auto zLow = _loc.z;
|
||||
auto zHigh = zLow + kPathClearance;
|
||||
if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED)
|
||||
{
|
||||
quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope & kTileElementDirectionMask);
|
||||
zHigh += kPathHeightStep;
|
||||
}
|
||||
|
||||
auto entranceElement = MapGetParkEntranceElementAt(_loc, 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 (IsSameAsEntranceElement(*entranceElement))
|
||||
entranceIsSamePath = true;
|
||||
else
|
||||
res.Cost -= 6.00_GBP;
|
||||
}
|
||||
|
||||
// Do not attempt to build a crossing with a queue or a sloped path.
|
||||
auto isQueue = _constructFlags & PathConstructFlag::IsQueue;
|
||||
auto crossingMode = isQueue || (_slope != kTileSlopeFlat) ? CreateCrossingMode::none : CreateCrossingMode::pathOverTrack;
|
||||
auto canBuild = MapCanConstructWithClearAt(
|
||||
{ _loc, zLow, zHigh }, &MapPlaceNonSceneryClearFunc, quarterTile, GetFlags(), crossingMode);
|
||||
if (!entrancePath && canBuild.Error != GameActions::Status::Ok)
|
||||
{
|
||||
canBuild.ErrorTitle = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE;
|
||||
return canBuild;
|
||||
}
|
||||
res.Cost += canBuild.Cost;
|
||||
|
||||
const auto clearanceData = canBuild.GetData<ConstructClearResult>();
|
||||
gFootpathGroundFlags = clearanceData.GroundFlags;
|
||||
|
||||
if (!getGameState().cheats.disableClearanceChecks && (clearanceData.GroundFlags & ELEMENT_IS_UNDERWATER))
|
||||
{
|
||||
return GameActions::Result(
|
||||
GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_CANT_BUILD_THIS_UNDERWATER);
|
||||
}
|
||||
|
||||
auto surfaceElement = MapGetSurfaceElementAt(_loc);
|
||||
if (surfaceElement == nullptr)
|
||||
{
|
||||
return GameActions::Result(
|
||||
GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE,
|
||||
STR_ERR_SURFACE_ELEMENT_NOT_FOUND);
|
||||
}
|
||||
int32_t supportHeight = zLow - surfaceElement->GetBaseZ();
|
||||
res.Cost += supportHeight < 0 ? 20.00_GBP : (supportHeight / kPathHeightStep) * 5.00_GBP;
|
||||
|
||||
// Prevent the place sound from being spammed
|
||||
if (entranceIsSamePath)
|
||||
auto res = Result();
|
||||
res.Cost = 0;
|
||||
res.Expenditure = ExpenditureType::landscaping;
|
||||
res.Position = _loc.ToTileCentre();
|
||||
|
||||
return res;
|
||||
}
|
||||
gFootpathGroundFlags = 0;
|
||||
|
||||
GameActions::Result FootpathLayoutPlaceAction::ElementInsertExecute(GameActions::Result res) const
|
||||
{
|
||||
bool entrancePath = false, entranceIsSamePath = false;
|
||||
|
||||
if (!(GetFlags() & (GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_GHOST)))
|
||||
{
|
||||
FootpathRemoveLitter(_loc);
|
||||
}
|
||||
|
||||
res.Cost = 12.00_GBP;
|
||||
|
||||
QuarterTile quarterTile{ 0b1111, 0 };
|
||||
auto zLow = _loc.z;
|
||||
auto zHigh = zLow + kPathClearance;
|
||||
if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED)
|
||||
{
|
||||
quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope & kTileElementDirectionMask);
|
||||
zHigh += kPathHeightStep;
|
||||
}
|
||||
|
||||
auto entranceElement = MapGetParkEntranceElementAt(_loc, 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 (IsSameAsEntranceElement(*entranceElement))
|
||||
entranceIsSamePath = true;
|
||||
else
|
||||
res.Cost -= 6.00_GBP;
|
||||
}
|
||||
|
||||
// Do not attempt to build a crossing with a queue or a sloped path.
|
||||
auto isQueue = _constructFlags & PathConstructFlag::IsQueue;
|
||||
auto crossingMode = isQueue || (_slope != kTileSlopeFlat) ? CreateCrossingMode::none : CreateCrossingMode::pathOverTrack;
|
||||
auto canBuild = MapCanConstructWithClearAt(
|
||||
{ _loc, zLow, zHigh }, &MapPlaceNonSceneryClearFunc, quarterTile, GAME_COMMAND_FLAG_APPLY | GetFlags(), crossingMode);
|
||||
if (!entrancePath && canBuild.Error != GameActions::Status::Ok)
|
||||
{
|
||||
canBuild.ErrorTitle = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE;
|
||||
return canBuild;
|
||||
}
|
||||
res.Cost += canBuild.Cost;
|
||||
|
||||
const auto clearanceData = canBuild.GetData<ConstructClearResult>();
|
||||
gFootpathGroundFlags = clearanceData.GroundFlags;
|
||||
|
||||
auto surfaceElement = MapGetSurfaceElementAt(_loc);
|
||||
if (surfaceElement == nullptr)
|
||||
{
|
||||
return GameActions::Result(
|
||||
GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE,
|
||||
STR_ERR_SURFACE_ELEMENT_NOT_FOUND);
|
||||
}
|
||||
int32_t supportHeight = zLow - surfaceElement->GetBaseZ();
|
||||
res.Cost += supportHeight < 0 ? 20.00_GBP : (supportHeight / kPathHeightStep) * 5.00_GBP;
|
||||
|
||||
if (entrancePath)
|
||||
{
|
||||
if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && !entranceIsSamePath)
|
||||
if (!LocationValid(_loc) || MapIsEdge(_loc))
|
||||
{
|
||||
return Result(Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_OFF_EDGE_OF_MAP);
|
||||
}
|
||||
|
||||
if (!(gLegacyScene == LegacyScene::scenarioEditor || getGameState().cheats.sandboxMode) && !MapIsLocationOwned(_loc))
|
||||
{
|
||||
return Result(Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_LAND_NOT_OWNED_BY_PARK);
|
||||
}
|
||||
|
||||
if (_loc.z < kFootpathMinHeight)
|
||||
{
|
||||
return Result(Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_TOO_LOW);
|
||||
}
|
||||
|
||||
if (_loc.z > kFootpathMaxHeight)
|
||||
{
|
||||
return Result(Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_TOO_HIGH);
|
||||
}
|
||||
|
||||
return ElementInsertQuery(std::move(res));
|
||||
}
|
||||
|
||||
Result FootpathLayoutPlaceAction::Execute() const
|
||||
{
|
||||
auto res = Result();
|
||||
res.Cost = 0;
|
||||
res.Expenditure = ExpenditureType::landscaping;
|
||||
res.Position = _loc.ToTileCentre();
|
||||
|
||||
if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST))
|
||||
{
|
||||
FootpathInterruptPeeps(_loc);
|
||||
}
|
||||
|
||||
gFootpathGroundFlags = 0;
|
||||
|
||||
// Force ride construction to recheck area
|
||||
_currentTrackSelectionFlags.set(TrackSelectionFlag::recheck);
|
||||
|
||||
return ElementInsertExecute(std::move(res));
|
||||
}
|
||||
|
||||
Result FootpathLayoutPlaceAction::ElementInsertQuery(Result res) const
|
||||
{
|
||||
bool entrancePath = false, entranceIsSamePath = false;
|
||||
|
||||
if (!MapCheckCapacityAndReorganise(_loc))
|
||||
{
|
||||
return Result(
|
||||
Status::NoFreeElements, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_TILE_ELEMENT_LIMIT_REACHED);
|
||||
}
|
||||
|
||||
res.Cost = 12.00_GBP;
|
||||
|
||||
QuarterTile quarterTile{ 0b1111, 0 };
|
||||
auto zLow = _loc.z;
|
||||
auto zHigh = zLow + kPathClearance;
|
||||
if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED)
|
||||
{
|
||||
quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope & kTileElementDirectionMask);
|
||||
zHigh += kPathHeightStep;
|
||||
}
|
||||
|
||||
auto entranceElement = MapGetParkEntranceElementAt(_loc, 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 (IsSameAsEntranceElement(*entranceElement))
|
||||
entranceIsSamePath = true;
|
||||
else
|
||||
res.Cost -= 6.00_GBP;
|
||||
}
|
||||
|
||||
// Do not attempt to build a crossing with a queue or a sloped path.
|
||||
auto isQueue = _constructFlags & PathConstructFlag::IsQueue;
|
||||
auto crossingMode = isQueue || (_slope != kTileSlopeFlat) ? CreateCrossingMode::none
|
||||
: CreateCrossingMode::pathOverTrack;
|
||||
auto canBuild = MapCanConstructWithClearAt(
|
||||
{ _loc, zLow, zHigh }, &MapPlaceNonSceneryClearFunc, quarterTile, GetFlags(), crossingMode);
|
||||
if (!entrancePath && canBuild.Error != Status::Ok)
|
||||
{
|
||||
canBuild.ErrorTitle = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE;
|
||||
return canBuild;
|
||||
}
|
||||
res.Cost += canBuild.Cost;
|
||||
|
||||
const auto clearanceData = canBuild.GetData<ConstructClearResult>();
|
||||
gFootpathGroundFlags = clearanceData.GroundFlags;
|
||||
|
||||
if (!getGameState().cheats.disableClearanceChecks && (clearanceData.GroundFlags & ELEMENT_IS_UNDERWATER))
|
||||
{
|
||||
return Result(Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_CANT_BUILD_THIS_UNDERWATER);
|
||||
}
|
||||
|
||||
auto surfaceElement = MapGetSurfaceElementAt(_loc);
|
||||
if (surfaceElement == nullptr)
|
||||
{
|
||||
return Result(
|
||||
Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_ERR_SURFACE_ELEMENT_NOT_FOUND);
|
||||
}
|
||||
int32_t supportHeight = zLow - surfaceElement->GetBaseZ();
|
||||
res.Cost += supportHeight < 0 ? 20.00_GBP : (supportHeight / kPathHeightStep) * 5.00_GBP;
|
||||
|
||||
// Prevent the place sound from being spammed
|
||||
if (entranceIsSamePath)
|
||||
res.Cost = 0;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
Result FootpathLayoutPlaceAction::ElementInsertExecute(Result res) const
|
||||
{
|
||||
bool entrancePath = false, entranceIsSamePath = false;
|
||||
|
||||
if (!(GetFlags() & (GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_GHOST)))
|
||||
{
|
||||
FootpathRemoveLitter(_loc);
|
||||
}
|
||||
|
||||
res.Cost = 12.00_GBP;
|
||||
|
||||
QuarterTile quarterTile{ 0b1111, 0 };
|
||||
auto zLow = _loc.z;
|
||||
auto zHigh = zLow + kPathClearance;
|
||||
if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED)
|
||||
{
|
||||
quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope & kTileElementDirectionMask);
|
||||
zHigh += kPathHeightStep;
|
||||
}
|
||||
|
||||
auto entranceElement = MapGetParkEntranceElementAt(_loc, 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 (IsSameAsEntranceElement(*entranceElement))
|
||||
entranceIsSamePath = true;
|
||||
else
|
||||
res.Cost -= 6.00_GBP;
|
||||
}
|
||||
|
||||
// Do not attempt to build a crossing with a queue or a sloped path.
|
||||
auto isQueue = _constructFlags & PathConstructFlag::IsQueue;
|
||||
auto crossingMode = isQueue || (_slope != kTileSlopeFlat) ? CreateCrossingMode::none
|
||||
: CreateCrossingMode::pathOverTrack;
|
||||
auto canBuild = MapCanConstructWithClearAt(
|
||||
{ _loc, zLow, zHigh }, &MapPlaceNonSceneryClearFunc, quarterTile, GAME_COMMAND_FLAG_APPLY | GetFlags(),
|
||||
crossingMode);
|
||||
if (!entrancePath && canBuild.Error != Status::Ok)
|
||||
{
|
||||
canBuild.ErrorTitle = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE;
|
||||
return canBuild;
|
||||
}
|
||||
res.Cost += canBuild.Cost;
|
||||
|
||||
const auto clearanceData = canBuild.GetData<ConstructClearResult>();
|
||||
gFootpathGroundFlags = clearanceData.GroundFlags;
|
||||
|
||||
auto surfaceElement = MapGetSurfaceElementAt(_loc);
|
||||
if (surfaceElement == nullptr)
|
||||
{
|
||||
return Result(
|
||||
Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_ERR_SURFACE_ELEMENT_NOT_FOUND);
|
||||
}
|
||||
int32_t supportHeight = zLow - surfaceElement->GetBaseZ();
|
||||
res.Cost += supportHeight < 0 ? 20.00_GBP : (supportHeight / kPathHeightStep) * 5.00_GBP;
|
||||
|
||||
if (entrancePath)
|
||||
{
|
||||
if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && !entranceIsSamePath)
|
||||
{
|
||||
if (_constructFlags & PathConstructFlag::IsLegacyPathObject)
|
||||
{
|
||||
entranceElement->SetLegacyPathEntryIndex(_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
entranceElement->SetSurfaceEntryIndex(_type);
|
||||
}
|
||||
MapInvalidateTileFull(_loc);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto* pathElement = TileElementInsert<PathElement>(_loc, 0b1111);
|
||||
Guard::Assert(pathElement != nullptr);
|
||||
|
||||
pathElement->SetClearanceZ(zHigh);
|
||||
if (_constructFlags & PathConstructFlag::IsLegacyPathObject)
|
||||
{
|
||||
entranceElement->SetLegacyPathEntryIndex(_type);
|
||||
pathElement->SetLegacyPathEntryIndex(_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
entranceElement->SetSurfaceEntryIndex(_type);
|
||||
pathElement->SetSurfaceEntryIndex(_type);
|
||||
pathElement->SetRailingsEntryIndex(_railingsType);
|
||||
}
|
||||
pathElement->SetSlopeDirection(_slope & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK);
|
||||
pathElement->SetSloped(_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED);
|
||||
pathElement->SetIsQueue(isQueue);
|
||||
pathElement->SetAddition(0);
|
||||
pathElement->SetRideIndex(RideId::GetNull());
|
||||
pathElement->SetAdditionStatus(255);
|
||||
pathElement->SetIsBroken(false);
|
||||
pathElement->SetEdges(_edges);
|
||||
pathElement->SetCorners(0);
|
||||
pathElement->SetGhost(GetFlags() & GAME_COMMAND_FLAG_GHOST);
|
||||
|
||||
MapInvalidateTileFull(_loc);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto* pathElement = TileElementInsert<PathElement>(_loc, 0b1111);
|
||||
Guard::Assert(pathElement != nullptr);
|
||||
|
||||
pathElement->SetClearanceZ(zHigh);
|
||||
// Prevent the place sound from being spammed
|
||||
if (entranceIsSamePath)
|
||||
res.Cost = 0;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool FootpathLayoutPlaceAction::IsSameAsEntranceElement(const EntranceElement& entranceElement) const
|
||||
{
|
||||
if (entranceElement.HasLegacyPathEntry())
|
||||
{
|
||||
if (_constructFlags & PathConstructFlag::IsLegacyPathObject)
|
||||
{
|
||||
return entranceElement.GetLegacyPathEntryIndex() == _type;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_constructFlags & PathConstructFlag::IsLegacyPathObject)
|
||||
{
|
||||
pathElement->SetLegacyPathEntryIndex(_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
pathElement->SetSurfaceEntryIndex(_type);
|
||||
pathElement->SetRailingsEntryIndex(_railingsType);
|
||||
}
|
||||
pathElement->SetSlopeDirection(_slope & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK);
|
||||
pathElement->SetSloped(_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED);
|
||||
pathElement->SetIsQueue(isQueue);
|
||||
pathElement->SetAddition(0);
|
||||
pathElement->SetRideIndex(RideId::GetNull());
|
||||
pathElement->SetAdditionStatus(255);
|
||||
pathElement->SetIsBroken(false);
|
||||
pathElement->SetEdges(_edges);
|
||||
pathElement->SetCorners(0);
|
||||
pathElement->SetGhost(GetFlags() & GAME_COMMAND_FLAG_GHOST);
|
||||
|
||||
MapInvalidateTileFull(_loc);
|
||||
}
|
||||
|
||||
// Prevent the place sound from being spammed
|
||||
if (entranceIsSamePath)
|
||||
res.Cost = 0;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool FootpathLayoutPlaceAction::IsSameAsEntranceElement(const EntranceElement& entranceElement) const
|
||||
{
|
||||
if (entranceElement.HasLegacyPathEntry())
|
||||
{
|
||||
if (_constructFlags & PathConstructFlag::IsLegacyPathObject)
|
||||
{
|
||||
return entranceElement.GetLegacyPathEntryIndex() == _type;
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
return entranceElement.GetSurfaceEntryIndex() == _type;
|
||||
}
|
||||
|
||||
if (_constructFlags & PathConstructFlag::IsLegacyPathObject)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return entranceElement.GetSurfaceEntryIndex() == _type;
|
||||
}
|
||||
} // namespace OpenRCT2::GameActions
|
||||
|
||||
@@ -12,32 +12,35 @@
|
||||
#include "../world/Footpath.h"
|
||||
#include "GameAction.h"
|
||||
|
||||
class FootpathLayoutPlaceAction final : public GameActionBase<GameCommand::PlacePathLayout>
|
||||
namespace OpenRCT2::GameActions
|
||||
{
|
||||
private:
|
||||
CoordsXYZ _loc;
|
||||
uint8_t _slope{};
|
||||
OpenRCT2::ObjectEntryIndex _type{};
|
||||
OpenRCT2::ObjectEntryIndex _railingsType{};
|
||||
uint8_t _edges{};
|
||||
PathConstructFlags _constructFlags{};
|
||||
class FootpathLayoutPlaceAction final : public GameActionBase<GameCommand::PlacePathLayout>
|
||||
{
|
||||
private:
|
||||
CoordsXYZ _loc;
|
||||
uint8_t _slope{};
|
||||
ObjectEntryIndex _type{};
|
||||
ObjectEntryIndex _railingsType{};
|
||||
uint8_t _edges{};
|
||||
PathConstructFlags _constructFlags{};
|
||||
|
||||
public:
|
||||
FootpathLayoutPlaceAction() = default;
|
||||
FootpathLayoutPlaceAction(
|
||||
const CoordsXYZ& loc, uint8_t slope, OpenRCT2::ObjectEntryIndex type, OpenRCT2::ObjectEntryIndex railingsType,
|
||||
uint8_t edges, PathConstructFlags constructFlags = 0);
|
||||
public:
|
||||
FootpathLayoutPlaceAction() = default;
|
||||
FootpathLayoutPlaceAction(
|
||||
const CoordsXYZ& loc, uint8_t slope, ObjectEntryIndex type, ObjectEntryIndex railingsType, uint8_t edges,
|
||||
PathConstructFlags constructFlags = 0);
|
||||
|
||||
void AcceptParameters(GameActionParameterVisitor& visitor) override;
|
||||
void AcceptParameters(GameActionParameterVisitor& visitor) override;
|
||||
|
||||
uint16_t GetActionFlags() const override;
|
||||
uint16_t GetActionFlags() const override;
|
||||
|
||||
void Serialise(DataSerialiser& stream) override;
|
||||
OpenRCT2::GameActions::Result Query() const override;
|
||||
OpenRCT2::GameActions::Result Execute() const override;
|
||||
void Serialise(DataSerialiser& stream) override;
|
||||
Result Query() const override;
|
||||
Result Execute() const override;
|
||||
|
||||
private:
|
||||
OpenRCT2::GameActions::Result ElementInsertQuery(OpenRCT2::GameActions::Result res) const;
|
||||
OpenRCT2::GameActions::Result ElementInsertExecute(OpenRCT2::GameActions::Result res) const;
|
||||
bool IsSameAsEntranceElement(const OpenRCT2::EntranceElement& entranceElement) const;
|
||||
};
|
||||
private:
|
||||
Result ElementInsertQuery(Result res) const;
|
||||
Result ElementInsertExecute(Result res) const;
|
||||
bool IsSameAsEntranceElement(const EntranceElement& entranceElement) const;
|
||||
};
|
||||
} // namespace OpenRCT2::GameActions
|
||||
|
||||
@@ -35,399 +35,212 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace OpenRCT2;
|
||||
|
||||
FootpathPlaceAction::FootpathPlaceAction(
|
||||
const CoordsXYZ& loc, uint8_t slope, ObjectEntryIndex type, ObjectEntryIndex railingsType, Direction direction,
|
||||
PathConstructFlags constructFlags)
|
||||
: _loc(loc)
|
||||
, _slope(slope)
|
||||
, _type(type)
|
||||
, _railingsType(railingsType)
|
||||
, _direction(direction)
|
||||
, _constructFlags(constructFlags)
|
||||
namespace OpenRCT2::GameActions
|
||||
{
|
||||
}
|
||||
|
||||
void FootpathPlaceAction::AcceptParameters(GameActionParameterVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(_loc);
|
||||
visitor.Visit("object", _type);
|
||||
visitor.Visit("railingsObject", _railingsType);
|
||||
visitor.Visit("direction", _direction);
|
||||
visitor.Visit("slope", _slope);
|
||||
visitor.Visit("constructFlags", _constructFlags);
|
||||
}
|
||||
|
||||
uint16_t FootpathPlaceAction::GetActionFlags() const
|
||||
{
|
||||
return GameAction::GetActionFlags();
|
||||
}
|
||||
|
||||
void FootpathPlaceAction::Serialise(DataSerialiser& stream)
|
||||
{
|
||||
GameAction::Serialise(stream);
|
||||
|
||||
stream << DS_TAG(_loc) << DS_TAG(_slope) << DS_TAG(_type) << DS_TAG(_railingsType) << DS_TAG(_direction)
|
||||
<< DS_TAG(_constructFlags);
|
||||
}
|
||||
|
||||
GameActions::Result FootpathPlaceAction::Query() const
|
||||
{
|
||||
auto res = GameActions::Result();
|
||||
res.Cost = 0;
|
||||
res.Expenditure = ExpenditureType::landscaping;
|
||||
res.Position = _loc.ToTileCentre();
|
||||
|
||||
gFootpathGroundFlags = 0;
|
||||
|
||||
if (!LocationValid(_loc) || MapIsEdge(_loc))
|
||||
FootpathPlaceAction::FootpathPlaceAction(
|
||||
const CoordsXYZ& loc, uint8_t slope, ObjectEntryIndex type, ObjectEntryIndex railingsType, Direction direction,
|
||||
PathConstructFlags constructFlags)
|
||||
: _loc(loc)
|
||||
, _slope(slope)
|
||||
, _type(type)
|
||||
, _railingsType(railingsType)
|
||||
, _direction(direction)
|
||||
, _constructFlags(constructFlags)
|
||||
{
|
||||
return GameActions::Result(GameActions::Status::InvalidParameters, STR_CANT_BUILD_FOOTPATH_HERE, STR_OFF_EDGE_OF_MAP);
|
||||
}
|
||||
|
||||
if (!(gLegacyScene == LegacyScene::scenarioEditor || getGameState().cheats.sandboxMode) && !MapIsLocationOwned(_loc))
|
||||
void FootpathPlaceAction::AcceptParameters(GameActionParameterVisitor& visitor)
|
||||
{
|
||||
return GameActions::Result(GameActions::Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_LAND_NOT_OWNED_BY_PARK);
|
||||
visitor.Visit(_loc);
|
||||
visitor.Visit("object", _type);
|
||||
visitor.Visit("railingsObject", _railingsType);
|
||||
visitor.Visit("direction", _direction);
|
||||
visitor.Visit("slope", _slope);
|
||||
visitor.Visit("constructFlags", _constructFlags);
|
||||
}
|
||||
|
||||
if (_slope & SLOPE_IS_IRREGULAR_FLAG)
|
||||
uint16_t FootpathPlaceAction::GetActionFlags() const
|
||||
{
|
||||
return GameActions::Result(GameActions::Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_LAND_SLOPE_UNSUITABLE);
|
||||
return GameAction::GetActionFlags();
|
||||
}
|
||||
|
||||
if (_loc.z < kFootpathMinHeight)
|
||||
void FootpathPlaceAction::Serialise(DataSerialiser& stream)
|
||||
{
|
||||
return GameActions::Result(GameActions::Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_TOO_LOW);
|
||||
GameAction::Serialise(stream);
|
||||
|
||||
stream << DS_TAG(_loc) << DS_TAG(_slope) << DS_TAG(_type) << DS_TAG(_railingsType) << DS_TAG(_direction)
|
||||
<< DS_TAG(_constructFlags);
|
||||
}
|
||||
|
||||
if (_loc.z > kFootpathMaxHeight)
|
||||
Result FootpathPlaceAction::Query() const
|
||||
{
|
||||
return GameActions::Result(GameActions::Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_TOO_HIGH);
|
||||
}
|
||||
auto res = Result();
|
||||
res.Cost = 0;
|
||||
res.Expenditure = ExpenditureType::landscaping;
|
||||
res.Position = _loc.ToTileCentre();
|
||||
|
||||
if (_direction != kInvalidDirection && !DirectionValid(_direction))
|
||||
{
|
||||
LOG_ERROR("Direction invalid. direction = %u", _direction);
|
||||
return GameActions::Result(
|
||||
GameActions::Status::InvalidParameters, STR_CANT_BUILD_FOOTPATH_HERE, STR_ERR_VALUE_OUT_OF_RANGE);
|
||||
}
|
||||
gFootpathGroundFlags = 0;
|
||||
|
||||
auto intent = Intent(INTENT_ACTION_REMOVE_PROVISIONAL_FOOTPATH);
|
||||
ContextBroadcastIntent(&intent);
|
||||
|
||||
auto tileElement = MapGetFootpathElementSlope(_loc, _slope);
|
||||
if (tileElement == nullptr)
|
||||
{
|
||||
return ElementInsertQuery(std::move(res));
|
||||
}
|
||||
return ElementUpdateQuery(tileElement, std::move(res));
|
||||
}
|
||||
|
||||
GameActions::Result FootpathPlaceAction::Execute() const
|
||||
{
|
||||
auto res = GameActions::Result();
|
||||
res.Cost = 0;
|
||||
res.Expenditure = ExpenditureType::landscaping;
|
||||
res.Position = _loc.ToTileCentre();
|
||||
|
||||
if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST))
|
||||
{
|
||||
FootpathInterruptPeeps(_loc);
|
||||
}
|
||||
|
||||
gFootpathGroundFlags = 0;
|
||||
|
||||
// Force ride construction to recheck area
|
||||
_currentTrackSelectionFlags.set(TrackSelectionFlag::recheck);
|
||||
|
||||
if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST))
|
||||
{
|
||||
if (_direction != kInvalidDirection && !getGameState().cheats.disableClearanceChecks)
|
||||
if (!LocationValid(_loc) || MapIsEdge(_loc))
|
||||
{
|
||||
// It is possible, let's remove walls between the old and new piece of path
|
||||
auto zLow = _loc.z;
|
||||
auto zHigh = zLow + kPathClearance;
|
||||
WallRemoveIntersectingWalls(
|
||||
{ _loc, zLow, zHigh + ((_slope & kTileSlopeRaisedCornersMask) ? 16 : 0) }, DirectionReverse(_direction));
|
||||
WallRemoveIntersectingWalls(
|
||||
{ _loc.x - CoordsDirectionDelta[_direction].x, _loc.y - CoordsDirectionDelta[_direction].y, zLow, zHigh },
|
||||
_direction);
|
||||
return Result(Status::InvalidParameters, STR_CANT_BUILD_FOOTPATH_HERE, STR_OFF_EDGE_OF_MAP);
|
||||
}
|
||||
|
||||
if (!(gLegacyScene == LegacyScene::scenarioEditor || getGameState().cheats.sandboxMode) && !MapIsLocationOwned(_loc))
|
||||
{
|
||||
return Result(Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_LAND_NOT_OWNED_BY_PARK);
|
||||
}
|
||||
|
||||
if (_slope & SLOPE_IS_IRREGULAR_FLAG)
|
||||
{
|
||||
return Result(Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_LAND_SLOPE_UNSUITABLE);
|
||||
}
|
||||
|
||||
if (_loc.z < kFootpathMinHeight)
|
||||
{
|
||||
return Result(Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_TOO_LOW);
|
||||
}
|
||||
|
||||
if (_loc.z > kFootpathMaxHeight)
|
||||
{
|
||||
return Result(Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_TOO_HIGH);
|
||||
}
|
||||
|
||||
if (_direction != kInvalidDirection && !DirectionValid(_direction))
|
||||
{
|
||||
LOG_ERROR("Direction invalid. direction = %u", _direction);
|
||||
return Result(Status::InvalidParameters, STR_CANT_BUILD_FOOTPATH_HERE, STR_ERR_VALUE_OUT_OF_RANGE);
|
||||
}
|
||||
|
||||
auto intent = Intent(INTENT_ACTION_REMOVE_PROVISIONAL_FOOTPATH);
|
||||
ContextBroadcastIntent(&intent);
|
||||
|
||||
auto tileElement = MapGetFootpathElementSlope(_loc, _slope);
|
||||
if (tileElement == nullptr)
|
||||
{
|
||||
return ElementInsertQuery(std::move(res));
|
||||
}
|
||||
return ElementUpdateQuery(tileElement, std::move(res));
|
||||
}
|
||||
|
||||
auto tileElement = MapGetFootpathElementSlope(_loc, _slope);
|
||||
if (tileElement == nullptr)
|
||||
Result FootpathPlaceAction::Execute() const
|
||||
{
|
||||
return ElementInsertExecute(std::move(res));
|
||||
}
|
||||
return ElementUpdateExecute(tileElement, std::move(res));
|
||||
}
|
||||
auto res = Result();
|
||||
res.Cost = 0;
|
||||
res.Expenditure = ExpenditureType::landscaping;
|
||||
res.Position = _loc.ToTileCentre();
|
||||
|
||||
if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST))
|
||||
{
|
||||
FootpathInterruptPeeps(_loc);
|
||||
}
|
||||
|
||||
gFootpathGroundFlags = 0;
|
||||
|
||||
// Force ride construction to recheck area
|
||||
_currentTrackSelectionFlags.set(TrackSelectionFlag::recheck);
|
||||
|
||||
if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST))
|
||||
{
|
||||
if (_direction != kInvalidDirection && !getGameState().cheats.disableClearanceChecks)
|
||||
{
|
||||
// It is possible, let's remove walls between the old and new piece of path
|
||||
auto zLow = _loc.z;
|
||||
auto zHigh = zLow + kPathClearance;
|
||||
WallRemoveIntersectingWalls(
|
||||
{ _loc, zLow, zHigh + ((_slope & kTileSlopeRaisedCornersMask) ? 16 : 0) }, DirectionReverse(_direction));
|
||||
WallRemoveIntersectingWalls(
|
||||
{ _loc.x - CoordsDirectionDelta[_direction].x, _loc.y - CoordsDirectionDelta[_direction].y, zLow, zHigh },
|
||||
_direction);
|
||||
}
|
||||
}
|
||||
|
||||
auto tileElement = MapGetFootpathElementSlope(_loc, _slope);
|
||||
if (tileElement == nullptr)
|
||||
{
|
||||
return ElementInsertExecute(std::move(res));
|
||||
}
|
||||
return ElementUpdateExecute(tileElement, std::move(res));
|
||||
}
|
||||
|
||||
bool FootpathPlaceAction::IsSameAsPathElement(const PathElement* pathElement) const
|
||||
{
|
||||
// Check if both this action and the element is queue
|
||||
if (pathElement->IsQueue() != ((_constructFlags & PathConstructFlag::IsQueue) != 0))
|
||||
return false;
|
||||
|
||||
auto footpathObj = pathElement->GetLegacyPathEntry();
|
||||
if (footpathObj == nullptr)
|
||||
{
|
||||
if (_constructFlags & PathConstructFlag::IsLegacyPathObject)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return pathElement->GetSurfaceEntryIndex() == _type && pathElement->GetRailingsEntryIndex() == _railingsType;
|
||||
}
|
||||
|
||||
if (_constructFlags & PathConstructFlag::IsLegacyPathObject)
|
||||
{
|
||||
return pathElement->GetLegacyPathEntryIndex() == _type;
|
||||
}
|
||||
|
||||
bool FootpathPlaceAction::IsSameAsPathElement(const PathElement* pathElement) const
|
||||
{
|
||||
// Check if both this action and the element is queue
|
||||
if (pathElement->IsQueue() != ((_constructFlags & PathConstructFlag::IsQueue) != 0))
|
||||
return false;
|
||||
}
|
||||
|
||||
auto footpathObj = pathElement->GetLegacyPathEntry();
|
||||
if (footpathObj == nullptr)
|
||||
bool FootpathPlaceAction::IsSameAsEntranceElement(const EntranceElement& entranceElement) const
|
||||
{
|
||||
if (entranceElement.HasLegacyPathEntry())
|
||||
{
|
||||
if (_constructFlags & PathConstructFlag::IsLegacyPathObject)
|
||||
{
|
||||
return entranceElement.GetLegacyPathEntryIndex() == _type;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_constructFlags & PathConstructFlag::IsLegacyPathObject)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return pathElement->GetSurfaceEntryIndex() == _type && pathElement->GetRailingsEntryIndex() == _railingsType;
|
||||
return entranceElement.GetSurfaceEntryIndex() == _type;
|
||||
}
|
||||
|
||||
if (_constructFlags & PathConstructFlag::IsLegacyPathObject)
|
||||
Result FootpathPlaceAction::ElementUpdateQuery(PathElement* pathElement, Result res) const
|
||||
{
|
||||
return pathElement->GetLegacyPathEntryIndex() == _type;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FootpathPlaceAction::IsSameAsEntranceElement(const EntranceElement& entranceElement) const
|
||||
{
|
||||
if (entranceElement.HasLegacyPathEntry())
|
||||
{
|
||||
if (_constructFlags & PathConstructFlag::IsLegacyPathObject)
|
||||
if (_constructFlags & PathConstructFlag::IsQueue && pathElement->IsLevelCrossing(_loc))
|
||||
{
|
||||
return entranceElement.GetLegacyPathEntryIndex() == _type;
|
||||
return Result(Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_QUEUE_PATHS_CANNOT_BE_USED_FOR_LEVEL_CROSSINGS);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_constructFlags & PathConstructFlag::IsLegacyPathObject)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return entranceElement.GetSurfaceEntryIndex() == _type;
|
||||
}
|
||||
|
||||
GameActions::Result FootpathPlaceAction::ElementUpdateQuery(PathElement* pathElement, GameActions::Result res) const
|
||||
{
|
||||
if (_constructFlags & PathConstructFlag::IsQueue && pathElement->IsLevelCrossing(_loc))
|
||||
{
|
||||
return GameActions::Result(
|
||||
GameActions::Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_QUEUE_PATHS_CANNOT_BE_USED_FOR_LEVEL_CROSSINGS);
|
||||
}
|
||||
|
||||
if (!IsSameAsPathElement(pathElement))
|
||||
{
|
||||
res.Cost += 6.00_GBP;
|
||||
}
|
||||
|
||||
if (GetFlags() & GAME_COMMAND_FLAG_GHOST && !pathElement->IsGhost())
|
||||
{
|
||||
return GameActions::Result(GameActions::Status::Unknown, STR_CANT_BUILD_FOOTPATH_HERE, kStringIdNone);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
GameActions::Result FootpathPlaceAction::ElementUpdateExecute(PathElement* pathElement, GameActions::Result res) const
|
||||
{
|
||||
if (!IsSameAsPathElement(pathElement))
|
||||
{
|
||||
res.Cost += 6.00_GBP;
|
||||
}
|
||||
|
||||
FootpathQueueChainReset();
|
||||
|
||||
if (!(GetFlags() & GAME_COMMAND_FLAG_TRACK_DESIGN))
|
||||
{
|
||||
FootpathRemoveEdgesAt(_loc, reinterpret_cast<TileElement*>(pathElement));
|
||||
}
|
||||
|
||||
if (_constructFlags & PathConstructFlag::IsLegacyPathObject)
|
||||
{
|
||||
pathElement->SetLegacyPathEntryIndex(_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
pathElement->SetSurfaceEntryIndex(_type);
|
||||
pathElement->SetRailingsEntryIndex(_railingsType);
|
||||
}
|
||||
|
||||
pathElement->SetIsQueue((_constructFlags & PathConstructFlag::IsQueue) != 0);
|
||||
|
||||
auto* elem = pathElement->GetAdditionEntry();
|
||||
if (elem != nullptr)
|
||||
{
|
||||
if (_constructFlags & PathConstructFlag::IsQueue)
|
||||
if (!IsSameAsPathElement(pathElement))
|
||||
{
|
||||
// remove any addition that isn't a TV or a lamp
|
||||
if ((elem->flags & PATH_ADDITION_FLAG_IS_QUEUE_SCREEN) == 0 && (elem->flags & PATH_ADDITION_FLAG_LAMP) == 0)
|
||||
{
|
||||
pathElement->SetIsBroken(false);
|
||||
pathElement->SetAddition(0);
|
||||
}
|
||||
res.Cost += 6.00_GBP;
|
||||
}
|
||||
else
|
||||
|
||||
if (GetFlags() & GAME_COMMAND_FLAG_GHOST && !pathElement->IsGhost())
|
||||
{
|
||||
// remove all TVs
|
||||
if ((elem->flags & PATH_ADDITION_FLAG_IS_QUEUE_SCREEN) != 0)
|
||||
{
|
||||
pathElement->SetIsBroken(false);
|
||||
pathElement->SetAddition(0);
|
||||
}
|
||||
return Result(Status::Unknown, STR_CANT_BUILD_FOOTPATH_HERE, kStringIdNone);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
RemoveIntersectingWalls(pathElement);
|
||||
return res;
|
||||
}
|
||||
|
||||
GameActions::Result FootpathPlaceAction::ElementInsertQuery(GameActions::Result res) const
|
||||
{
|
||||
bool entrancePath = false, entranceIsSamePath = false;
|
||||
|
||||
if (!MapCheckCapacityAndReorganise(_loc))
|
||||
Result FootpathPlaceAction::ElementUpdateExecute(PathElement* pathElement, Result res) const
|
||||
{
|
||||
return GameActions::Result(GameActions::Status::NoFreeElements, STR_CANT_BUILD_FOOTPATH_HERE, kStringIdNone);
|
||||
}
|
||||
|
||||
res.Cost = 12.00_GBP;
|
||||
|
||||
QuarterTile quarterTile{ 0b1111, 0 };
|
||||
auto zLow = _loc.z;
|
||||
auto zHigh = zLow + kPathClearance;
|
||||
if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED)
|
||||
{
|
||||
quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope & kTileElementDirectionMask);
|
||||
zHigh += kPathHeightStep;
|
||||
}
|
||||
|
||||
auto entranceElement = MapGetParkEntranceElementAt(_loc, 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 (IsSameAsEntranceElement(*entranceElement))
|
||||
entranceIsSamePath = true;
|
||||
else
|
||||
res.Cost -= 6.00_GBP;
|
||||
}
|
||||
|
||||
// Do not attempt to build a crossing with a queue or a sloped path.
|
||||
auto isQueue = _constructFlags & PathConstructFlag::IsQueue;
|
||||
auto crossingMode = isQueue || (_slope != kTileSlopeFlat) ? CreateCrossingMode::none : CreateCrossingMode::pathOverTrack;
|
||||
auto canBuild = MapCanConstructWithClearAt(
|
||||
{ _loc, zLow, zHigh }, &MapPlaceNonSceneryClearFunc, quarterTile, GetFlags(), crossingMode);
|
||||
if (!entrancePath && canBuild.Error != GameActions::Status::Ok)
|
||||
{
|
||||
canBuild.ErrorTitle = STR_CANT_BUILD_FOOTPATH_HERE;
|
||||
return canBuild;
|
||||
}
|
||||
res.Cost += canBuild.Cost;
|
||||
|
||||
const auto clearanceData = canBuild.GetData<ConstructClearResult>();
|
||||
|
||||
gFootpathGroundFlags = clearanceData.GroundFlags;
|
||||
if (!getGameState().cheats.disableClearanceChecks && (clearanceData.GroundFlags & ELEMENT_IS_UNDERWATER))
|
||||
{
|
||||
return GameActions::Result(
|
||||
GameActions::Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_CANT_BUILD_THIS_UNDERWATER);
|
||||
}
|
||||
|
||||
auto surfaceElement = MapGetSurfaceElementAt(_loc);
|
||||
if (surfaceElement == nullptr)
|
||||
{
|
||||
return GameActions::Result(
|
||||
GameActions::Status::InvalidParameters, STR_CANT_BUILD_FOOTPATH_HERE, STR_ERR_SURFACE_ELEMENT_NOT_FOUND);
|
||||
}
|
||||
int32_t supportHeight = zLow - surfaceElement->GetBaseZ();
|
||||
res.Cost += supportHeight < 0 ? 20.00_GBP : (supportHeight / kPathHeightStep) * 5.00_GBP;
|
||||
|
||||
// Prevent the place sound from being spammed
|
||||
if (entranceIsSamePath)
|
||||
res.Cost = 0;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
GameActions::Result FootpathPlaceAction::ElementInsertExecute(GameActions::Result res) const
|
||||
{
|
||||
bool entrancePath = false, entranceIsSamePath = false;
|
||||
|
||||
if (!(GetFlags() & (GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_GHOST)))
|
||||
{
|
||||
FootpathRemoveLitter(_loc);
|
||||
}
|
||||
|
||||
res.Cost = 12.00_GBP;
|
||||
|
||||
QuarterTile quarterTile{ 0b1111, 0 };
|
||||
auto zLow = _loc.z;
|
||||
auto zHigh = zLow + kPathClearance;
|
||||
if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED)
|
||||
{
|
||||
quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope & kTileElementDirectionMask);
|
||||
zHigh += kPathHeightStep;
|
||||
}
|
||||
|
||||
auto entranceElement = MapGetParkEntranceElementAt(_loc, 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 (IsSameAsEntranceElement(*entranceElement))
|
||||
entranceIsSamePath = true;
|
||||
else
|
||||
res.Cost -= 6.00_GBP;
|
||||
}
|
||||
|
||||
// Do not attempt to build a crossing with a queue or a sloped.
|
||||
auto isQueue = _constructFlags & PathConstructFlag::IsQueue;
|
||||
auto crossingMode = isQueue || (_slope != kTileSlopeFlat) ? CreateCrossingMode::none : CreateCrossingMode::pathOverTrack;
|
||||
auto canBuild = MapCanConstructWithClearAt(
|
||||
{ _loc, zLow, zHigh }, &MapPlaceNonSceneryClearFunc, quarterTile, GAME_COMMAND_FLAG_APPLY | GetFlags(), crossingMode);
|
||||
if (!entrancePath && canBuild.Error != GameActions::Status::Ok)
|
||||
{
|
||||
canBuild.ErrorTitle = STR_CANT_BUILD_FOOTPATH_HERE;
|
||||
return canBuild;
|
||||
}
|
||||
res.Cost += canBuild.Cost;
|
||||
|
||||
const auto clearanceData = canBuild.GetData<ConstructClearResult>();
|
||||
gFootpathGroundFlags = clearanceData.GroundFlags;
|
||||
|
||||
auto surfaceElement = MapGetSurfaceElementAt(_loc);
|
||||
if (surfaceElement == nullptr)
|
||||
{
|
||||
return GameActions::Result(
|
||||
GameActions::Status::InvalidParameters, STR_CANT_BUILD_FOOTPATH_HERE, STR_ERR_SURFACE_ELEMENT_NOT_FOUND);
|
||||
}
|
||||
int32_t supportHeight = zLow - surfaceElement->GetBaseZ();
|
||||
res.Cost += supportHeight < 0 ? 20.00_GBP : (supportHeight / kPathHeightStep) * 5.00_GBP;
|
||||
|
||||
if (entrancePath)
|
||||
{
|
||||
if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && !entranceIsSamePath)
|
||||
if (!IsSameAsPathElement(pathElement))
|
||||
{
|
||||
if (_constructFlags & PathConstructFlag::IsLegacyPathObject)
|
||||
{
|
||||
entranceElement->SetLegacyPathEntryIndex(_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
entranceElement->SetSurfaceEntryIndex(_type);
|
||||
}
|
||||
MapInvalidateTileFull(_loc);
|
||||
res.Cost += 6.00_GBP;
|
||||
}
|
||||
|
||||
FootpathQueueChainReset();
|
||||
|
||||
if (!(GetFlags() & GAME_COMMAND_FLAG_TRACK_DESIGN))
|
||||
{
|
||||
FootpathRemoveEdgesAt(_loc, reinterpret_cast<TileElement*>(pathElement));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto* pathElement = TileElementInsert<PathElement>(_loc, 0b1111);
|
||||
Guard::Assert(pathElement != nullptr);
|
||||
|
||||
pathElement->SetClearanceZ(zHigh);
|
||||
if (_constructFlags & PathConstructFlag::IsLegacyPathObject)
|
||||
{
|
||||
pathElement->SetLegacyPathEntryIndex(_type);
|
||||
@@ -437,110 +250,296 @@ GameActions::Result FootpathPlaceAction::ElementInsertExecute(GameActions::Resul
|
||||
pathElement->SetSurfaceEntryIndex(_type);
|
||||
pathElement->SetRailingsEntryIndex(_railingsType);
|
||||
}
|
||||
pathElement->SetSlopeDirection(_slope & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK);
|
||||
pathElement->SetSloped(_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED);
|
||||
pathElement->SetIsQueue(isQueue);
|
||||
pathElement->SetAddition(0);
|
||||
pathElement->SetRideIndex(RideId::GetNull());
|
||||
pathElement->SetAdditionStatus(255);
|
||||
pathElement->SetIsBroken(false);
|
||||
pathElement->SetGhost(GetFlags() & GAME_COMMAND_FLAG_GHOST);
|
||||
|
||||
FootpathQueueChainReset();
|
||||
pathElement->SetIsQueue((_constructFlags & PathConstructFlag::IsQueue) != 0);
|
||||
|
||||
if (!(GetFlags() & GAME_COMMAND_FLAG_TRACK_DESIGN))
|
||||
auto* elem = pathElement->GetAdditionEntry();
|
||||
if (elem != nullptr)
|
||||
{
|
||||
FootpathRemoveEdgesAt(_loc, pathElement->as<TileElement>());
|
||||
}
|
||||
if (gLegacyScene == LegacyScene::scenarioEditor && !(GetFlags() & GAME_COMMAND_FLAG_GHOST))
|
||||
{
|
||||
AutomaticallySetPeepSpawn();
|
||||
if (_constructFlags & PathConstructFlag::IsQueue)
|
||||
{
|
||||
// remove any addition that isn't a TV or a lamp
|
||||
if ((elem->flags & PATH_ADDITION_FLAG_IS_QUEUE_SCREEN) == 0 && (elem->flags & PATH_ADDITION_FLAG_LAMP) == 0)
|
||||
{
|
||||
pathElement->SetIsBroken(false);
|
||||
pathElement->SetAddition(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// remove all TVs
|
||||
if ((elem->flags & PATH_ADDITION_FLAG_IS_QUEUE_SCREEN) != 0)
|
||||
{
|
||||
pathElement->SetIsBroken(false);
|
||||
pathElement->SetAddition(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RemoveIntersectingWalls(pathElement);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Prevent the place sound from being spammed
|
||||
if (entranceIsSamePath)
|
||||
res.Cost = 0;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* rct2: 0x006A65AD
|
||||
*/
|
||||
void FootpathPlaceAction::AutomaticallySetPeepSpawn() const
|
||||
{
|
||||
auto mapSizeUnits = GetMapSizeUnits();
|
||||
uint8_t direction = 0;
|
||||
if (_loc.x != kCoordsXYStep)
|
||||
Result FootpathPlaceAction::ElementInsertQuery(Result res) const
|
||||
{
|
||||
direction++;
|
||||
if (_loc.y != mapSizeUnits.y - kCoordsXYStep)
|
||||
bool entrancePath = false, entranceIsSamePath = false;
|
||||
|
||||
if (!MapCheckCapacityAndReorganise(_loc))
|
||||
{
|
||||
direction++;
|
||||
if (_loc.x != mapSizeUnits.x - kCoordsXYStep)
|
||||
return Result(Status::NoFreeElements, STR_CANT_BUILD_FOOTPATH_HERE, kStringIdNone);
|
||||
}
|
||||
|
||||
res.Cost = 12.00_GBP;
|
||||
|
||||
QuarterTile quarterTile{ 0b1111, 0 };
|
||||
auto zLow = _loc.z;
|
||||
auto zHigh = zLow + kPathClearance;
|
||||
if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED)
|
||||
{
|
||||
quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope & kTileElementDirectionMask);
|
||||
zHigh += kPathHeightStep;
|
||||
}
|
||||
|
||||
auto entranceElement = MapGetParkEntranceElementAt(_loc, 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 (IsSameAsEntranceElement(*entranceElement))
|
||||
entranceIsSamePath = true;
|
||||
else
|
||||
res.Cost -= 6.00_GBP;
|
||||
}
|
||||
|
||||
// Do not attempt to build a crossing with a queue or a sloped path.
|
||||
auto isQueue = _constructFlags & PathConstructFlag::IsQueue;
|
||||
auto crossingMode = isQueue || (_slope != kTileSlopeFlat) ? CreateCrossingMode::none
|
||||
: CreateCrossingMode::pathOverTrack;
|
||||
auto canBuild = MapCanConstructWithClearAt(
|
||||
{ _loc, zLow, zHigh }, &MapPlaceNonSceneryClearFunc, quarterTile, GetFlags(), crossingMode);
|
||||
if (!entrancePath && canBuild.Error != Status::Ok)
|
||||
{
|
||||
canBuild.ErrorTitle = STR_CANT_BUILD_FOOTPATH_HERE;
|
||||
return canBuild;
|
||||
}
|
||||
res.Cost += canBuild.Cost;
|
||||
|
||||
const auto clearanceData = canBuild.GetData<ConstructClearResult>();
|
||||
|
||||
gFootpathGroundFlags = clearanceData.GroundFlags;
|
||||
if (!getGameState().cheats.disableClearanceChecks && (clearanceData.GroundFlags & ELEMENT_IS_UNDERWATER))
|
||||
{
|
||||
return Result(Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_CANT_BUILD_THIS_UNDERWATER);
|
||||
}
|
||||
|
||||
auto surfaceElement = MapGetSurfaceElementAt(_loc);
|
||||
if (surfaceElement == nullptr)
|
||||
{
|
||||
return Result(Status::InvalidParameters, STR_CANT_BUILD_FOOTPATH_HERE, STR_ERR_SURFACE_ELEMENT_NOT_FOUND);
|
||||
}
|
||||
int32_t supportHeight = zLow - surfaceElement->GetBaseZ();
|
||||
res.Cost += supportHeight < 0 ? 20.00_GBP : (supportHeight / kPathHeightStep) * 5.00_GBP;
|
||||
|
||||
// Prevent the place sound from being spammed
|
||||
if (entranceIsSamePath)
|
||||
res.Cost = 0;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
Result FootpathPlaceAction::ElementInsertExecute(Result res) const
|
||||
{
|
||||
bool entrancePath = false, entranceIsSamePath = false;
|
||||
|
||||
if (!(GetFlags() & (GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_GHOST)))
|
||||
{
|
||||
FootpathRemoveLitter(_loc);
|
||||
}
|
||||
|
||||
res.Cost = 12.00_GBP;
|
||||
|
||||
QuarterTile quarterTile{ 0b1111, 0 };
|
||||
auto zLow = _loc.z;
|
||||
auto zHigh = zLow + kPathClearance;
|
||||
if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED)
|
||||
{
|
||||
quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope & kTileElementDirectionMask);
|
||||
zHigh += kPathHeightStep;
|
||||
}
|
||||
|
||||
auto entranceElement = MapGetParkEntranceElementAt(_loc, 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 (IsSameAsEntranceElement(*entranceElement))
|
||||
entranceIsSamePath = true;
|
||||
else
|
||||
res.Cost -= 6.00_GBP;
|
||||
}
|
||||
|
||||
// Do not attempt to build a crossing with a queue or a sloped.
|
||||
auto isQueue = _constructFlags & PathConstructFlag::IsQueue;
|
||||
auto crossingMode = isQueue || (_slope != kTileSlopeFlat) ? CreateCrossingMode::none
|
||||
: CreateCrossingMode::pathOverTrack;
|
||||
auto canBuild = MapCanConstructWithClearAt(
|
||||
{ _loc, zLow, zHigh }, &MapPlaceNonSceneryClearFunc, quarterTile, GAME_COMMAND_FLAG_APPLY | GetFlags(),
|
||||
crossingMode);
|
||||
if (!entrancePath && canBuild.Error != Status::Ok)
|
||||
{
|
||||
canBuild.ErrorTitle = STR_CANT_BUILD_FOOTPATH_HERE;
|
||||
return canBuild;
|
||||
}
|
||||
res.Cost += canBuild.Cost;
|
||||
|
||||
const auto clearanceData = canBuild.GetData<ConstructClearResult>();
|
||||
gFootpathGroundFlags = clearanceData.GroundFlags;
|
||||
|
||||
auto surfaceElement = MapGetSurfaceElementAt(_loc);
|
||||
if (surfaceElement == nullptr)
|
||||
{
|
||||
return Result(Status::InvalidParameters, STR_CANT_BUILD_FOOTPATH_HERE, STR_ERR_SURFACE_ELEMENT_NOT_FOUND);
|
||||
}
|
||||
int32_t supportHeight = zLow - surfaceElement->GetBaseZ();
|
||||
res.Cost += supportHeight < 0 ? 20.00_GBP : (supportHeight / kPathHeightStep) * 5.00_GBP;
|
||||
|
||||
if (entrancePath)
|
||||
{
|
||||
if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && !entranceIsSamePath)
|
||||
{
|
||||
direction++;
|
||||
if (_loc.y != kCoordsXYStep)
|
||||
return;
|
||||
if (_constructFlags & PathConstructFlag::IsLegacyPathObject)
|
||||
{
|
||||
entranceElement->SetLegacyPathEntryIndex(_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
entranceElement->SetSurfaceEntryIndex(_type);
|
||||
}
|
||||
MapInvalidateTileFull(_loc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto& gameState = getGameState();
|
||||
if (gameState.peepSpawns.empty())
|
||||
{
|
||||
gameState.peepSpawns.emplace_back();
|
||||
}
|
||||
PeepSpawn* peepSpawn = &gameState.peepSpawns[0];
|
||||
peepSpawn->x = _loc.x + (DirectionOffsets[direction].x * 15) + 16;
|
||||
peepSpawn->y = _loc.y + (DirectionOffsets[direction].y * 15) + 16;
|
||||
peepSpawn->direction = direction;
|
||||
peepSpawn->z = _loc.z;
|
||||
}
|
||||
|
||||
void FootpathPlaceAction::RemoveIntersectingWalls(PathElement* pathElement) const
|
||||
{
|
||||
if (pathElement->IsSloped() && !(GetFlags() & GAME_COMMAND_FLAG_GHOST))
|
||||
{
|
||||
auto direction = pathElement->GetSlopeDirection();
|
||||
int32_t z = pathElement->GetBaseZ();
|
||||
WallRemoveIntersectingWalls({ _loc, z, z + (6 * kCoordsZStep) }, DirectionReverse(direction));
|
||||
WallRemoveIntersectingWalls({ _loc, z, z + (6 * kCoordsZStep) }, direction);
|
||||
// Removing walls may have made the pointer invalid, so find it again
|
||||
pathElement = MapGetFootpathElement(CoordsXYZ(_loc, z));
|
||||
if (pathElement == nullptr)
|
||||
else
|
||||
{
|
||||
LOG_ERROR("Something went wrong. Could not refind footpath.");
|
||||
return;
|
||||
auto* pathElement = TileElementInsert<PathElement>(_loc, 0b1111);
|
||||
Guard::Assert(pathElement != nullptr);
|
||||
|
||||
pathElement->SetClearanceZ(zHigh);
|
||||
if (_constructFlags & PathConstructFlag::IsLegacyPathObject)
|
||||
{
|
||||
pathElement->SetLegacyPathEntryIndex(_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
pathElement->SetSurfaceEntryIndex(_type);
|
||||
pathElement->SetRailingsEntryIndex(_railingsType);
|
||||
}
|
||||
pathElement->SetSlopeDirection(_slope & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK);
|
||||
pathElement->SetSloped(_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED);
|
||||
pathElement->SetIsQueue(isQueue);
|
||||
pathElement->SetAddition(0);
|
||||
pathElement->SetRideIndex(RideId::GetNull());
|
||||
pathElement->SetAdditionStatus(255);
|
||||
pathElement->SetIsBroken(false);
|
||||
pathElement->SetGhost(GetFlags() & GAME_COMMAND_FLAG_GHOST);
|
||||
|
||||
FootpathQueueChainReset();
|
||||
|
||||
if (!(GetFlags() & GAME_COMMAND_FLAG_TRACK_DESIGN))
|
||||
{
|
||||
FootpathRemoveEdgesAt(_loc, pathElement->as<TileElement>());
|
||||
}
|
||||
if (gLegacyScene == LegacyScene::scenarioEditor && !(GetFlags() & GAME_COMMAND_FLAG_GHOST))
|
||||
{
|
||||
AutomaticallySetPeepSpawn();
|
||||
}
|
||||
|
||||
RemoveIntersectingWalls(pathElement);
|
||||
}
|
||||
|
||||
// Prevent the place sound from being spammed
|
||||
if (entranceIsSamePath)
|
||||
res.Cost = 0;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
if (!(GetFlags() & GAME_COMMAND_FLAG_TRACK_DESIGN))
|
||||
FootpathConnectEdges(_loc, reinterpret_cast<TileElement*>(pathElement), GetFlags());
|
||||
|
||||
FootpathUpdateQueueChains();
|
||||
MapInvalidateTileFull(_loc);
|
||||
}
|
||||
|
||||
PathElement* FootpathPlaceAction::MapGetFootpathElementSlope(const CoordsXYZ& footpathPos, int32_t slope) const
|
||||
{
|
||||
const bool isSloped = slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED;
|
||||
const auto slopeDirection = slope & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK;
|
||||
|
||||
for (auto* pathElement : TileElementsView<PathElement>(footpathPos))
|
||||
/**
|
||||
*
|
||||
* rct2: 0x006A65AD
|
||||
*/
|
||||
void FootpathPlaceAction::AutomaticallySetPeepSpawn() const
|
||||
{
|
||||
if (pathElement->GetBaseZ() != footpathPos.z)
|
||||
continue;
|
||||
if (pathElement->IsSloped() != isSloped)
|
||||
continue;
|
||||
if (pathElement->GetSlopeDirection() != slopeDirection)
|
||||
continue;
|
||||
return pathElement;
|
||||
auto mapSizeUnits = GetMapSizeUnits();
|
||||
uint8_t direction = 0;
|
||||
if (_loc.x != kCoordsXYStep)
|
||||
{
|
||||
direction++;
|
||||
if (_loc.y != mapSizeUnits.y - kCoordsXYStep)
|
||||
{
|
||||
direction++;
|
||||
if (_loc.x != mapSizeUnits.x - kCoordsXYStep)
|
||||
{
|
||||
direction++;
|
||||
if (_loc.y != kCoordsXYStep)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto& gameState = getGameState();
|
||||
if (gameState.peepSpawns.empty())
|
||||
{
|
||||
gameState.peepSpawns.emplace_back();
|
||||
}
|
||||
PeepSpawn* peepSpawn = &gameState.peepSpawns[0];
|
||||
peepSpawn->x = _loc.x + (DirectionOffsets[direction].x * 15) + 16;
|
||||
peepSpawn->y = _loc.y + (DirectionOffsets[direction].y * 15) + 16;
|
||||
peepSpawn->direction = direction;
|
||||
peepSpawn->z = _loc.z;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
void FootpathPlaceAction::RemoveIntersectingWalls(PathElement* pathElement) const
|
||||
{
|
||||
if (pathElement->IsSloped() && !(GetFlags() & GAME_COMMAND_FLAG_GHOST))
|
||||
{
|
||||
auto direction = pathElement->GetSlopeDirection();
|
||||
int32_t z = pathElement->GetBaseZ();
|
||||
WallRemoveIntersectingWalls({ _loc, z, z + (6 * kCoordsZStep) }, DirectionReverse(direction));
|
||||
WallRemoveIntersectingWalls({ _loc, z, z + (6 * kCoordsZStep) }, direction);
|
||||
// Removing walls may have made the pointer invalid, so find it again
|
||||
pathElement = MapGetFootpathElement(CoordsXYZ(_loc, z));
|
||||
if (pathElement == nullptr)
|
||||
{
|
||||
LOG_ERROR("Something went wrong. Could not refind footpath.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(GetFlags() & GAME_COMMAND_FLAG_TRACK_DESIGN))
|
||||
FootpathConnectEdges(_loc, reinterpret_cast<TileElement*>(pathElement), GetFlags());
|
||||
|
||||
FootpathUpdateQueueChains();
|
||||
MapInvalidateTileFull(_loc);
|
||||
}
|
||||
|
||||
PathElement* FootpathPlaceAction::MapGetFootpathElementSlope(const CoordsXYZ& footpathPos, int32_t slope) const
|
||||
{
|
||||
const bool isSloped = slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED;
|
||||
const auto slopeDirection = slope & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK;
|
||||
|
||||
for (auto* pathElement : TileElementsView<PathElement>(footpathPos))
|
||||
{
|
||||
if (pathElement->GetBaseZ() != footpathPos.z)
|
||||
continue;
|
||||
if (pathElement->IsSloped() != isSloped)
|
||||
continue;
|
||||
if (pathElement->GetSlopeDirection() != slopeDirection)
|
||||
continue;
|
||||
return pathElement;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
} // namespace OpenRCT2::GameActions
|
||||
|
||||
@@ -12,39 +12,40 @@
|
||||
#include "../world/Footpath.h"
|
||||
#include "GameAction.h"
|
||||
|
||||
class FootpathPlaceAction final : public GameActionBase<GameCommand::PlacePath>
|
||||
namespace OpenRCT2::GameActions
|
||||
{
|
||||
private:
|
||||
CoordsXYZ _loc;
|
||||
uint8_t _slope{};
|
||||
OpenRCT2::ObjectEntryIndex _type{};
|
||||
OpenRCT2::ObjectEntryIndex _railingsType{};
|
||||
Direction _direction{ kInvalidDirection };
|
||||
PathConstructFlags _constructFlags{};
|
||||
class FootpathPlaceAction final : public GameActionBase<GameCommand::PlacePath>
|
||||
{
|
||||
private:
|
||||
CoordsXYZ _loc;
|
||||
uint8_t _slope{};
|
||||
ObjectEntryIndex _type{};
|
||||
ObjectEntryIndex _railingsType{};
|
||||
Direction _direction{ kInvalidDirection };
|
||||
PathConstructFlags _constructFlags{};
|
||||
|
||||
public:
|
||||
FootpathPlaceAction() = default;
|
||||
FootpathPlaceAction(
|
||||
const CoordsXYZ& loc, uint8_t slope, OpenRCT2::ObjectEntryIndex type, OpenRCT2::ObjectEntryIndex railingsType,
|
||||
Direction direction = kInvalidDirection, PathConstructFlags constructFlags = 0);
|
||||
void AcceptParameters(GameActionParameterVisitor& visitor) override;
|
||||
public:
|
||||
FootpathPlaceAction() = default;
|
||||
FootpathPlaceAction(
|
||||
const CoordsXYZ& loc, uint8_t slope, ObjectEntryIndex type, ObjectEntryIndex railingsType,
|
||||
Direction direction = kInvalidDirection, PathConstructFlags constructFlags = 0);
|
||||
void AcceptParameters(GameActionParameterVisitor& visitor) override;
|
||||
|
||||
uint16_t GetActionFlags() const override;
|
||||
uint16_t GetActionFlags() const override;
|
||||
|
||||
void Serialise(DataSerialiser& stream) override;
|
||||
OpenRCT2::GameActions::Result Query() const override;
|
||||
OpenRCT2::GameActions::Result Execute() const override;
|
||||
void Serialise(DataSerialiser& stream) override;
|
||||
Result Query() const override;
|
||||
Result Execute() const override;
|
||||
|
||||
private:
|
||||
OpenRCT2::GameActions::Result ElementUpdateQuery(
|
||||
OpenRCT2::PathElement* pathElement, OpenRCT2::GameActions::Result res) const;
|
||||
OpenRCT2::GameActions::Result ElementUpdateExecute(
|
||||
OpenRCT2::PathElement* pathElement, OpenRCT2::GameActions::Result res) const;
|
||||
OpenRCT2::GameActions::Result ElementInsertQuery(OpenRCT2::GameActions::Result res) const;
|
||||
OpenRCT2::GameActions::Result ElementInsertExecute(OpenRCT2::GameActions::Result res) const;
|
||||
void AutomaticallySetPeepSpawn() const;
|
||||
void RemoveIntersectingWalls(OpenRCT2::PathElement* pathElement) const;
|
||||
OpenRCT2::PathElement* MapGetFootpathElementSlope(const CoordsXYZ& footpathPos, int32_t slope) const;
|
||||
bool IsSameAsPathElement(const OpenRCT2::PathElement* pathElement) const;
|
||||
bool IsSameAsEntranceElement(const OpenRCT2::EntranceElement& entranceElement) const;
|
||||
};
|
||||
private:
|
||||
Result ElementUpdateQuery(PathElement* pathElement, Result res) const;
|
||||
Result ElementUpdateExecute(PathElement* pathElement, Result res) const;
|
||||
Result ElementInsertQuery(Result res) const;
|
||||
Result ElementInsertExecute(Result res) const;
|
||||
void AutomaticallySetPeepSpawn() const;
|
||||
void RemoveIntersectingWalls(PathElement* pathElement) const;
|
||||
PathElement* MapGetFootpathElementSlope(const CoordsXYZ& footpathPos, int32_t slope) const;
|
||||
bool IsSameAsPathElement(const PathElement* pathElement) const;
|
||||
bool IsSameAsEntranceElement(const EntranceElement& entranceElement) const;
|
||||
};
|
||||
} // namespace OpenRCT2::GameActions
|
||||
|
||||
@@ -656,7 +656,7 @@ static void ApplyPathFixes(const json_t& scenarioPatch)
|
||||
for (auto coordinate : coordinates)
|
||||
{
|
||||
auto slope = direction != kInvalidDirection ? direction + 4 : 0;
|
||||
auto footpathPlaceAction = FootpathPlaceAction(
|
||||
auto footpathPlaceAction = GameActions::FootpathPlaceAction(
|
||||
coordinate.ToCoordsXYZ(), slope, surfaceObjIndex, railingsObjIndex, direction, constructionFlags);
|
||||
auto result = footpathPlaceAction.Execute();
|
||||
if (result.Error != GameActions::Status::Ok)
|
||||
|
||||
@@ -1199,7 +1199,7 @@ static GameActions::Result TrackDesignPlaceSceneryElement(
|
||||
constructFlags |= PathConstructFlag::IsQueue;
|
||||
if (entryInfo->Type == ObjectType::paths)
|
||||
constructFlags |= PathConstructFlag::IsLegacyPathObject;
|
||||
auto footpathPlaceAction = FootpathLayoutPlaceAction(
|
||||
auto footpathPlaceAction = GameActions::FootpathLayoutPlaceAction(
|
||||
{ mapCoord.x, mapCoord.y, z }, slope, entryInfo->Index, entryInfo->SecondaryIndex, edges, constructFlags);
|
||||
footpathPlaceAction.SetFlags(flags);
|
||||
auto res = flags & GAME_COMMAND_FLAG_APPLY ? GameActions::ExecuteNested(&footpathPlaceAction)
|
||||
|
||||
@@ -1072,7 +1072,7 @@ void ScriptEngine::RemoveNetworkPlugins()
|
||||
}
|
||||
}
|
||||
|
||||
GameActions::Result ScriptEngine::QueryOrExecuteCustomGameAction(const CustomAction& customAction, bool isExecute)
|
||||
GameActions::Result ScriptEngine::QueryOrExecuteCustomGameAction(const GameActions::CustomAction& customAction, bool isExecute)
|
||||
{
|
||||
std::string actionz = customAction.GetId();
|
||||
auto kvp = _customActions.find(actionz);
|
||||
@@ -1473,7 +1473,7 @@ void ScriptEngine::RunGameActionHooks(const GameAction& action, GameActions::Res
|
||||
auto actionId = action.GetType();
|
||||
if (action.GetType() == GameCommand::Custom)
|
||||
{
|
||||
auto customAction = static_cast<const CustomAction&>(action);
|
||||
auto customAction = static_cast<const GameActions::CustomAction&>(action);
|
||||
obj.Set("action", customAction.GetId());
|
||||
|
||||
auto dukArgs = DuktapeTryParseJson(_context, customAction.GetJson());
|
||||
@@ -1559,7 +1559,7 @@ std::unique_ptr<GameAction> ScriptEngine::CreateGameAction(
|
||||
auto jsonz = duk_json_encode(ctx, -1);
|
||||
auto json = std::string(jsonz);
|
||||
duk_pop(ctx);
|
||||
auto customAction = std::make_unique<CustomAction>(actionid, json, pluginName);
|
||||
auto customAction = std::make_unique<GameActions::CustomAction>(actionid, json, pluginName);
|
||||
|
||||
if (customAction->GetPlayer() == -1 && NetworkGetMode() != NETWORK_MODE_NONE)
|
||||
{
|
||||
|
||||
@@ -248,7 +248,8 @@ namespace OpenRCT2::Scripting
|
||||
void AddNetworkPlugin(std::string_view code);
|
||||
void RemoveNetworkPlugins();
|
||||
|
||||
[[nodiscard]] GameActions::Result QueryOrExecuteCustomGameAction(const CustomAction& action, bool isExecute);
|
||||
[[nodiscard]] GameActions::Result QueryOrExecuteCustomGameAction(
|
||||
const GameActions::CustomAction& action, bool isExecute);
|
||||
bool RegisterCustomAction(
|
||||
const std::shared_ptr<Plugin>& plugin, std::string_view action, const DukValue& query, const DukValue& execute);
|
||||
void RunGameActionHooks(const GameAction& action, GameActions::Result& result, bool isExecute);
|
||||
|
||||
@@ -260,7 +260,7 @@ void SceneryRemoveGhostToolPlacement()
|
||||
if (tileElement->GetBaseZ() != gSceneryGhostPosition.z)
|
||||
continue;
|
||||
|
||||
auto footpathAdditionRemoveAction = FootpathAdditionRemoveAction(gSceneryGhostPosition);
|
||||
auto footpathAdditionRemoveAction = GameActions::FootpathAdditionRemoveAction(gSceneryGhostPosition);
|
||||
footpathAdditionRemoveAction.SetFlags(
|
||||
GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_NO_SPEND | GAME_COMMAND_FLAG_GHOST);
|
||||
GameActions::Execute(&footpathAdditionRemoveAction);
|
||||
|
||||
Reference in New Issue
Block a user