diff --git a/src/openrct2/libopenrct2.vcxproj b/src/openrct2/libopenrct2.vcxproj
index 868b309ddf..d6775939d9 100644
--- a/src/openrct2/libopenrct2.vcxproj
+++ b/src/openrct2/libopenrct2.vcxproj
@@ -543,6 +543,7 @@
+
@@ -1092,6 +1093,7 @@
+
@@ -1196,4 +1198,4 @@
-
+
\ No newline at end of file
diff --git a/src/openrct2/ride/CableLift.cpp b/src/openrct2/ride/CableLift.cpp
index c7466697fc..44818b2259 100644
--- a/src/openrct2/ride/CableLift.cpp
+++ b/src/openrct2/ride/CableLift.cpp
@@ -21,8 +21,10 @@
#include "Track.h"
#include "Vehicle.h"
#include "VehicleData.h"
+#include "VehicleGeometry.h"
using namespace OpenRCT2;
+using namespace OpenRCT2::RideVehicle;
Vehicle* CableLiftSegmentCreate(
Ride& ride, int32_t x, int32_t y, int32_t z, int32_t direction, uint16_t var_44, int32_t remaining_distance, bool head)
@@ -274,19 +276,10 @@ bool Vehicle::CableLiftUpdateTrackMotionForwards()
const auto moveInfo = GetMoveInfo();
auto nextVehiclePosition = CoordsXYZ{ moveInfo->x, moveInfo->y, moveInfo->z } + TrackLocation;
- uint8_t remainingDistanceFlags = 0;
nextVehiclePosition.z += GetRideTypeDescriptor(curRide->type).Heights.VehicleZOffset;
- if (nextVehiclePosition.x != _vehicleCurPosition.x)
- remainingDistanceFlags |= (1 << 0);
- if (nextVehiclePosition.y != _vehicleCurPosition.y)
- remainingDistanceFlags |= (1 << 1);
- if (nextVehiclePosition.z != _vehicleCurPosition.z)
- remainingDistanceFlags |= (1 << 2);
- remaining_distance -= SubpositionTranslationDistances[remainingDistanceFlags];
- _vehicleCurPosition.x = nextVehiclePosition.x;
- _vehicleCurPosition.y = nextVehiclePosition.y;
- _vehicleCurPosition.z = nextVehiclePosition.z;
+ remaining_distance -= Geometry::getTranslationDistance(nextVehiclePosition - _vehicleCurPosition, false);
+ _vehicleCurPosition = nextVehiclePosition;
Orientation = moveInfo->direction;
roll = moveInfo->roll;
@@ -294,7 +287,7 @@ bool Vehicle::CableLiftUpdateTrackMotionForwards()
if (remaining_distance >= 13962)
{
- acceleration += AccelerationFromPitch[EnumValue(pitch)];
+ acceleration += Geometry::getAccelerationFromPitch(pitch);
}
}
return true;
@@ -341,29 +334,20 @@ bool Vehicle::CableLiftUpdateTrackMotionBackwards()
}
track_progress = trackProgress;
const auto moveInfo = GetMoveInfo();
- auto unk = CoordsXYZ{ moveInfo->x, moveInfo->y, moveInfo->z } + TrackLocation;
+ auto nextVehiclePosition = CoordsXYZ{ moveInfo->x, moveInfo->y, moveInfo->z } + TrackLocation;
- uint8_t remainingDistanceFlags = 0;
- unk.z += GetRideTypeDescriptor(curRide->type).Heights.VehicleZOffset;
- if (unk.x != _vehicleCurPosition.x)
- remainingDistanceFlags |= (1 << 0);
- if (unk.y != _vehicleCurPosition.y)
- remainingDistanceFlags |= (1 << 1);
- if (unk.z != _vehicleCurPosition.z)
- remainingDistanceFlags |= (1 << 2);
+ nextVehiclePosition.z += GetRideTypeDescriptor(curRide->type).Heights.VehicleZOffset;
- remaining_distance += SubpositionTranslationDistances[remainingDistanceFlags];
- _vehicleCurPosition.x = unk.x;
- _vehicleCurPosition.y = unk.y;
- _vehicleCurPosition.z = unk.z;
+ remaining_distance += Geometry::getTranslationDistance(nextVehiclePosition - _vehicleCurPosition, false);
+ _vehicleCurPosition = nextVehiclePosition;
Orientation = moveInfo->direction;
roll = moveInfo->roll;
pitch = moveInfo->pitch;
if (remaining_distance < 0)
{
- acceleration += AccelerationFromPitch[EnumValue(pitch)];
+ acceleration += Geometry::getAccelerationFromPitch(pitch);
}
}
return true;
@@ -394,7 +378,7 @@ int32_t Vehicle::CableLiftUpdateTrackMotion()
for (Vehicle* vehicle = frontVehicle; vehicle != nullptr;)
{
- vehicle->acceleration = AccelerationFromPitch[EnumValue(vehicle->pitch)];
+ vehicle->acceleration = Geometry::getAccelerationFromPitch(vehicle->pitch);
_vehicleUnkF64E10 = 1;
vehicle->remaining_distance += _vehicleVelocityF64E0C;
@@ -415,7 +399,7 @@ int32_t Vehicle::CableLiftUpdateTrackMotion()
_vehicleMotionTrackFlags |= VEHICLE_UPDATE_MOTION_TRACK_FLAG_5;
_vehicleVelocityF64E0C -= vehicle->remaining_distance - 13962;
vehicle->remaining_distance = 13962;
- vehicle->acceleration += AccelerationFromPitch[EnumValue(vehicle->pitch)];
+ vehicle->acceleration += Geometry::getAccelerationFromPitch(vehicle->pitch);
_vehicleUnkF64E10++;
continue;
}
@@ -428,7 +412,7 @@ int32_t Vehicle::CableLiftUpdateTrackMotion()
_vehicleMotionTrackFlags |= VEHICLE_UPDATE_MOTION_TRACK_FLAG_5;
_vehicleVelocityF64E0C -= vehicle->remaining_distance + 1;
vehicle->remaining_distance = -1;
- vehicle->acceleration += AccelerationFromPitch[EnumValue(vehicle->pitch)];
+ vehicle->acceleration += Geometry::getAccelerationFromPitch(vehicle->pitch);
_vehicleUnkF64E10++;
}
vehicle->MoveTo(_vehicleCurPosition);
diff --git a/src/openrct2/ride/Vehicle.cpp b/src/openrct2/ride/Vehicle.cpp
index ec2c627e92..27ad6bd91b 100644
--- a/src/openrct2/ride/Vehicle.cpp
+++ b/src/openrct2/ride/Vehicle.cpp
@@ -62,6 +62,7 @@
#include "TrackData.h"
#include "TrainManager.h"
#include "VehicleData.h"
+#include "VehicleGeometry.h"
#include "VehicleSubpositionData.h"
#include
@@ -71,6 +72,7 @@ using namespace OpenRCT2;
using namespace OpenRCT2::Audio;
using namespace OpenRCT2::TrackMetaData;
using namespace OpenRCT2::Math::Trigonometry;
+using namespace OpenRCT2::RideVehicle;
static bool vehicle_boat_is_location_accessible(const CoordsXYZ& location);
constexpr int16_t kVehicleMaxSpinSpeed = 1536;
@@ -378,23 +380,6 @@ static constexpr const int8_t* SwingingTimeToSpriteMaps[] = {
kSwingingTimeToSpriteMap8, kSwingingTimeToSpriteMap9, kSwingingTimeToSpriteMap10, kSwingingTimeToSpriteMap11,
};
-struct Unk9A36C4Struct
-{
- int16_t x;
- int16_t y;
- uint32_t distance;
-};
-
-/** rct2: 0x009A36C4 */
-static constexpr Unk9A36C4Struct kUnk9A36C4[] = {
- { -1, 0, 8716 }, { -1, 0, 8716 }, { -1, 0, 8716 }, { -1, 1, 12327 }, { -1, 1, 12327 }, { -1, 1, 12327 },
- { 0, 1, 8716 }, { -1, 1, 12327 }, { 0, 1, 8716 }, { 0, 1, 8716 }, { 0, 1, 8716 }, { 1, 1, 12327 },
- { 1, 1, 12327 }, { 1, 1, 12327 }, { 1, 0, 8716 }, { 1, 1, 12327 }, { 1, 0, 8716 }, { 1, 0, 8716 },
- { 1, 0, 8716 }, { 1, -1, 12327 }, { 1, -1, 12327 }, { 1, -1, 12327 }, { 0, -1, 8716 }, { 1, -1, 12327 },
- { 0, -1, 8716 }, { 0, -1, 8716 }, { 0, -1, 8716 }, { -1, -1, 12327 }, { -1, -1, 12327 }, { -1, -1, 12327 },
- { -1, 0, 8716 }, { -1, -1, 12327 },
-};
-
/** rct2: 0x009A37C4 */
static constexpr CoordsXY kSurroundingTiles[] = {
{ 0, 0 },
@@ -408,34 +393,6 @@ static constexpr CoordsXY kSurroundingTiles[] = {
{ 0, +kCoordsXYStep },
};
-/** rct2: 0x009A37E4 */
-static constexpr int32_t kUnk9A37E4[] = {
- 2147483647, 2106585154, 1985590284, 1636362342, 1127484953, 2106585154, 1985590284, 1636362342, 1127484953,
- 58579923, 0, -555809667, -1073741824, -1518500249, -1859775391, -2074309916, -2147483647, 58579923,
- 0, -555809667, -1073741824, -1518500249, -1859775391, -2074309916, 1859775393, 1073741824, 0,
- -1073741824, -1859775393, 1859775393, 1073741824, 0, -1073741824, -1859775393, 1859775393, 1073741824,
- 0, -1073741824, -1859775393, 1859775393, 1073741824, 0, -1073741824, -1859775393, 2144540595,
- 2139311823, 2144540595, 2139311823, 2135719507, 2135719507, 2125953864, 2061796213, 1411702590, 2125953864,
- 2061796213, 1411702590, 1985590284, 1636362342, 1127484953, 2115506168, 2115506168,
-};
-
-/** rct2: 0x009A38D4 */
-static constexpr int32_t kUnk9A38D4[] = {
- 0, 417115092, 817995863, 1390684831, 1827693544, -417115092, -817995863, -1390684831, -1827693544,
- 2066040965, 2147483647, 2074309916, 1859775393, 1518500249, 1073741824, 555809666, 0, -2066040965,
- -2147483647, -2074309916, -1859775393, -1518500249, -1073741824, -555809666, 1073741824, 1859775393, 2147483647,
- 1859775393, 1073741824, -1073741824, -1859775393, -2147483647, -1859775393, -1073741824, 1073741824, 1859775393,
- 2147483647, 1859775393, 1073741824, -1073741824, -1859775393, -2147483647, -1859775393, -1073741824, 112390610,
- 187165532, -112390610, -187165532, 224473165, -224473165, 303325208, 600568389, 1618265062, -303325208,
- -600568389, -1618265062, -817995863, -1390684831, -1827693544, 369214930, -369214930,
-};
-
-/** rct2: 0x009A39C4 */
-static constexpr int32_t kUnk9A39C4[] = {
- 2147483647, 2096579710, 1946281152, 2096579710, 1946281152, 1380375879, 555809667, -372906620, -1231746017, -1859775391,
- 1380375879, 555809667, -372906620, -1231746017, -1859775391, 0, 2096579710, 1946281152, 2096579710, 1946281152,
-};
-
static constexpr OpenRCT2::Audio::SoundId kDoorOpenSoundIds[] = {
OpenRCT2::Audio::SoundId::null, // DoorSoundType::none
OpenRCT2::Audio::SoundId::doorOpen, // DoorSoundType::door
@@ -2926,12 +2883,6 @@ void Vehicle::UpdateCollisionSetup()
velocity = 0;
}
-/** rct2: 0x009A3AC4, 0x009A3AC6 */
-static constexpr CoordsXY stru_9A3AC4[] = {
- { -256, 0 }, { -236, 98 }, { -181, 181 }, { -98, 236 }, { 0, 256 }, { 98, 236 }, { 181, 181 }, { 236, 98 },
- { 256, 0 }, { 236, -98 }, { 181, -181 }, { 98, -236 }, { 0, -256 }, { -98, -236 }, { -181, -181 }, { -236, -98 },
-};
-
/**
*
* rct2: 0x006D9EFE
@@ -2965,11 +2916,14 @@ void Vehicle::UpdateCrashSetup()
lastVehicle = trainVehicle;
trainVehicle->sub_state = 0;
- int32_t trainX = stru_9A3AC4[trainVehicle->Orientation / 2].x;
- int32_t trainY = stru_9A3AC4[trainVehicle->Orientation / 2].y;
- auto trainZ = kUnk9A38D4[EnumValue(trainVehicle->pitch)] >> 23;
+ auto crashDirection = Geometry::getCrashDirectionComponents(trainVehicle->Orientation);
+ int32_t trainX = crashDirection.x;
+ int32_t trainY = crashDirection.y;
- int32_t ecx = kUnk9A37E4[EnumValue(trainVehicle->pitch)] >> 15;
+ auto carLaunchDirection = Geometry::getPitchVector32(trainVehicle->pitch);
+
+ auto trainZ = carLaunchDirection.y >> 23;
+ int32_t ecx = carLaunchDirection.x >> 15;
trainX *= ecx;
trainY *= ecx;
trainX >>= 16;
@@ -3790,7 +3744,7 @@ void Vehicle::UpdateMotionBoatHire()
}
int32_t edi = (Orientation | (var_35 & 1)) & 0x1F;
- loc2 = { x + kUnk9A36C4[edi].x, y + kUnk9A36C4[edi].y };
+ loc2 = { x + Geometry::getFreeroamVehicleMovementData(edi).x, y + Geometry::getFreeroamVehicleMovementData(edi).y };
if (UpdateMotionCollisionDetection({ loc2, z }, nullptr))
{
remaining_distance = 0;
@@ -3888,7 +3842,7 @@ void Vehicle::UpdateMotionBoatHire()
TrackLocation = { flooredLocation, TrackLocation.z };
}
- remaining_distance -= kUnk9A36C4[edi].distance;
+ remaining_distance -= Geometry::getFreeroamVehicleMovementData(edi).distance;
_vehicleCurPosition.x = loc2.x;
_vehicleCurPosition.y = loc2.y;
if (remaining_distance < 0x368A)
@@ -4963,7 +4917,7 @@ void Vehicle::UpdateSound()
sound2_volume = soundIdVolume.volume;
// Calculate Sound Vector (used for sound frequency calcs)
- int32_t soundDirection = SpriteDirectionToSoundDirection[Orientation];
+ int32_t soundDirection = Geometry::getSoundDirectionFromOrientation(Orientation);
int32_t soundVector = ((velocity >> 14) * soundDirection) >> 14;
soundVector = std::clamp(soundVector, -127, 127);
@@ -5070,8 +5024,8 @@ OpenRCT2::Audio::SoundId Vehicle::ProduceScreamSound(const int32_t totalNumPeeps
*/
GForces Vehicle::GetGForces() const
{
- int32_t gForceVert = ((static_cast(0x280000)) * kUnk9A37E4[EnumValue(pitch)]) >> 32;
- gForceVert = ((static_cast(gForceVert)) * kUnk9A39C4[EnumValue(roll)]) >> 32;
+ int32_t gForceVert = ((static_cast(0x280000)) * Geometry::getPitchVector32(pitch).x) >> 32;
+ gForceVert = ((static_cast(gForceVert)) * Geometry::getRollHorizontalComponent(roll)) >> 32;
const auto& ted = GetTrackElementDescriptor(GetTrackType());
const int32_t vertFactor = ted.verticalFactor(track_progress);
@@ -5227,10 +5181,10 @@ int32_t Vehicle::UpdateMotionDodgems()
CoordsXYZ location = { x, y, z };
- location.x += kUnk9A36C4[oldCollisionDirection].x;
- location.y += kUnk9A36C4[oldCollisionDirection].y;
- location.x += kUnk9A36C4[oldCollisionDirection + 1].x;
- location.y += kUnk9A36C4[oldCollisionDirection + 1].y;
+ location.x += Geometry::getFreeroamVehicleMovementData(oldCollisionDirection).x;
+ location.y += Geometry::getFreeroamVehicleMovementData(oldCollisionDirection).y;
+ location.x += Geometry::getFreeroamVehicleMovementData(oldCollisionDirection + 1).x;
+ location.y += Geometry::getFreeroamVehicleMovementData(oldCollisionDirection + 1).y;
if (collideSprite = DodgemsCarWouldCollideAt(location); !collideSprite.has_value())
{
@@ -5254,15 +5208,15 @@ int32_t Vehicle::UpdateMotionDodgems()
direction |= var_35 & 1;
CoordsXY location = _vehicleCurPosition;
- location.x += kUnk9A36C4[direction].x;
- location.y += kUnk9A36C4[direction].y;
+ location.x += Geometry::getFreeroamVehicleMovementData(direction).x;
+ location.y += Geometry::getFreeroamVehicleMovementData(direction).y;
if (collideSprite = DodgemsCarWouldCollideAt(location); collideSprite.has_value())
{
break;
}
- remaining_distance -= kUnk9A36C4[direction].distance;
+ remaining_distance -= Geometry::getFreeroamVehicleMovementData(direction).distance;
_vehicleCurPosition.x = location.x;
_vehicleCurPosition.y = location.y;
if (remaining_distance < 13962)
@@ -5420,7 +5374,7 @@ void Vehicle::UpdateTrackMotionUpStopCheck() const
gForces.LateralG = std::abs(gForces.LateralG);
if (gForces.LateralG <= 150)
{
- if (AccelerationFromPitch[EnumValue(pitch)] < 0)
+ if (Geometry::getAccelerationFromPitch(pitch) < 0)
{
if (gForces.VerticalG > -40)
{
@@ -5446,7 +5400,7 @@ void Vehicle::UpdateTrackMotionUpStopCheck() const
{
auto gForces = GetGForces();
- if (AccelerationFromPitch[EnumValue(pitch)] < 0)
+ if (Geometry::getAccelerationFromPitch(pitch) < 0)
{
if (gForces.VerticalG > -45)
{
@@ -7275,32 +7229,18 @@ bool Vehicle::UpdateTrackMotionForwards(const CarEntry* carEntry, const Ride& cu
// Loc6DB706
const auto moveInfo = GetMoveInfo();
trackType = GetTrackType();
- uint8_t moveInfovehicleAnimationGroup;
{
auto nextVehiclePosition = TrackLocation
+ CoordsXYZ{ moveInfo->x, moveInfo->y,
moveInfo->z + GetRideTypeDescriptor(curRide.type).Heights.VehicleZOffset };
- uint8_t remainingDistanceFlags = 0;
- if (nextVehiclePosition.x != _vehicleCurPosition.x)
- {
- remainingDistanceFlags |= 1;
- }
- if (nextVehiclePosition.y != _vehicleCurPosition.y)
- {
- remainingDistanceFlags |= 2;
- }
- if (nextVehiclePosition.z != _vehicleCurPosition.z)
- {
- remainingDistanceFlags |= 4;
- }
-
- if (TrackSubposition == VehicleTrackSubposition::ReverserRCFrontBogie
+ bool useReverserDistance = TrackSubposition == VehicleTrackSubposition::ReverserRCFrontBogie
&& (trackType == TrackElemType::LeftReverser || trackType == TrackElemType::RightReverser)
- && track_progress >= 30 && track_progress <= 66)
- {
- remainingDistanceFlags |= 8;
- }
+ && track_progress >= 30 && track_progress <= 66;
+
+ // Loc6DB8A5
+ remaining_distance -= Geometry::getTranslationDistance(
+ nextVehiclePosition - _vehicleCurPosition, useReverserDistance);
if (TrackSubposition == VehicleTrackSubposition::ReverserRCRearBogie
&& (trackType == TrackElemType::LeftReverser || trackType == TrackElemType::RightReverser)
@@ -7313,15 +7253,11 @@ bool Vehicle::UpdateTrackMotionForwards(const CarEntry* carEntry, const Ride& cu
nextVehiclePosition.y = y + moveInfo2->y;
}
- // Loc6DB8A5
- remaining_distance -= SubpositionTranslationDistances[remainingDistanceFlags];
_vehicleCurPosition = nextVehiclePosition;
Orientation = moveInfo->direction;
roll = moveInfo->roll;
pitch = moveInfo->pitch;
- moveInfovehicleAnimationGroup = EnumValue(moveInfo->pitch);
-
if ((carEntry->flags & CAR_ENTRY_FLAG_WOODEN_WILD_MOUSE_SWING) && moveInfo->pitch != VehiclePitch::flat)
{
SwingSprite = 0;
@@ -7385,7 +7321,7 @@ bool Vehicle::UpdateTrackMotionForwards(const CarEntry* carEntry, const Ride& cu
return true;
}
- acceleration += AccelerationFromPitch[moveInfovehicleAnimationGroup];
+ acceleration += Geometry::getAccelerationFromPitch(pitch);
_vehicleUnkF64E10++;
}
}
@@ -7607,33 +7543,18 @@ bool Vehicle::UpdateTrackMotionBackwards(const CarEntry* carEntry, const Ride& c
// Loc6DBD42
track_progress = newTrackProgress;
- VehiclePitch moveInfoVehicleAnimationGroup;
{
const VehicleInfo* moveInfo = GetMoveInfo();
auto nextVehiclePosition = TrackLocation
+ CoordsXYZ{ moveInfo->x, moveInfo->y,
moveInfo->z + GetRideTypeDescriptor(curRide.type).Heights.VehicleZOffset };
- uint8_t remainingDistanceFlags = 0;
- if (nextVehiclePosition.x != _vehicleCurPosition.x)
- {
- remainingDistanceFlags |= 1;
- }
- if (nextVehiclePosition.y != _vehicleCurPosition.y)
- {
- remainingDistanceFlags |= 2;
- }
- if (nextVehiclePosition.z != _vehicleCurPosition.z)
- {
- remainingDistanceFlags |= 4;
- }
- remaining_distance += SubpositionTranslationDistances[remainingDistanceFlags];
+ remaining_distance += Geometry::getTranslationDistance(nextVehiclePosition - _vehicleCurPosition, false);
_vehicleCurPosition = nextVehiclePosition;
Orientation = moveInfo->direction;
roll = moveInfo->roll;
pitch = moveInfo->pitch;
- moveInfoVehicleAnimationGroup = moveInfo->pitch;
if ((carEntry->flags & CAR_ENTRY_FLAG_WOODEN_WILD_MOUSE_SWING) && pitch != VehiclePitch::flat)
{
@@ -7694,7 +7615,7 @@ bool Vehicle::UpdateTrackMotionBackwards(const CarEntry* carEntry, const Ride& c
{
return true;
}
- acceleration += AccelerationFromPitch[EnumValue(moveInfoVehicleAnimationGroup)];
+ acceleration += Geometry::getAccelerationFromPitch(pitch);
_vehicleUnkF64E10++;
}
}
@@ -7715,7 +7636,7 @@ bool Vehicle::UpdateTrackMotionBackwards(const CarEntry* carEntry, const Ride& c
Loc6DCDE4(curRide);
return Vehicle::UpdateMiniGolfSubroutineStatus::stop;
}
- acceleration = AccelerationFromPitch[EnumValue(pitch)];
+ acceleration = Geometry::getAccelerationFromPitch(pitch);
_vehicleUnkF64E10++;
return Vehicle::UpdateMiniGolfSubroutineStatus::restart;
}
@@ -7737,7 +7658,7 @@ bool Vehicle::UpdateTrackMotionBackwards(const CarEntry* carEntry, const Ride& c
Loc6DCDE4(curRide);
return Vehicle::UpdateMiniGolfSubroutineStatus::stop;
}
- acceleration = AccelerationFromPitch[EnumValue(pitch)];
+ acceleration = Geometry::getAccelerationFromPitch(pitch);
_vehicleUnkF64E10++;
return Vehicle::UpdateMiniGolfSubroutineStatus::restart;
}
@@ -7765,7 +7686,7 @@ bool Vehicle::UpdateTrackMotionBackwards(const CarEntry* carEntry, const Ride& c
Loc6DCDE4(curRide);
return Vehicle::UpdateMiniGolfSubroutineStatus::stop;
}
- acceleration = AccelerationFromPitch[EnumValue(pitch)];
+ acceleration = Geometry::getAccelerationFromPitch(pitch);
_vehicleUnkF64E10++;
return Vehicle::UpdateMiniGolfSubroutineStatus::restart;
}
@@ -7782,7 +7703,7 @@ bool Vehicle::UpdateTrackMotionBackwards(const CarEntry* carEntry, const Ride& c
Loc6DCDE4(curRide);
return Vehicle::UpdateMiniGolfSubroutineStatus::stop;
}
- acceleration = AccelerationFromPitch[EnumValue(pitch)];
+ acceleration = Geometry::getAccelerationFromPitch(pitch);
_vehicleUnkF64E10++;
return Vehicle::UpdateMiniGolfSubroutineStatus::restart;
}
@@ -7811,7 +7732,7 @@ bool Vehicle::UpdateTrackMotionBackwards(const CarEntry* carEntry, const Ride& c
Loc6DCDE4(curRide);
return Vehicle::UpdateMiniGolfSubroutineStatus::stop;
}
- acceleration = AccelerationFromPitch[EnumValue(pitch)];
+ acceleration = Geometry::getAccelerationFromPitch(pitch);
_vehicleUnkF64E10++;
return Vehicle::UpdateMiniGolfSubroutineStatus::restart;
}
@@ -7828,7 +7749,7 @@ bool Vehicle::UpdateTrackMotionBackwards(const CarEntry* carEntry, const Ride& c
Loc6DCDE4(curRide);
return Vehicle::UpdateMiniGolfSubroutineStatus::stop;
}
- acceleration = AccelerationFromPitch[EnumValue(pitch)];
+ acceleration = Geometry::getAccelerationFromPitch(pitch);
_vehicleUnkF64E10++;
return Vehicle::UpdateMiniGolfSubroutineStatus::restart;
}
@@ -7864,7 +7785,7 @@ bool Vehicle::UpdateTrackMotionBackwards(const CarEntry* carEntry, const Ride& c
Loc6DCDE4(curRide);
return Vehicle::UpdateMiniGolfSubroutineStatus::stop;
}
- acceleration = AccelerationFromPitch[EnumValue(pitch)];
+ acceleration = Geometry::getAccelerationFromPitch(pitch);
_vehicleUnkF64E10++;
return Vehicle::UpdateMiniGolfSubroutineStatus::restart;
}
@@ -7903,7 +7824,7 @@ bool Vehicle::UpdateTrackMotionBackwards(const CarEntry* carEntry, const Ride& c
_vehicleMotionTrackFlags |= VEHICLE_UPDATE_MOTION_TRACK_FLAG_5;
_vehicleVelocityF64E0C -= remaining_distance + 1;
remaining_distance = -1;
- acceleration += AccelerationFromPitch[EnumValue(pitch)];
+ acceleration += Geometry::getAccelerationFromPitch(pitch);
_vehicleUnkF64E10++;
return UpdateMiniGolfSubroutineStatus::carryOn;
}
@@ -7920,7 +7841,7 @@ bool Vehicle::UpdateTrackMotionBackwards(const CarEntry* carEntry, const Ride& c
{
Loc6DCDE4(curRide);
}
- acceleration += AccelerationFromPitch[EnumValue(pitch)];
+ acceleration += Geometry::getAccelerationFromPitch(pitch);
_vehicleUnkF64E10++;
return UpdateMiniGolfSubroutineStatus::carryOn;
}
@@ -8078,7 +7999,7 @@ bool Vehicle::UpdateTrackMotionBackwards(const CarEntry* carEntry, const Ride& c
Loc6DCDE4(curRide);
return UpdateMiniGolfSubroutineStatus::stop;
}
- acceleration = AccelerationFromPitch[EnumValue(pitch)];
+ acceleration = Geometry::getAccelerationFromPitch(pitch);
_vehicleUnkF64E10++;
}
}
@@ -8096,7 +8017,7 @@ bool Vehicle::UpdateTrackMotionBackwards(const CarEntry* carEntry, const Ride& c
_vehicleMotionTrackFlags |= VEHICLE_UPDATE_MOTION_TRACK_FLAG_5;
_vehicleVelocityF64E0C -= remaining_distance + 1;
remaining_distance = -1;
- acceleration += AccelerationFromPitch[EnumValue(pitch)];
+ acceleration += Geometry::getAccelerationFromPitch(pitch);
_vehicleUnkF64E10++;
continue;
}
@@ -8109,7 +8030,7 @@ bool Vehicle::UpdateTrackMotionBackwards(const CarEntry* carEntry, const Ride& c
_vehicleMotionTrackFlags |= VEHICLE_UPDATE_MOTION_TRACK_FLAG_5;
_vehicleVelocityF64E0C -= remaining_distance - 0x368A;
remaining_distance = 0x368A;
- acceleration = AccelerationFromPitch[EnumValue(pitch)];
+ acceleration = Geometry::getAccelerationFromPitch(pitch);
_vehicleUnkF64E10++;
return Vehicle::UpdateMiniGolfSubroutineStatus::restart;
}
@@ -8179,7 +8100,7 @@ bool Vehicle::UpdateTrackMotionBackwards(const CarEntry* carEntry, const Ride& c
vEBP->velocity = vEDI->velocity >> 1;
}
_vehicleMotionTrackFlags |= VEHICLE_UPDATE_MOTION_TRACK_FLAG_2;
- acceleration = AccelerationFromPitch[EnumValue(pitch)];
+ acceleration = Geometry::getAccelerationFromPitch(pitch);
_vehicleUnkF64E10++;
return UpdateMiniGolfSubroutineStatus::restart;
}
@@ -8191,7 +8112,7 @@ bool Vehicle::UpdateTrackMotionBackwards(const CarEntry* carEntry, const Ride& c
Loc6DCDE4(curRide);
return UpdateMiniGolfSubroutineStatus::stop;
}
- acceleration += AccelerationFromPitch[EnumValue(pitch)];
+ acceleration += Geometry::getAccelerationFromPitch(pitch);
_vehicleUnkF64E10++;
}
}
@@ -8205,7 +8126,7 @@ bool Vehicle::UpdateTrackMotionBackwards(const CarEntry* carEntry, const Ride& c
void Vehicle::UpdateTrackMotionMiniGolfVehicle(const Ride& curRide, const RideObjectEntry& rideEntry, const CarEntry* carEntry)
{
_vehicleUnkF64E10 = 1;
- acceleration = AccelerationFromPitch[EnumValue(pitch)];
+ acceleration = Geometry::getAccelerationFromPitch(pitch);
if (!HasFlag(VehicleFlags::MoveSingleCar))
{
remaining_distance = _vehicleVelocityF64E0C + remaining_distance;
@@ -8531,7 +8452,7 @@ void Vehicle::UpdateTrackMotionPreUpdate(
{
car.UpdateAdditionalAnimation();
}
- car.acceleration = AccelerationFromPitch[EnumValue(car.pitch)];
+ car.acceleration = Geometry::getAccelerationFromPitch(car.pitch);
_vehicleUnkF64E10 = 1;
if (!car.HasFlag(VehicleFlags::MoveSingleCar))
@@ -8559,7 +8480,7 @@ void Vehicle::UpdateTrackMotionPreUpdate(
{
break;
}
- car.acceleration += AccelerationFromPitch[EnumValue(car.pitch)];
+ car.acceleration += Geometry::getAccelerationFromPitch(car.pitch);
_vehicleUnkF64E10++;
continue;
}
@@ -8577,7 +8498,7 @@ void Vehicle::UpdateTrackMotionPreUpdate(
{
break;
}
- car.acceleration = AccelerationFromPitch[EnumValue(car.pitch)];
+ car.acceleration = Geometry::getAccelerationFromPitch(car.pitch);
_vehicleUnkF64E10++;
continue;
}
diff --git a/src/openrct2/ride/VehicleData.cpp b/src/openrct2/ride/VehicleData.cpp
index 9bf2f47d27..ad3f4fd10d 100644
--- a/src/openrct2/ride/VehicleData.cpp
+++ b/src/openrct2/ride/VehicleData.cpp
@@ -794,132 +794,4 @@ const uint8_t MotionSimulatorTimeToSpriteMap[] = {
};
const int32_t MotionSimulatorTimeToSpriteMapCount = static_cast(std::size(MotionSimulatorTimeToSpriteMap));
-
-/** rct2: 0x009A2930
-The distance between subposition points in a movement direction (but not distance).
-*/
-const int32_t SubpositionTranslationDistances[] = {
- // For a base length of 8716 (0x220C) on the horizontal and 6554 (0x199A) on the vertical,
- // use the Pythagoras theorem and round up.
- 0, // no movement
- 8716, // X translation
- 8716, // Y translation
- 12327, // XY translation
- 6554, // Z translation
- 10905, // XZ translation
- 10905, // YZ translation
- 13961, // XYZ translation
- // For the reverser car, multiply the horizontal distance by 2.5 and the vertical distance by 4.072.
- 0, // no movement
- 21790, // X translation
- 21790, // Y translation
- 30817, // Z translation
- 16385, // XY translation
- 27262, // XZ translation
- 27262, // YZ translation
- 34902, // XYZ translation
-};
-
-/** rct2: 0x009A2970 */
-const int32_t AccelerationFromPitch[] = {
- 0, // Flat
- // The geometric angle of slopes 12.5 and 25 are actually 11.1 and 22.2 respectively.
- -124548, // 1 Slope Up 12.5
- -243318, // 2 Slope Up 25
- -416016, // 3 Slope Up 42.5
- -546342, // 4 Slope Up 60
- 124548, // 5 Slope Down 12.5
- 243318, // 6 Slope Down 25
- 416016, // 7 Slope Down 42.5
- 546342, // 8 Slope Down 60
- -617604, // 9 Slope Up 75
- -642000, // 10 Slope Up 90
- -620172, // 11 Slope Up 105
- -555972, // 12 Slope Up 120
- -453894, // 13 Slope Up 135
- -321000, // 14 Slope Up 150
- -166278, // 15 Slope Up 165
- 0, // 16 Fully Inverted
- 617604, // 17 Slope Down 75
- 642000, // 18 Slope Down 90
- 620172, // 19 Slope Down 105
- 555972, // 20 Slope Down 120
- 453894, // 21 Slope Down 135
- 321000, // 22 Slope Down 150
- 166278, // 23 Slope Down 165
- -321000, // 24 Corkscrew Right Up 0
- -555972, // 25 Corkscrew Right Up 1
- -642000, // 26 Corkscrew Right Up 2
- -555972, // 27 Corkscrew Right Up 3
- -321000, // 28 Corkscrew Right Up 4
- 321000, // 29 Corkscrew Right Down 4
- 555972, // 30 Corkscrew Right Down 3
- 642000, // 31 Corkscrew Right Down 2
- 555972, // 32 Corkscrew Right Down 1
- 321000, // 33 Corkscrew Right Down 0
- -321000, // 34 Corkscrew Left Up 0
- -555972, // 35 Corkscrew Left Up 1
- -642000, // 36 Corkscrew Left Up 2
- -555972, // 37 Corkscrew Left Up 3
- -321000, // 38 Corkscrew Left Up 4
- 321000, // 39 Corkscrew Left Down 4
- 555972, // 40 Corkscrew Left Down 2
- 642000, // 41 Corkscrew Left Down 1
- 555972, // 42 Corkscrew Left Down 1
- 321000, // 43 Corkscrew Left Down 0
- -33384, // 44 Half Helix Up Large
- -55854, // 45 Half Helix Up Small
- 33384, // 46 Half Helix Down Large
- 55854, // 47 Half Helix Down Small
- -66768, // 48 Quarter Helix Up
- 66768, // 49 Quarter Helix Down
- // currently only diagonal elements use slopes angles 8, 16, 50. Diagonal gentle-to-steep transition uses
- // diagonal sprites of slopes 25 and 42.
- -90522, // 50 Slope Up 8
- -179760, // 51 Slope Down 16
- -484068, // 52 Slope Up 50
- 90522, // 53 Slope Down 8
- 179760, // 54 Slope Down 16
- 484068, // 55 Slope Down 50
- 243318, // 56 Inverting Loop Down 25
- 416016, // 57 Inverting Loop Down 42.5
- 546342, // 58 Inverting Loop Down 60
- -110424, // 59 Slope Up Spiral Lift Hill
-};
-
-/** rct2: 0x009A3684 */
-const int32_t SpriteDirectionToSoundDirection[] = {
- -0x4000, // 0
- -0x3000, // 1
- -0x2000, // 2
- -0x1000, // 3
- 0, // 4
- 0x1000, // 5
- 0x2000, // 6
- 0x3000, // 7
- 0x4000, // 8
- 0x4800, // 9
- 0x4800, // 10
- 0x4800, // 11
- 0x4800, // 12
- 0x4800, // 13
- 0x4800, // 14
- 0x4800, // 15
- 0x4000, // 16
- 0x3000, // 17
- 0x2000, // 18
- 0x1000, // 19
- 0, // 20
- -0x1000, // 21
- -0x2000, // 22
- -0x3000, // 23
- -0x4000, // 24
- -0x4800, // 25
- -0x4800, // 26
- -0x4800, // 27
- -0x4800, // 28
- -0x4800, // 29
- -0x4800, // 30
- -0x4800, // 31
-};
// clang-format on
diff --git a/src/openrct2/ride/VehicleData.h b/src/openrct2/ride/VehicleData.h
index 5a7c47c80a..8665a430d5 100644
--- a/src/openrct2/ride/VehicleData.h
+++ b/src/openrct2/ride/VehicleData.h
@@ -25,8 +25,3 @@ extern const TopSpinTimeToSpriteMap* TopSpinTimeToSpriteMaps[];
extern const uint8_t MotionSimulatorTimeToSpriteMap[];
extern const int32_t MotionSimulatorTimeToSpriteMapCount;
-
-extern const int32_t SubpositionTranslationDistances[];
-extern const int32_t AccelerationFromPitch[];
-
-extern const int32_t SpriteDirectionToSoundDirection[];
diff --git a/src/openrct2/ride/VehicleGeometry.cpp b/src/openrct2/ride/VehicleGeometry.cpp
new file mode 100644
index 0000000000..d834bb1e84
--- /dev/null
+++ b/src/openrct2/ride/VehicleGeometry.cpp
@@ -0,0 +1,298 @@
+/*****************************************************************************
+ * Copyright (c) 2014-2025 OpenRCT2 developers
+ *
+ * For a complete list of all authors, please refer to contributors.md
+ * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
+ *
+ * OpenRCT2 is licensed under the GNU General Public License version 3.
+ *****************************************************************************/
+
+#include "VehicleGeometry.h"
+
+#include
+
+namespace OpenRCT2::RideVehicle::Geometry
+{
+
+ // clang-format off
+ /** rct2: 0x009A2930 */
+ constexpr auto kSubpositionTranslationDistances = std::to_array({
+ // For a base length of 8716 (0x220C) on the horizontal and 6554 (0x199A) on the vertical,
+ // use the Pythagoras theorem and round up.
+ 0, // no movement
+ 8716, // X translation
+ 8716, // Y translation
+ 12327, // XY translation
+ 6554, // Z translation
+ 10905, // XZ translation
+ 10905, // YZ translation
+ 13961, // XYZ translation
+ // For the reverser car, multiply the horizontal distance by 2.5 and the vertical distance by 4.072.
+ 0, // no movement
+ 21790, // X translation
+ 21790, // Y translation
+ 30817, // Z translation
+ 16385, // XY translation
+ 27262, // XZ translation
+ 27262, // YZ translation
+ 34902, // XYZ translation
+ });
+ // clang-format on
+ static_assert(std::size(kSubpositionTranslationDistances) == 16);
+
+ /** rct2: 0x009A36C4 */
+ const auto kFreeroamVehicleMovementData = std::to_array({
+ { -1, 0, 8716 }, { -1, 0, 8716 }, { -1, 0, 8716 }, { -1, 1, 12327 }, { -1, 1, 12327 }, { -1, 1, 12327 },
+ { 0, 1, 8716 }, { -1, 1, 12327 }, { 0, 1, 8716 }, { 0, 1, 8716 }, { 0, 1, 8716 }, { 1, 1, 12327 },
+ { 1, 1, 12327 }, { 1, 1, 12327 }, { 1, 0, 8716 }, { 1, 1, 12327 }, { 1, 0, 8716 }, { 1, 0, 8716 },
+ { 1, 0, 8716 }, { 1, -1, 12327 }, { 1, -1, 12327 }, { 1, -1, 12327 }, { 0, -1, 8716 }, { 1, -1, 12327 },
+ { 0, -1, 8716 }, { 0, -1, 8716 }, { 0, -1, 8716 }, { -1, -1, 12327 }, { -1, -1, 12327 }, { -1, -1, 12327 },
+ { -1, 0, 8716 }, { -1, -1, 12327 },
+ });
+ static_assert(std::size(kFreeroamVehicleMovementData) == 32);
+
+ /** rct2: 0x009A2970 */
+ constexpr auto kAccelerationFromPitch = std::to_array({
+ 0, // Flat
+ -124548, // 1 Slope Up 12.5
+ -243318, // 2 Slope Up 25
+ -416016, // 3 Slope Up 42.5
+ -546342, // 4 Slope Up 60
+ 124548, // 5 Slope Down 12.5
+ 243318, // 6 Slope Down 25
+ 416016, // 7 Slope Down 42.5
+ 546342, // 8 Slope Down 60
+ -617604, // 9 Slope Up 75
+ -642000, // 10 Slope Up 90
+ -620172, // 11 Slope Up 105
+ -555972, // 12 Slope Up 120
+ -453894, // 13 Slope Up 135
+ -321000, // 14 Slope Up 150
+ -166278, // 15 Slope Up 165
+ 0, // 16 Fully Inverted
+ 617604, // 17 Slope Down 75
+ 642000, // 18 Slope Down 90
+ 620172, // 19 Slope Down 105
+ 555972, // 20 Slope Down 120
+ 453894, // 21 Slope Down 135
+ 321000, // 22 Slope Down 150
+ 166278, // 23 Slope Down 165
+ -321000, // 24 Corkscrew Right Up 0
+ -555972, // 25 Corkscrew Right Up 1
+ -642000, // 26 Corkscrew Right Up 2
+ -555972, // 27 Corkscrew Right Up 3
+ -321000, // 28 Corkscrew Right Up 4
+ 321000, // 29 Corkscrew Right Down 4
+ 555972, // 30 Corkscrew Right Down 3
+ 642000, // 31 Corkscrew Right Down 2
+ 555972, // 32 Corkscrew Right Down 1
+ 321000, // 33 Corkscrew Right Down 0
+ -321000, // 34 Corkscrew Left Up 0
+ -555972, // 35 Corkscrew Left Up 1
+ -642000, // 36 Corkscrew Left Up 2
+ -555972, // 37 Corkscrew Left Up 3
+ -321000, // 38 Corkscrew Left Up 4
+ 321000, // 39 Corkscrew Left Down 4
+ 555972, // 40 Corkscrew Left Down 2
+ 642000, // 41 Corkscrew Left Down 1
+ 555972, // 42 Corkscrew Left Down 1
+ 321000, // 43 Corkscrew Left Down 0
+ -33384, // 44 Half Helix Up Large
+ -55854, // 45 Half Helix Up Small
+ 33384, // 46 Half Helix Down Large
+ 55854, // 47 Half Helix Down Small
+ -66768, // 48 Quarter Helix Up
+ 66768, // 49 Quarter Helix Down
+ -90522, // 50 Slope Up 8
+ -179760, // 51 Slope Down 16
+ -484068, // 52 Slope Up 50
+ 90522, // 53 Slope Down 8
+ 179760, // 54 Slope Down 16
+ 484068, // 55 Slope Down 50
+ 243318, // 56 Inverting Loop Down 25
+ 416016, // 57 Inverting Loop Down 42.5
+ 546342, // 58 Inverting Loop Down 60
+ -110424, // 59 Slope Up Spiral Lift Hill
+ 110424, // 60 Slope Down Spiral Lift Hill
+ });
+ static_assert(std::size(kAccelerationFromPitch) == EnumValue(VehiclePitch::pitchCount));
+
+ /** rct2: 0x009A37E4
+ * rct2: 0x009A38D4
+ */
+ constexpr auto kPitchToDirectionVectorInt32 = std::to_array({
+ { 2147483647, 0 }, // flat
+ { 2106585154, 417115092 }, // up12
+ { 1985590284, 817995863 }, // up25
+ { 1636362342, 1390684831 }, // up42
+ { 1127484953, 1827693544 }, // up60
+ { 2106585154, -417115092 }, // down12
+ { 1985590284, -817995863 }, // down25
+ { 1636362342, -1390684831 }, // down42
+ { 1127484953, -1827693544 }, // down60
+ { 58579923, 2066040965 }, // up75
+ { 0, 2147483647 }, // up90
+ { -555809667, 2074309916 }, // up115
+ { -1073741824, 1859775393 }, // up120
+ { -1518500249, 1518500249 }, // up135
+ { -1859775391, 1073741824 }, // up150
+ { -2074309916, 555809666 }, // up165
+ { -2147483647, 0 }, // inverted
+ { 58579923, -2066040965 }, // down75
+ { 0, -2147483647 }, // down90
+ { -555809667, -2074309916 }, // down115
+ { -1073741824, -1859775393 }, // down120
+ { -1518500249, -1518500249 }, // down135
+ { -1859775391, -1073741824 }, // down150
+ { -2074309916, -555809666 }, // down165
+ { 1859775393, 1073741824 }, // corkscrewUpRight0
+ { 1073741824, 1859775393 }, // corkscrewUpRight1
+ { 0, 2147483647 }, // corkscrewUpRight2
+ { -1073741824, 1859775393 }, // corkscrewUpRight3
+ { -1859775393, 1073741824 }, // corkscrewUpRight4
+ { 1859775393, -1073741824 }, // corkscrewDownLeft0
+ { 1073741824, -1859775393 }, // corkscrewDownLeft1
+ { 0, -2147483647 }, // corkscrewDownLeft2
+ { -1073741824, -1859775393 }, // corkscrewDownLeft3
+ { -1859775393, -1073741824 }, // corkscrewDownLeft4
+ { 1859775393, 1073741824 }, // corkscrewUpLeft0
+ { 1073741824, 1859775393 }, // corkscrewUpLeft1
+ { 0, 2147483647 }, // corkscrewUpLeft2
+ { -1073741824, 1859775393 }, // corkscrewUpLeft3
+ { -1859775393, 1073741824 }, // corkscrewUpLeft4
+ { 1859775393, -1073741824 }, // corkscrewDownRight0
+ { 1073741824, -1859775393 }, // corkscrewDownRight1
+ { 0, -2147483647 }, // corkscrewDownRight2
+ { -1073741824, -1859775393 }, // corkscrewDownRight3
+ { -1859775393, -1073741824 }, // corkscrewDownRight4
+ { 2144540595, 112390610 }, // upHalfHelixLarge
+ { 2139311823, 187165532 }, // upHalfHelixSmall
+ { 2144540595, -112390610 }, // downHalfHelixLarge
+ { 2139311823, -187165532 }, // downHalfHelixSmall
+ { 2135719507, 224473165 }, // upQuarterHelix
+ { 2135719507, -224473165 }, // downQuarterHelix
+ { 2125953864, 303325208 }, // up8
+ { 2061796213, 600568389 }, // up16
+ { 1411702590, 1618265062 }, // up50
+ { 2125953864, -303325208 }, // down8
+ { 2061796213, -600568389 }, // down16
+ { 1411702590, -1618265062 }, // down50
+ { 1985590284, -817995863 }, // uninvertingDown25
+ { 1636362342, -1390684831 }, // uninvertingDown42
+ { 1127484953, -1827693544 }, // uninvertingDown60
+ { 2115506168, 369214930 }, // curvedLifthillUp
+ { 2115506168, -369214930 }, // curvedLiftHillDown
+ });
+ static_assert(std::size(kPitchToDirectionVectorInt32) == EnumValue(VehiclePitch::pitchCount));
+
+ /** rct2: 0x009A39C4 */
+ const auto kRollHorizontalComponent = std::to_array({
+ 2147483647, 2096579710, 1946281152, 2096579710, 1946281152, 1380375879, 555809667,
+ -372906620, -1231746017, -1859775391, 1380375879, 555809667, -372906620, -1231746017,
+ -1859775391, 0, 2096579710, 1946281152, 2096579710, 1946281152,
+ });
+ static_assert(std::size(kRollHorizontalComponent) == EnumValue(VehicleRoll::rollCount));
+
+ /** rct2: 0x009A3684 */
+ const auto kSpriteDirectionToSoundDirection = std::to_array({
+ -0x4000, // 0
+ -0x3000, // 1
+ -0x2000, // 2
+ -0x1000, // 3
+ 0, // 4
+ 0x1000, // 5
+ 0x2000, // 6
+ 0x3000, // 7
+ 0x4000, // 8
+ 0x4800, // 9
+ 0x4800, // 10
+ 0x4800, // 11
+ 0x4800, // 12
+ 0x4800, // 13
+ 0x4800, // 14
+ 0x4800, // 15
+ 0x4000, // 16
+ 0x3000, // 17
+ 0x2000, // 18
+ 0x1000, // 19
+ 0, // 20
+ -0x1000, // 21
+ -0x2000, // 22
+ -0x3000, // 23
+ -0x4000, // 24
+ -0x4800, // 25
+ -0x4800, // 26
+ -0x4800, // 27
+ -0x4800, // 28
+ -0x4800, // 29
+ -0x4800, // 30
+ -0x4800, // 31
+ });
+
+ /** rct2: 0x009A3AC4, 0x009A3AC6 */
+ const auto kCrashDirectionComponents = std::to_array({
+ { -256, 0 },
+ { -236, 98 },
+ { -181, 181 },
+ { -98, 236 },
+ { 0, 256 },
+ { 98, 236 },
+ { 181, 181 },
+ { 236, 98 },
+ { 256, 0 },
+ { 236, -98 },
+ { 181, -181 },
+ { 98, -236 },
+ { 0, -256 },
+ { -98, -236 },
+ { -181, -181 },
+ { -236, -98 },
+ });
+ static_assert(std::size(kCrashDirectionComponents) == 16);
+
+ Unk9A36C4Struct getFreeroamVehicleMovementData(uint8_t orientation)
+ {
+ return kFreeroamVehicleMovementData[orientation];
+ }
+
+ int32_t getRollHorizontalComponent(VehicleRoll roll)
+ {
+ return kRollHorizontalComponent[EnumValue(roll)];
+ }
+
+ int32_t getSoundDirectionFromOrientation(uint8_t orientation)
+ {
+ return kSpriteDirectionToSoundDirection[orientation];
+ }
+
+ CoordsXY getCrashDirectionComponents(uint8_t orientation)
+ {
+ return kCrashDirectionComponents[orientation / 2];
+ }
+
+ int32_t getTranslationDistance(CoordsXYZ distance, bool useReverserDistance)
+ {
+ uint8_t index = ((distance.x != 0) << 0) | ((distance.y != 0) << 1) | ((distance.z != 0) << 2)
+ | ((useReverserDistance) << 3);
+ return kSubpositionTranslationDistances[index];
+ }
+
+ int32_t getAccelerationFromPitch(VehiclePitch pitch)
+ {
+ if (pitch >= VehiclePitch::pitchCount)
+ {
+ return 0;
+ }
+ return kAccelerationFromPitch[EnumValue(pitch)];
+ }
+
+ CoordsXY getPitchVector32(VehiclePitch pitch)
+ {
+ if (pitch >= VehiclePitch::pitchCount)
+ {
+ pitch = VehiclePitch::flat;
+ }
+ return kPitchToDirectionVectorInt32[EnumValue(pitch)];
+ }
+
+} // namespace OpenRCT2::RideVehicle::Geometry
diff --git a/src/openrct2/ride/VehicleGeometry.h b/src/openrct2/ride/VehicleGeometry.h
new file mode 100644
index 0000000000..4d2e64958c
--- /dev/null
+++ b/src/openrct2/ride/VehicleGeometry.h
@@ -0,0 +1,44 @@
+/*****************************************************************************
+ * Copyright (c) 2014-2025 OpenRCT2 developers
+ *
+ * For a complete list of all authors, please refer to contributors.md
+ * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
+ *
+ * OpenRCT2 is licensed under the GNU General Public License version 3.
+ *****************************************************************************/
+
+#pragma once
+
+#include "../core/EnumUtils.hpp"
+#include "../world/Location.hpp"
+#include "Angles.h"
+
+#include
+
+namespace OpenRCT2::RideVehicle::Geometry
+{
+ struct Unk9A36C4Struct
+ {
+ int16_t x;
+ int16_t y;
+ uint32_t distance;
+ };
+
+ Unk9A36C4Struct getFreeroamVehicleMovementData(uint8_t orientation);
+
+ int32_t getRollHorizontalComponent(VehicleRoll roll);
+
+ int32_t getSoundDirectionFromOrientation(uint8_t orientation);
+
+ CoordsXY getCrashDirectionComponents(uint8_t orientation);
+
+ /** The distance between subposition points in a movement vector.
+ * Squashes vector components to 0 or !0, so vector length is ignored.
+ */
+ int32_t getTranslationDistance(CoordsXYZ distance, bool useReverserDistance);
+
+ int32_t getAccelerationFromPitch(VehiclePitch pitch);
+
+ CoordsXY getPitchVector32(VehiclePitch pitch);
+
+} // namespace OpenRCT2::RideVehicle::Geometry