From 0d385e27d001bce3c955fd5c9d7d546dd39fad80 Mon Sep 17 00:00:00 2001 From: jonschz <17198703+jonschz@users.noreply.github.com> Date: Fri, 26 Jul 2024 19:53:09 +0200 Subject: [PATCH] Implement/match `LegoRaceCar::VTable0x94` (#1068) * Implement LegoRaceCar::VTable0x94 * Remove redundant inline modifiers * Fix offsets * Fix minor inconsistency * Address review comments * Address review comments, round 2 --------- Co-authored-by: jonschz --- LEGO1/lego/legoomni/include/legoentity.h | 3 + LEGO1/lego/legoomni/include/legopathactor.h | 8 ++ LEGO1/lego/legoomni/include/legoracers.h | 12 +- LEGO1/lego/legoomni/src/race/legoracers.cpp | 124 +++++++++++++++++++- LEGO1/lego/sources/roi/legoroi.h | 2 + LEGO1/mxgeometry/mxmatrix.h | 2 + LEGO1/omni/include/mxtimer.h | 2 + LEGO1/realtime/orientableroi.h | 2 + 8 files changed, 148 insertions(+), 7 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legoentity.h b/LEGO1/lego/legoomni/include/legoentity.h index b5b4e880..4fb01d61 100644 --- a/LEGO1/lego/legoomni/include/legoentity.h +++ b/LEGO1/lego/legoomni/include/legoentity.h @@ -83,7 +83,10 @@ public: MxBool GetFlagsIsSet(MxU8 p_flag) { return m_flags & p_flag; } MxU8 GetFlags() { return m_flags; } MxFloat GetWorldSpeed() { return m_worldSpeed; } + + // FUNCTION: BETA10 0x1000f2f0 LegoROI* GetROI() { return m_roi; } + MxU8 GetType() { return m_type; } MxBool GetCameraFlag() { return m_cameraFlag; } diff --git a/LEGO1/lego/legoomni/include/legopathactor.h b/LEGO1/lego/legoomni/include/legopathactor.h index 70ee6950..5110c8ee 100644 --- a/LEGO1/lego/legoomni/include/legopathactor.h +++ b/LEGO1/lego/legoomni/include/legopathactor.h @@ -13,6 +13,8 @@ struct LegoPathEdgeContainer; struct LegoUnknown100db7f4; class LegoWEEdge; +extern MxLong g_unk0x100f3308; + // VTABLE: LEGO1 0x100d6e28 // SIZE 0x154 class LegoPathActor : public LegoActor { @@ -124,12 +126,18 @@ public: virtual void VTable0xc8(MxU8 p_unk0x148) { m_unk0x148 = p_unk0x148; } // vtable+0xc8 LegoPathBoundary* GetBoundary() { return m_boundary; } + + // FUNCTION: BETA10 0x1001c860 MxU32 GetState() { return m_state; } + LegoPathController* GetController() { return m_controller; } MxBool GetCollideBox() { return m_collideBox; } void SetBoundary(LegoPathBoundary* p_boundary) { m_boundary = p_boundary; } + + // FUNCTION: BETA10 0x10013430 void SetState(MxU32 p_state) { m_state = p_state; } + void SetController(LegoPathController* p_controller) { m_controller = p_controller; } // SYNTHETIC: LEGO1 0x1002d800 diff --git a/LEGO1/lego/legoomni/include/legoracers.h b/LEGO1/lego/legoomni/include/legoracers.h index f460a050..ab5310a7 100644 --- a/LEGO1/lego/legoomni/include/legoracers.h +++ b/LEGO1/lego/legoomni/include/legoracers.h @@ -88,11 +88,21 @@ private: static EdgeReference g_edgeReferences[]; static const SkeletonKickPhase g_skeletonKickPhases[]; - static const char* g_strSpeedCopy; + static const char* g_strSpeed; + static const char* g_srtsl18to29[]; + static const char* g_srtsl6to10[]; + static const char* g_emptySoundKeyList[]; + static const char* g_srtrh[]; static const char* g_srt001ra; static const char* g_soundSkel3; + static MxU32 g_srtsl18to29Index; + static MxU32 g_srtsl6to10Index; + static MxU32 g_emptySoundKeyListIndex; + static MxU32 g_srtrhIndex; + static MxLong g_timeLastSoundPlayed; static MxS32 g_unk0x100f0b88; static MxBool g_unk0x100f0b8c; + static Mx3DPointFloat g_unk0x10102af0; }; #endif // LEGORACERS_H diff --git a/LEGO1/lego/legoomni/src/race/legoracers.cpp b/LEGO1/lego/legoomni/src/race/legoracers.cpp index c5e227fa..355f3b79 100644 --- a/LEGO1/lego/legoomni/src/race/legoracers.cpp +++ b/LEGO1/lego/legoomni/src/race/legoracers.cpp @@ -12,6 +12,7 @@ #include "mxdebug.h" #include "mxmisc.h" #include "mxnotificationmanager.h" +#include "mxtimer.h" #include "mxutilities.h" #include "mxvariabletable.h" #include "raceskel.h" @@ -66,7 +67,32 @@ const SkeletonKickPhase LegoRaceCar::g_skeletonKickPhases[] = { // GLOBAL: LEGO1 0x100f0b10 // STRING: LEGO1 0x100f09cc -const char* LegoRaceCar::g_strSpeedCopy = "SPEED"; +const char* LegoRaceCar::g_strSpeed = "SPEED"; + +// GLOBAL: LEGO1 0x100f0b18 +const char* LegoRaceCar::g_srtsl18to29[] = { + "srt018sl", + "srt019sl", + "srt020sl", + "srt021sl", + "srt022sl", + "srt023sl", + "srt024sl", + "srt025sl", + "srt026sl", + "srt027sl", + "srt028sl", + "srt029sl" +}; + +// GLOBAL: LEGO1 0x100f0b48 +const char* LegoRaceCar::g_srtsl6to10[] = {"srt006sl", "srt007sl", "srt008sl", "srt009sl", "srt010sl"}; + +// GLOBAL: LEGO1 0x100f0b5c +const char* LegoRaceCar::g_emptySoundKeyList[] = {NULL}; + +// GLOBAL: LEGO1 0x100f0b60 +const char* LegoRaceCar::g_srtrh[] = {"srt004rh", "srt005rh", "srt006rh"}; // GLOBAL: LEGO1 0x100f0b6c // STRING: LEGO1 0x100f08c4 @@ -76,6 +102,21 @@ const char* LegoRaceCar::g_srt001ra = "srt001ra"; // STRING: LEGO1 0x100f08bc const char* LegoRaceCar::g_soundSkel3 = "skel3"; +// GLOBAL: LEGO1 0x100f0b74 +MxU32 LegoRaceCar::g_srtsl18to29Index = 0; + +// GLOBAL: LEGO1 0x100f0b78 +MxU32 LegoRaceCar::g_srtsl6to10Index = 0; + +// GLOBAL: LEGO1 0x100f0b7c +MxU32 LegoRaceCar::g_emptySoundKeyListIndex = 0; + +// GLOBAL: LEGO1 0x100f0b80 +MxU32 LegoRaceCar::g_srtrhIndex = 0; + +// GLOBAL: LEGO1 0x100f0b84 +MxLong LegoRaceCar::g_timeLastSoundPlayed = 0; + // GLOBAL: LEGO1 0x100f0b88 // GLOBAL: BETA10 0x101f5f94 MxS32 LegoRaceCar::g_unk0x100f0b88 = 0; @@ -84,6 +125,10 @@ MxS32 LegoRaceCar::g_unk0x100f0b88 = 0; // GLOBAL: BETA10 0x101f5f98 MxBool LegoRaceCar::g_unk0x100f0b8c = TRUE; +// Initialized at LEGO1 0x10012db0 +// GLOBAL: LEGO1 0x10102af0 +Mx3DPointFloat LegoRaceCar::g_unk0x10102af0 = Mx3DPointFloat(0.0f, 2.0f, 0.0f); + // FUNCTION: LEGO1 0x10012950 LegoRaceCar::LegoRaceCar() { @@ -260,7 +305,6 @@ MxU32 LegoRaceCar::HandleSkeletonKicks(float p_param1) MxTrace( // STRING: BETA10 0x101f64c8 "Got kicked in boundary %s %d %g:%g %g\n", - // TODO: same as in above comparison m_boundary->GetName(), skeletonCurAnimPosition, skeletonCurAnimDuration, @@ -306,7 +350,7 @@ void LegoRaceCar::VTable0x70(float p_float) sprintf(buffer, "%g", absoluteSpeed / maximumSpeed); - VariableTable()->SetVariable(g_strSpeedCopy, buffer); + VariableTable()->SetVariable(g_strSpeed, buffer); if (m_sound) { // pitches up the engine sound based on the velocity @@ -332,11 +376,79 @@ void LegoRaceCar::VTable0x70(float p_float) } } -// STUB: LEGO1 0x100133c0 +// FUNCTION: LEGO1 0x100133c0 +// FUNCTION: BETA10 0x100cbb84 MxResult LegoRaceCar::VTable0x94(LegoPathActor* p_actor, MxBool p_bool) { - // TODO - return 0; + if (!p_actor->GetUserNavFlag()) { + if (p_actor->GetState()) { + return FAILURE; + } + + if (p_bool) { + LegoROI* roi = p_actor->GetROI(); // name verified by BETA10 0x100cbbf5 + assert(roi); + MxMatrix matr; + matr = roi->GetLocal2World(); + + Vector3(matr[3]).Add(g_unk0x10102af0); + roi->FUN_100a58f0(matr); + + p_actor->SetState(2); + } + + if (m_userNavFlag) { + MxBool actorIsStuds = strcmpi(p_actor->GetROI()->GetName(), "studs") == 0; + MxBool actorIsRhoda = strcmpi(p_actor->GetROI()->GetName(), "rhoda") == 0; + MxLong time = Timer()->GetTime(); + + const char* soundKey = NULL; + MxLong timeElapsed = time - g_timeLastSoundPlayed; + + if (timeElapsed > 3000) { + if (p_bool) { + if (actorIsStuds) { + soundKey = g_srtsl18to29[g_srtsl18to29Index++]; + if (g_srtsl18to29Index >= sizeOfArray(g_srtsl18to29)) { + g_srtsl18to29Index = 0; + } + } + else if (actorIsRhoda) { + soundKey = g_emptySoundKeyList[g_emptySoundKeyListIndex++]; + if (g_emptySoundKeyListIndex >= sizeOfArray(g_emptySoundKeyList)) { + g_emptySoundKeyListIndex = 0; + } + } + } + else { + if (actorIsStuds) { + soundKey = g_srtsl6to10[g_srtsl6to10Index++]; + if (g_srtsl6to10Index >= sizeOfArray(g_srtsl6to10)) { + g_srtsl6to10Index = 0; + } + } + else if (actorIsRhoda) { + soundKey = g_srtrh[g_srtrhIndex++]; + if (g_srtrhIndex >= sizeOfArray(g_srtrh)) { + g_srtrhIndex = 0; + } + } + } + + if (soundKey) { + SoundManager()->GetCacheSoundManager()->Play(soundKey, NULL, FALSE); + g_timeLastSoundPlayed = g_unk0x100f3308 = time; + } + } + + if (p_bool && m_worldSpeed != 0) { + return SUCCESS; + } + + return FAILURE; + } + } + return SUCCESS; } // STUB: LEGO1 0x10013600 diff --git a/LEGO1/lego/sources/roi/legoroi.h b/LEGO1/lego/sources/roi/legoroi.h index ef01fddf..d570ac56 100644 --- a/LEGO1/lego/sources/roi/legoroi.h +++ b/LEGO1/lego/sources/roi/legoroi.h @@ -60,7 +60,9 @@ public: ); static LegoBool FUN_100a9cf0(const LegoChar* p_param, unsigned char* paletteEntries, LegoU32 p_numEntries); + // FUNCTION: BETA10 0x1000f320 const LegoChar* GetName() const { return m_name; } + LegoEntity* GetEntity() { return m_entity; } void SetEntity(LegoEntity* p_entity) { m_entity = p_entity; } diff --git a/LEGO1/mxgeometry/mxmatrix.h b/LEGO1/mxgeometry/mxmatrix.h index 1b8bbfbc..5f471a8d 100644 --- a/LEGO1/mxgeometry/mxmatrix.h +++ b/LEGO1/mxgeometry/mxmatrix.h @@ -16,7 +16,9 @@ public: MxMatrix(const Matrix4& p_matrix) : Matrix4(m_elements) { Equals(p_matrix); } + // FUNCTION: BETA10 0x10010860 float* operator[](int idx) { return m_data[idx]; } + const float* operator[](int idx) const { return m_data[idx]; } // FUNCTION: LEGO1 0x10002850 diff --git a/LEGO1/omni/include/mxtimer.h b/LEGO1/omni/include/mxtimer.h index 1e33d548..034b1565 100644 --- a/LEGO1/omni/include/mxtimer.h +++ b/LEGO1/omni/include/mxtimer.h @@ -14,8 +14,10 @@ public: MxLong GetRealTime(); + // FUNCTION: BETA10 0x10017810 MxLong GetTime() { + // Note that the BETA10 implementation differs - it only consists of the second branch of this `if` call if (this->m_isRunning) { return g_lastTimeTimerStarted; } diff --git a/LEGO1/realtime/orientableroi.h b/LEGO1/realtime/orientableroi.h index 25e09a5d..54059f20 100644 --- a/LEGO1/realtime/orientableroi.h +++ b/LEGO1/realtime/orientableroi.h @@ -39,7 +39,9 @@ public: void FUN_100a58f0(const Matrix4& p_transform); void FUN_100a5a30(const Vector3& p_world_velocity); + // FUNCTION: BETA10 0x1000fbf0 const Matrix4& GetLocal2World() const { return m_local2world; } + const float* GetWorldPosition() const { return m_local2world[3]; } const float* GetWorldDirection() const { return m_local2world[2]; } const float* GetWorldUp() const { return m_local2world[1]; }