diff --git a/distribution/openrct2.d.ts b/distribution/openrct2.d.ts index b7415c2f80..c2d95d2cfc 100644 --- a/distribution/openrct2.d.ts +++ b/distribution/openrct2.d.ts @@ -225,6 +225,10 @@ declare global { getObject(type: "music", index: number): LoadedObject; getObject(type: "ride", index: number): RideObject; getObject(type: "small_scenery", index: number): SmallSceneryObject; + getObject(type: "large_scenery", index: number): LargeSceneryObject; + getObject(type: "wall", index: number): WallSceneryObject; + getObject(type: "footpath_addition", index: number): FootpathAdditionSceneryObject; + getObject(type: "banner", index: number): BannerSceneryObject; getAllObjects(type: ObjectType): LoadedImageObject[]; getAllObjects(type: "music"): LoadedObject[]; @@ -1752,10 +1756,46 @@ declare global { readonly numVerticalFramesOverride: number; } + interface SceneryObject extends LoadedImageObject { + /** + * A list of scenery groups this object belongs to. This may not contain any + * scenery groups that contain this object by default. This is typically + * used for custom objects to be part of existing scenery groups. + */ + readonly sceneryGroups: ObjectReference[]; + } + + /** + * Represents a reference to an object which may or may not be loaded. + */ + interface ObjectReference { + /** + * The JSON identifier of the object. + * Undefined if object only has a legacy identifier. + */ + identifier?: string; + + /** + * The DAT identifier of the object. + * Undefined if object only has a JSON identifier. + */ + legacyIdentifier?: string; + + /** + * The type of object + */ + type?: ObjectType; + + /** + * The object index + */ + object: number | null; + } + /** * Represents the object definition of a small scenery item such a tree. */ - interface SmallSceneryObject extends LoadedImageObject { + interface SmallSceneryObject extends SceneryObject { /** * Raw bit flags that describe characteristics of the scenery item. */ @@ -1777,6 +1817,22 @@ declare global { readonly removalPrice: number; } + interface LargeSceneryObject extends SceneryObject { + + } + + interface WallSceneryObject extends SceneryObject { + + } + + interface FootpathAdditionSceneryObject extends SceneryObject { + + } + + interface BannerSceneryObject extends SceneryObject { + + } + /** * Represents the object definition of a scenery group. */ @@ -1784,31 +1840,7 @@ declare global { /** * The scenery items that belong to this scenery group. */ - readonly items: SceneryGroupObjectItem[]; - } - - interface SceneryGroupObjectItem { - /** - * The JSON identifier of the object. - * Undefined if object only has a legacy identifier. - */ - identifier?: string; - - /** - * The DAT identifier of the object. - * Undefined if object only has a JSON identifier. - */ - legacyIdentifier?: string; - - /** - * The type of object - */ - type: ObjectType; - - /** - * The object index - */ - object: number | null; + readonly items: ObjectReference[]; } /** diff --git a/src/openrct2/scripting/ScriptEngine.cpp b/src/openrct2/scripting/ScriptEngine.cpp index 4893325724..f23a859ecf 100644 --- a/src/openrct2/scripting/ScriptEngine.cpp +++ b/src/openrct2/scripting/ScriptEngine.cpp @@ -404,7 +404,12 @@ void ScriptEngine::Initialise() ScMap::Register(ctx); ScNetwork::Register(ctx); ScObject::Register(ctx); + ScSceneryObject::Register(ctx); ScSmallSceneryObject::Register(ctx); + ScLargeSceneryObject::Register(ctx); + ScWallSceneryObject::Register(ctx); + ScFootpathAdditionSceneryObject::Register(ctx); + ScBannerSceneryObject::Register(ctx); ScSceneryGroupObject::Register(ctx); ScPark::Register(ctx); ScParkMessage::Register(ctx); diff --git a/src/openrct2/scripting/bindings/game/ScContext.hpp b/src/openrct2/scripting/bindings/game/ScContext.hpp index ffd2dc72c3..af02bf58e1 100644 --- a/src/openrct2/scripting/bindings/game/ScContext.hpp +++ b/src/openrct2/scripting/bindings/game/ScContext.hpp @@ -168,6 +168,14 @@ namespace OpenRCT2::Scripting return GetObjectAsDukValue(ctx, std::make_shared(type, index)); case ObjectType::SmallScenery: return GetObjectAsDukValue(ctx, std::make_shared(type, index)); + case ObjectType::LargeScenery: + return GetObjectAsDukValue(ctx, std::make_shared(type, index)); + case ObjectType::Walls: + return GetObjectAsDukValue(ctx, std::make_shared(type, index)); + case ObjectType::PathBits: + return GetObjectAsDukValue(ctx, std::make_shared(type, index)); + case ObjectType::Banners: + return GetObjectAsDukValue(ctx, std::make_shared(type, index)); case ObjectType::SceneryGroup: return GetObjectAsDukValue(ctx, std::make_shared(type, index)); default: diff --git a/src/openrct2/scripting/bindings/object/ScObject.hpp b/src/openrct2/scripting/bindings/object/ScObject.hpp index a8978817da..5dce6c83f9 100644 --- a/src/openrct2/scripting/bindings/object/ScObject.hpp +++ b/src/openrct2/scripting/bindings/object/ScObject.hpp @@ -792,17 +792,114 @@ namespace OpenRCT2::Scripting } }; - class ScSmallSceneryObject : public ScObject + class ScSceneryObject : public ScObject { public: - ScSmallSceneryObject(ObjectType type, int32_t index) + ScSceneryObject(ObjectType type, int32_t index) : ScObject(type, index) { } static void Register(duk_context* ctx) { - dukglue_set_base_class(ctx); + dukglue_set_base_class(ctx); + dukglue_register_property(ctx, &ScSceneryObject::sceneryGroups_get, nullptr, "sceneryGroups"); + } + + private: + DukValue sceneryGroups_get() const + { + auto* gameContext = GetContext(); + auto* ctx = gameContext->GetScriptEngine().GetContext(); + + duk_push_array(ctx); + + auto obj = GetObject(); + if (obj != nullptr) + { + auto& scgDescriptor = obj->GetPrimarySceneryGroup(); + if (scgDescriptor.HasValue()) + { + auto dukScg = CreateObjectMetaReference(scgDescriptor); + dukScg.push(); + duk_put_prop_index(ctx, -2, 0); + } + } + + return DukValue::take_from_stack(ctx, -1); + } + + SceneryObject* GetObject() const + { + return static_cast(ScObject::GetObject()); + } + + public: + static DukValue CreateObjectMetaReference(const ObjectEntryDescriptor& descriptor) + { + auto* gameContext = GetContext(); + auto* ctx = gameContext->GetScriptEngine().GetContext(); + auto& objManager = gameContext->GetObjectManager(); + + auto objectIndex = objManager.GetLoadedObjectEntryIndex(descriptor); + auto object = objManager.GetLoadedObject(descriptor); + + DukObject dukObj(ctx); + if (descriptor.Generation == ObjectGeneration::JSON) + { + dukObj.Set("identifier", descriptor.Identifier); + if (object != nullptr) + { + auto legacyIdentifier = object->GetLegacyIdentifier(); + if (!legacyIdentifier.empty()) + { + dukObj.Set("legacyIdentifier", legacyIdentifier); + } + } + } + else + { + dukObj.Set("legacyIdentifier", descriptor.Entry.GetName()); + if (object != nullptr) + { + auto identifier = object->GetIdentifier(); + if (!identifier.empty()) + { + dukObj.Set("identifier", identifier); + } + } + } + if (object != nullptr) + { + dukObj.Set("type", ObjectTypeToString(EnumValue(object->GetObjectType()))); + } + else + { + dukObj.Set("type", ObjectTypeToString(EnumValue(descriptor.Type))); + } + if (objectIndex == OBJECT_ENTRY_INDEX_NULL) + { + dukObj.Set("object", nullptr); + } + else + { + dukObj.Set("object", objectIndex); + } + return dukObj.Take(); + } + }; + + class ScSmallSceneryObject : public ScSceneryObject + { + public: + ScSmallSceneryObject(ObjectType type, int32_t index) + : ScSceneryObject(type, index) + { + } + + static void Register(duk_context* ctx) + { + dukglue_set_base_class(ctx); dukglue_register_property(ctx, &ScSmallSceneryObject::flags_get, nullptr, "flags"); dukglue_register_property(ctx, &ScSmallSceneryObject::height_get, nullptr, "height"); dukglue_register_property(ctx, &ScSmallSceneryObject::price_get, nullptr, "price"); @@ -820,16 +917,6 @@ namespace OpenRCT2::Scripting return 0; } - uint8_t height_get() const - { - auto sceneryEntry = GetLegacyData(); - if (sceneryEntry != nullptr) - { - return sceneryEntry->height; - } - return 0; - } - uint8_t price_get() const { auto sceneryEntry = GetLegacyData(); @@ -840,6 +927,16 @@ namespace OpenRCT2::Scripting return 0; } + uint8_t height_get() const + { + auto sceneryEntry = GetLegacyData(); + if (sceneryEntry != nullptr) + { + return sceneryEntry->height; + } + return 0; + } + uint8_t removalPrice_get() const { auto sceneryEntry = GetLegacyData(); @@ -867,6 +964,62 @@ namespace OpenRCT2::Scripting } }; + class ScLargeSceneryObject : public ScSceneryObject + { + public: + ScLargeSceneryObject(ObjectType type, int32_t index) + : ScSceneryObject(type, index) + { + } + + static void Register(duk_context* ctx) + { + dukglue_set_base_class(ctx); + } + }; + + class ScWallSceneryObject : public ScSceneryObject + { + public: + ScWallSceneryObject(ObjectType type, int32_t index) + : ScSceneryObject(type, index) + { + } + + static void Register(duk_context* ctx) + { + dukglue_set_base_class(ctx); + } + }; + + class ScFootpathAdditionSceneryObject : public ScSceneryObject + { + public: + ScFootpathAdditionSceneryObject(ObjectType type, int32_t index) + : ScSceneryObject(type, index) + { + } + + static void Register(duk_context* ctx) + { + dukglue_set_base_class(ctx); + } + }; + + class ScBannerSceneryObject : public ScSceneryObject + { + public: + ScBannerSceneryObject(ObjectType type, int32_t index) + : ScSceneryObject(type, index) + { + } + + static void Register(duk_context* ctx) + { + dukglue_set_base_class(ctx); + } + }; + class ScSceneryGroupObject : public ScObject { public: @@ -884,66 +1037,19 @@ namespace OpenRCT2::Scripting private: DukValue items_get() const { - auto* gameContext = GetContext(); - auto* ctx = gameContext->GetScriptEngine().GetContext(); + auto* ctx = GetContext()->GetScriptEngine().GetContext(); duk_push_array(ctx); auto obj = GetObject(); if (obj != nullptr) { - auto& objManager = gameContext->GetObjectManager(); - duk_uarridx_t index = 0; auto& items = obj->GetItems(); for (const auto& item : items) { - auto objectIndex = objManager.GetLoadedObjectEntryIndex(item); - auto object = objManager.GetLoadedObject(item); - - DukObject dukObj(ctx); - if (item.Generation == ObjectGeneration::JSON) - { - dukObj.Set("identifier", item.Identifier); - if (object != nullptr) - { - auto legacyIdentifier = object->GetLegacyIdentifier(); - if (!legacyIdentifier.empty()) - { - dukObj.Set("legacyIdentifier", legacyIdentifier); - } - } - } - else - { - dukObj.Set("legacyIdentifier", item.Entry.GetName()); - if (object != nullptr) - { - auto identifier = object->GetIdentifier(); - if (!identifier.empty()) - { - dukObj.Set("identifier", identifier); - } - } - } - if (object != nullptr) - { - dukObj.Set("type", ObjectTypeToString(EnumValue(object->GetObjectType()))); - } - else - { - dukObj.Set("type", ObjectTypeToString(EnumValue(item.Type))); - } - if (objectIndex == OBJECT_ENTRY_INDEX_NULL) - { - dukObj.Set("object", nullptr); - } - else - { - dukObj.Set("object", objectIndex); - } - - dukObj.Take().push(); + auto dukItem = ScSceneryObject::CreateObjectMetaReference(item); + dukItem.push(); duk_put_prop_index(ctx, -2, index); index++; }