diff --git a/distribution/openrct2.d.ts b/distribution/openrct2.d.ts index a78b2ce1b5..c174afa86e 100644 --- a/distribution/openrct2.d.ts +++ b/distribution/openrct2.d.ts @@ -854,6 +854,139 @@ declare global { remove(): void; } + /** + * Represents a single car on a ride. A train is made up of multiple cars, but + * something like boat hire will be one car per boat. + */ + interface Car extends Entity { + /** + * The ride this car belongs to. + */ + ride: number; + + /** + * The ride object for this car, e.g. the ladybird trains object. + */ + rideObject: number; + + /** + * The vehicle type for the ride object used. This is a local index + * into the ride object list of vehicle types. + */ + vehicleObject: number; + + spriteType: number; + + /** + * How many seats the car has, i.e. the capacity. + */ + numSeats: number; + + /** + * The next car on the same train. If this is the last or only car on the train, + * this will return null. + */ + nextCarOnTrain: number | null; + + /** + * The previous car on the ride. This may be the on the same train or the previous + * train. This will point to the last car if this is the first car on the ride. + */ + previousCarOnRide: number; + + /** + * The next car on the ride. This may be the on the same train or the next + * train. This will point to the first car if this is the last car on the ride. + */ + nextCarOnRide: number; + + /** + * The current station the train is in or departing. + */ + currentStation: number; + + /** + * How heavy the car is. This is the sum of the mass of the empty car and the + * mass of each guest that is riding it. + */ + mass: number; + + /** + * How much the car's velocity changes per tick. + */ + acceleration: number; + + /** + * How fast the car is moving. + */ + velocity: number; + + /** + * The current tilt of the car in the X/Y axis. + */ + bankRotation: number; + + /** + * The colour of the car. + */ + colours: VehicleColour; + + /** + * The acceleration for vehicles with constant power, e.g. + * transport rides and boats. + */ + poweredAcceleration: number; + + /** + * The maximum speed for vehicles with constant power, e.g. + * transport rides and boats. + */ + poweredMaxSpeed: number; + + /** + * Current status of the car or train. + */ + status: VehicleStatus; + + /** + * List of peep IDs ordered by seat. + */ + peeps: (number | null)[]; + } + + type VehicleStatus = + "arriving" | + "crashed" | + "crashing" | + "crooked_house_operating" | + "departing" | + "doing_circus_show" | + "ferris_wheel_rotating" | + "haunted_house_operating" | + "moving_to_end_of_station" | + "operating_1a" | + "rotating" | + "showing_film" | + "simulator_operating" | + "space_rings_operating" | + "starting" | + "stopped_by_block_brake" | + "stopping_1b" | + "stopping" | + "swinging" | + "top_spin_operating" | + "travelling_boat" | + "travelling_cable_lift" | + "travelling_dodgems" | + "travelling" | + "unloading_passengers_1c" | + "unloading_passengers" | + "waiting_for_cable_lift" | + "waiting_for_passengers_17" | + "waiting_for_passengers" | + "waiting_to_depart" | + "waiting_to_start"; + /** * Represents a guest or staff member. */ diff --git a/src/openrct2/scripting/Duktape.hpp b/src/openrct2/scripting/Duktape.hpp index 43b535a698..4460451509 100644 --- a/src/openrct2/scripting/Duktape.hpp +++ b/src/openrct2/scripting/Duktape.hpp @@ -219,7 +219,7 @@ namespace OpenRCT2::Scripting auto it = _s2n.find(k); if (it == _s2n.end()) { - return 0; + return static_cast(0); } return it->second; } diff --git a/src/openrct2/scripting/ScEntity.hpp b/src/openrct2/scripting/ScEntity.hpp index 82fec97adb..60a1b5bb06 100644 --- a/src/openrct2/scripting/ScEntity.hpp +++ b/src/openrct2/scripting/ScEntity.hpp @@ -17,6 +17,7 @@ # include "../peep/Staff.h" # include "../world/Sprite.h" # include "Duktape.hpp" +# include "ScRide.hpp" # include "ScriptEngine.h" # include @@ -176,6 +177,418 @@ namespace OpenRCT2::Scripting } }; + static const DukEnumMap VehicleStatusMap({ + { "moving_to_end_of_station", VEHICLE_STATUS_MOVING_TO_END_OF_STATION }, + { "waiting_for_passengers", VEHICLE_STATUS_WAITING_FOR_PASSENGERS }, + { "waiting_to_depart", VEHICLE_STATUS_WAITING_TO_DEPART }, + { "departing", VEHICLE_STATUS_DEPARTING }, + { "travelling", VEHICLE_STATUS_TRAVELLING }, + { "arriving", VEHICLE_STATUS_ARRIVING }, + { "unloading_passengers", VEHICLE_STATUS_UNLOADING_PASSENGERS }, + { "travelling_boat", VEHICLE_STATUS_TRAVELLING_BOAT }, + { "crashing", VEHICLE_STATUS_CRASHING }, + { "crashed", VEHICLE_STATUS_CRASHED }, + { "travelling_dodgems", VEHICLE_STATUS_TRAVELLING_DODGEMS }, + { "swinging", VEHICLE_STATUS_SWINGING }, + { "rotating", VEHICLE_STATUS_ROTATING }, + { "ferris_wheel_rotating", VEHICLE_STATUS_FERRIS_WHEEL_ROTATING }, + { "simulator_operating", VEHICLE_STATUS_SIMULATOR_OPERATING }, + { "showing_film", VEHICLE_STATUS_SHOWING_FILM }, + { "space_rings_operating", VEHICLE_STATUS_SPACE_RINGS_OPERATING }, + { "top_spin_operating", VEHICLE_STATUS_TOP_SPIN_OPERATING }, + { "haunted_house_operating", VEHICLE_STATUS_HAUNTED_HOUSE_OPERATING }, + { "doing_circus_show", VEHICLE_STATUS_DOING_CIRCUS_SHOW }, + { "crooked_house_operating", VEHICLE_STATUS_CROOKED_HOUSE_OPERATING }, + { "waiting_for_cable_lift", VEHICLE_STATUS_WAITING_FOR_CABLE_LIFT }, + { "travelling_cable_lift", VEHICLE_STATUS_TRAVELLING_CABLE_LIFT }, + { "stopping", VEHICLE_STATUS_STOPPING }, + { "waiting_for_passengers_17", VEHICLE_STATUS_WAITING_FOR_PASSENGERS_17 }, + { "waiting_to_start", VEHICLE_STATUS_WAITING_TO_START }, + { "starting", VEHICLE_STATUS_STARTING }, + { "operating_1a", VEHICLE_STATUS_OPERATING_1A }, + { "stopping_1b", VEHICLE_STATUS_STOPPING_1B }, + { "unloading_passengers_1c", VEHICLE_STATUS_UNLOADING_PASSENGERS_1C }, + { "stopped_by_block_brake", VEHICLE_STATUS_STOPPED_BY_BLOCK_BRAKES }, + }); + + class ScVehicle : public ScEntity + { + public: + ScVehicle(uint16_t id) + : ScEntity(id) + { + } + + static void Register(duk_context* ctx) + { + dukglue_set_base_class(ctx); + dukglue_register_property(ctx, &ScVehicle::ride_get, &ScVehicle::ride_set, "ride"); + dukglue_register_property(ctx, &ScVehicle::rideObject_get, &ScVehicle::rideObject_set, "rideObject"); + dukglue_register_property(ctx, &ScVehicle::vehicleObject_get, &ScVehicle::vehicleObject_set, "vehicleObject"); + dukglue_register_property(ctx, &ScVehicle::spriteType_get, &ScVehicle::spriteType_set, "spriteType"); + dukglue_register_property(ctx, &ScVehicle::numSeats_get, &ScVehicle::numSeats_set, "numSeats"); + dukglue_register_property(ctx, &ScVehicle::nextCarOnTrain_get, &ScVehicle::nextCarOnTrain_set, "nextCarOnTrain"); + dukglue_register_property( + ctx, &ScVehicle::previousCarOnRide_get, &ScVehicle::previousCarOnRide_set, "previousCarOnRide"); + dukglue_register_property(ctx, &ScVehicle::nextCarOnRide_get, &ScVehicle::nextCarOnRide_set, "nextCarOnRide"); + dukglue_register_property(ctx, &ScVehicle::currentStation_get, &ScVehicle::currentStation_set, "currentStation"); + dukglue_register_property(ctx, &ScVehicle::mass_get, &ScVehicle::mass_set, "mass"); + dukglue_register_property(ctx, &ScVehicle::acceleration_get, &ScVehicle::acceleration_set, "acceleration"); + dukglue_register_property(ctx, &ScVehicle::velocity_get, &ScVehicle::velocity_set, "velocity"); + dukglue_register_property(ctx, &ScVehicle::bankRotation_get, &ScVehicle::bankRotation_set, "bankRotation"); + dukglue_register_property(ctx, &ScVehicle::colours_get, &ScVehicle::colours_set, "colours"); + dukglue_register_property(ctx, &ScVehicle::trackLocation_get, &ScVehicle::trackLocation_set, "trackLocation"); + dukglue_register_property( + ctx, &ScVehicle::poweredAcceleration_get, &ScVehicle::poweredAcceleration_set, "poweredAcceleration"); + dukglue_register_property(ctx, &ScVehicle::poweredMaxSpeed_get, &ScVehicle::poweredMaxSpeed_set, "poweredMaxSpeed"); + dukglue_register_property(ctx, &ScVehicle::status_get, &ScVehicle::status_set, "status"); + dukglue_register_property(ctx, &ScVehicle::peeps_get, nullptr, "peeps"); + } + + private: + Vehicle* GetVehicle() const + { + return get_sprite(_id)->generic.As(); + } + + uint8_t rideObject_get() const + { + auto vehicle = GetVehicle(); + return vehicle != nullptr ? vehicle->ride_subtype : 0; + } + void rideObject_set(uint8_t value) + { + ThrowIfGameStateNotMutable(); + auto vehicle = GetVehicle(); + if (vehicle != nullptr) + { + vehicle->ride_subtype = value; + } + } + + uint8_t vehicleObject_get() const + { + auto vehicle = GetVehicle(); + return vehicle != nullptr ? vehicle->vehicle_type : 0; + } + void vehicleObject_set(uint8_t value) + { + ThrowIfGameStateNotMutable(); + auto vehicle = GetVehicle(); + if (vehicle != nullptr) + { + vehicle->vehicle_type = value; + } + } + + uint8_t spriteType_get() const + { + auto vehicle = GetVehicle(); + return vehicle != nullptr ? vehicle->vehicle_sprite_type : 0; + } + void spriteType_set(uint8_t value) + { + ThrowIfGameStateNotMutable(); + auto vehicle = GetVehicle(); + if (vehicle != nullptr) + { + vehicle->vehicle_sprite_type = value; + } + } + + ride_id_t ride_get() const + { + auto vehicle = GetVehicle(); + return vehicle != nullptr ? vehicle->ride : 0; + } + void ride_set(ride_id_t value) + { + ThrowIfGameStateNotMutable(); + auto vehicle = GetVehicle(); + if (vehicle != nullptr) + { + vehicle->ride = value; + } + } + + uint8_t numSeats_get() const + { + auto vehicle = GetVehicle(); + return vehicle != nullptr ? vehicle->num_seats & VEHICLE_SEAT_NUM_MASK : 0; + } + void numSeats_set(uint8_t value) + { + ThrowIfGameStateNotMutable(); + auto vehicle = GetVehicle(); + if (vehicle != nullptr) + { + vehicle->num_seats &= ~VEHICLE_SEAT_NUM_MASK; + vehicle->num_seats |= value & VEHICLE_SEAT_NUM_MASK; + } + } + + DukValue nextCarOnTrain_get() const + { + auto ctx = GetContext()->GetScriptEngine().GetContext(); + auto vehicle = GetVehicle(); + if (vehicle != nullptr) + { + if (vehicle->next_vehicle_on_train != SPRITE_INDEX_NULL) + { + return ToDuk(ctx, vehicle->next_vehicle_on_train); + } + } + return ToDuk(ctx, nullptr); + } + void nextCarOnTrain_set(DukValue value) + { + ThrowIfGameStateNotMutable(); + auto vehicle = GetVehicle(); + if (vehicle != nullptr) + { + if (value.type() == DukValue::Type::NUMBER) + { + vehicle->next_vehicle_on_train = static_cast(value.as_int()); + } + else + { + vehicle->next_vehicle_on_train = SPRITE_INDEX_NULL; + } + } + } + + uint16_t previousCarOnRide_get() const + { + auto vehicle = GetVehicle(); + return vehicle != nullptr ? vehicle->prev_vehicle_on_ride : 0; + } + void previousCarOnRide_set(uint16_t value) + { + ThrowIfGameStateNotMutable(); + auto vehicle = GetVehicle(); + if (vehicle != nullptr) + { + vehicle->prev_vehicle_on_ride = value; + } + } + + uint16_t nextCarOnRide_get() const + { + auto vehicle = GetVehicle(); + return vehicle != nullptr ? vehicle->next_vehicle_on_ride : 0; + } + void nextCarOnRide_set(uint16_t value) + { + ThrowIfGameStateNotMutable(); + auto vehicle = GetVehicle(); + if (vehicle != nullptr) + { + vehicle->next_vehicle_on_ride = value; + } + } + + StationIndex currentStation_get() const + { + auto vehicle = GetVehicle(); + return vehicle != nullptr ? vehicle->current_station : 0; + } + void currentStation_set(StationIndex value) + { + ThrowIfGameStateNotMutable(); + auto vehicle = GetVehicle(); + if (vehicle != nullptr) + { + vehicle->current_station = value; + } + } + + uint16_t mass_get() const + { + auto vehicle = GetVehicle(); + return vehicle != nullptr ? vehicle->mass : 0; + } + void mass_set(uint16_t value) + { + ThrowIfGameStateNotMutable(); + auto vehicle = GetVehicle(); + if (vehicle != nullptr) + { + vehicle->mass = value; + } + } + + int32_t acceleration_get() const + { + auto vehicle = GetVehicle(); + return vehicle != nullptr ? vehicle->acceleration : 0; + } + void acceleration_set(int32_t value) + { + ThrowIfGameStateNotMutable(); + auto vehicle = GetVehicle(); + if (vehicle != nullptr) + { + vehicle->acceleration = value; + } + } + + int32_t velocity_get() const + { + auto vehicle = GetVehicle(); + return vehicle != nullptr ? vehicle->velocity : 0; + } + void velocity_set(int32_t value) + { + ThrowIfGameStateNotMutable(); + auto vehicle = GetVehicle(); + if (vehicle != nullptr) + { + vehicle->velocity = value; + } + } + + uint8_t bankRotation_get() const + { + auto vehicle = GetVehicle(); + return vehicle != nullptr ? vehicle->bank_rotation : 0; + } + void bankRotation_set(uint8_t value) + { + ThrowIfGameStateNotMutable(); + auto vehicle = GetVehicle(); + if (vehicle != nullptr) + { + vehicle->bank_rotation = value; + } + } + + DukValue colours_get() const + { + auto ctx = GetContext()->GetScriptEngine().GetContext(); + auto vehicle = GetVehicle(); + if (vehicle != nullptr) + { + VehicleColour colours; + colours.Body = vehicle->colours.body_colour; + colours.Trim = vehicle->colours.trim_colour; + colours.Ternary = vehicle->colours_extended; + return ToDuk(ctx, colours); + } + return ToDuk(ctx, nullptr); + } + void colours_set(const DukValue& value) + { + ThrowIfGameStateNotMutable(); + auto vehicle = GetVehicle(); + if (vehicle != nullptr) + { + auto colours = FromDuk(value); + vehicle->colours.body_colour = colours.Body; + vehicle->colours.trim_colour = colours.Trim; + vehicle->colours_extended = colours.Ternary; + } + } + + DukValue trackLocation_get() const + { + auto ctx = GetContext()->GetScriptEngine().GetContext(); + auto vehicle = GetVehicle(); + if (vehicle != nullptr) + { + auto coords = CoordsXYZD(vehicle->TrackLocation, vehicle->track_direction & 3); + return ToDuk(ctx, coords); + } + return ToDuk(ctx, nullptr); + } + void trackLocation_set(const DukValue& value) + { + ThrowIfGameStateNotMutable(); + auto vehicle = GetVehicle(); + if (vehicle != nullptr) + { + auto coords = FromDuk(value); + vehicle->TrackLocation = CoordsXYZ(coords.x, coords.y, coords.z); + vehicle->track_direction &= ~3; + vehicle->track_direction |= coords.direction & 3; + } + } + + uint8_t poweredAcceleration_get() const + { + auto vehicle = GetVehicle(); + return vehicle != nullptr ? vehicle->powered_acceleration : 0; + } + void poweredAcceleration_set(uint8_t value) + { + ThrowIfGameStateNotMutable(); + auto vehicle = GetVehicle(); + if (vehicle != nullptr) + { + vehicle->powered_acceleration = value; + } + } + + uint8_t poweredMaxSpeed_get() const + { + auto vehicle = GetVehicle(); + return vehicle != nullptr ? vehicle->speed : 0; + } + void poweredMaxSpeed_set(uint8_t value) + { + ThrowIfGameStateNotMutable(); + auto vehicle = GetVehicle(); + if (vehicle != nullptr) + { + vehicle->speed = value; + } + } + + std::string status_get() const + { + auto vehicle = GetVehicle(); + if (vehicle != nullptr) + { + return std::string(VehicleStatusMap[vehicle->status]); + } + return {}; + } + void status_set(const std::string& value) + { + ThrowIfGameStateNotMutable(); + auto vehicle = GetVehicle(); + if (vehicle != nullptr) + { + vehicle->status = VehicleStatusMap[value]; + } + } + + std::vector peeps_get() const + { + auto ctx = GetContext()->GetScriptEngine().GetContext(); + std::vector result; + auto vehicle = GetVehicle(); + if (vehicle != nullptr) + { + size_t len = 0; + for (size_t i = 0; i < std::size(vehicle->peep); i++) + { + auto peep = vehicle->peep[i]; + if (peep == SPRITE_INDEX_NULL) + { + result.push_back(ToDuk(ctx, nullptr)); + } + else + { + result.push_back(ToDuk(ctx, peep)); + len = i + 1; + } + } + result.resize(len); + } + return result; + } + }; + static const DukEnumMap PeepFlagMap({ { "leavingPark", PEEP_FLAGS_LEAVING_PARK }, { "slowWalk", PEEP_FLAGS_SLOW_WALK }, diff --git a/src/openrct2/scripting/ScMap.hpp b/src/openrct2/scripting/ScMap.hpp index 3f6088e906..e37ac06783 100644 --- a/src/openrct2/scripting/ScMap.hpp +++ b/src/openrct2/scripting/ScMap.hpp @@ -163,7 +163,7 @@ namespace OpenRCT2::Scripting } else { - result.push_back(GetObjectAsDukValue(_context, std::make_shared(carId))); + result.push_back(GetObjectAsDukValue(_context, std::make_shared(carId))); carId = car->vehicle.next_vehicle_on_train; } } @@ -197,6 +197,8 @@ namespace OpenRCT2::Scripting auto spriteId = sprite->generic.sprite_index; switch (sprite->generic.sprite_identifier) { + case SPRITE_IDENTIFIER_VEHICLE: + return GetObjectAsDukValue(_context, std::make_shared(spriteId)); case SPRITE_IDENTIFIER_PEEP: if (sprite->peep.type == PEEP_TYPE_STAFF) return GetObjectAsDukValue(_context, std::make_shared(spriteId)); diff --git a/src/openrct2/scripting/ScriptEngine.cpp b/src/openrct2/scripting/ScriptEngine.cpp index 875ff98136..7167a5bdf2 100644 --- a/src/openrct2/scripting/ScriptEngine.cpp +++ b/src/openrct2/scripting/ScriptEngine.cpp @@ -390,6 +390,7 @@ void ScriptEngine::Initialise() ScTile::Register(ctx); ScTileElement::Register(ctx); ScEntity::Register(ctx); + ScVehicle::Register(ctx); ScPeep::Register(ctx); ScGuest::Register(ctx); ScStaff::Register(ctx);