diff --git a/distribution/openrct2.d.ts b/distribution/openrct2.d.ts index b7b37839ed..3a8f60f3d3 100644 --- a/distribution/openrct2.d.ts +++ b/distribution/openrct2.d.ts @@ -151,7 +151,7 @@ declare global { } type TileElementType = - "surface" | "footpath" | "track" | "small_scenery" | "entrance" | "large_scenery" | "banner"; + "surface" | "footpath" | "track" | "small_scenery" | "wall" | "entrance" | "large_scenery" | "banner"; interface BaseTileElement { type: TileElementType; @@ -276,52 +276,125 @@ declare global { removeElement(index: number): void; } + /** + * Represents the definition of a loaded object (.DAT or .json) such a ride type or scenery item. + */ interface Object { + /** + * The unique name identifier of the object, e.g. "BURGB ". + * This may have trailing spaces if the name is shorter than 8 characters. + */ readonly identifier: string; + /** + * The name in the user's current language. + */ readonly name: string; } + /** + * Represents the object definition of a ride or stall. + */ interface RideObject extends Object { + /** + * The description of the ride / stall in the player's current language. + */ readonly description: string; + /** + * A text description describing the capacity of the ride in the player's current language. + */ readonly capacity: string; } + /** + * Represents a ride or stall within the park. + */ interface Ride { + /** + * The object metadata for this ride. + */ readonly object: RideObject; + /** + * The unique ID / index of the ride. + */ readonly id: number; + /** + * The type of the ride represented as the internal built-in ride type ID. + */ type: number; + /** + * The generated or custom name of the ride. + */ name: string; + /** + * The excitement metric of the ride represented as a 2 decimal point fixed integer. + * For example, `652` equates to `6.52`. + */ excitement: number; + /** + * The intensity metric of the ride represented as a 2 decimal point fixed integer. + * For example, `652` equates to `6.52`. + */ intensity: number; + /** + * The nausea metric of the ride represented as a 2 decimal point fixed integer. + * For example, `652` equates to `6.52`. + */ nausea: number; + /** + * The total number of customers the ride has served since it was built. + */ totalCustomers: number; } type ThingType = "car" | "duck" | "peep"; + /** + * Represents an object "thing" on the map that can typically moves and has a sub-tile coordinate. + */ interface Thing { + /** + * The type of thing, e.g. car, duck, litter, or peep. + */ readonly type: ThingType; + /** + * The x-coordinate of the thing in game units. + */ x: number; + /** + * The y-coordinate of the thing in game units. + */ y: number; + /** + * The z-coordinate of the thing in game units. + */ z: number; - - asPeep(): Thing | null; } + /** + * Represents a guest or staff member. + */ interface Peep extends Thing { + /** + * Colour of the peep's t-shirt. + */ tshirt: number; + /** + * Colour of the peep's trousers. + */ trousers: number; } interface GameMap { - readonly size: { x: number; y: number; }; - readonly rides: number; - readonly things: number; + readonly size: Coord2; + readonly numRides: number; + readonly numThings: number; + readonly rides: Ride[]; getRide(id: number): Ride; getTile(x: number, y: number): Tile; getThing(id: number): Thing; + getAllThings(type: ThingType); } type ParkMessageType = diff --git a/src/openrct2/scripting/ScMap.hpp b/src/openrct2/scripting/ScMap.hpp index 191821d416..94badbfb98 100644 --- a/src/openrct2/scripting/ScMap.hpp +++ b/src/openrct2/scripting/ScMap.hpp @@ -43,16 +43,27 @@ namespace OpenRCT2::Scripting return DukValue::take_from_stack(ctx); } - int32_t rides_get() + int32_t numRides_get() { return static_cast(GetRideManager().size()); } - int32_t things_get() + int32_t numThings_get() { return MAX_SPRITES; } + std::vector> rides_get() + { + std::vector> result; + auto rideManager = GetRideManager(); + for (const auto& ride : rideManager) + { + result.push_back(std::make_shared(ride.id)); + } + return result; + } + std::shared_ptr getRide(int32_t id) { auto rideManager = GetRideManager(); @@ -61,10 +72,10 @@ namespace OpenRCT2::Scripting auto ride = rideManager[static_cast(id)]; if (ride != nullptr) { - return std::make_shared(ride); + return std::make_shared(ride->id); } } - return nullptr; + return {}; } std::shared_ptr getTile(int32_t x, int32_t y) @@ -77,23 +88,75 @@ namespace OpenRCT2::Scripting { if (id >= 0 && id < MAX_SPRITES) { - auto sprite = get_sprite(id); + auto spriteId = static_cast(id); + auto sprite = get_sprite(spriteId); if (sprite != nullptr && sprite->generic.sprite_identifier != SPRITE_IDENTIFIER_NULL) { - return std::make_shared(sprite); + return std::make_shared(spriteId); } } return nullptr; } + std::vector> getAllThings(const std::string& type) + { + SPRITE_LIST targetList{}; + uint8_t targetType{}; + if (type == "balloon") + { + targetList = SPRITE_LIST_MISC; + targetType = SPRITE_MISC_BALLOON; + } + if (type == "car") + { + targetList = SPRITE_LIST_VEHICLE; + } + else if (type == "litter") + { + targetList = SPRITE_LIST_LITTER; + } + else if (type == "duck") + { + targetList = SPRITE_LIST_MISC; + targetType = SPRITE_MISC_DUCK; + } + else if (type == "peep") + { + targetList = SPRITE_LIST_PEEP; + } + else + { + duk_error(_context, DUK_ERR_ERROR, "Invalid thing type."); + } + + std::vector> result; + auto spriteId = gSpriteListHead[targetList]; + while (spriteId != SPRITE_INDEX_NULL) + { + auto sprite = get_sprite(spriteId); + if (sprite != nullptr) + { + // Only the misc list checks the type property + if (targetList != SPRITE_LIST_MISC || sprite->generic.type == targetType) + { + result.push_back(std::make_shared(spriteId)); + } + spriteId = sprite->generic.next; + } + } + return result; + } + static void Register(duk_context* ctx) { dukglue_register_property(ctx, &ScMap::size_get, nullptr, "size"); + dukglue_register_property(ctx, &ScMap::numRides_get, nullptr, "numRides"); + dukglue_register_property(ctx, &ScMap::numThings_get, nullptr, "numThings"); dukglue_register_property(ctx, &ScMap::rides_get, nullptr, "rides"); - dukglue_register_property(ctx, &ScMap::things_get, nullptr, "things"); dukglue_register_method(ctx, &ScMap::getRide, "getRide"); dukglue_register_method(ctx, &ScMap::getTile, "getTile"); dukglue_register_method(ctx, &ScMap::getThing, "getThing"); + dukglue_register_method(ctx, &ScMap::getAllThings, "getAllThings"); } }; } // namespace OpenRCT2::Scripting diff --git a/src/openrct2/scripting/ScPark.hpp b/src/openrct2/scripting/ScPark.hpp index 7b908b8cd4..2226421b73 100644 --- a/src/openrct2/scripting/ScPark.hpp +++ b/src/openrct2/scripting/ScPark.hpp @@ -93,8 +93,9 @@ namespace OpenRCT2::Scripting } news_item_add_to_queue_raw(type, text.c_str(), static_cast(-1)); } - catch (const std::exception&) + catch (const DukException&) { + duk_error(message.context(), DUK_ERR_ERROR, "Invalid message argument."); } } diff --git a/src/openrct2/scripting/ScRide.hpp b/src/openrct2/scripting/ScRide.hpp index 71fc3c8ad1..c5d1d83b0b 100644 --- a/src/openrct2/scripting/ScRide.hpp +++ b/src/openrct2/scripting/ScRide.hpp @@ -22,12 +22,12 @@ namespace OpenRCT2::Scripting class ScRideObject { private: - rct_ride_entry* _entry; + rct_ride_entry* _entry{}; public: ScRideObject(rct_ride_entry* entry) + : _entry(entry) { - _entry = entry; } static void Register(duk_context* ctx) @@ -83,84 +83,121 @@ namespace OpenRCT2::Scripting class ScRide { private: - Ride* _ride; + ride_id_t _rideId = RIDE_ID_NULL; public: - ScRide(Ride* ride) - : _ride(ride) + ScRide(ride_id_t rideId) + : _rideId(rideId) { } + private: int32_t id_get() { - return _ride->id; + return _rideId; } std::shared_ptr object_get() { - auto rideEntry = _ride->GetRideEntry(); - if (rideEntry != nullptr) + auto ride = GetRide(); + if (ride != nullptr) { - return std::make_shared(rideEntry); + auto rideEntry = ride->GetRideEntry(); + if (rideEntry != nullptr) + { + return std::make_shared(rideEntry); + } } return nullptr; } int32_t type_get() { - return _ride->type; + auto ride = GetRide(); + return ride != nullptr ? ride->type : 0; } std::string name_get() { - return _ride->GetName(); + auto ride = GetRide(); + return ride != nullptr ? ride->GetName() : std::string(); } void name_set(std::string value) { ThrowIfGameStateNotMutable(); - _ride->custom_name = value; + auto ride = GetRide(); + if (ride != nullptr) + { + ride->custom_name = value; + } } int32_t excitement_get() { - return _ride->excitement; + auto ride = GetRide(); + return ride != nullptr ? ride->excitement : 0; } void excitement_set(int32_t value) { ThrowIfGameStateNotMutable(); - _ride->excitement = value; + auto ride = GetRide(); + if (ride != nullptr) + { + ride->excitement = value; + } } int32_t intensity_get() { - return _ride->intensity; + auto ride = GetRide(); + return ride != nullptr ? ride->intensity : 0; } void intensity_set(int32_t value) { ThrowIfGameStateNotMutable(); - _ride->intensity = value; + auto ride = GetRide(); + if (ride != nullptr) + { + ride->intensity = value; + } } int32_t nausea_get() { - return _ride->nausea; + auto ride = GetRide(); + return ride != nullptr ? ride->nausea : 0; } void nausea_set(int32_t value) { ThrowIfGameStateNotMutable(); - _ride->nausea = value; + auto ride = GetRide(); + if (ride != nullptr) + { + ride->nausea = value; + } } int32_t totalCustomers_get() { - return _ride->total_customers; + auto ride = GetRide(); + return ride != nullptr ? ride->total_customers : 0; } void totalCustomers_set(int32_t value) { ThrowIfGameStateNotMutable(); - _ride->total_customers = value; + auto ride = GetRide(); + if (ride != nullptr) + { + ride->total_customers = value; + } } + Ride* GetRide() + { + return get_ride(_rideId); + } + + public: static void Register(duk_context* ctx) { dukglue_register_property(ctx, &ScRide::id_get, nullptr, "id"); diff --git a/src/openrct2/scripting/ScThing.hpp b/src/openrct2/scripting/ScThing.hpp index d741a0e811..73990147b9 100644 --- a/src/openrct2/scripting/ScThing.hpp +++ b/src/openrct2/scripting/ScThing.hpp @@ -21,19 +21,38 @@ namespace OpenRCT2::Scripting class ScThing { private: - rct_sprite* _sprite; + uint16_t _id = SPRITE_INDEX_NULL; public: - ScThing(rct_sprite* sprite) - : _sprite(sprite) + ScThing(uint16_t id) + : _id(id) { } + private: std::string type_get() { - if (_sprite->generic.sprite_identifier == SPRITE_IDENTIFIER_PEEP) + auto thing = GetThing(); + if (thing != nullptr) { - return "peep"; + switch (thing->sprite_identifier) + { + case SPRITE_IDENTIFIER_VEHICLE: + return "car"; + case SPRITE_IDENTIFIER_PEEP: + return "peep"; + case SPRITE_IDENTIFIER_MISC: + switch (thing->type) + { + case SPRITE_MISC_BALLOON: + return "balloon"; + case SPRITE_MISC_DUCK: + return "duck"; + } + break; + case SPRITE_IDENTIFIER_LITTER: + return "litter"; + } } return "unknown"; } @@ -41,58 +60,93 @@ namespace OpenRCT2::Scripting // x getter and setter int32_t x_get() { - return _sprite->generic.x; + auto thing = GetThing(); + return thing != nullptr ? thing->x : 0; } void x_set(int32_t value) { ThrowIfGameStateNotMutable(); - sprite_move(value, _sprite->generic.y, _sprite->generic.z, &_sprite->generic); + auto thing = GetThing(); + if (thing != nullptr) + { + sprite_move(value, thing->y, thing->z, thing); + } } // y getter and setter int32_t y_get() { - return _sprite->generic.y; + auto thing = GetThing(); + return thing != nullptr ? thing->y : 0; } void y_set(int32_t value) { ThrowIfGameStateNotMutable(); - sprite_move(_sprite->generic.x, value, _sprite->generic.z, &_sprite->generic); + auto thing = GetThing(); + if (thing != nullptr) + { + sprite_move(thing->x, value, thing->z, thing); + } } // z getter and setter int16_t z_get() { - return _sprite->generic.z; + auto thing = GetThing(); + return thing != nullptr ? thing->z : 0; } void z_set(int16_t value) { ThrowIfGameStateNotMutable(); - sprite_move(_sprite->generic.x, _sprite->generic.y, value, &_sprite->generic); + auto thing = GetThing(); + if (thing != nullptr) + { + sprite_move(thing->x, thing->y, value, thing); + } } uint8_t tshirtColour_get() { - return _sprite->peep.tshirt_colour; + auto peep = GetPeep(); + return peep != nullptr ? peep->tshirt_colour : 0; } void tshirtColour_set(uint8_t value) { ThrowIfGameStateNotMutable(); - _sprite->peep.tshirt_colour = value; + auto peep = GetPeep(); + if (peep != nullptr) + { + peep->tshirt_colour = value; + } } uint8_t trousersColour_get() { - return _sprite->peep.trousers_colour; + auto peep = GetPeep(); + return peep != nullptr ? peep->trousers_colour : 0; } void trousersColour_set(uint8_t value) { ThrowIfGameStateNotMutable(); - _sprite->peep.trousers_colour = value; + auto peep = GetPeep(); + if (peep != nullptr) + { + peep->trousers_colour = value; + } } + SpriteBase* GetThing() + { + return &get_sprite(_id)->generic; + } + + Peep* GetPeep() + { + return get_sprite(_id)->AsPeep(); + } + + public: static void Register(duk_context* ctx) { - dukglue_register_constructor(ctx, "Thing"); dukglue_register_property(ctx, &ScThing::type_get, nullptr, "type"); dukglue_register_property(ctx, &ScThing::x_get, &ScThing::x_set, "x"); dukglue_register_property(ctx, &ScThing::y_get, &ScThing::y_set, "y");