mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-02-01 11:15:13 +01:00
2380 lines
81 KiB
C++
2380 lines
81 KiB
C++
/*****************************************************************************
|
|
* Copyright (c) 2014-2025 OpenRCT2 developers
|
|
*
|
|
* For a complete list of all authors, please refer to contributors.md
|
|
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
|
*
|
|
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
|
*****************************************************************************/
|
|
|
|
#ifdef ENABLE_SCRIPTING
|
|
|
|
#include "ScTileElement.hpp"
|
|
|
|
#include "../../../Context.h"
|
|
#include "../../../core/Guard.hpp"
|
|
#include "../../../entity/EntityRegistry.h"
|
|
#include "../../../object/LargeSceneryEntry.h"
|
|
#include "../../../object/WallSceneryEntry.h"
|
|
#include "../../../ride/Ride.h"
|
|
#include "../../../ride/RideData.h"
|
|
#include "../../../ride/Track.h"
|
|
#include "../../../world/Footpath.h"
|
|
#include "../../../world/Scenery.h"
|
|
#include "../../../world/tile_element/BannerElement.h"
|
|
#include "../../../world/tile_element/EntranceElement.h"
|
|
#include "../../../world/tile_element/LargeSceneryElement.h"
|
|
#include "../../../world/tile_element/PathElement.h"
|
|
#include "../../../world/tile_element/SmallSceneryElement.h"
|
|
#include "../../../world/tile_element/SurfaceElement.h"
|
|
#include "../../../world/tile_element/TrackElement.h"
|
|
#include "../../../world/tile_element/WallElement.h"
|
|
#include "../../Duktape.hpp"
|
|
#include "../../ScriptEngine.h"
|
|
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
#include <utility>
|
|
|
|
namespace OpenRCT2::Scripting
|
|
{
|
|
ScTileElement::ScTileElement(const CoordsXY& coords, TileElement* element)
|
|
: _coords(coords)
|
|
, _element(element)
|
|
{
|
|
}
|
|
|
|
std::string ScTileElement::type_get() const
|
|
{
|
|
switch (_element->GetType())
|
|
{
|
|
case TileElementType::Surface:
|
|
return "surface";
|
|
case TileElementType::Path:
|
|
return "footpath";
|
|
case TileElementType::Track:
|
|
return "track";
|
|
case TileElementType::SmallScenery:
|
|
return "small_scenery";
|
|
case TileElementType::Entrance:
|
|
return "entrance";
|
|
case TileElementType::Wall:
|
|
return "wall";
|
|
case TileElementType::LargeScenery:
|
|
return "large_scenery";
|
|
case TileElementType::Banner:
|
|
return "banner";
|
|
default:
|
|
return "unknown";
|
|
}
|
|
}
|
|
|
|
void ScTileElement::type_set(std::string value)
|
|
{
|
|
RemoveBannerEntryIfNeeded();
|
|
if (value == "surface")
|
|
_element->SetType(TileElementType::Surface);
|
|
else if (value == "footpath")
|
|
_element->SetType(TileElementType::Path);
|
|
else if (value == "track")
|
|
_element->SetType(TileElementType::Track);
|
|
else if (value == "small_scenery")
|
|
_element->SetType(TileElementType::SmallScenery);
|
|
else if (value == "entrance")
|
|
_element->SetType(TileElementType::Entrance);
|
|
else if (value == "wall")
|
|
_element->SetType(TileElementType::Wall);
|
|
else if (value == "large_scenery")
|
|
_element->SetType(TileElementType::LargeScenery);
|
|
else if (value == "banner")
|
|
_element->SetType(TileElementType::Banner);
|
|
else
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
scriptEngine.LogPluginInfo("Element type not recognised!");
|
|
return;
|
|
}
|
|
CreateBannerEntryIfNeeded();
|
|
Invalidate();
|
|
}
|
|
|
|
uint8_t ScTileElement::baseHeight_get() const
|
|
{
|
|
return _element->BaseHeight;
|
|
}
|
|
void ScTileElement::baseHeight_set(uint8_t newBaseHeight)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
_element->BaseHeight = newBaseHeight;
|
|
Invalidate();
|
|
}
|
|
|
|
uint16_t ScTileElement::baseZ_get() const
|
|
{
|
|
return _element->GetBaseZ();
|
|
}
|
|
void ScTileElement::baseZ_set(uint16_t value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
_element->SetBaseZ(value);
|
|
Invalidate();
|
|
}
|
|
|
|
uint8_t ScTileElement::clearanceHeight_get() const
|
|
{
|
|
return _element->ClearanceHeight;
|
|
}
|
|
void ScTileElement::clearanceHeight_set(uint8_t newClearanceHeight)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
_element->ClearanceHeight = newClearanceHeight;
|
|
Invalidate();
|
|
}
|
|
|
|
uint16_t ScTileElement::clearanceZ_get() const
|
|
{
|
|
return _element->GetClearanceZ();
|
|
}
|
|
void ScTileElement::clearanceZ_set(uint16_t value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
_element->SetClearanceZ(value);
|
|
Invalidate();
|
|
}
|
|
|
|
DukValue ScTileElement::slope_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
switch (_element->GetType())
|
|
{
|
|
case TileElementType::Surface:
|
|
{
|
|
auto* el = _element->AsSurface();
|
|
duk_push_int(ctx, el->GetSlope());
|
|
break;
|
|
}
|
|
case TileElementType::Wall:
|
|
{
|
|
auto* el = _element->AsWall();
|
|
duk_push_int(ctx, el->GetSlope());
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
scriptEngine.LogPluginInfo(
|
|
"Cannot read 'slope' property, tile element is not a SurfaceElement or WallElement.");
|
|
duk_push_null(ctx);
|
|
break;
|
|
}
|
|
}
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::slope_set(uint8_t value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
const auto type = _element->GetType();
|
|
|
|
if (type == TileElementType::Surface)
|
|
{
|
|
auto* el = _element->AsSurface();
|
|
el->SetSlope(value);
|
|
Invalidate();
|
|
}
|
|
else if (type == TileElementType::Wall)
|
|
{
|
|
auto* el = _element->AsWall();
|
|
el->SetSlope(value);
|
|
Invalidate();
|
|
}
|
|
else
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
scriptEngine.LogPluginInfo("Cannot set 'slope' property, tile element is not a SurfaceElement or WallElement.");
|
|
}
|
|
}
|
|
|
|
DukValue ScTileElement::waterHeight_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
auto* el = _element->AsSurface();
|
|
if (el != nullptr)
|
|
{
|
|
duk_push_int(ctx, el->GetWaterHeight());
|
|
}
|
|
else
|
|
{
|
|
scriptEngine.LogPluginInfo("Cannot read 'waterHeight' property, tile element is not a SurfaceElement.");
|
|
duk_push_null(ctx);
|
|
}
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::waterHeight_set(int32_t value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
auto* el = _element->AsSurface();
|
|
if (el == nullptr)
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
scriptEngine.LogPluginInfo("Cannot set 'waterHeight' property, tile element is not a SurfaceElement.");
|
|
return;
|
|
}
|
|
|
|
el->SetWaterHeight(value);
|
|
Invalidate();
|
|
}
|
|
|
|
DukValue ScTileElement::surfaceStyle_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
auto* el = _element->AsSurface();
|
|
if (el != nullptr)
|
|
{
|
|
duk_push_int(ctx, el->GetSurfaceObjectIndex());
|
|
}
|
|
else
|
|
{
|
|
scriptEngine.LogPluginInfo("Cannot read 'surfaceStyle' property, tile element is not a SurfaceElement.");
|
|
duk_push_null(ctx);
|
|
}
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::surfaceStyle_set(uint32_t value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
auto* el = _element->AsSurface();
|
|
if (el == nullptr)
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
scriptEngine.LogPluginInfo("Cannot set 'surfaceStyle' property, tile element is not a SurfaceElement.");
|
|
return;
|
|
}
|
|
|
|
el->SetSurfaceObjectIndex(value);
|
|
Invalidate();
|
|
}
|
|
|
|
DukValue ScTileElement::edgeStyle_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
auto* el = _element->AsSurface();
|
|
if (el != nullptr)
|
|
{
|
|
duk_push_int(ctx, el->GetEdgeObjectIndex());
|
|
}
|
|
else
|
|
{
|
|
scriptEngine.LogPluginInfo("Cannot read 'edgeStyle' property, tile element is not a SurfaceElement.");
|
|
duk_push_null(ctx);
|
|
}
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::edgeStyle_set(uint32_t value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
auto* el = _element->AsSurface();
|
|
if (el == nullptr)
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
scriptEngine.LogPluginInfo("Cannot set 'edgeStyle' property, tile element is not a SurfaceElement.");
|
|
return;
|
|
}
|
|
|
|
el->SetEdgeObjectIndex(value);
|
|
Invalidate();
|
|
}
|
|
|
|
DukValue ScTileElement::grassLength_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
auto* el = _element->AsSurface();
|
|
if (el != nullptr)
|
|
{
|
|
duk_push_int(ctx, el->GetGrassLength());
|
|
}
|
|
else
|
|
{
|
|
scriptEngine.LogPluginInfo("Cannot read 'grassLength' property, tile element is not a SurfaceElement.");
|
|
duk_push_null(ctx);
|
|
}
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::grassLength_set(uint8_t value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
auto* el = _element->AsSurface();
|
|
if (el == nullptr)
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
scriptEngine.LogPluginInfo("Cannot set 'grassLength' property, tile element is not a SurfaceElement.");
|
|
return;
|
|
}
|
|
|
|
// TODO: Give warning when value > GRASS_LENGTH_CLUMPS_2
|
|
el->SetGrassLengthAndInvalidate(value, _coords);
|
|
Invalidate();
|
|
}
|
|
|
|
DukValue ScTileElement::hasOwnership_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
auto* el = _element->AsSurface();
|
|
if (el != nullptr)
|
|
{
|
|
duk_push_boolean(ctx, el->GetOwnership() & OWNERSHIP_OWNED);
|
|
}
|
|
else
|
|
{
|
|
scriptEngine.LogPluginInfo("Cannot read 'hasOwnership' property, tile element is not a SurfaceElement.");
|
|
duk_push_null(ctx);
|
|
}
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
|
|
DukValue ScTileElement::hasConstructionRights_get()
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
auto* el = _element->AsSurface();
|
|
if (el != nullptr)
|
|
{
|
|
auto ownership = el->GetOwnership();
|
|
duk_push_boolean(ctx, (ownership & OWNERSHIP_OWNED) || (ownership & OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED));
|
|
}
|
|
else
|
|
{
|
|
scriptEngine.LogPluginInfo("Cannot read 'hasConstructionRights' property, tile element is not a SurfaceElement.");
|
|
duk_push_null(ctx);
|
|
}
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
|
|
DukValue ScTileElement::ownership_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
auto* el = _element->AsSurface();
|
|
if (el != nullptr)
|
|
{
|
|
duk_push_int(ctx, el->GetOwnership());
|
|
}
|
|
else
|
|
{
|
|
scriptEngine.LogPluginInfo("Cannot read 'ownership' property, tile element is not a SurfaceElement.");
|
|
duk_push_null(ctx);
|
|
}
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::ownership_set(uint8_t value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
auto* el = _element->AsSurface();
|
|
if (el == nullptr)
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
scriptEngine.LogPluginInfo("Cannot set 'ownership' property, tile element is not a SurfaceElement.");
|
|
return;
|
|
}
|
|
|
|
el->SetOwnership(value);
|
|
Invalidate();
|
|
}
|
|
|
|
DukValue ScTileElement::parkFences_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
auto* el = _element->AsSurface();
|
|
if (el != nullptr)
|
|
{
|
|
duk_push_int(ctx, el->GetParkFences());
|
|
}
|
|
else
|
|
{
|
|
scriptEngine.LogPluginInfo("Cannot read 'parkFences' property, tile element is not a SurfaceElement.");
|
|
duk_push_null(ctx);
|
|
}
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::parkFences_set(uint8_t value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
auto* el = _element->AsSurface();
|
|
if (el == nullptr)
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
scriptEngine.LogPluginInfo("Cannot set 'parkFences' property, tile element is not a SurfaceElement.");
|
|
return;
|
|
}
|
|
|
|
el->SetParkFences(value);
|
|
Invalidate();
|
|
}
|
|
|
|
DukValue ScTileElement::trackType_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
auto* el = _element->AsTrack();
|
|
if (el != nullptr)
|
|
{
|
|
duk_push_int(ctx, EnumValue(el->GetTrackType()));
|
|
}
|
|
else
|
|
{
|
|
scriptEngine.LogPluginInfo("Cannot read 'trackType' property, tile element is not a TrackElement.");
|
|
duk_push_null(ctx);
|
|
}
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::trackType_set(uint16_t value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
auto* el = _element->AsTrack();
|
|
if (el == nullptr)
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
scriptEngine.LogPluginInfo("Cannot set 'trackType' property, tile element is not a TrackElement.");
|
|
return;
|
|
}
|
|
|
|
el->SetTrackType(static_cast<TrackElemType>(value));
|
|
Invalidate();
|
|
}
|
|
|
|
DukValue ScTileElement::rideType_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
auto* el = _element->AsTrack();
|
|
if (el != nullptr)
|
|
{
|
|
duk_push_int(ctx, el->GetRideType());
|
|
}
|
|
else
|
|
{
|
|
scriptEngine.LogPluginInfo("Cannot read 'rideType' property, tile element is not a TrackElement.");
|
|
duk_push_null(ctx);
|
|
}
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::rideType_set(uint16_t value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
|
|
try
|
|
{
|
|
if (value >= RIDE_TYPE_COUNT)
|
|
throw DukException() << "'rideType' value is invalid.";
|
|
|
|
auto* el = _element->AsTrack();
|
|
if (el == nullptr)
|
|
throw DukException() << "Cannot set 'rideType' property, tile element is not a TrackElement.";
|
|
|
|
el->SetRideType(value);
|
|
Invalidate();
|
|
}
|
|
catch (const DukException& e)
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
scriptEngine.LogPluginInfo(e.what());
|
|
}
|
|
}
|
|
|
|
DukValue ScTileElement::sequence_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
try
|
|
{
|
|
switch (_element->GetType())
|
|
{
|
|
case TileElementType::LargeScenery:
|
|
{
|
|
auto* el = _element->AsLargeScenery();
|
|
duk_push_int(ctx, el->GetSequenceIndex());
|
|
break;
|
|
}
|
|
case TileElementType::Track:
|
|
{
|
|
auto* el = _element->AsTrack();
|
|
auto* ride = GetRide(el->GetRideIndex());
|
|
|
|
if (ride != nullptr)
|
|
{
|
|
const auto& rtd = ride->getRideTypeDescriptor();
|
|
if (rtd.specialType == RtdSpecialType::maze)
|
|
throw DukException() << "Cannot read 'sequence' property, TrackElement belongs to a maze.";
|
|
}
|
|
|
|
duk_push_int(ctx, el->GetSequenceIndex());
|
|
break;
|
|
}
|
|
case TileElementType::Entrance:
|
|
{
|
|
auto* el = _element->AsEntrance();
|
|
duk_push_int(ctx, el->GetSequenceIndex());
|
|
break;
|
|
}
|
|
default:
|
|
throw DukException() << "Cannot read 'sequence' property, tile element is not a TrackElement, "
|
|
"LargeSceneryElement, or EntranceElement.";
|
|
}
|
|
}
|
|
catch (const DukException& e)
|
|
{
|
|
scriptEngine.LogPluginInfo(e.what());
|
|
duk_push_null(ctx);
|
|
}
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::sequence_set(const DukValue& value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
|
|
try
|
|
{
|
|
if (value.type() != DukValue::Type::NUMBER)
|
|
throw DukException() << "'sequence' must be a number.";
|
|
|
|
switch (_element->GetType())
|
|
{
|
|
case TileElementType::LargeScenery:
|
|
{
|
|
RemoveBannerEntryIfNeeded();
|
|
auto* el = _element->AsLargeScenery();
|
|
el->SetSequenceIndex(value.as_uint());
|
|
CreateBannerEntryIfNeeded();
|
|
Invalidate();
|
|
break;
|
|
}
|
|
case TileElementType::Track:
|
|
{
|
|
auto* el = _element->AsTrack();
|
|
auto ride = GetRide(el->GetRideIndex());
|
|
|
|
if (ride != nullptr)
|
|
{
|
|
const auto& rtd = ride->getRideTypeDescriptor();
|
|
if (rtd.specialType == RtdSpecialType::maze)
|
|
throw DukException() << "Cannot set 'sequence' property, TrackElement belongs to a maze.";
|
|
}
|
|
|
|
el->SetSequenceIndex(value.as_uint());
|
|
Invalidate();
|
|
break;
|
|
}
|
|
case TileElementType::Entrance:
|
|
{
|
|
auto* el = _element->AsEntrance();
|
|
el->SetSequenceIndex(value.as_uint());
|
|
Invalidate();
|
|
break;
|
|
}
|
|
default:
|
|
throw DukException() << "Cannot set 'sequence' property, tile element is not a TrackElement, "
|
|
"LargeSceneryElement, or EntranceElement.";
|
|
}
|
|
}
|
|
catch (const DukException& e)
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
scriptEngine.LogPluginInfo(e.what());
|
|
}
|
|
}
|
|
|
|
DukValue ScTileElement::ride_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
try
|
|
{
|
|
switch (_element->GetType())
|
|
{
|
|
case TileElementType::Path:
|
|
{
|
|
auto* el = _element->AsPath();
|
|
if (!el->IsQueue())
|
|
throw DukException() << "Cannot read 'ride' property, path is not a queue.";
|
|
|
|
if (!el->GetRideIndex().IsNull())
|
|
duk_push_int(ctx, el->GetRideIndex().ToUnderlying());
|
|
else
|
|
duk_push_null(ctx);
|
|
break;
|
|
}
|
|
case TileElementType::Track:
|
|
{
|
|
auto* el = _element->AsTrack();
|
|
duk_push_int(ctx, el->GetRideIndex().ToUnderlying());
|
|
break;
|
|
}
|
|
case TileElementType::Entrance:
|
|
{
|
|
auto* el = _element->AsEntrance();
|
|
duk_push_int(ctx, el->GetRideIndex().ToUnderlying());
|
|
break;
|
|
}
|
|
default:
|
|
throw DukException()
|
|
<< "Cannot read 'ride' property, tile element is not PathElement, TrackElement, or EntranceElement";
|
|
}
|
|
}
|
|
catch (const DukException& e)
|
|
{
|
|
scriptEngine.LogPluginInfo(e.what());
|
|
duk_push_null(ctx);
|
|
}
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::ride_set(const DukValue& value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
|
|
try
|
|
{
|
|
switch (_element->GetType())
|
|
{
|
|
case TileElementType::Path:
|
|
{
|
|
auto* el = _element->AsPath();
|
|
if (!el->IsQueue())
|
|
throw DukException() << "Cannot set ride property, path is not a queue.";
|
|
|
|
if (value.type() == DukValue::Type::NUMBER)
|
|
el->SetRideIndex(RideId::FromUnderlying(value.as_uint()));
|
|
else if (value.type() == DukValue::Type::NULLREF)
|
|
el->SetRideIndex(RideId::GetNull());
|
|
else
|
|
throw DukException() << "'ride' must be a number or null.";
|
|
Invalidate();
|
|
break;
|
|
}
|
|
case TileElementType::Track:
|
|
{
|
|
if (value.type() != DukValue::Type::NUMBER)
|
|
throw DukException() << "'ride' must be a number.";
|
|
|
|
auto* el = _element->AsTrack();
|
|
el->SetRideIndex(RideId::FromUnderlying(value.as_uint()));
|
|
Invalidate();
|
|
break;
|
|
}
|
|
case TileElementType::Entrance:
|
|
{
|
|
if (value.type() != DukValue::Type::NUMBER)
|
|
throw DukException() << "'ride' must be a number.";
|
|
|
|
auto* el = _element->AsEntrance();
|
|
el->SetRideIndex(RideId::FromUnderlying(value.as_uint()));
|
|
Invalidate();
|
|
break;
|
|
}
|
|
default:
|
|
throw DukException()
|
|
<< "Cannot set 'ride' property, tile element is not PathElement, TrackElement, or EntranceElement";
|
|
}
|
|
}
|
|
catch (const DukException& e)
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
scriptEngine.LogPluginInfo(e.what());
|
|
}
|
|
}
|
|
|
|
DukValue ScTileElement::station_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
try
|
|
{
|
|
switch (_element->GetType())
|
|
{
|
|
case TileElementType::Path:
|
|
{
|
|
auto* el = _element->AsPath();
|
|
if (!el->IsQueue())
|
|
throw DukException() << "Cannot read 'station' property, path is not a queue.";
|
|
|
|
if (el->GetRideIndex().IsNull())
|
|
throw DukException() << "Cannot read 'station' property, queue is not linked to a ride.";
|
|
|
|
if (!el->GetStationIndex().IsNull())
|
|
duk_push_int(ctx, el->GetStationIndex().ToUnderlying());
|
|
else
|
|
duk_push_null(ctx);
|
|
break;
|
|
}
|
|
case TileElementType::Track:
|
|
{
|
|
auto* el = _element->AsTrack();
|
|
if (!el->IsStation())
|
|
throw DukException() << "Cannot read 'station' property, track is not a station.";
|
|
|
|
duk_push_int(ctx, el->GetStationIndex().ToUnderlying());
|
|
break;
|
|
}
|
|
case TileElementType::Entrance:
|
|
{
|
|
auto* el = _element->AsEntrance();
|
|
duk_push_int(ctx, el->GetStationIndex().ToUnderlying());
|
|
break;
|
|
}
|
|
default:
|
|
throw DukException()
|
|
<< "Cannot read 'station' property, tile element is not PathElement, TrackElement, or EntranceElement";
|
|
}
|
|
}
|
|
catch (const DukException& e)
|
|
{
|
|
scriptEngine.LogPluginInfo(e.what());
|
|
duk_push_null(ctx);
|
|
}
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::station_set(const DukValue& value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
|
|
try
|
|
{
|
|
switch (_element->GetType())
|
|
{
|
|
case TileElementType::Path:
|
|
{
|
|
auto* el = _element->AsPath();
|
|
if (value.type() == DukValue::Type::NUMBER)
|
|
el->SetStationIndex(StationIndex::FromUnderlying(value.as_uint()));
|
|
else if (value.type() == DukValue::Type::NULLREF)
|
|
el->SetStationIndex(StationIndex::GetNull());
|
|
else
|
|
throw DukException() << "'station' must be a number or null.";
|
|
Invalidate();
|
|
break;
|
|
}
|
|
case TileElementType::Track:
|
|
{
|
|
if (value.type() != DukValue::Type::NUMBER)
|
|
throw DukException() << "'station' must be a number.";
|
|
|
|
auto* el = _element->AsTrack();
|
|
el->SetStationIndex(StationIndex::FromUnderlying(value.as_uint()));
|
|
Invalidate();
|
|
break;
|
|
}
|
|
case TileElementType::Entrance:
|
|
{
|
|
if (value.type() != DukValue::Type::NUMBER)
|
|
throw DukException() << "'station' must be a number.";
|
|
|
|
auto* el = _element->AsEntrance();
|
|
el->SetStationIndex(StationIndex::FromUnderlying(value.as_uint()));
|
|
Invalidate();
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
catch (const DukException& e)
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
scriptEngine.LogPluginInfo(e.what());
|
|
}
|
|
}
|
|
|
|
DukValue ScTileElement::hasChainLift_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
auto* el = _element->AsTrack();
|
|
if (el != nullptr)
|
|
{
|
|
duk_push_boolean(ctx, el->HasChain());
|
|
}
|
|
else
|
|
{
|
|
scriptEngine.LogPluginInfo("Cannot read 'hasChainLift' property, tile element is not a TrackElement.");
|
|
duk_push_null(ctx);
|
|
}
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::hasChainLift_set(bool value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
auto* el = _element->AsTrack();
|
|
if (el == nullptr)
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
scriptEngine.LogPluginInfo("Cannot set 'hasChainLift' property, tile element is not a TrackElement.");
|
|
return;
|
|
}
|
|
|
|
el->SetHasChain(value);
|
|
Invalidate();
|
|
}
|
|
|
|
DukValue ScTileElement::mazeEntry_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
try
|
|
{
|
|
auto* el = _element->AsTrack();
|
|
if (el == nullptr)
|
|
throw DukException() << "Cannot read 'mazeEntry' property, element is not a TrackElement.";
|
|
|
|
Ride* ride = GetRide(el->GetRideIndex());
|
|
if (ride == nullptr)
|
|
throw DukException() << "Cannot read 'mazeEntry' property, ride is invalid.";
|
|
|
|
const auto& rtd = ride->getRideTypeDescriptor();
|
|
if (rtd.specialType != RtdSpecialType::maze)
|
|
throw DukException() << "Cannot read 'mazeEntry' property, ride is not a maze.";
|
|
|
|
duk_push_int(ctx, el->GetMazeEntry());
|
|
}
|
|
catch (const DukException& e)
|
|
{
|
|
scriptEngine.LogPluginInfo(e.what());
|
|
duk_push_null(ctx);
|
|
}
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::mazeEntry_set(const DukValue& value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
|
|
try
|
|
{
|
|
if (value.type() != DukValue::Type::NUMBER)
|
|
throw DukException() << "'mazeEntry' property must be a number.";
|
|
|
|
auto* el = _element->AsTrack();
|
|
if (el == nullptr)
|
|
throw DukException() << "Cannot set 'mazeEntry' property, tile element is not a TrackElement.";
|
|
|
|
auto* ride = GetRide(el->GetRideIndex());
|
|
if (ride == nullptr)
|
|
throw DukException() << "Cannot set 'mazeEntry' property, ride is invalid.";
|
|
|
|
const auto& rtd = ride->getRideTypeDescriptor();
|
|
if (rtd.specialType != RtdSpecialType::maze)
|
|
throw DukException() << "Cannot set 'mazeEntry' property, ride is not a maze.";
|
|
|
|
el->SetMazeEntry(value.as_uint());
|
|
Invalidate();
|
|
}
|
|
catch (const DukException& e)
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
scriptEngine.LogPluginInfo(e.what());
|
|
}
|
|
}
|
|
|
|
DukValue ScTileElement::colourScheme_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
try
|
|
{
|
|
auto* el = _element->AsTrack();
|
|
if (el == nullptr)
|
|
throw DukException() << "Cannot read 'colourScheme' property, tile element is not a TrackElement.";
|
|
|
|
auto* ride = GetRide(el->GetRideIndex());
|
|
if (ride == nullptr)
|
|
throw DukException() << "Cannot read 'colourScheme' property, ride is invalid.";
|
|
|
|
const auto& rtd = ride->getRideTypeDescriptor();
|
|
if (rtd.specialType == RtdSpecialType::maze)
|
|
throw DukException() << "Cannot read 'colourScheme' property, TrackElement belongs to a maze.";
|
|
|
|
duk_push_int(ctx, el->GetColourScheme());
|
|
}
|
|
catch (const DukException& e)
|
|
{
|
|
scriptEngine.LogPluginInfo(e.what());
|
|
duk_push_null(ctx);
|
|
}
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::colourScheme_set(const DukValue& value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
|
|
try
|
|
{
|
|
if (value.type() != DukValue::Type::NUMBER)
|
|
throw DukException() << "'colourScheme' must be a number.";
|
|
|
|
auto* el = _element->AsTrack();
|
|
if (el == nullptr)
|
|
throw DukException() << "Cannot set 'colourScheme' property, tile element is not a TrackElement.";
|
|
|
|
auto* ride = GetRide(el->GetRideIndex());
|
|
if (ride == nullptr)
|
|
throw DukException() << "Cannot set 'colourScheme', ride is invalid.";
|
|
|
|
const auto& rtd = ride->getRideTypeDescriptor();
|
|
if (rtd.specialType == RtdSpecialType::maze)
|
|
throw DukException() << "Cannot set 'colourScheme' property, TrackElement belongs to a maze.";
|
|
|
|
el->SetColourScheme(static_cast<RideColourScheme>(value.as_uint()));
|
|
Invalidate();
|
|
}
|
|
catch (const DukException& e)
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
scriptEngine.LogPluginInfo(e.what());
|
|
}
|
|
}
|
|
|
|
DukValue ScTileElement::seatRotation_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
try
|
|
{
|
|
auto* el = _element->AsTrack();
|
|
if (el == nullptr)
|
|
throw DukException() << "Cannot read 'seatRotation' property, tile element is not a TrackElement.";
|
|
|
|
auto* ride = GetRide(el->GetRideIndex());
|
|
if (ride == nullptr)
|
|
throw DukException() << "Cannot read 'seatRotation' property, ride is invalid.";
|
|
|
|
const auto& rtd = ride->getRideTypeDescriptor();
|
|
if (rtd.specialType == RtdSpecialType::maze)
|
|
throw DukException() << "Cannot read 'seatRotation' property, TrackElement belongs to a maze.";
|
|
|
|
duk_push_int(ctx, el->GetSeatRotation());
|
|
}
|
|
catch (const DukException& e)
|
|
{
|
|
scriptEngine.LogPluginInfo(e.what());
|
|
duk_push_null(ctx);
|
|
}
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::seatRotation_set(const DukValue& value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
|
|
try
|
|
{
|
|
if (value.type() != DukValue::Type::NUMBER)
|
|
throw DukException() << "'seatRotation' must be a number.";
|
|
|
|
auto* el = _element->AsTrack();
|
|
if (el == nullptr)
|
|
throw DukException() << "Cannot set 'seatRotation' property, tile element is not a TrackElement.";
|
|
|
|
auto* ride = GetRide(el->GetRideIndex());
|
|
if (ride == nullptr)
|
|
throw DukException() << "Cannot set 'seatRotation' property, ride is invalid.";
|
|
|
|
const auto& rtd = ride->getRideTypeDescriptor();
|
|
if (rtd.specialType != RtdSpecialType::maze)
|
|
throw DukException() << "Cannot set 'seatRotation' property, TrackElement belongs to a maze.";
|
|
|
|
el->SetSeatRotation(value.as_uint());
|
|
Invalidate();
|
|
}
|
|
catch (const DukException& e)
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
scriptEngine.LogPluginInfo(e.what());
|
|
}
|
|
}
|
|
|
|
DukValue ScTileElement::brakeBoosterSpeed_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
try
|
|
{
|
|
auto* el = _element->AsTrack();
|
|
if (el == nullptr)
|
|
throw DukException() << "Cannot read 'brakeBoosterSpeed' property, tile element is not a TrackElement.";
|
|
|
|
if (!TrackTypeHasSpeedSetting(el->GetTrackType()))
|
|
throw DukException() << "Cannot read 'brakeBoosterSpeed' property, track element has no speed setting.";
|
|
|
|
duk_push_int(ctx, el->GetBrakeBoosterSpeed());
|
|
}
|
|
catch (const DukException& e)
|
|
{
|
|
scriptEngine.LogPluginInfo(e.what());
|
|
duk_push_null(ctx);
|
|
}
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::brakeBoosterSpeed_set(const DukValue& value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
|
|
try
|
|
{
|
|
if (value.type() != DukValue::Type::NUMBER)
|
|
throw DukException() << "'brakeBoosterSpeed' must be a number.";
|
|
|
|
auto* el = _element->AsTrack();
|
|
if (el == nullptr)
|
|
throw DukException() << "Cannot set 'brakeBoosterSpeed' property, tile element is not a TrackElement.";
|
|
|
|
if (!TrackTypeHasSpeedSetting(el->GetTrackType()))
|
|
throw DukException() << "Cannot set 'brakeBoosterSpeed' property, track element has no speed setting.";
|
|
|
|
el->SetBrakeBoosterSpeed(value.as_uint());
|
|
Invalidate();
|
|
}
|
|
catch (const DukException& e)
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
scriptEngine.LogPluginInfo(e.what());
|
|
}
|
|
}
|
|
|
|
DukValue ScTileElement::isInverted_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
auto* el = _element->AsTrack();
|
|
if (el != nullptr)
|
|
{
|
|
duk_push_boolean(ctx, el->IsInverted());
|
|
}
|
|
else
|
|
{
|
|
scriptEngine.LogPluginInfo("Cannot read 'isInverted' property, tile element is not a TrackElement.");
|
|
duk_push_null(ctx);
|
|
}
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::isInverted_set(bool value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
auto* el = _element->AsTrack();
|
|
if (el == nullptr)
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
scriptEngine.LogPluginInfo("Cannot set 'isInverted' property, tile element is not a TrackElement.");
|
|
return;
|
|
}
|
|
|
|
el->SetInverted(value);
|
|
Invalidate();
|
|
}
|
|
|
|
DukValue ScTileElement::hasCableLift_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
auto* el = _element->AsTrack();
|
|
if (el != nullptr)
|
|
{
|
|
duk_push_boolean(ctx, el->HasCableLift());
|
|
}
|
|
else
|
|
{
|
|
scriptEngine.LogPluginInfo("Cannot read 'hasCableLift' property, tile element is not a TrackElement.");
|
|
duk_push_null(ctx);
|
|
}
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::hasCableLift_set(bool value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
auto* el = _element->AsTrack();
|
|
if (el == nullptr)
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
scriptEngine.LogPluginInfo("Cannot set 'hasCableLift' property, tile element is not a TrackElement.");
|
|
return;
|
|
}
|
|
|
|
el->SetHasCableLift(value);
|
|
Invalidate();
|
|
}
|
|
|
|
DukValue ScTileElement::isHighlighted_get() const
|
|
{
|
|
auto ctx = GetContext()->GetScriptEngine().GetContext();
|
|
auto el = _element->AsTrack();
|
|
if (el != nullptr)
|
|
duk_push_boolean(ctx, el->IsHighlighted());
|
|
else
|
|
duk_push_null(ctx);
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::isHighlighted_set(bool value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
auto el = _element->AsTrack();
|
|
if (el != nullptr)
|
|
{
|
|
el->SetHighlight(value);
|
|
Invalidate();
|
|
}
|
|
}
|
|
|
|
DukValue ScTileElement::object_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
switch (_element->GetType())
|
|
{
|
|
case TileElementType::Path:
|
|
{
|
|
auto* el = _element->AsPath();
|
|
auto index = el->GetLegacyPathEntryIndex();
|
|
if (index != kObjectEntryIndexNull)
|
|
duk_push_int(ctx, index);
|
|
else
|
|
duk_push_null(ctx);
|
|
break;
|
|
}
|
|
case TileElementType::SmallScenery:
|
|
{
|
|
auto* el = _element->AsSmallScenery();
|
|
duk_push_int(ctx, el->GetEntryIndex());
|
|
break;
|
|
}
|
|
case TileElementType::LargeScenery:
|
|
{
|
|
auto* el = _element->AsLargeScenery();
|
|
duk_push_int(ctx, el->GetEntryIndex());
|
|
break;
|
|
}
|
|
case TileElementType::Wall:
|
|
{
|
|
auto* el = _element->AsWall();
|
|
duk_push_int(ctx, el->GetEntryIndex());
|
|
break;
|
|
}
|
|
case TileElementType::Entrance:
|
|
{
|
|
auto* el = _element->AsEntrance();
|
|
duk_push_int(ctx, el->GetEntranceType());
|
|
break;
|
|
}
|
|
case TileElementType::Banner:
|
|
{
|
|
auto* el = _element->AsBanner();
|
|
duk_push_int(ctx, el->GetBanner()->type);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
duk_push_null(ctx);
|
|
break;
|
|
}
|
|
}
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
|
|
void ScTileElement::object_set(const DukValue& value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
|
|
auto index = FromDuk<ObjectEntryIndex>(value);
|
|
switch (_element->GetType())
|
|
{
|
|
case TileElementType::Path:
|
|
{
|
|
if (value.type() == DukValue::Type::NUMBER)
|
|
{
|
|
auto* el = _element->AsPath();
|
|
el->SetLegacyPathEntryIndex(index);
|
|
Invalidate();
|
|
}
|
|
break;
|
|
}
|
|
case TileElementType::SmallScenery:
|
|
{
|
|
auto* el = _element->AsSmallScenery();
|
|
el->SetEntryIndex(index);
|
|
Invalidate();
|
|
break;
|
|
}
|
|
case TileElementType::LargeScenery:
|
|
{
|
|
RemoveBannerEntryIfNeeded();
|
|
auto* el = _element->AsLargeScenery();
|
|
el->SetEntryIndex(index);
|
|
CreateBannerEntryIfNeeded();
|
|
Invalidate();
|
|
break;
|
|
}
|
|
case TileElementType::Wall:
|
|
{
|
|
RemoveBannerEntryIfNeeded();
|
|
auto* el = _element->AsWall();
|
|
el->SetEntryIndex(index);
|
|
CreateBannerEntryIfNeeded();
|
|
Invalidate();
|
|
break;
|
|
}
|
|
case TileElementType::Entrance:
|
|
{
|
|
auto* el = _element->AsEntrance();
|
|
el->SetEntranceType(index);
|
|
Invalidate();
|
|
break;
|
|
}
|
|
case TileElementType::Banner:
|
|
{
|
|
auto* el = _element->AsBanner();
|
|
el->GetBanner()->type = index;
|
|
Invalidate();
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool ScTileElement::isHidden_get() const
|
|
{
|
|
return _element->IsInvisible();
|
|
}
|
|
|
|
void ScTileElement::isHidden_set(bool hide)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
_element->SetInvisible(hide);
|
|
Invalidate();
|
|
}
|
|
|
|
DukValue ScTileElement::age_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
auto* el = _element->AsSmallScenery();
|
|
if (el != nullptr)
|
|
duk_push_int(ctx, el->GetAge());
|
|
else
|
|
duk_push_null(ctx);
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::age_set(uint8_t value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
auto* el = _element->AsSmallScenery();
|
|
if (el != nullptr)
|
|
{
|
|
el->SetAge(value);
|
|
Invalidate();
|
|
}
|
|
}
|
|
|
|
DukValue ScTileElement::quadrant_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
auto* el = _element->AsSmallScenery();
|
|
if (el != nullptr)
|
|
duk_push_int(ctx, el->GetSceneryQuadrant());
|
|
else
|
|
duk_push_null(ctx);
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::quadrant_set(uint8_t value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
auto* el = _element->AsSmallScenery();
|
|
if (el != nullptr)
|
|
{
|
|
el->SetSceneryQuadrant(value);
|
|
Invalidate();
|
|
}
|
|
}
|
|
|
|
uint8_t ScTileElement::occupiedQuadrants_get() const
|
|
{
|
|
return _element->GetOccupiedQuadrants();
|
|
}
|
|
void ScTileElement::occupiedQuadrants_set(uint8_t value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
_element->SetOccupiedQuadrants(value);
|
|
Invalidate();
|
|
}
|
|
|
|
bool ScTileElement::isGhost_get() const
|
|
{
|
|
return _element->IsGhost();
|
|
}
|
|
void ScTileElement::isGhost_set(bool value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
_element->SetGhost(value);
|
|
Invalidate();
|
|
}
|
|
|
|
DukValue ScTileElement::primaryColour_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
switch (_element->GetType())
|
|
{
|
|
case TileElementType::SmallScenery:
|
|
{
|
|
auto* el = _element->AsSmallScenery();
|
|
duk_push_int(ctx, el->GetPrimaryColour());
|
|
break;
|
|
}
|
|
case TileElementType::LargeScenery:
|
|
{
|
|
auto* el = _element->AsLargeScenery();
|
|
duk_push_int(ctx, el->GetPrimaryColour());
|
|
break;
|
|
}
|
|
case TileElementType::Wall:
|
|
{
|
|
auto* el = _element->AsWall();
|
|
duk_push_int(ctx, el->GetPrimaryColour());
|
|
break;
|
|
}
|
|
case TileElementType::Banner:
|
|
{
|
|
auto* el = _element->AsBanner();
|
|
duk_push_int(ctx, el->GetBanner()->colour);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
duk_push_null(ctx);
|
|
break;
|
|
}
|
|
}
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::primaryColour_set(uint8_t value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
switch (_element->GetType())
|
|
{
|
|
case TileElementType::SmallScenery:
|
|
{
|
|
auto* el = _element->AsSmallScenery();
|
|
el->SetPrimaryColour(value);
|
|
Invalidate();
|
|
break;
|
|
}
|
|
case TileElementType::LargeScenery:
|
|
{
|
|
auto* el = _element->AsLargeScenery();
|
|
el->SetPrimaryColour(value);
|
|
Invalidate();
|
|
break;
|
|
}
|
|
case TileElementType::Wall:
|
|
{
|
|
auto* el = _element->AsWall();
|
|
el->SetPrimaryColour(value);
|
|
Invalidate();
|
|
break;
|
|
}
|
|
case TileElementType::Banner:
|
|
{
|
|
auto* el = _element->AsBanner();
|
|
el->GetBanner()->colour = value;
|
|
Invalidate();
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
DukValue ScTileElement::secondaryColour_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
switch (_element->GetType())
|
|
{
|
|
case TileElementType::SmallScenery:
|
|
{
|
|
auto* el = _element->AsSmallScenery();
|
|
duk_push_int(ctx, el->GetSecondaryColour());
|
|
break;
|
|
}
|
|
case TileElementType::LargeScenery:
|
|
{
|
|
auto* el = _element->AsLargeScenery();
|
|
duk_push_int(ctx, el->GetSecondaryColour());
|
|
break;
|
|
}
|
|
case TileElementType::Wall:
|
|
{
|
|
auto* el = _element->AsWall();
|
|
duk_push_int(ctx, el->GetSecondaryColour());
|
|
break;
|
|
}
|
|
case TileElementType::Banner:
|
|
{
|
|
auto* el = _element->AsBanner();
|
|
duk_push_int(ctx, EnumValue(el->GetBanner()->textColour));
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
duk_push_null(ctx);
|
|
break;
|
|
}
|
|
}
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::secondaryColour_set(uint8_t value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
switch (_element->GetType())
|
|
{
|
|
case TileElementType::SmallScenery:
|
|
{
|
|
auto* el = _element->AsSmallScenery();
|
|
el->SetSecondaryColour(value);
|
|
Invalidate();
|
|
break;
|
|
}
|
|
case TileElementType::LargeScenery:
|
|
{
|
|
auto* el = _element->AsLargeScenery();
|
|
el->SetSecondaryColour(value);
|
|
Invalidate();
|
|
break;
|
|
}
|
|
case TileElementType::Wall:
|
|
{
|
|
auto* el = _element->AsWall();
|
|
el->SetSecondaryColour(value);
|
|
Invalidate();
|
|
break;
|
|
}
|
|
case TileElementType::Banner:
|
|
{
|
|
auto* el = _element->AsBanner();
|
|
el->GetBanner()->textColour = static_cast<TextColour>(value);
|
|
Invalidate();
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
DukValue ScTileElement::tertiaryColour_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
switch (_element->GetType())
|
|
{
|
|
case TileElementType::SmallScenery:
|
|
{
|
|
auto* el = _element->AsSmallScenery();
|
|
duk_push_int(ctx, el->GetTertiaryColour());
|
|
break;
|
|
}
|
|
case TileElementType::LargeScenery:
|
|
{
|
|
auto* el = _element->AsLargeScenery();
|
|
duk_push_int(ctx, el->GetTertiaryColour());
|
|
break;
|
|
}
|
|
case TileElementType::Wall:
|
|
{
|
|
auto* el = _element->AsWall();
|
|
duk_push_int(ctx, el->GetTertiaryColour());
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
duk_push_null(ctx);
|
|
break;
|
|
}
|
|
}
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::tertiaryColour_set(uint8_t value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
switch (_element->GetType())
|
|
{
|
|
case TileElementType::SmallScenery:
|
|
{
|
|
auto* el = _element->AsSmallScenery();
|
|
el->SetTertiaryColour(value);
|
|
Invalidate();
|
|
break;
|
|
}
|
|
case TileElementType::LargeScenery:
|
|
{
|
|
auto* el = _element->AsLargeScenery();
|
|
el->SetTertiaryColour(value);
|
|
Invalidate();
|
|
break;
|
|
}
|
|
case TileElementType::Wall:
|
|
{
|
|
auto* el = _element->AsWall();
|
|
el->SetTertiaryColour(value);
|
|
Invalidate();
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
DukValue ScTileElement::bannerIndex_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
BannerIndex idx = _element->GetBannerIndex();
|
|
if (idx == BannerIndex::GetNull())
|
|
duk_push_null(ctx);
|
|
else
|
|
duk_push_int(ctx, idx.ToUnderlying());
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::bannerIndex_set(const DukValue& value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
switch (_element->GetType())
|
|
{
|
|
case TileElementType::LargeScenery:
|
|
{
|
|
auto* el = _element->AsLargeScenery();
|
|
if (value.type() == DukValue::Type::NUMBER)
|
|
el->SetBannerIndex(BannerIndex::FromUnderlying(value.as_uint()));
|
|
else
|
|
el->SetBannerIndex(BannerIndex::GetNull());
|
|
Invalidate();
|
|
break;
|
|
}
|
|
case TileElementType::Wall:
|
|
{
|
|
auto* el = _element->AsWall();
|
|
if (value.type() == DukValue::Type::NUMBER)
|
|
el->SetBannerIndex(BannerIndex::FromUnderlying(value.as_uint()));
|
|
else
|
|
el->SetBannerIndex(BannerIndex::GetNull());
|
|
Invalidate();
|
|
break;
|
|
}
|
|
case TileElementType::Banner:
|
|
{
|
|
auto* el = _element->AsBanner();
|
|
if (value.type() == DukValue::Type::NUMBER)
|
|
el->SetIndex(BannerIndex::FromUnderlying(value.as_uint()));
|
|
else
|
|
el->SetIndex(BannerIndex::GetNull());
|
|
Invalidate();
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Deprecated in favor of seperate 'edges' and 'corners' properties,
|
|
// left here to maintain compatibility with older plugins.
|
|
/** @deprecated */
|
|
uint8_t ScTileElement::edgesAndCorners_get() const
|
|
{
|
|
auto* el = _element->AsPath();
|
|
return el != nullptr ? el->GetEdgesAndCorners() : 0;
|
|
}
|
|
/** @deprecated */
|
|
void ScTileElement::edgesAndCorners_set(uint8_t value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
auto* el = _element->AsPath();
|
|
if (el != nullptr)
|
|
{
|
|
el->SetEdgesAndCorners(value);
|
|
Invalidate();
|
|
}
|
|
}
|
|
|
|
DukValue ScTileElement::edges_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
auto* el = _element->AsPath();
|
|
if (el != nullptr)
|
|
duk_push_int(ctx, el->GetEdges());
|
|
else
|
|
duk_push_null(ctx);
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::edges_set(uint8_t value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
auto* el = _element->AsPath();
|
|
if (el != nullptr)
|
|
{
|
|
el->SetEdges(value);
|
|
Invalidate();
|
|
}
|
|
}
|
|
|
|
DukValue ScTileElement::corners_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
auto* el = _element->AsPath();
|
|
if (el != nullptr)
|
|
duk_push_int(ctx, el->GetCorners());
|
|
else
|
|
duk_push_null(ctx);
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::corners_set(uint8_t value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
auto* el = _element->AsPath();
|
|
if (el != nullptr)
|
|
{
|
|
el->SetCorners(value);
|
|
Invalidate();
|
|
}
|
|
}
|
|
|
|
DukValue ScTileElement::slopeDirection_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
auto* el = _element->AsPath();
|
|
if (el != nullptr && el->IsSloped())
|
|
duk_push_int(ctx, el->GetSlopeDirection());
|
|
else
|
|
duk_push_null(ctx);
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::slopeDirection_set(const DukValue& value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
auto* el = _element->AsPath();
|
|
if (el != nullptr)
|
|
{
|
|
if (value.type() == DukValue::Type::NUMBER)
|
|
{
|
|
el->SetSloped(true);
|
|
el->SetSlopeDirection(value.as_uint());
|
|
}
|
|
else
|
|
{
|
|
el->SetSloped(false);
|
|
el->SetSlopeDirection(0);
|
|
}
|
|
Invalidate();
|
|
}
|
|
}
|
|
|
|
DukValue ScTileElement::isQueue_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
auto* el = _element->AsPath();
|
|
if (el != nullptr)
|
|
duk_push_boolean(ctx, el->IsQueue());
|
|
else
|
|
duk_push_null(ctx);
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::isQueue_set(bool value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
auto* el = _element->AsPath();
|
|
if (el != nullptr)
|
|
{
|
|
el->SetIsQueue(value);
|
|
Invalidate();
|
|
}
|
|
}
|
|
|
|
DukValue ScTileElement::queueBannerDirection_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
auto* el = _element->AsPath();
|
|
if (el != nullptr && el->HasQueueBanner())
|
|
duk_push_int(ctx, el->GetQueueBannerDirection());
|
|
else
|
|
duk_push_null(ctx);
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::queueBannerDirection_set(const DukValue& value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
auto* el = _element->AsPath();
|
|
if (el != nullptr)
|
|
{
|
|
if (value.type() == DukValue::Type::NUMBER)
|
|
{
|
|
el->SetHasQueueBanner(true);
|
|
el->SetQueueBannerDirection(value.as_uint());
|
|
}
|
|
else
|
|
{
|
|
el->SetHasQueueBanner(false);
|
|
el->SetQueueBannerDirection(0);
|
|
}
|
|
Invalidate();
|
|
}
|
|
}
|
|
|
|
DukValue ScTileElement::isBlockedByVehicle_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
auto* el = _element->AsPath();
|
|
if (el != nullptr)
|
|
duk_push_boolean(ctx, el->IsBlockedByVehicle());
|
|
else
|
|
duk_push_null(ctx);
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::isBlockedByVehicle_set(bool value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
auto* el = _element->AsPath();
|
|
if (el != nullptr)
|
|
{
|
|
el->SetIsBlockedByVehicle(value);
|
|
Invalidate();
|
|
}
|
|
}
|
|
|
|
DukValue ScTileElement::isWide_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
auto* el = _element->AsPath();
|
|
if (el != nullptr)
|
|
duk_push_boolean(ctx, el->IsWide());
|
|
else
|
|
duk_push_null(ctx);
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::isWide_set(bool value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
auto* el = _element->AsPath();
|
|
if (el != nullptr)
|
|
{
|
|
el->SetWide(value);
|
|
Invalidate();
|
|
}
|
|
}
|
|
|
|
DukValue ScTileElement::surfaceObject_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
if (_element->GetType() == TileElementType::Path)
|
|
{
|
|
auto* el = _element->AsPath();
|
|
auto index = el->GetSurfaceEntryIndex();
|
|
if (index != kObjectEntryIndexNull)
|
|
{
|
|
duk_push_int(ctx, index);
|
|
}
|
|
else
|
|
{
|
|
duk_push_null(ctx);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
duk_push_null(ctx);
|
|
}
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
|
|
void ScTileElement::surfaceObject_set(const DukValue& value)
|
|
{
|
|
if (value.type() == DukValue::Type::NUMBER)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
if (_element->GetType() == TileElementType::Path)
|
|
{
|
|
auto* el = _element->AsPath();
|
|
el->SetSurfaceEntryIndex(FromDuk<ObjectEntryIndex>(value));
|
|
Invalidate();
|
|
}
|
|
}
|
|
}
|
|
|
|
DukValue ScTileElement::railingsObject_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
if (_element->GetType() == TileElementType::Path)
|
|
{
|
|
auto* el = _element->AsPath();
|
|
auto index = el->GetRailingsEntryIndex();
|
|
if (index != kObjectEntryIndexNull)
|
|
{
|
|
duk_push_int(ctx, index);
|
|
}
|
|
else
|
|
{
|
|
duk_push_null(ctx);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
duk_push_null(ctx);
|
|
}
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
|
|
void ScTileElement::railingsObject_set(const DukValue& value)
|
|
{
|
|
if (value.type() == DukValue::Type::NUMBER)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
if (_element->GetType() == TileElementType::Path)
|
|
{
|
|
auto* el = _element->AsPath();
|
|
el->SetRailingsEntryIndex(FromDuk<ObjectEntryIndex>(value));
|
|
Invalidate();
|
|
}
|
|
}
|
|
}
|
|
|
|
DukValue ScTileElement::addition_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
auto* el = _element->AsPath();
|
|
if (el != nullptr && el->HasAddition())
|
|
duk_push_int(ctx, el->GetAdditionEntryIndex());
|
|
else
|
|
duk_push_null(ctx);
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::addition_set(const DukValue& value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
auto* el = _element->AsPath();
|
|
if (el != nullptr)
|
|
{
|
|
if (value.type() == DukValue::Type::NUMBER)
|
|
{
|
|
auto addition = value.as_uint();
|
|
if (addition <= 254)
|
|
{
|
|
el->SetAdditionEntryIndex(addition);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
el->SetAddition(0);
|
|
}
|
|
Invalidate();
|
|
}
|
|
}
|
|
|
|
DukValue ScTileElement::additionStatus_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
auto* el = _element->AsPath();
|
|
if (el != nullptr && el->HasAddition() && !el->IsQueue())
|
|
duk_push_int(ctx, el->GetAdditionStatus());
|
|
else
|
|
duk_push_null(ctx);
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::additionStatus_set(const DukValue& value)
|
|
{
|
|
if (value.type() == DukValue::Type::NUMBER)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
auto* el = _element->AsPath();
|
|
if (el != nullptr)
|
|
if (el->HasAddition() && !el->IsQueue())
|
|
{
|
|
el->SetAdditionStatus(value.as_uint());
|
|
Invalidate();
|
|
}
|
|
}
|
|
}
|
|
|
|
DukValue ScTileElement::isAdditionBroken_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
auto* el = _element->AsPath();
|
|
if (el != nullptr && el->HasAddition())
|
|
duk_push_boolean(ctx, el->IsBroken());
|
|
else
|
|
duk_push_null(ctx);
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::isAdditionBroken_set(const DukValue& value)
|
|
{
|
|
if (value.type() == DukValue::Type::BOOLEAN)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
auto* el = _element->AsPath();
|
|
if (el != nullptr)
|
|
{
|
|
el->SetIsBroken(value.as_bool());
|
|
Invalidate();
|
|
}
|
|
}
|
|
}
|
|
|
|
DukValue ScTileElement::isAdditionGhost_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
auto* el = _element->AsPath();
|
|
if (el != nullptr && el->HasAddition())
|
|
duk_push_boolean(ctx, el->AdditionIsGhost());
|
|
else
|
|
duk_push_null(ctx);
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::isAdditionGhost_set(const DukValue& value)
|
|
{
|
|
if (value.type() == DukValue::Type::BOOLEAN)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
auto* el = _element->AsPath();
|
|
if (el != nullptr)
|
|
{
|
|
el->SetAdditionIsGhost(value.as_bool());
|
|
Invalidate();
|
|
}
|
|
}
|
|
}
|
|
|
|
DukValue ScTileElement::footpathObject_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
auto* el = _element->AsEntrance();
|
|
if (el != nullptr)
|
|
{
|
|
auto index = el->GetLegacyPathEntryIndex();
|
|
if (index != kObjectEntryIndexNull)
|
|
{
|
|
duk_push_int(ctx, index);
|
|
}
|
|
else
|
|
{
|
|
duk_push_null(ctx);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
duk_push_null(ctx);
|
|
}
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::footpathObject_set(const DukValue& value)
|
|
{
|
|
if (value.type() == DukValue::Type::NUMBER)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
auto* el = _element->AsEntrance();
|
|
if (el != nullptr)
|
|
{
|
|
el->SetLegacyPathEntryIndex(FromDuk<ObjectEntryIndex>(value));
|
|
Invalidate();
|
|
}
|
|
}
|
|
}
|
|
|
|
DukValue ScTileElement::footpathSurfaceObject_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
auto* el = _element->AsEntrance();
|
|
if (el != nullptr)
|
|
{
|
|
auto index = el->GetSurfaceEntryIndex();
|
|
if (index != kObjectEntryIndexNull)
|
|
{
|
|
duk_push_int(ctx, index);
|
|
}
|
|
else
|
|
{
|
|
duk_push_null(ctx);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
duk_push_null(ctx);
|
|
}
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
|
|
void ScTileElement::footpathSurfaceObject_set(const DukValue& value)
|
|
{
|
|
if (value.type() == DukValue::Type::NUMBER)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
auto* el = _element->AsEntrance();
|
|
if (el != nullptr)
|
|
{
|
|
el->SetSurfaceEntryIndex(FromDuk<ObjectEntryIndex>(value));
|
|
Invalidate();
|
|
}
|
|
}
|
|
}
|
|
|
|
DukValue ScTileElement::direction_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
switch (_element->GetType())
|
|
{
|
|
case TileElementType::Banner:
|
|
{
|
|
auto* el = _element->AsBanner();
|
|
duk_push_int(ctx, el->GetPosition());
|
|
break;
|
|
}
|
|
case TileElementType::Path:
|
|
case TileElementType::Surface:
|
|
{
|
|
duk_push_null(ctx);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
duk_push_int(ctx, _element->GetDirection());
|
|
break;
|
|
}
|
|
}
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::direction_set(uint8_t value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
switch (_element->GetType())
|
|
{
|
|
case TileElementType::Banner:
|
|
{
|
|
auto* el = _element->AsBanner();
|
|
el->SetPosition(value);
|
|
Invalidate();
|
|
break;
|
|
}
|
|
case TileElementType::Path:
|
|
case TileElementType::Surface:
|
|
{
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
_element->SetDirection(value);
|
|
Invalidate();
|
|
}
|
|
}
|
|
}
|
|
|
|
DukValue ScTileElement::bannerText_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
BannerIndex idx = _element->GetBannerIndex();
|
|
if (idx == BannerIndex::GetNull())
|
|
duk_push_null(ctx);
|
|
else
|
|
duk_push_string(ctx, GetBanner(idx)->GetText().c_str());
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::bannerText_set(std::string value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
BannerIndex idx = _element->GetBannerIndex();
|
|
if (idx != BannerIndex::GetNull())
|
|
{
|
|
auto banner = GetBanner(idx);
|
|
banner->text = value;
|
|
if (_element->GetType() != TileElementType::Banner)
|
|
{
|
|
if (value.empty())
|
|
banner->ride_index = BannerGetClosestRideIndex({ banner->position.ToCoordsXY(), 16 });
|
|
else
|
|
banner->ride_index = RideId::GetNull();
|
|
|
|
banner->flags.set(BannerFlag::linkedToRide, !banner->ride_index.IsNull());
|
|
}
|
|
}
|
|
}
|
|
|
|
DukValue ScTileElement::isNoEntry_get() const
|
|
{
|
|
auto& scriptEngine = GetContext()->GetScriptEngine();
|
|
auto* ctx = scriptEngine.GetContext();
|
|
auto* el = _element->AsBanner();
|
|
if (el != nullptr)
|
|
duk_push_boolean(ctx, el->GetBanner()->flags.has(BannerFlag::noEntry));
|
|
else
|
|
duk_push_null(ctx);
|
|
return DukValue::take_from_stack(ctx);
|
|
}
|
|
void ScTileElement::isNoEntry_set(bool value)
|
|
{
|
|
ThrowIfGameStateNotMutable();
|
|
auto* el = _element->AsBanner();
|
|
if (el != nullptr)
|
|
{
|
|
el->GetBanner()->flags.set(BannerFlag::noEntry, value);
|
|
Invalidate();
|
|
}
|
|
}
|
|
|
|
void ScTileElement::Invalidate()
|
|
{
|
|
MapInvalidateTileFull(_coords);
|
|
}
|
|
|
|
const LargeSceneryElement* ScTileElement::GetOtherLargeSceneryElement(
|
|
const CoordsXY& loc, const LargeSceneryElement* const largeScenery)
|
|
{
|
|
const auto* const largeEntry = largeScenery->GetEntry();
|
|
const auto direction = largeScenery->GetDirection();
|
|
const auto sequenceIndex = largeScenery->GetSequenceIndex();
|
|
const auto& tiles = largeEntry->tiles;
|
|
const auto& initialTile = tiles[sequenceIndex];
|
|
const auto rotatedFirstTile = CoordsXYZ{
|
|
CoordsXY{ initialTile.offset }.Rotate(direction),
|
|
initialTile.offset.z,
|
|
};
|
|
|
|
const auto firstTile = CoordsXYZ{ loc, largeScenery->GetBaseZ() } - rotatedFirstTile;
|
|
for (auto& tile : tiles)
|
|
{
|
|
const auto rotatedCurrentTile = CoordsXYZ{ CoordsXY{ tile.offset }.Rotate(direction), tile.offset.z };
|
|
|
|
const auto currentTile = firstTile + rotatedCurrentTile;
|
|
|
|
const TileElement* tileElement = MapGetFirstElementAt(currentTile);
|
|
if (tileElement != nullptr)
|
|
{
|
|
do
|
|
{
|
|
if (tileElement->GetType() != TileElementType::LargeScenery)
|
|
continue;
|
|
if (tileElement->GetDirection() != direction)
|
|
continue;
|
|
if (tileElement->GetBaseZ() != currentTile.z)
|
|
continue;
|
|
|
|
if (tileElement->AsLargeScenery() == largeScenery)
|
|
continue;
|
|
if (tileElement->AsLargeScenery()->GetEntryIndex() != largeScenery->GetEntryIndex())
|
|
continue;
|
|
if (tileElement->AsLargeScenery()->GetSequenceIndex() != tile.index)
|
|
continue;
|
|
|
|
return tileElement->AsLargeScenery();
|
|
} while (!(tileElement++)->IsLastForTile());
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void ScTileElement::RemoveBannerEntryIfNeeded()
|
|
{
|
|
// check if other element still uses the banner entry
|
|
if (_element->GetType() == TileElementType::LargeScenery
|
|
&& _element->AsLargeScenery()->GetEntry()->scrolling_mode != kScrollingModeNone
|
|
&& GetOtherLargeSceneryElement(_coords, _element->AsLargeScenery()) != nullptr)
|
|
return;
|
|
// remove banner entry (if one exists)
|
|
_element->RemoveBannerEntry();
|
|
}
|
|
|
|
void ScTileElement::CreateBannerEntryIfNeeded()
|
|
{
|
|
// check if creation is needed
|
|
switch (_element->GetType())
|
|
{
|
|
case TileElementType::Banner:
|
|
break;
|
|
case TileElementType::Wall:
|
|
{
|
|
auto wallEntry = _element->AsWall()->GetEntry();
|
|
if (wallEntry == nullptr || wallEntry->scrolling_mode == kScrollingModeNone)
|
|
return;
|
|
break;
|
|
}
|
|
case TileElementType::LargeScenery:
|
|
{
|
|
auto largeScenery = _element->AsLargeScenery();
|
|
auto largeSceneryEntry = largeScenery->GetEntry();
|
|
if (largeSceneryEntry == nullptr || largeSceneryEntry->scrolling_mode == kScrollingModeNone)
|
|
return;
|
|
|
|
auto otherElement = GetOtherLargeSceneryElement(_coords, largeScenery);
|
|
if (otherElement != nullptr)
|
|
{
|
|
largeScenery->SetBannerIndex(otherElement->GetBannerIndex());
|
|
return;
|
|
}
|
|
|
|
break;
|
|
}
|
|
default:
|
|
return;
|
|
}
|
|
|
|
// create banner entry and initialise it
|
|
auto* banner = CreateBanner();
|
|
if (banner == nullptr)
|
|
GetContext()->GetScriptEngine().LogPluginInfo("No free banners available.");
|
|
else
|
|
{
|
|
banner->text = {};
|
|
banner->colour = 0;
|
|
banner->textColour = TextColour::black;
|
|
banner->flags = {};
|
|
if (_element->GetType() == TileElementType::Wall)
|
|
banner->flags.set(BannerFlag::isWall);
|
|
if (_element->GetType() == TileElementType::LargeScenery)
|
|
banner->flags.set(BannerFlag::isLargeScenery);
|
|
banner->type = 0;
|
|
banner->position = TileCoordsXY(_coords);
|
|
|
|
if (_element->GetType() == TileElementType::Wall || _element->GetType() == TileElementType::LargeScenery)
|
|
{
|
|
RideId rideIndex = BannerGetClosestRideIndex({ _coords, _element->BaseHeight });
|
|
if (!rideIndex.IsNull())
|
|
{
|
|
banner->ride_index = rideIndex;
|
|
banner->flags.set(BannerFlag::linkedToRide);
|
|
}
|
|
}
|
|
|
|
_element->SetBannerIndex(banner->id);
|
|
}
|
|
}
|
|
|
|
void ScTileElement::Register(duk_context* ctx)
|
|
{
|
|
// All
|
|
dukglue_register_property(ctx, &ScTileElement::type_get, &ScTileElement::type_set, "type");
|
|
dukglue_register_property(ctx, &ScTileElement::baseHeight_get, &ScTileElement::baseHeight_set, "baseHeight");
|
|
dukglue_register_property(ctx, &ScTileElement::baseZ_get, &ScTileElement::baseZ_set, "baseZ");
|
|
dukglue_register_property(
|
|
ctx, &ScTileElement::clearanceHeight_get, &ScTileElement::clearanceHeight_set, "clearanceHeight");
|
|
dukglue_register_property(ctx, &ScTileElement::clearanceZ_get, &ScTileElement::clearanceZ_set, "clearanceZ");
|
|
dukglue_register_property(
|
|
ctx, &ScTileElement::occupiedQuadrants_get, &ScTileElement::occupiedQuadrants_set, "occupiedQuadrants");
|
|
dukglue_register_property(ctx, &ScTileElement::isGhost_get, &ScTileElement::isGhost_set, "isGhost");
|
|
dukglue_register_property(ctx, &ScTileElement::isHidden_get, &ScTileElement::isHidden_set, "isHidden");
|
|
|
|
// Track | Small Scenery | Wall | Entrance | Large Scenery | Banner
|
|
dukglue_register_property(ctx, &ScTileElement::direction_get, &ScTileElement::direction_set, "direction");
|
|
|
|
// Path | Small Scenery | Wall | Entrance | Large Scenery | Banner
|
|
dukglue_register_property(ctx, &ScTileElement::object_get, &ScTileElement::object_set, "object");
|
|
|
|
// Small Scenery | Wall | Large Scenery | Banner
|
|
dukglue_register_property(ctx, &ScTileElement::primaryColour_get, &ScTileElement::primaryColour_set, "primaryColour");
|
|
dukglue_register_property(
|
|
ctx, &ScTileElement::secondaryColour_get, &ScTileElement::secondaryColour_set, "secondaryColour");
|
|
|
|
// Small Scenery | Wall | Large Scenery
|
|
dukglue_register_property(
|
|
ctx, &ScTileElement::tertiaryColour_get, &ScTileElement::tertiaryColour_set, "tertiaryColour");
|
|
|
|
// Wall | Large Scenery | Banner
|
|
dukglue_register_property(ctx, &ScTileElement::bannerText_get, &ScTileElement::bannerText_set, "bannerText");
|
|
dukglue_register_property(ctx, &ScTileElement::bannerIndex_get, &ScTileElement::bannerIndex_set, "bannerIndex");
|
|
|
|
// Path | Track | Entrance
|
|
dukglue_register_property(ctx, &ScTileElement::ride_get, &ScTileElement::ride_set, "ride");
|
|
dukglue_register_property(ctx, &ScTileElement::station_get, &ScTileElement::station_set, "station");
|
|
|
|
// Track | Entrance | Large Scenery
|
|
dukglue_register_property(ctx, &ScTileElement::sequence_get, &ScTileElement::sequence_set, "sequence");
|
|
|
|
// Surface | Wall
|
|
dukglue_register_property(ctx, &ScTileElement::slope_get, &ScTileElement::slope_set, "slope");
|
|
|
|
// Surface only
|
|
dukglue_register_property(ctx, &ScTileElement::waterHeight_get, &ScTileElement::waterHeight_set, "waterHeight");
|
|
dukglue_register_property(ctx, &ScTileElement::surfaceStyle_get, &ScTileElement::surfaceStyle_set, "surfaceStyle");
|
|
dukglue_register_property(ctx, &ScTileElement::edgeStyle_get, &ScTileElement::edgeStyle_set, "edgeStyle");
|
|
dukglue_register_property(ctx, &ScTileElement::grassLength_get, &ScTileElement::grassLength_set, "grassLength");
|
|
dukglue_register_property(ctx, &ScTileElement::hasOwnership_get, nullptr, "hasOwnership");
|
|
dukglue_register_property(ctx, &ScTileElement::hasConstructionRights_get, nullptr, "hasConstructionRights");
|
|
dukglue_register_property(ctx, &ScTileElement::ownership_get, &ScTileElement::ownership_set, "ownership");
|
|
dukglue_register_property(ctx, &ScTileElement::parkFences_get, &ScTileElement::parkFences_set, "parkFences");
|
|
|
|
// Footpath only
|
|
dukglue_register_property(
|
|
ctx, &ScTileElement::edgesAndCorners_get, &ScTileElement::edgesAndCorners_set, "edgesAndCorners");
|
|
dukglue_register_property(ctx, &ScTileElement::edges_get, &ScTileElement::edges_set, "edges");
|
|
dukglue_register_property(ctx, &ScTileElement::corners_get, &ScTileElement::corners_set, "corners");
|
|
dukglue_register_property(
|
|
ctx, &ScTileElement::slopeDirection_get, &ScTileElement::slopeDirection_set, "slopeDirection");
|
|
dukglue_register_property(ctx, &ScTileElement::isQueue_get, &ScTileElement::isQueue_set, "isQueue");
|
|
dukglue_register_property(
|
|
ctx, &ScTileElement::queueBannerDirection_get, &ScTileElement::queueBannerDirection_set, "queueBannerDirection");
|
|
|
|
dukglue_register_property(
|
|
ctx, &ScTileElement::isBlockedByVehicle_get, &ScTileElement::isBlockedByVehicle_set, "isBlockedByVehicle");
|
|
dukglue_register_property(ctx, &ScTileElement::isWide_get, &ScTileElement::isWide_set, "isWide");
|
|
|
|
dukglue_register_property(ctx, &ScTileElement::surfaceObject_get, &ScTileElement::surfaceObject_set, "surfaceObject");
|
|
dukglue_register_property(
|
|
ctx, &ScTileElement::railingsObject_get, &ScTileElement::railingsObject_set, "railingsObject");
|
|
|
|
dukglue_register_property(ctx, &ScTileElement::addition_get, &ScTileElement::addition_set, "addition");
|
|
dukglue_register_property(
|
|
ctx, &ScTileElement::additionStatus_get, &ScTileElement::additionStatus_set, "additionStatus");
|
|
dukglue_register_property(
|
|
ctx, &ScTileElement::isAdditionBroken_get, &ScTileElement::isAdditionBroken_set, "isAdditionBroken");
|
|
dukglue_register_property(
|
|
ctx, &ScTileElement::isAdditionGhost_get, &ScTileElement::isAdditionGhost_set, "isAdditionGhost");
|
|
|
|
// Track only
|
|
dukglue_register_property(ctx, &ScTileElement::trackType_get, &ScTileElement::trackType_set, "trackType");
|
|
dukglue_register_property(ctx, &ScTileElement::rideType_get, &ScTileElement::rideType_set, "rideType");
|
|
dukglue_register_property(ctx, &ScTileElement::mazeEntry_get, &ScTileElement::mazeEntry_set, "mazeEntry");
|
|
dukglue_register_property(ctx, &ScTileElement::colourScheme_get, &ScTileElement::colourScheme_set, "colourScheme");
|
|
dukglue_register_property(ctx, &ScTileElement::seatRotation_get, &ScTileElement::seatRotation_set, "seatRotation");
|
|
dukglue_register_property(
|
|
ctx, &ScTileElement::brakeBoosterSpeed_get, &ScTileElement::brakeBoosterSpeed_set, "brakeBoosterSpeed");
|
|
dukglue_register_property(ctx, &ScTileElement::hasChainLift_get, &ScTileElement::hasChainLift_set, "hasChainLift");
|
|
dukglue_register_property(ctx, &ScTileElement::isInverted_get, &ScTileElement::isInverted_set, "isInverted");
|
|
dukglue_register_property(ctx, &ScTileElement::hasCableLift_get, &ScTileElement::hasCableLift_set, "hasCableLift");
|
|
dukglue_register_property(ctx, &ScTileElement::isHighlighted_get, &ScTileElement::isHighlighted_set, "isHighlighted");
|
|
|
|
// Small Scenery only
|
|
dukglue_register_property(ctx, &ScTileElement::age_get, &ScTileElement::age_set, "age");
|
|
dukglue_register_property(ctx, &ScTileElement::quadrant_get, &ScTileElement::quadrant_set, "quadrant");
|
|
|
|
// Entrance only
|
|
dukglue_register_property(
|
|
ctx, &ScTileElement::footpathObject_get, &ScTileElement::footpathObject_set, "footpathObject");
|
|
dukglue_register_property(
|
|
ctx, &ScTileElement::footpathSurfaceObject_get, &ScTileElement::footpathSurfaceObject_set, "footpathSurfaceObject");
|
|
|
|
// Banner only
|
|
dukglue_register_property(ctx, &ScTileElement::isNoEntry_get, &ScTileElement::isNoEntry_set, "isNoEntry");
|
|
}
|
|
|
|
} // namespace OpenRCT2::Scripting
|
|
|
|
#endif
|