Clear unknowns in LegoCarRaceActor (#1748)

This commit is contained in:
Fabian Neundorf 2026-03-13 23:09:17 +01:00 committed by GitHub
parent a6ee94b680
commit 2c20492bf6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 82 additions and 75 deletions

View File

@ -53,27 +53,33 @@ class LegoCarRaceActor : public virtual LegoRaceActor {
// LegoCarRaceActor vtable
virtual void FUN_10080590(float p_time); // vtable+0x00
virtual void UpdateWorldSpeed(float p_time); // vtable+0x00
// FUNCTION: LEGO1 0x10012bb0
virtual void FUN_10012bb0(float p_unk0x14) { m_unk0x14 = p_unk0x14; } // vtable+0x04
virtual void SetAcceleration(float p_acceleration) { m_acceleration = p_acceleration; } // vtable+0x04
// FUNCTION: LEGO1 0x10012bc0
virtual float FUN_10012bc0() { return m_unk0x14; } // vtable+0x08
virtual float GetAcceleration() { return m_acceleration; } // vtable+0x08
// FUNCTION: LEGO1 0x10012bd0
virtual void FUN_10012bd0(float p_unk0x10) { m_unk0x10 = p_unk0x10; } // vtable+0x0c
virtual void SetCurveSpeedFactor(float p_curveSpeedFactor)
{
m_curveSpeedFactor = p_curveSpeedFactor;
} // vtable+0x0c
// FUNCTION: LEGO1 0x10012be0
virtual float FUN_10012be0() { return m_unk0x10; } // vtable+0x10
virtual float GetCurveSpeedFactor() { return m_curveSpeedFactor; } // vtable+0x10
// FUNCTION: LEGO1 0x10012bf0
virtual void FUN_10012bf0(float p_unk0x18) { m_unk0x18 = p_unk0x18; } // vtable+0x14
virtual void SetRubberBandFactor(float p_rubberBandFactor)
{
m_rubberBandFactor = p_rubberBandFactor;
} // vtable+0x14
// FUNCTION: LEGO1 0x10012c00
virtual float FUN_10012c00() { return m_unk0x18; } // vtable+0x18
virtual float GetRubberBandFactor() { return m_rubberBandFactor; } // vtable+0x18
virtual MxS32 VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_edge); // vtable+0x1c
virtual MxS32 HandleJump(LegoPathBoundary* p_boundary, LegoEdge* p_edge); // vtable+0x1c
// SYNTHETIC: LEGO1 0x10012c30
// LegoCarRaceActor::`vbase destructor'
@ -88,18 +94,18 @@ class LegoCarRaceActor : public virtual LegoRaceActor {
MxFloat m_unk0x08; // 0x08
MxU8 m_animState; // 0x0c
// Could be a multiplier for the maximum speed when going straight
MxFloat m_unk0x10; // 0x10
// A multiplier for the maximum speed when going around a curve
MxFloat m_curveSpeedFactor; // 0x10
// Could be the acceleration
MxFloat m_unk0x14; // 0x14
MxFloat m_acceleration; // 0x14
MxFloat m_unk0x18; // 0x18
MxFloat m_rubberBandFactor; // 0x18
// Could be the current timestamp for time-based movement
MxFloat m_unk0x1c; // 0x1c
MxFloat m_lastAcceleration; // 0x1c
static MxFloat g_unk0x100f7aec;
static MxFloat g_maxSpeed;
};
// VTABLE: LEGO1 0x100da208 LegoCarRaceActor
@ -139,7 +145,7 @@ class LegoJetskiRaceActor : public virtual LegoCarRaceActor {
Vector3& p_intersectionPoint
) override; // vtable+0x6c
void Animate(float p_time) override; // vtable+0x70
MxS32 VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_edge) override; // vtable+0x1c
MxS32 HandleJump(LegoPathBoundary* p_boundary, LegoEdge* p_edge) override; // vtable+0x1c
// SYNTHETIC: LEGO1 0x10013a80
// LegoJetskiRaceActor::`vbase destructor'

