1 /*****************************************************************************
2  * Copyright (c) 2014-2021 OpenRCT2 developers
3  *
4  * For a complete list of all authors, please refer to contributors.md
5  * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
6  *
7  * OpenRCT2 is licensed under the GNU General Public License version 3.
8  *****************************************************************************/
9 
10 #include "ScVehicle.hpp"
11 
12 #include "../ride/ScRide.hpp"
13 
14 #ifdef ENABLE_SCRIPTING
15 
16 namespace OpenRCT2::Scripting
17 {
18     static const DukEnumMap<Vehicle::Status> VehicleStatusMap({
19         { "moving_to_end_of_station", Vehicle::Status::MovingToEndOfStation },
20         { "waiting_for_passengers", Vehicle::Status::WaitingForPassengers },
21         { "waiting_to_depart", Vehicle::Status::WaitingToDepart },
22         { "departing", Vehicle::Status::Departing },
23         { "travelling", Vehicle::Status::Travelling },
24         { "arriving", Vehicle::Status::Arriving },
25         { "unloading_passengers", Vehicle::Status::UnloadingPassengers },
26         { "travelling_boat", Vehicle::Status::TravellingBoat },
27         { "crashing", Vehicle::Status::Crashing },
28         { "crashed", Vehicle::Status::Crashed },
29         { "travelling_dodgems", Vehicle::Status::TravellingDodgems },
30         { "swinging", Vehicle::Status::Swinging },
31         { "rotating", Vehicle::Status::Rotating },
32         { "ferris_wheel_rotating", Vehicle::Status::FerrisWheelRotating },
33         { "simulator_operating", Vehicle::Status::SimulatorOperating },
34         { "showing_film", Vehicle::Status::ShowingFilm },
35         { "space_rings_operating", Vehicle::Status::SpaceRingsOperating },
36         { "top_spin_operating", Vehicle::Status::TopSpinOperating },
37         { "haunted_house_operating", Vehicle::Status::HauntedHouseOperating },
38         { "doing_circus_show", Vehicle::Status::DoingCircusShow },
39         { "crooked_house_operating", Vehicle::Status::CrookedHouseOperating },
40         { "waiting_for_cable_lift", Vehicle::Status::WaitingForCableLift },
41         { "travelling_cable_lift", Vehicle::Status::TravellingCableLift },
42         { "stopping", Vehicle::Status::Stopping },
43         { "waiting_for_passengers_17", Vehicle::Status::WaitingForPassengers17 },
44         { "waiting_to_start", Vehicle::Status::WaitingToStart },
45         { "starting", Vehicle::Status::Starting },
46         { "operating_1a", Vehicle::Status::Operating1A },
47         { "stopping_1b", Vehicle::Status::Stopping1B },
48         { "unloading_passengers_1c", Vehicle::Status::UnloadingPassengers1C },
49         { "stopped_by_block_brake", Vehicle::Status::StoppedByBlockBrakes },
50     });
51 
ScVehicle(uint16_t id)52     ScVehicle::ScVehicle(uint16_t id)
53         : ScEntity(id)
54     {
55     }
56 
Register(duk_context * ctx)57     void ScVehicle::Register(duk_context* ctx)
58     {
59         dukglue_set_base_class<ScEntity, ScVehicle>(ctx);
60         dukglue_register_property(ctx, &ScVehicle::ride_get, &ScVehicle::ride_set, "ride");
61         dukglue_register_property(ctx, &ScVehicle::rideObject_get, &ScVehicle::rideObject_set, "rideObject");
62         dukglue_register_property(ctx, &ScVehicle::vehicleObject_get, &ScVehicle::vehicleObject_set, "vehicleObject");
63         dukglue_register_property(ctx, &ScVehicle::spriteType_get, &ScVehicle::spriteType_set, "spriteType");
64         dukglue_register_property(ctx, &ScVehicle::numSeats_get, &ScVehicle::numSeats_set, "numSeats");
65         dukglue_register_property(ctx, &ScVehicle::nextCarOnTrain_get, &ScVehicle::nextCarOnTrain_set, "nextCarOnTrain");
66         dukglue_register_property(
67             ctx, &ScVehicle::previousCarOnRide_get, &ScVehicle::previousCarOnRide_set, "previousCarOnRide");
68         dukglue_register_property(ctx, &ScVehicle::nextCarOnRide_get, &ScVehicle::nextCarOnRide_set, "nextCarOnRide");
69         dukglue_register_property(ctx, &ScVehicle::currentStation_get, &ScVehicle::currentStation_set, "currentStation");
70         dukglue_register_property(ctx, &ScVehicle::mass_get, &ScVehicle::mass_set, "mass");
71         dukglue_register_property(ctx, &ScVehicle::acceleration_get, &ScVehicle::acceleration_set, "acceleration");
72         dukglue_register_property(ctx, &ScVehicle::velocity_get, &ScVehicle::velocity_set, "velocity");
73         dukglue_register_property(ctx, &ScVehicle::bankRotation_get, &ScVehicle::bankRotation_set, "bankRotation");
74         dukglue_register_property(ctx, &ScVehicle::colours_get, &ScVehicle::colours_set, "colours");
75         dukglue_register_property(ctx, &ScVehicle::trackLocation_get, &ScVehicle::trackLocation_set, "trackLocation");
76         dukglue_register_property(ctx, &ScVehicle::trackProgress_get, nullptr, "trackProgress");
77         dukglue_register_property(ctx, &ScVehicle::remainingDistance_get, nullptr, "remainingDistance");
78         dukglue_register_property(
79             ctx, &ScVehicle::poweredAcceleration_get, &ScVehicle::poweredAcceleration_set, "poweredAcceleration");
80         dukglue_register_property(ctx, &ScVehicle::poweredMaxSpeed_get, &ScVehicle::poweredMaxSpeed_set, "poweredMaxSpeed");
81         dukglue_register_property(ctx, &ScVehicle::status_get, &ScVehicle::status_set, "status");
82         dukglue_register_property(ctx, &ScVehicle::guests_get, nullptr, "peeps");
83         dukglue_register_property(ctx, &ScVehicle::guests_get, nullptr, "guests");
84         dukglue_register_property(ctx, &ScVehicle::gForces_get, nullptr, "gForces");
85         dukglue_register_method(ctx, &ScVehicle::travelBy, "travelBy");
86     }
87 
GetVehicle() const88     Vehicle* ScVehicle::GetVehicle() const
89     {
90         return ::GetEntity<Vehicle>(_id);
91     }
92 
rideObject_get() const93     uint8_t ScVehicle::rideObject_get() const
94     {
95         auto vehicle = GetVehicle();
96         return vehicle != nullptr ? vehicle->ride_subtype : 0;
97     }
rideObject_set(uint8_t value)98     void ScVehicle::rideObject_set(uint8_t value)
99     {
100         ThrowIfGameStateNotMutable();
101         auto vehicle = GetVehicle();
102         if (vehicle != nullptr)
103         {
104             vehicle->ride_subtype = value;
105         }
106     }
107 
vehicleObject_get() const108     uint8_t ScVehicle::vehicleObject_get() const
109     {
110         auto vehicle = GetVehicle();
111         return vehicle != nullptr ? vehicle->vehicle_type : 0;
112     }
vehicleObject_set(uint8_t value)113     void ScVehicle::vehicleObject_set(uint8_t value)
114     {
115         ThrowIfGameStateNotMutable();
116         auto vehicle = GetVehicle();
117         if (vehicle != nullptr)
118         {
119             vehicle->vehicle_type = value;
120         }
121     }
122 
spriteType_get() const123     uint8_t ScVehicle::spriteType_get() const
124     {
125         auto vehicle = GetVehicle();
126         return vehicle != nullptr ? vehicle->Pitch : 0;
127     }
spriteType_set(uint8_t value)128     void ScVehicle::spriteType_set(uint8_t value)
129     {
130         ThrowIfGameStateNotMutable();
131         auto vehicle = GetVehicle();
132         if (vehicle != nullptr)
133         {
134             vehicle->Pitch = value;
135         }
136     }
137 
ride_get() const138     int32_t ScVehicle::ride_get() const
139     {
140         auto vehicle = GetVehicle();
141         return EnumValue(vehicle != nullptr ? vehicle->ride : RIDE_ID_NULL);
142     }
ride_set(int32_t value)143     void ScVehicle::ride_set(int32_t value)
144     {
145         ThrowIfGameStateNotMutable();
146         auto vehicle = GetVehicle();
147         if (vehicle != nullptr)
148         {
149             vehicle->ride = static_cast<ride_id_t>(value);
150         }
151     }
152 
numSeats_get() const153     uint8_t ScVehicle::numSeats_get() const
154     {
155         auto vehicle = GetVehicle();
156         return vehicle != nullptr ? vehicle->num_seats & VEHICLE_SEAT_NUM_MASK : 0;
157     }
numSeats_set(uint8_t value)158     void ScVehicle::numSeats_set(uint8_t value)
159     {
160         ThrowIfGameStateNotMutable();
161         auto vehicle = GetVehicle();
162         if (vehicle != nullptr)
163         {
164             vehicle->num_seats &= ~VEHICLE_SEAT_NUM_MASK;
165             vehicle->num_seats |= value & VEHICLE_SEAT_NUM_MASK;
166         }
167     }
168 
nextCarOnTrain_get() const169     DukValue ScVehicle::nextCarOnTrain_get() const
170     {
171         auto ctx = GetContext()->GetScriptEngine().GetContext();
172         auto vehicle = GetVehicle();
173         if (vehicle != nullptr)
174         {
175             if (vehicle->next_vehicle_on_train != SPRITE_INDEX_NULL)
176             {
177                 return ToDuk<int32_t>(ctx, vehicle->next_vehicle_on_train);
178             }
179         }
180         return ToDuk(ctx, nullptr);
181     }
nextCarOnTrain_set(DukValue value)182     void ScVehicle::nextCarOnTrain_set(DukValue value)
183     {
184         ThrowIfGameStateNotMutable();
185         auto vehicle = GetVehicle();
186         if (vehicle != nullptr)
187         {
188             if (value.type() == DukValue::Type::NUMBER)
189             {
190                 vehicle->next_vehicle_on_train = static_cast<uint16_t>(value.as_int());
191             }
192             else
193             {
194                 vehicle->next_vehicle_on_train = SPRITE_INDEX_NULL;
195             }
196         }
197     }
198 
previousCarOnRide_get() const199     uint16_t ScVehicle::previousCarOnRide_get() const
200     {
201         auto vehicle = GetVehicle();
202         return vehicle != nullptr ? vehicle->prev_vehicle_on_ride : 0;
203     }
previousCarOnRide_set(uint16_t value)204     void ScVehicle::previousCarOnRide_set(uint16_t value)
205     {
206         ThrowIfGameStateNotMutable();
207         auto vehicle = GetVehicle();
208         if (vehicle != nullptr)
209         {
210             vehicle->prev_vehicle_on_ride = value;
211         }
212     }
213 
nextCarOnRide_get() const214     uint16_t ScVehicle::nextCarOnRide_get() const
215     {
216         auto vehicle = GetVehicle();
217         return vehicle != nullptr ? vehicle->next_vehicle_on_ride : 0;
218     }
nextCarOnRide_set(uint16_t value)219     void ScVehicle::nextCarOnRide_set(uint16_t value)
220     {
221         ThrowIfGameStateNotMutable();
222         auto vehicle = GetVehicle();
223         if (vehicle != nullptr)
224         {
225             vehicle->next_vehicle_on_ride = value;
226         }
227     }
228 
currentStation_get() const229     StationIndex ScVehicle::currentStation_get() const
230     {
231         auto vehicle = GetVehicle();
232         return vehicle != nullptr ? vehicle->current_station : 0;
233     }
currentStation_set(StationIndex value)234     void ScVehicle::currentStation_set(StationIndex value)
235     {
236         ThrowIfGameStateNotMutable();
237         auto vehicle = GetVehicle();
238         if (vehicle != nullptr)
239         {
240             vehicle->current_station = value;
241         }
242     }
243 
mass_get() const244     uint16_t ScVehicle::mass_get() const
245     {
246         auto vehicle = GetVehicle();
247         return vehicle != nullptr ? vehicle->mass : 0;
248     }
mass_set(uint16_t value)249     void ScVehicle::mass_set(uint16_t value)
250     {
251         ThrowIfGameStateNotMutable();
252         auto vehicle = GetVehicle();
253         if (vehicle != nullptr)
254         {
255             vehicle->mass = value;
256         }
257     }
258 
acceleration_get() const259     int32_t ScVehicle::acceleration_get() const
260     {
261         auto vehicle = GetVehicle();
262         return vehicle != nullptr ? vehicle->acceleration : 0;
263     }
acceleration_set(int32_t value)264     void ScVehicle::acceleration_set(int32_t value)
265     {
266         ThrowIfGameStateNotMutable();
267         auto vehicle = GetVehicle();
268         if (vehicle != nullptr)
269         {
270             vehicle->acceleration = value;
271         }
272     }
273 
velocity_get() const274     int32_t ScVehicle::velocity_get() const
275     {
276         auto vehicle = GetVehicle();
277         return vehicle != nullptr ? vehicle->velocity : 0;
278     }
velocity_set(int32_t value)279     void ScVehicle::velocity_set(int32_t value)
280     {
281         ThrowIfGameStateNotMutable();
282         auto vehicle = GetVehicle();
283         if (vehicle != nullptr)
284         {
285             vehicle->velocity = value;
286         }
287     }
288 
bankRotation_get() const289     uint8_t ScVehicle::bankRotation_get() const
290     {
291         auto vehicle = GetVehicle();
292         return vehicle != nullptr ? vehicle->bank_rotation : 0;
293     }
bankRotation_set(uint8_t value)294     void ScVehicle::bankRotation_set(uint8_t value)
295     {
296         ThrowIfGameStateNotMutable();
297         auto vehicle = GetVehicle();
298         if (vehicle != nullptr)
299         {
300             vehicle->bank_rotation = value;
301         }
302     }
303 
colours_get() const304     DukValue ScVehicle::colours_get() const
305     {
306         auto ctx = GetContext()->GetScriptEngine().GetContext();
307         auto vehicle = GetVehicle();
308         if (vehicle != nullptr)
309         {
310             VehicleColour colours;
311             colours.Body = vehicle->colours.body_colour;
312             colours.Trim = vehicle->colours.trim_colour;
313             colours.Ternary = vehicle->colours_extended;
314             return ToDuk<VehicleColour>(ctx, colours);
315         }
316         return ToDuk(ctx, nullptr);
317     }
colours_set(const DukValue & value)318     void ScVehicle::colours_set(const DukValue& value)
319     {
320         ThrowIfGameStateNotMutable();
321         auto vehicle = GetVehicle();
322         if (vehicle != nullptr)
323         {
324             auto colours = FromDuk<VehicleColour>(value);
325             vehicle->colours.body_colour = colours.Body;
326             vehicle->colours.trim_colour = colours.Trim;
327             vehicle->colours_extended = colours.Ternary;
328         }
329     }
330 
trackLocation_get() const331     DukValue ScVehicle::trackLocation_get() const
332     {
333         auto ctx = GetContext()->GetScriptEngine().GetContext();
334         auto vehicle = GetVehicle();
335         if (vehicle != nullptr)
336         {
337             auto coords = CoordsXYZD(vehicle->TrackLocation, vehicle->GetTrackDirection());
338             return ToDuk<CoordsXYZD>(ctx, coords);
339         }
340         return ToDuk(ctx, nullptr);
341     }
trackLocation_set(const DukValue & value)342     void ScVehicle::trackLocation_set(const DukValue& value)
343     {
344         ThrowIfGameStateNotMutable();
345         auto vehicle = GetVehicle();
346         if (vehicle != nullptr)
347         {
348             auto coords = FromDuk<CoordsXYZD>(value);
349             vehicle->TrackLocation = CoordsXYZ(coords.x, coords.y, coords.z);
350             vehicle->SetTrackDirection(coords.direction);
351         }
352     }
353 
trackProgress_get() const354     uint16_t ScVehicle::trackProgress_get() const
355     {
356         auto vehicle = GetVehicle();
357         return vehicle != nullptr ? vehicle->track_progress : 0;
358     }
359 
remainingDistance_get() const360     int32_t ScVehicle::remainingDistance_get() const
361     {
362         auto vehicle = GetVehicle();
363         return vehicle != nullptr ? vehicle->remaining_distance : 0;
364     }
365 
poweredAcceleration_get() const366     uint8_t ScVehicle::poweredAcceleration_get() const
367     {
368         auto vehicle = GetVehicle();
369         return vehicle != nullptr ? vehicle->powered_acceleration : 0;
370     }
poweredAcceleration_set(uint8_t value)371     void ScVehicle::poweredAcceleration_set(uint8_t value)
372     {
373         ThrowIfGameStateNotMutable();
374         auto vehicle = GetVehicle();
375         if (vehicle != nullptr)
376         {
377             vehicle->powered_acceleration = value;
378         }
379     }
380 
poweredMaxSpeed_get() const381     uint8_t ScVehicle::poweredMaxSpeed_get() const
382     {
383         auto vehicle = GetVehicle();
384         return vehicle != nullptr ? vehicle->speed : 0;
385     }
poweredMaxSpeed_set(uint8_t value)386     void ScVehicle::poweredMaxSpeed_set(uint8_t value)
387     {
388         ThrowIfGameStateNotMutable();
389         auto vehicle = GetVehicle();
390         if (vehicle != nullptr)
391         {
392             vehicle->speed = value;
393         }
394     }
395 
status_get() const396     std::string ScVehicle::status_get() const
397     {
398         auto vehicle = GetVehicle();
399         if (vehicle != nullptr)
400         {
401             return std::string(VehicleStatusMap[vehicle->status]);
402         }
403         return {};
404     }
status_set(const std::string & value)405     void ScVehicle::status_set(const std::string& value)
406     {
407         ThrowIfGameStateNotMutable();
408         auto vehicle = GetVehicle();
409         if (vehicle != nullptr)
410         {
411             vehicle->status = VehicleStatusMap[value];
412         }
413     }
414 
guests_get() const415     std::vector<DukValue> ScVehicle::guests_get() const
416     {
417         auto ctx = GetContext()->GetScriptEngine().GetContext();
418         std::vector<DukValue> result;
419         auto vehicle = GetVehicle();
420         if (vehicle != nullptr)
421         {
422             size_t len = 0;
423             for (size_t i = 0; i < std::size(vehicle->peep); i++)
424             {
425                 auto peep = vehicle->peep[i];
426                 if (peep == SPRITE_INDEX_NULL)
427                 {
428                     result.push_back(ToDuk(ctx, nullptr));
429                 }
430                 else
431                 {
432                     result.push_back(ToDuk<int32_t>(ctx, peep));
433                     len = i + 1;
434                 }
435             }
436             result.resize(len);
437         }
438         return result;
439     }
440 
gForces_get() const441     DukValue ScVehicle::gForces_get() const
442     {
443         auto ctx = GetContext()->GetScriptEngine().GetContext();
444         auto vehicle = GetVehicle();
445         if (vehicle != nullptr)
446         {
447             GForces gForces = vehicle->GetGForces();
448             return ToDuk<GForces>(ctx, gForces);
449         }
450         return ToDuk(ctx, nullptr);
451     }
452 
travelBy(int32_t value)453     void ScVehicle::travelBy(int32_t value)
454     {
455         ThrowIfGameStateNotMutable();
456         auto vehicle = GetVehicle();
457         if (vehicle != nullptr)
458         {
459             vehicle->MoveRelativeDistance(value);
460         }
461     }
462 
463 } // namespace OpenRCT2::Scripting
464 
465 #endif
466