From 1f251ff817b0e068d67503defc7bb7c3af484e11 Mon Sep 17 00:00:00 2001 From: jonschz <17198703+jonschz@users.noreply.github.com> Date: Sun, 28 Jul 2024 20:13:18 +0200 Subject: [PATCH] Implement/match `LegoCarRaceActor::FUN_10080590` (#1070) * Implement/match `LegoCarRaceActor::FUN_10080590` * Add vbtable annotations * disable formatter for assertion * Fix BETA10 annotations * Address review comments --------- Co-authored-by: jonschz <jonschz@users.noreply.github.com> --- .../lego/legoomni/include/legocarraceactor.h | 36 ++++++++--- LEGO1/lego/legoomni/src/common/misc.cpp | 2 + .../legoomni/src/entity/legocarraceactor.cpp | 61 +++++++++++++++++-- LEGO1/lego/legoomni/src/race/raceskel.cpp | 2 +- LEGO1/lego/sources/geom/legounkown100db7f4.h | 6 ++ LEGO1/lego/sources/geom/legoweedge.h | 2 + LEGO1/realtime/orientableroi.h | 3 + 7 files changed, 100 insertions(+), 12 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legocarraceactor.h b/LEGO1/lego/legoomni/include/legocarraceactor.h index 6f1c72f4..e1d41dce 100644 --- a/LEGO1/lego/legoomni/include/legocarraceactor.h +++ b/LEGO1/lego/legoomni/include/legocarraceactor.h @@ -7,12 +7,17 @@ // VTABLE: LEGO1 0x100da0c8 LegoAnimActor // VTABLE: LEGO1 0x100da0d8 LegoPathActor // VTABLE: LEGO1 0x100da1a8 LegoCarRaceActor +// VTABLE: BETA10 0x101bea74 LegoRaceActor +// VTABLE: BETA10 0x101bea78 LegoAnimActor +// VTABLE: BETA10 0x101bea90 LegoPathActor +// VTABLE: BETA10 0x101beb80 LegoCarRaceActor // SIZE 0x1a0 class LegoCarRaceActor : public virtual LegoRaceActor { public: LegoCarRaceActor(); // FUNCTION: LEGO1 0x10081660 + // FUNCTION: BETA10 0x100aab10 const char* ClassName() const override // vtable+0x0c { // STRING: LEGO1 0x100f0568 @@ -20,6 +25,7 @@ public: } // FUNCTION: LEGO1 0x10081680 + // FUNCTION: BETA10 0x100aa9e0 MxBool IsA(const char* p_name) const override // vtable+0x10 { return !strcmp(p_name, LegoCarRaceActor::ClassName()) || LegoRaceActor::IsA(p_name); @@ -38,7 +44,7 @@ public: override; // vtable+0x98 MxResult VTable0x9c() override; // vtable+0x9c - virtual void FUN_10080590(float); + virtual void FUN_10080590(float p_float); // FUNCTION: LEGO1 0x10012bb0 virtual void FUN_10012bb0(float p_unk0x14) { m_unk0x14 = p_unk0x14; } @@ -67,12 +73,28 @@ public: // LegoCarRaceActor::`scalar deleting destructor' protected: - float m_unk0x08; // 0x08 - MxU8 m_unk0x0c; // 0x0c - float m_unk0x10; // 0x10 - float m_unk0x14; // 0x14 - float m_unk0x18; // 0x18 - undefined4 m_unk0x1c; // 0x1c + MxFloat m_unk0x08; // 0x08 + MxU8 m_unk0x0c; // 0x0c + + // Could be a multiplier for the maximum speed when going straight + MxFloat m_unk0x10; // 0x10 + + // Could be the acceleration + MxFloat m_unk0x14; // 0x14 + + MxFloat m_unk0x18; // 0x18 + + // Could be the current timestamp for time-based movement + MxFloat m_unk0x1c; // 0x1c }; +// GLOBAL: LEGO1 0x100da0b0 +// LegoCarRaceActor::`vbtable' + +// GLOBAL: LEGO1 0x100da0a8 +// LegoCarRaceActor::`vbtable'{for `LegoAnimActor'} + +// GLOBAL: LEGO1 0x100da098 +// LegoCarRaceActor::`vbtable'{for `LegoRaceActor'} + #endif // LEGOCARRACEACTOR_H diff --git a/LEGO1/lego/legoomni/src/common/misc.cpp b/LEGO1/lego/legoomni/src/common/misc.cpp index 6d879aa1..901810d0 100644 --- a/LEGO1/lego/legoomni/src/common/misc.cpp +++ b/LEGO1/lego/legoomni/src/common/misc.cpp @@ -67,8 +67,10 @@ LegoNavController* NavController() } // FUNCTION: LEGO1 0x10015790 +// FUNCTION: BETA10 0x100e49ff LegoPathActor* UserActor() { + assert(LegoOmni::GetInstance()); return LegoOmni::GetInstance()->GetUserActor(); } diff --git a/LEGO1/lego/legoomni/src/entity/legocarraceactor.cpp b/LEGO1/lego/legoomni/src/entity/legocarraceactor.cpp index b74a652b..3dd009da 100644 --- a/LEGO1/lego/legoomni/src/entity/legocarraceactor.cpp +++ b/LEGO1/lego/legoomni/src/entity/legocarraceactor.cpp @@ -1,5 +1,8 @@ #include "legocarraceactor.h" +#include "geom/legounkown100db7f4.h" +#include "legopathboundary.h" +#include "misc.h" #include "mxmisc.h" #include "mxvariabletable.h" @@ -10,6 +13,7 @@ DECOMP_SIZE_ASSERT(LegoCarRaceActor, 0x1a0) const char* g_fuel = "FUEL"; // FUNCTION: LEGO1 0x10080350 +// FUNCTION: BETA10 0x100cd6b0 LegoCarRaceActor::LegoCarRaceActor() { m_unk0x08 = 1.0f; @@ -27,9 +31,57 @@ LegoCarRaceActor::LegoCarRaceActor() VariableTable()->SetVariable(g_fuel, "0.8"); } -// STUB: LEGO1 0x10080590 -void LegoCarRaceActor::FUN_10080590(float) +// FUNCTION: LEGO1 0x10080590 +// FUNCTION: BETA10 0x100cd8cf +void LegoCarRaceActor::FUN_10080590(float p_float) { + MxFloat maxSpeed = m_maxLinearVel; + Mx3DPointFloat destEdgeUnknownVector; + Mx3DPointFloat worldDirection = Mx3DPointFloat(m_roi->GetWorldDirection()); + + m_destEdge->FUN_1002ddc0(*m_boundary, destEdgeUnknownVector); + + if (abs(destEdgeUnknownVector.Dot(destEdgeUnknownVector.GetData(), worldDirection.GetData())) > 0.5) { + maxSpeed *= m_unk0x10; + } + + MxS32 deltaUnk0x70; + LegoPathActor* userActor = UserActor(); + + if (userActor) { + // All known implementations of LegoPathActor->VTable0x5c() return LegoPathActor::m_unk0x70 + deltaUnk0x70 = m_unk0x70 - userActor->VTable0x5c(); + } + else { + deltaUnk0x70 = 0; + } + + if (deltaUnk0x70 > 1) { + if (deltaUnk0x70 > 3) { + deltaUnk0x70 = 3; + } + + maxSpeed *= (m_unk0x18 * (--deltaUnk0x70) * -0.25f + 1.0f); + } + else if (deltaUnk0x70 < -1) { + maxSpeed *= 1.3; + } + + MxFloat deltaSpeed = maxSpeed - m_worldSpeed; + MxFloat changeInSpeed = (p_float - m_unk0x1c) * m_unk0x14; + m_unk0x1c = p_float; + + if (deltaSpeed < 0.0f) { + changeInSpeed = -changeInSpeed; + } + + MxFloat newWorldSpeed = changeInSpeed + m_worldSpeed; + + if (newWorldSpeed > maxSpeed) { + newWorldSpeed = maxSpeed; + } + + SetWorldSpeed(newWorldSpeed); } // STUB: LEGO1 0x10080740 @@ -37,10 +89,11 @@ void LegoCarRaceActor::VTable0x1c() { } -// STUB: LEGO1 0x10080b40 +// FUNCTION: LEGO1 0x10080b40 +// FUNCTION: BETA10 0x100cdb3c void LegoCarRaceActor::SwitchBoundary(LegoPathBoundary*& p_boundary, LegoUnknown100db7f4*& p_edge, float& p_unk0xe4) { - // TODO + LegoPathActor::SwitchBoundary(m_boundary, m_destEdge, m_unk0xe4); } // STUB: LEGO1 0x10080b70 diff --git a/LEGO1/lego/legoomni/src/race/raceskel.cpp b/LEGO1/lego/legoomni/src/race/raceskel.cpp index dd7e87f3..2d5c71bf 100644 --- a/LEGO1/lego/legoomni/src/race/raceskel.cpp +++ b/LEGO1/lego/legoomni/src/race/raceskel.cpp @@ -1,6 +1,6 @@ #include "raceskel.h" -#include <cassert> +#include <assert.h> DECOMP_SIZE_ASSERT(RaceSkel, 0x178) diff --git a/LEGO1/lego/sources/geom/legounkown100db7f4.h b/LEGO1/lego/sources/geom/legounkown100db7f4.h index 4e6ffead..68f4c9f2 100644 --- a/LEGO1/lego/sources/geom/legounkown100db7f4.h +++ b/LEGO1/lego/sources/geom/legounkown100db7f4.h @@ -5,6 +5,8 @@ #include "legowegedge.h" #include "mxgeometry/mxgeometry3d.h" +#include <assert.h> + // VTABLE: LEGO1 0x100db7f4 // SIZE 0x40 struct LegoUnknown100db7f4 : public LegoEdge { @@ -28,6 +30,10 @@ public: p_point[2] = -m_unk0x28[2]; } else { + // clang-format off + // FIXME: There is no * dereference in the original assertion + assert(p_f.IsEqual( *m_faceB )); + // clang-format on p_point = m_unk0x28; } diff --git a/LEGO1/lego/sources/geom/legoweedge.h b/LEGO1/lego/sources/geom/legoweedge.h index 74dc6a45..6e5f4548 100644 --- a/LEGO1/lego/sources/geom/legoweedge.h +++ b/LEGO1/lego/sources/geom/legoweedge.h @@ -20,6 +20,8 @@ public: // FUNCTION: BETA10 0x1001cc30 LegoEdge** GetEdges() { return m_edges; } + // TODO: The assertion at BETA10 0x10037352 suggests that this function might take a pointer instead of a reference + // FUNCTION: BETA10 0x100373f0 LegoU32 IsEqual(LegoWEEdge& p_other) { return this == &p_other; } void SetEdges(LegoEdge** p_edges, LegoU8 p_numEdges) diff --git a/LEGO1/realtime/orientableroi.h b/LEGO1/realtime/orientableroi.h index 54059f20..ad84d9ed 100644 --- a/LEGO1/realtime/orientableroi.h +++ b/LEGO1/realtime/orientableroi.h @@ -43,7 +43,10 @@ public: const Matrix4& GetLocal2World() const { return m_local2world; } const float* GetWorldPosition() const { return m_local2world[3]; } + + // FUNCTION: BETA10 0x10011780 const float* GetWorldDirection() const { return m_local2world[2]; } + const float* GetWorldUp() const { return m_local2world[1]; } OrientableROI* GetParentROI() const { return m_parentROI; }