View File

@ -414,7 +414,7 @@ void LegoRaceCar::Animate(float p_time)
UpdateMapLocatorPosition();
if (!m_userNavFlag) {
FUN_10080590(p_time);
UpdateWorldSpeed(p_time);
return;
}
@ -613,7 +613,7 @@ void LegoJetski::Animate(float p_time)
UpdateMapLocatorPosition();
if (!m_userNavFlag) {
FUN_10080590(p_time);
UpdateWorldSpeed(p_time);
return;
}

View File

@ -32,11 +32,11 @@ const char* g_fuel = "FUEL";
const char* g_racing = "RACING";
// GLOBAL: LEGO1 0x100f7aec
MxFloat LegoCarRaceActor::g_unk0x100f7aec = 8.0f;
MxFloat LegoCarRaceActor::g_maxSpeed = 8.0f;
// GLOBAL: LEGO1 0x100da044
// GLOBAL: BETA10 0x101be9fc
MxFloat g_unk0x100da044 = 8.0f;
MxFloat g_maxWorldSpeed = 8.0f;
// FUNCTION: LEGO1 0x10080350
// FUNCTION: BETA10 0x100cd6b0
@ -47,10 +47,10 @@ LegoCarRaceActor::LegoCarRaceActor()
m_animState = 0;
m_maxLinearVel = 0.0f;
m_frequencyFactor = 1.0f;
m_unk0x1c = 0;
m_unk0x10 = 0.65f;
m_unk0x14 = 0.03f;
m_unk0x18 = 0.6f;
m_lastAcceleration = 0;
m_curveSpeedFactor = 0.65f;
m_acceleration = 0.03f;
m_rubberBandFactor = 0.6f;
m_wallHitDirectionFactor = 0.1f;
m_linearRotationRatio = -5.0f;
m_canRotate = 1;
@ -59,43 +59,43 @@ LegoCarRaceActor::LegoCarRaceActor()
// FUNCTION: LEGO1 0x10080590
// FUNCTION: BETA10 0x100cd8cf
void LegoCarRaceActor::FUN_10080590(float p_time)
void LegoCarRaceActor::UpdateWorldSpeed(float p_time)
{
MxFloat maxSpeed = m_maxLinearVel;
Mx3DPointFloat destEdgeUnknownVector;
Mx3DPointFloat edgeNormal;
Mx3DPointFloat worldDirection = Mx3DPointFloat(m_roi->GetWorldDirection());
m_destEdge->GetFaceNormal(*m_boundary, destEdgeUnknownVector);
m_destEdge->GetFaceNormal(*m_boundary, edgeNormal);
if (abs(destEdgeUnknownVector.Dot(destEdgeUnknownVector.GetData(), worldDirection.GetData())) > 0.5) {
maxSpeed *= m_unk0x10;
if (abs(edgeNormal.Dot(edgeNormal.GetData(), worldDirection.GetData())) > 0.5) {
maxSpeed *= m_curveSpeedFactor;
}
MxS32 deltaUnk0x70;
MxS32 deltaPathStructs;
LegoPathActor* userActor = UserActor();
if (userActor) {
// All known implementations of LegoPathActor->GetLastPathStruct() return LegoPathActor::m_lastPathStruct
deltaUnk0x70 = m_lastPathStruct - userActor->GetLastPathStruct();
deltaPathStructs = m_lastPathStruct - userActor->GetLastPathStruct();
}
else {
deltaUnk0x70 = 0;
deltaPathStructs = 0;
}
if (deltaUnk0x70 > 1) {
if (deltaUnk0x70 > 3) {
deltaUnk0x70 = 3;
if (deltaPathStructs > 1) {
if (deltaPathStructs > 3) {
deltaPathStructs = 3;
}
maxSpeed *= (m_unk0x18 * (--deltaUnk0x70) * -0.25f + 1.0f);
maxSpeed *= (m_rubberBandFactor * (--deltaPathStructs) * -0.25f + 1.0f);
}
else if (deltaUnk0x70 < -1) {
else if (deltaPathStructs < -1) {
maxSpeed *= 1.3;
}
MxFloat deltaSpeed = maxSpeed - m_worldSpeed;
MxFloat changeInSpeed = (p_time - m_unk0x1c) * m_unk0x14;
m_unk0x1c = p_time;
MxFloat changeInSpeed = (p_time - m_lastAcceleration) * m_acceleration;
m_lastAcceleration = p_time;
if (deltaSpeed < 0.0f) {
changeInSpeed = -changeInSpeed;
@ -112,16 +112,17 @@ void LegoCarRaceActor::FUN_10080590(float p_time)
// FUNCTION: LEGO1 0x10080740
// FUNCTION: BETA10 0x100cece0
MxS32 LegoCarRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_edge)
MxS32 LegoCarRaceActor::HandleJump(LegoPathBoundary* p_boundary, LegoEdge* p_edge)
{
Mx3DPointFloat pointUnknown;
Mx3DPointFloat targetPosition;
Mx3DPointFloat destEdgeUnknownVector;
Mx3DPointFloat crossProduct;
Mx3DPointFloat targetDirection;
if (m_actorState == c_ready) {
m_boundary = NULL;
// Not sure where the upper bound of 11 comes from, the underlying array has a size of 16
// The first 12 elements are used for the car race, the other 4 for jetski
// As it increments by 2, counting to 10 or 11 is the same.
for (MxS32 i = 0; i < 11; i += 2) {
if (LegoPathController::GetControlEdgeA(i + 1) == m_destEdge) {
m_boundary = LegoPathController::GetControlBoundaryA(i + 1);
@ -147,8 +148,8 @@ MxS32 LegoCarRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_edg
if (LegoPathController::GetControlEdgeA(i) == p_edge) {
m_actorState = c_ready;
if (m_worldSpeed < g_unk0x100f7aec) {
m_worldSpeed = g_unk0x100f7aec;
if (m_worldSpeed < g_maxSpeed) {
m_worldSpeed = g_maxSpeed;
}
m_destEdge = LegoPathController::GetControlEdgeA(i + 1);
@ -167,12 +168,12 @@ MxS32 LegoCarRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_edg
Vector3* v2 = m_destEdge->CWVertex(*m_boundary);
assert(v1 && v2);
LERP3(pointUnknown, *v1, *v2, m_destScale);
LERP3(targetPosition, *v1, *v2, m_destScale);
m_destEdge->GetFaceNormal(*m_boundary, destEdgeUnknownVector);
crossProduct.EqualsCross(*m_boundary->GetUp(), destEdgeUnknownVector);
crossProduct.Unitize();
targetDirection.EqualsCross(*m_boundary->GetUp(), destEdgeUnknownVector);
targetDirection.Unitize();
Mx3DPointFloat worldDirection(Vector3(m_roi->GetWorldDirection()));
@ -181,10 +182,10 @@ MxS32 LegoCarRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_edg
}
worldDirection *= 5.0f;
crossProduct *= 5.0f;
targetDirection *= 5.0f;
MxResult callResult =
SetSpline(Vector3(m_roi->GetWorldPosition()), worldDirection, pointUnknown, crossProduct);
SetSpline(Vector3(m_roi->GetWorldPosition()), worldDirection, targetPosition, targetDirection);
if (callResult) {
m_traveledDistance = 0;
@ -230,7 +231,7 @@ void LegoCarRaceActor::Animate(float p_time)
if (strcmpi(value, g_racing) == 0) {
m_animState = 1;
m_transformTime = p_time - 1.0f;
m_unk0x1c = p_time;
m_lastAcceleration = p_time;
}
}
@ -245,7 +246,7 @@ MxResult LegoCarRaceActor::CalculateSpline()
{
LegoOrientedEdge* d = m_destEdge;
if (VTable0x1c(m_boundary, m_destEdge)) {
if (HandleJump(m_boundary, m_destEdge)) {
LegoPathBoundary* b = m_boundary;
SwitchBoundary(m_boundary, m_destEdge, m_destScale);
@ -256,27 +257,27 @@ MxResult LegoCarRaceActor::CalculateSpline()
Vector3* v2 = m_destEdge->CCWVertex(*m_boundary);
assert(v1 && v2);
Mx3DPointFloat point1;
LERP3(point1, *v1, *v2, m_destScale);
Mx3DPointFloat end;
LERP3(end, *v1, *v2, m_destScale);
Mx3DPointFloat point2;
Mx3DPointFloat point3;
Mx3DPointFloat point4;
Mx3DPointFloat point5;
Mx3DPointFloat startEdgeNormal;
Mx3DPointFloat endEdgeNormal;
Mx3DPointFloat startDirection;
Mx3DPointFloat endDirection;
d->GetFaceNormal(*b, point2);
m_destEdge->GetFaceNormal(*m_boundary, point3);
d->GetFaceNormal(*b, startEdgeNormal);
m_destEdge->GetFaceNormal(*m_boundary, endEdgeNormal);
point4.EqualsCross(point2, *m_boundary->GetUp());
point5.EqualsCross(*m_boundary->GetUp(), point3);
startDirection.EqualsCross(startEdgeNormal, *m_boundary->GetUp());
endDirection.EqualsCross(*m_boundary->GetUp(), endEdgeNormal);
point4.Unitize();
point5.Unitize();
startDirection.Unitize();
endDirection.Unitize();
point4 *= 5.0f;
point5 *= 5.0f;
startDirection *= 5.0f;
endDirection *= 5.0f;
MxResult res = SetSpline(m_roi->GetWorldPosition(), point4, point1, point5);
MxResult res = SetSpline(m_roi->GetWorldPosition(), startDirection, end, endDirection);
#ifdef BETA10
if (res) {
@ -295,15 +296,15 @@ MxResult LegoCarRaceActor::CalculateSpline()
// FUNCTION: BETA10 0x100a8990
LegoJetskiRaceActor::LegoJetskiRaceActor()
{
m_unk0x10 = 0.95f;
m_unk0x14 = 0.04f;
m_unk0x18 = 0.5f;
m_curveSpeedFactor = 0.95f;
m_acceleration = 0.04f;
m_rubberBandFactor = 0.5f;
m_linearRotationRatio = 1.5f;
}
// FUNCTION: LEGO1 0x10081120
// FUNCTION: BETA10 0x100ce19f
MxS32 LegoJetskiRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_edge)
MxS32 LegoJetskiRaceActor::HandleJump(LegoPathBoundary* p_boundary, LegoEdge* p_edge)
{
// These are almost certainly not the correct names, but they produce the correct BETA10 stack
Mx3DPointFloat a;
@ -337,8 +338,8 @@ MxS32 LegoJetskiRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_
if (p_edge == LegoPathController::GetControlEdgeA(12)) {
m_actorState = c_ready;
if (m_worldSpeed < g_unk0x100da044) {
m_worldSpeed = g_unk0x100da044;
if (m_worldSpeed < g_maxWorldSpeed) {
m_worldSpeed = g_maxWorldSpeed;
}
m_destEdge = LegoPathController::GetControlEdgeA(13);
@ -347,8 +348,8 @@ MxS32 LegoJetskiRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_
else if (p_edge == LegoPathController::GetControlEdgeA(14)) {
m_actorState = c_ready;
if (m_worldSpeed < g_unk0x100da044) {
m_worldSpeed = g_unk0x100da044;
if (m_worldSpeed < g_maxWorldSpeed) {
m_worldSpeed = g_maxWorldSpeed;
}
m_destEdge = LegoPathController::GetControlEdgeA(15);
@ -403,7 +404,7 @@ void LegoJetskiRaceActor::Animate(float p_time)
if (!stricmp(raceState, g_racing)) {
m_animState = 1;
m_transformTime = p_time - 1.0f;
m_unk0x1c = p_time;
m_lastAcceleration = p_time;
}
else if (!m_userNavFlag) {
LegoAnimActor::Animate(m_transformTime + 1.0f);