1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2025-12-14 11:32:56 +01:00

Scripting: Add Car.moveToTrack API (#23359)

* Scripting: Redraw vehicle when setting track location

* Scripting: introduce car.moveToTrack

A new function to move cars to tracks easier. Also redraws the car.

* Revert car.trackLocation to CoordsXYZD

reverts 30a555d3c2
car.moveToTrack() achieves the same thing in a saner API.

* Final fixes for vehicle.moveToTrack

added back tracklocation.Get with track type
added EntityTweener call at the end of travelBy/moveToTrack

* moveToTrack: final bassie review fixes.

* moveToTrack: use tile coords

* moveToTrack: api increment

---------

Co-authored-by: Guy Sviry <guy@axissecurity.com>
Co-authored-by: Tulio Leao <tupaschoal@gmail.com>
This commit is contained in:
Guy Sviry
2025-04-03 02:42:30 +03:00
committed by GitHub
parent 910ba56a06
commit b92e05bc14
7 changed files with 77 additions and 20 deletions

View File

@@ -20,6 +20,7 @@
- Fix: [#19506] Queue paths can be placed on level crossings by replacing an existing regular path. - Fix: [#19506] Queue paths can be placed on level crossings by replacing an existing regular path.
- Fix: [#21908] Ride mode warnings when hovering track designs. - Fix: [#21908] Ride mode warnings when hovering track designs.
- Fix: [#22961] Clicking on the construction preview places duplicate flat rides and stalls. - Fix: [#22961] Clicking on the construction preview places duplicate flat rides and stalls.
- Fix: [#23359] Scripting: Add car.moveToTrack, an easier API than setting car.trackLocation directly.
- Fix: [#23443] New GOG version of RCT2 is not extracted correctly. - Fix: [#23443] New GOG version of RCT2 is not extracted correctly.
- Fix: [#23484] Stray coloured pixels on castle-themed stations and Roman-themed entrances/exits (original bug). - Fix: [#23484] Stray coloured pixels on castle-themed stations and Roman-themed entrances/exits (original bug).
- Fix: [#23486] Object selection minimum requirements can be bypassed with close window hotkey. - Fix: [#23486] Object selection minimum requirements can be bypassed with close window hotkey.

View File

@@ -120,8 +120,8 @@ declare global {
/** /**
* A track piece coordinate and type within the game. * A track piece coordinate and type within the game.
*/ */
interface CarTrackLocation extends CoordsXYZD { interface CarTrackLocation extends Readonly<CoordsXYZD> {
trackType: number; readonly trackType: number;
} }
/** /**
@@ -2930,7 +2930,7 @@ declare global {
/** /**
* The location and direction of where the car is on the track. * The location and direction of where the car is on the track.
*/ */
trackLocation: CarTrackLocation; readonly trackLocation: CarTrackLocation;
/** /**
* The current g-forces of this car. * The current g-forces of this car.
@@ -2970,6 +2970,12 @@ declare global {
* on the direction its moving in. * on the direction its moving in.
*/ */
travelBy(distance: number): void; travelBy(distance: number): void;
/**
* Moves the vehicle to the track piece specified in the parameters.
* Coordinates are tile coords.
*/
moveToTrack(x: number, y: number, elemIndex: number): void;
} }
type VehicleStatus = type VehicleStatus =

View File

@@ -588,6 +588,24 @@ void Vehicle::MoveRelativeDistance(int32_t distance)
ClearFlag(VehicleFlags::MoveSingleCar | VehicleFlags::CollisionDisabled); ClearFlag(VehicleFlags::MoveSingleCar | VehicleFlags::CollisionDisabled);
} }
void Vehicle::UpdateTrackChange()
{
auto curRide = GetRide();
if (curRide == nullptr)
return;
const auto moveInfo = GetMoveInfo();
if (moveInfo == nullptr || moveInfo->IsInvalid())
return;
_vehicleCurPosition = TrackLocation
+ CoordsXYZ{ moveInfo->x, moveInfo->y, moveInfo->z + GetRideTypeDescriptor((*curRide).type).Heights.VehicleZOffset };
Orientation = moveInfo->direction;
bank_rotation = moveInfo->bank_rotation;
Pitch = moveInfo->Pitch;
MoveTo(_vehicleCurPosition);
}
Vehicle* TryGetVehicle(EntityId spriteIndex) Vehicle* TryGetVehicle(EntityId spriteIndex)
{ {
return TryGetEntity<Vehicle>(spriteIndex); return TryGetEntity<Vehicle>(spriteIndex);

View File

@@ -47,6 +47,11 @@ struct VehicleInfo
uint8_t direction; // 0x06 uint8_t direction; // 0x06
uint8_t Pitch; // 0x07 uint8_t Pitch; // 0x07
uint8_t bank_rotation; // 0x08 uint8_t bank_rotation; // 0x08
bool IsInvalid() const
{
return x == 0 && y == 0 && z == 0 && direction == 0 && Pitch == 0 && bank_rotation == 0;
}
}; };
struct SoundIdVolume; struct SoundIdVolume;
@@ -230,12 +235,14 @@ struct Vehicle : EntityBase
Ride* GetRide() const; Ride* GetRide() const;
Vehicle* TrainHead() const; Vehicle* TrainHead() const;
Vehicle* TrainTail() const; Vehicle* TrainTail() const;
uint16_t GetTrackProgress() const;
void UpdateAnimationAnimalFlying(); void UpdateAnimationAnimalFlying();
void EnableCollisionsForTrain(); void EnableCollisionsForTrain();
/** /**
* Instantly moves the specific car forward or backwards along the track. * Instantly moves the specific car forward or backwards along the track.
*/ */
void MoveRelativeDistance(int32_t distance); void MoveRelativeDistance(int32_t distance);
void UpdateTrackChange();
OpenRCT2::TrackElemType GetTrackType() const OpenRCT2::TrackElemType GetTrackType() const
{ {
return static_cast<OpenRCT2::TrackElemType>(TrackTypeAndDirection >> 2); return static_cast<OpenRCT2::TrackElemType>(TrackTypeAndDirection >> 2);
@@ -279,7 +286,6 @@ struct Vehicle : EntityBase
private: private:
const VehicleInfo* GetMoveInfo() const; const VehicleInfo* GetMoveInfo() const;
uint16_t GetTrackProgress() const;
void CableLiftUpdate(); void CableLiftUpdate();
bool CableLiftUpdateTrackMotionForwards(); bool CableLiftUpdateTrackMotionForwards();
bool CableLiftUpdateTrackMotionBackwards(); bool CableLiftUpdateTrackMotionBackwards();

View File

@@ -46,7 +46,7 @@ namespace OpenRCT2
namespace OpenRCT2::Scripting namespace OpenRCT2::Scripting
{ {
static constexpr int32_t kPluginApiVersion = 104; static constexpr int32_t kPluginApiVersion = 105;
// Versions marking breaking changes. // Versions marking breaking changes.
static constexpr int32_t kApiVersionPeepDeprecation = 33; static constexpr int32_t kApiVersionPeepDeprecation = 33;

View File

@@ -9,10 +9,13 @@
#include "ScVehicle.hpp" #include "ScVehicle.hpp"
#include "../../../world/tile_element/TrackElement.h"
#include "../ride/ScRide.hpp" #include "../ride/ScRide.hpp"
#ifdef ENABLE_SCRIPTING #ifdef ENABLE_SCRIPTING
using namespace OpenRCT2::Drawing;
namespace OpenRCT2::Scripting namespace OpenRCT2::Scripting
{ {
static const DukEnumMap<Vehicle::Status> VehicleStatusMap({ static const DukEnumMap<Vehicle::Status> VehicleStatusMap({
@@ -75,7 +78,7 @@ namespace OpenRCT2::Scripting
ctx, &ScVehicle::flag_get<VehicleFlags::CarIsReversed>, &ScVehicle::flag_set<VehicleFlags::CarIsReversed>, ctx, &ScVehicle::flag_get<VehicleFlags::CarIsReversed>, &ScVehicle::flag_set<VehicleFlags::CarIsReversed>,
"isReversed"); "isReversed");
dukglue_register_property(ctx, &ScVehicle::colours_get, &ScVehicle::colours_set, "colours"); 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::trackLocation_get, nullptr, "trackLocation");
dukglue_register_property(ctx, &ScVehicle::trackProgress_get, nullptr, "trackProgress"); dukglue_register_property(ctx, &ScVehicle::trackProgress_get, nullptr, "trackProgress");
dukglue_register_property(ctx, &ScVehicle::remainingDistance_get, nullptr, "remainingDistance"); dukglue_register_property(ctx, &ScVehicle::remainingDistance_get, nullptr, "remainingDistance");
dukglue_register_property(ctx, &ScVehicle::subposition_get, nullptr, "subposition"); dukglue_register_property(ctx, &ScVehicle::subposition_get, nullptr, "subposition");
@@ -88,6 +91,7 @@ namespace OpenRCT2::Scripting
dukglue_register_property(ctx, &ScVehicle::guests_get, nullptr, "guests"); dukglue_register_property(ctx, &ScVehicle::guests_get, nullptr, "guests");
dukglue_register_property(ctx, &ScVehicle::gForces_get, nullptr, "gForces"); dukglue_register_property(ctx, &ScVehicle::gForces_get, nullptr, "gForces");
dukglue_register_method(ctx, &ScVehicle::travelBy, "travelBy"); dukglue_register_method(ctx, &ScVehicle::travelBy, "travelBy");
dukglue_register_method(ctx, &ScVehicle::moveToTrack, "moveToTrack");
} }
Vehicle* ScVehicle::GetVehicle() const Vehicle* ScVehicle::GetVehicle() const
@@ -397,20 +401,6 @@ namespace OpenRCT2::Scripting
} }
return ToDuk(ctx, nullptr); return ToDuk(ctx, nullptr);
} }
void ScVehicle::trackLocation_set(const DukValue& value)
{
ThrowIfGameStateNotMutable();
auto vehicle = GetVehicle();
if (vehicle != nullptr)
{
auto x = AsOrDefault(value["x"], 0);
auto y = AsOrDefault(value["y"], 0);
auto z = AsOrDefault(value["z"], 0);
vehicle->TrackLocation = CoordsXYZ(x, y, z);
vehicle->SetTrackDirection(AsOrDefault(value["direction"], 0));
vehicle->SetTrackType(static_cast<TrackElemType>(AsOrDefault(value["trackType"], 0)));
}
}
uint16_t ScVehicle::trackProgress_get() const uint16_t ScVehicle::trackProgress_get() const
{ {
@@ -543,8 +533,41 @@ namespace OpenRCT2::Scripting
if (vehicle != nullptr) if (vehicle != nullptr)
{ {
vehicle->MoveRelativeDistance(value); vehicle->MoveRelativeDistance(value);
EntityTweener::Get().RemoveEntity(vehicle);
} }
} }
void ScVehicle::moveToTrack(int32_t x, int32_t y, int32_t elementIndex)
{
CoordsXY coords = TileCoordsXY(x, y).ToCoordsXY();
auto vehicle = GetVehicle();
if (vehicle == nullptr)
return;
auto el = MapGetNthElementAt(coords, elementIndex);
if (el == nullptr)
return;
auto origin = GetTrackSegmentOrigin(CoordsXYE(coords, el));
if (!origin)
return;
auto trackEl = el->AsTrack();
vehicle->TrackLocation.x = origin->x;
vehicle->TrackLocation.y = origin->y;
vehicle->TrackLocation.z = origin->z;
vehicle->SetTrackDirection(origin->direction);
vehicle->SetTrackType(trackEl->GetTrackType());
// Clip track progress to avoid being out of bounds of current piece
uint16_t trackTotalProgress = vehicle->GetTrackProgress();
if (trackTotalProgress && vehicle->track_progress >= trackTotalProgress)
vehicle->track_progress = trackTotalProgress - 1;
vehicle->UpdateTrackChange();
EntityTweener::Get().RemoveEntity(vehicle);
}
} // namespace OpenRCT2::Scripting } // namespace OpenRCT2::Scripting
#endif #endif

View File

@@ -11,6 +11,7 @@
#ifdef ENABLE_SCRIPTING #ifdef ENABLE_SCRIPTING
#include "../../../entity/EntityTweener.h"
#include "../../../ride/Ride.h" #include "../../../ride/Ride.h"
#include "ScEntity.hpp" #include "ScEntity.hpp"
@@ -101,6 +102,8 @@ namespace OpenRCT2::Scripting
DukValue gForces_get() const; DukValue gForces_get() const;
void travelBy(int32_t value); void travelBy(int32_t value);
void moveToTrack(int32_t x, int32_t y, int32_t elementIndex);
}; };
} // namespace OpenRCT2::Scripting } // namespace OpenRCT2::Scripting