1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2025-12-10 09:32:29 +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: [#21908] Ride mode warnings when hovering track designs.
- 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: [#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.

View File

@@ -120,8 +120,8 @@ declare global {
/**
* A track piece coordinate and type within the game.
*/
interface CarTrackLocation extends CoordsXYZD {
trackType: number;
interface CarTrackLocation extends Readonly<CoordsXYZD> {
readonly trackType: number;
}
/**
@@ -2930,7 +2930,7 @@ declare global {
/**
* The location and direction of where the car is on the track.
*/
trackLocation: CarTrackLocation;
readonly trackLocation: CarTrackLocation;
/**
* The current g-forces of this car.
@@ -2970,6 +2970,12 @@ declare global {
* on the direction its moving in.
*/
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 =

View File

@@ -588,6 +588,24 @@ void Vehicle::MoveRelativeDistance(int32_t distance)
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)
{
return TryGetEntity<Vehicle>(spriteIndex);

View File

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

View File

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

View File

@@ -9,10 +9,13 @@
#include "ScVehicle.hpp"
#include "../../../world/tile_element/TrackElement.h"
#include "../ride/ScRide.hpp"
#ifdef ENABLE_SCRIPTING
using namespace OpenRCT2::Drawing;
namespace OpenRCT2::Scripting
{
static const DukEnumMap<Vehicle::Status> VehicleStatusMap({
@@ -75,7 +78,7 @@ namespace OpenRCT2::Scripting
ctx, &ScVehicle::flag_get<VehicleFlags::CarIsReversed>, &ScVehicle::flag_set<VehicleFlags::CarIsReversed>,
"isReversed");
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::remainingDistance_get, nullptr, "remainingDistance");
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::gForces_get, nullptr, "gForces");
dukglue_register_method(ctx, &ScVehicle::travelBy, "travelBy");
dukglue_register_method(ctx, &ScVehicle::moveToTrack, "moveToTrack");
}
Vehicle* ScVehicle::GetVehicle() const
@@ -397,20 +401,6 @@ namespace OpenRCT2::Scripting
}
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
{
@@ -543,8 +533,41 @@ namespace OpenRCT2::Scripting
if (vehicle != nullptr)
{
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
#endif

View File

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