From 87a9a37b33c564bae70f2a1981b6a175ebbd3bc0 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Thu, 4 Jul 2024 17:11:20 -0700 Subject: [PATCH 01/11] Implement/match Jetski class (#1061) --- LEGO1/lego/legoomni/include/dunebuggy.h | 4 +- LEGO1/lego/legoomni/include/jetski.h | 10 +- LEGO1/lego/legoomni/include/legovariables.h | 2 + LEGO1/lego/legoomni/src/actors/dunebuggy.cpp | 18 +-- LEGO1/lego/legoomni/src/actors/jetski.cpp | 151 +++++++++++++++--- .../legoomni/src/common/legovariables.cpp | 8 + LEGO1/lego/legoomni/src/worlds/isle.cpp | 2 +- 7 files changed, 159 insertions(+), 36 deletions(-) diff --git a/LEGO1/lego/legoomni/include/dunebuggy.h b/LEGO1/lego/legoomni/include/dunebuggy.h index 81b7bfe5..7302e0ce 100644 --- a/LEGO1/lego/legoomni/include/dunebuggy.h +++ b/LEGO1/lego/legoomni/include/dunebuggy.h @@ -32,12 +32,12 @@ class DuneBuggy : public IslePathActor { void ActivateSceneActions(); + static MxS32 GetColorOffset(const char* p_variable); + // SYNTHETIC: LEGO1 0x10067dc0 // DuneBuggy::`scalar deleting destructor' private: - static MxS32 GetDashboardOffset(const char* p_variable); - MxS16 m_dashboard; // 0x160 MxFloat m_fuel; // 0x164 MxFloat m_time; // 0x168 diff --git a/LEGO1/lego/legoomni/include/jetski.h b/LEGO1/lego/legoomni/include/jetski.h index 70102eac..e81824be 100644 --- a/LEGO1/lego/legoomni/include/jetski.h +++ b/LEGO1/lego/legoomni/include/jetski.h @@ -26,12 +26,12 @@ class Jetski : public IslePathActor { } MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 - void VTable0x70(float p_float) override; // vtable+0x70 + void VTable0x70(float p_time) override; // vtable+0x70 MxLong HandleClick() override; // vtable+0xcc MxLong HandleControl(LegoControlManagerNotificationParam&) override; // vtable+0xd4 void Exit() override; // vtable+0xe4 - void FUN_1007e990(); + void ActivateSceneActions(); MxS16 GetUnknown0x160() { return m_unk0x160; } @@ -39,9 +39,9 @@ class Jetski : public IslePathActor { // Jetski::`scalar deleting destructor' private: - // TODO: Jetski fields - MxS16 m_unk0x160; // 0x160 - undefined m_unk0x162[2]; // 0x162 + void RemoveFromWorld(); + + MxS16 m_unk0x160; // 0x160 }; #endif // JETSKI_H diff --git a/LEGO1/lego/legoomni/include/legovariables.h b/LEGO1/lego/legoomni/include/legovariables.h index 1901a254..b209776c 100644 --- a/LEGO1/lego/legoomni/include/legovariables.h +++ b/LEGO1/lego/legoomni/include/legovariables.h @@ -3,6 +3,8 @@ #include "mxvariable.h" +extern const char* g_varJETSPEED; +extern const char* g_varJETFUEL; extern const char* g_varDUNESPEED; extern const char* g_varDUNEFUEL; extern const char* g_varMOTOSPEED; diff --git a/LEGO1/lego/legoomni/src/actors/dunebuggy.cpp b/LEGO1/lego/legoomni/src/actors/dunebuggy.cpp index 30aff459..a4504310 100644 --- a/LEGO1/lego/legoomni/src/actors/dunebuggy.cpp +++ b/LEGO1/lego/legoomni/src/actors/dunebuggy.cpp @@ -102,7 +102,7 @@ MxLong DuneBuggy::HandleClick() } m_time = Timer()->GetTime(); - m_dashboard = IsleScript::c_DuneCarSpeedMeter + GetDashboardOffset(g_varDBFRFNY4); + m_dashboard = IsleScript::c_DuneCarSpeedMeter + GetColorOffset(g_varDBFRFNY4); InvokeAction(Extra::ActionType::e_start, *g_isleScript, m_dashboard, NULL); InvokeAction(Extra::ActionType::e_start, *g_isleScript, IsleScript::c_DuneCarDashboard, NULL); @@ -157,30 +157,30 @@ MxLong DuneBuggy::HandlePathStruct(LegoPathStructNotificationParam& p_param) } // FUNCTION: LEGO1 0x10068290 -MxS32 DuneBuggy::GetDashboardOffset(const char* p_variable) +MxS32 DuneBuggy::GetColorOffset(const char* p_variable) { - MxS32 color = 1; + MxS32 offset = 1; const char* colorName = VariableTable()->GetVariable(p_variable); if (strcmpi(colorName, "lego green")) { if (!strcmpi(colorName, "lego red")) { - color = 2; + offset = 2; } else if (!strcmpi(colorName, "lego yellow")) { - color = 3; + offset = 3; } else if (!strcmpi(colorName, "lego black")) { - color = 4; + offset = 4; } else if (!strcmpi(colorName, "lego blue")) { - color = 5; + offset = 5; } else if (!strcmpi(colorName, "lego white")) { - color = 6; + offset = 6; } } - return color; + return offset; } // FUNCTION: LEGO1 0x10068350 diff --git a/LEGO1/lego/legoomni/src/actors/jetski.cpp b/LEGO1/lego/legoomni/src/actors/jetski.cpp index a65268ac..158df471 100644 --- a/LEGO1/lego/legoomni/src/actors/jetski.cpp +++ b/LEGO1/lego/legoomni/src/actors/jetski.cpp @@ -1,50 +1,163 @@ #include "jetski.h" +#include "dunebuggy.h" +#include "isle.h" +#include "isle_actions.h" +#include "jukebox_actions.h" +#include "legoanimationmanager.h" +#include "legocontrolmanager.h" +#include "legonavcontroller.h" +#include "legoutils.h" +#include "legovariables.h" +#include "legoworld.h" +#include "misc.h" +#include "mxmisc.h" +#include "mxtransitionmanager.h" +#include "mxvariabletable.h" +#include "scripts.h" + DECOMP_SIZE_ASSERT(Jetski, 0x164) +// GLOBAL: LEGO1 0x100f7ab8 +// STRING: LEGO1 0x100f3ce0 +const char* g_varJSFRNTY5 = "c_jsfrnty5"; + +// GLOBAL: LEGO1 0x100f7abc +// STRING: LEGO1 0x100f3ca4 +const char* g_varJSWNSHY5 = "c_jswnshy5"; + // FUNCTION: LEGO1 0x1007e3b0 Jetski::Jetski() { - this->m_maxLinearVel = 25.0; - this->m_unk0x150 = 2.0; - this->m_unk0x148 = 1; + m_maxLinearVel = 25.0; + m_unk0x150 = 2.0; + m_unk0x148 = 1; } -// STUB: LEGO1 0x1007e630 +// FUNCTION: LEGO1 0x1007e630 MxResult Jetski::Create(MxDSAction& p_dsAction) { - // TODO - return SUCCESS; + MxResult result = IslePathActor::Create(p_dsAction); + m_world = CurrentWorld(); + + if (m_world) { + m_world->Add(this); + } + + VariableTable()->SetVariable(g_varJETFUEL, "0.8"); + return result; } -// STUB: LEGO1 0x1007e680 -void Jetski::VTable0x70(float p_float) +// FUNCTION: LEGO1 0x1007e680 +void Jetski::VTable0x70(float p_time) { - // TODO + IslePathActor::VTable0x70(p_time); + + char buf[200]; + float speed = abs(m_worldSpeed); + float maxLinearVel = NavController()->GetMaxLinearVel(); + + sprintf(buf, "%g", speed / maxLinearVel); + VariableTable()->SetVariable(g_varJETSPEED, buf); } -// STUB: LEGO1 0x1007e6f0 +// FUNCTION: LEGO1 0x1007e6f0 void Jetski::Exit() { - // TODO + SpawnPlayer(LegoGameState::e_unk45, FALSE, c_spawnBit1 | c_playMusic | c_spawnBit3); + IslePathActor::Exit(); + GameState()->m_currentArea = LegoGameState::e_jetski; + RemoveFromWorld(); + EnableAnimations(TRUE); + SetIsWorldActive(TRUE); + ControlManager()->Unregister(this); } -// STUB: LEGO1 0x1007e750 +// FUNCTION: LEGO1 0x1007e750 +// FUNCTION: BETA10 0x10037621 MxLong Jetski::HandleClick() { - // TODO - return 0; + if (!FUN_1003ef60()) { + return 1; + } + + FUN_10015820(TRUE, 0); + + ((Isle*) CurrentWorld())->SetDestLocation(LegoGameState::Area::e_jetski); + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, TRUE); + + if (GameState()->GetActorId() != UserActor()->GetActorId()) { + ((IslePathActor*) UserActor())->Exit(); + } + + // TODO: Match + m_unk0x160 = ((DuneBuggy::GetColorOffset(g_varJSWNSHY5) * 5 + 15) * 2); + m_unk0x160 += DuneBuggy::GetColorOffset(g_varJSFRNTY5); + + InvokeAction(Extra::ActionType::e_start, *g_isleScript, m_unk0x160, NULL); + InvokeAction(Extra::ActionType::e_start, *g_isleScript, IsleScript::c_JetskiDashboard, NULL); + GetCurrentAction().SetObjectId(-1); + + AnimationManager()->FUN_1005f6d0(FALSE); + AnimationManager()->FUN_10064670(NULL); + Enter(); + ControlManager()->Register(this); + return 1; } -// STUB: LEGO1 0x1007e8e0 +// FUNCTION: LEGO1 0x1007e880 +void Jetski::RemoveFromWorld() +{ + RemoveFromCurrentWorld(*g_isleScript, m_unk0x160); + RemoveFromCurrentWorld(*g_isleScript, IsleScript::c_JetskiArms_Ctl); + RemoveFromCurrentWorld(*g_isleScript, IsleScript::c_JetskiInfo_Ctl); + RemoveFromCurrentWorld(*g_isleScript, IsleScript::c_JetskiSpeedMeter); + RemoveFromCurrentWorld(*g_isleScript, IsleScript::c_JetskiFuelMeter); +} + +// FUNCTION: LEGO1 0x1007e8e0 MxLong Jetski::HandleControl(LegoControlManagerNotificationParam& p_param) { - // TODO + if (p_param.GetUnknown0x28() == 1 && CurrentWorld()->IsA("Isle")) { + switch (p_param.GetClickedObjectId()) { + case IsleScript::c_JetskiArms_Ctl: + Exit(); + ((IslePathActor*) UserActor()) + ->SpawnPlayer(LegoGameState::e_jetraceExterior, TRUE, c_spawnBit1 | c_playMusic | c_spawnBit3); + GameState()->m_currentArea = LegoGameState::e_unk66; + return 1; + case IsleScript::c_JetskiInfo_Ctl: + ((Isle*) CurrentWorld())->SetDestLocation(LegoGameState::e_infomain); + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + Exit(); + return 1; + } + } + return 0; } -// STUB: LEGO1 0x1007e990 -void Jetski::FUN_1007e990() +// FUNCTION: LEGO1 0x1007e990 +void Jetski::ActivateSceneActions() { - // TODO + PlayMusic(JukeboxScript::c_JetskiRace_Music); + + Act1State* act1state = (Act1State*) GameState()->GetState("Act1State"); + if (!act1state->m_unk0x018) { + if (act1state->m_unk0x022) { + PlayCamAnim(this, FALSE, 68, TRUE); + } + else { + act1state->m_unk0x022 = TRUE; + + LegoPathActor* user = UserActor(); + if (user != NULL) { + MxMatrix mat(user->GetROI()->GetLocal2World()); + mat.TranslateBy(mat[2][0] * 2.5, mat[2][1] + 0.6, mat[2][2] * 2.5); + + AnimationManager() + ->FUN_10060dc0(IsleScript::c_sjs007in_RunAnim, &mat, TRUE, FALSE, NULL, FALSE, TRUE, TRUE, TRUE); + } + } + } } diff --git a/LEGO1/lego/legoomni/src/common/legovariables.cpp b/LEGO1/lego/legoomni/src/common/legovariables.cpp index fcb4b975..54569743 100644 --- a/LEGO1/lego/legoomni/src/common/legovariables.cpp +++ b/LEGO1/lego/legoomni/src/common/legovariables.cpp @@ -16,6 +16,14 @@ DECOMP_SIZE_ASSERT(CursorVariable, 0x24) DECOMP_SIZE_ASSERT(WhoAmIVariable, 0x24) DECOMP_SIZE_ASSERT(CustomizeAnimFileVariable, 0x24) +// GLOBAL: LEGO1 0x100f7ab0 +// STRING: LEGO1 0x100f09c0 +const char* g_varJETSPEED = "jetSPEED"; + +// GLOBAL: LEGO1 0x100f7ab4 +// STRING: LEGO1 0x100f7aa8 +const char* g_varJETFUEL = "jetFUEL"; + // GLOBAL: LEGO1 0x100f7658 // STRING: LEGO1 0x100f764c const char* g_varDUNESPEED = "duneSPEED"; diff --git a/LEGO1/lego/legoomni/src/worlds/isle.cpp b/LEGO1/lego/legoomni/src/worlds/isle.cpp index d7cabb7b..fa9f9c5f 100644 --- a/LEGO1/lego/legoomni/src/worlds/isle.cpp +++ b/LEGO1/lego/legoomni/src/worlds/isle.cpp @@ -1044,7 +1044,7 @@ MxLong Isle::HandleTransitionEnd() FUN_10032d30((IsleScript::Script) m_jetski->GetUnknown0x160(), JukeboxScript::c_MusicTheme1, NULL, TRUE); if (!m_act1state->m_unk0x01f) { - m_jetski->FUN_1007e990(); + m_jetski->ActivateSceneActions(); } break; default: From 807526476702f4f003dca0739dd87001262db215 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Fri, 5 Jul 2024 04:49:36 +0200 Subject: [PATCH 02/11] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0f7edf0b..80217489 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ This is a **work-in-progress** decompilation of LEGO Island (Version 1.1, Englis Currently, `ISLE.EXE` is completely decompiled and behaves identically to the original. A handful of stubborn instructions are not yet matching; however, we anticipate they will as more of the overall codebase is implemented. -`LEGO1.DLL` is still incomplete and cannot be used for gameplay at this time. If you would like to use this, it is instead recommended to pair the recompiled `ISLE.EXE` with the `LEGO1.DLL` from the original game. +`LEGO1.DLL` is still lacking some gameplay features but is generally workable. If you would like to use this, make sure to do so without interacting with save files created by the retail version, as there might still be some incompatibilities. ## Building From 4833d2edf129d1ae573dfde32e14cc63bc6a6a4b Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Fri, 5 Jul 2024 04:51:04 +0200 Subject: [PATCH 03/11] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 80217489..3afbe0cc 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ If you have a CMake-compatible IDE, it should be pretty straightforward to use t ## Usage -Simply place the compiled `ISLE.EXE` into LEGO Island's install folder (usually `C:\Program Files\LEGO Island` or `C:\Program Files (x86)\LEGO Island`). Unless you're a developer, disregard the compiled `LEGO1.DLL` for now as it is too incomplete to be usable. Alternatively, LEGO Island can run from any directory as long as `ISLE.EXE` and `LEGO1.DLL` are in the same directory, and the registry keys (usually `HKEY_LOCAL_MACHINE\Software\Mindscape\LEGO Island` or `HKEY_LOCAL_MACHINE\Software\Wow6432Node\Mindscape\LEGO Island`) point to the correct location for the asset files. +Simply place the compiled `ISLE.EXE` and `LEGO1.DLL` into LEGO Island's install folder (usually `C:\Program Files\LEGO Island` or `C:\Program Files (x86)\LEGO Island`). Alternatively, LEGO Island can run from any directory as long as `ISLE.EXE` and `LEGO1.DLL` are in the same directory, and the registry keys (usually `HKEY_LOCAL_MACHINE\Software\Mindscape\LEGO Island` or `HKEY_LOCAL_MACHINE\Software\Wow6432Node\Mindscape\LEGO Island`) point to the correct location for the asset files. ## Contributing From a75ace8a53b3d79c414e578887b4bc92faffd207 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Fri, 5 Jul 2024 19:44:01 -0700 Subject: [PATCH 04/11] Implement/match TowTrack::VTable0x70 (#1062) --- LEGO1/lego/legoomni/include/legovariables.h | 1 + LEGO1/lego/legoomni/include/towtrack.h | 10 +++-- LEGO1/lego/legoomni/src/actors/towtrack.cpp | 44 ++++++++++++++++--- .../legoomni/src/common/legovariables.cpp | 4 ++ 4 files changed, 49 insertions(+), 10 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legovariables.h b/LEGO1/lego/legoomni/include/legovariables.h index b209776c..1b5cd93b 100644 --- a/LEGO1/lego/legoomni/include/legovariables.h +++ b/LEGO1/lego/legoomni/include/legovariables.h @@ -11,6 +11,7 @@ extern const char* g_varMOTOSPEED; extern const char* g_varMOTOFUEL; extern const char* g_varAMBULSPEED; extern const char* g_varAMBULFUEL; +extern const char* g_varTOWSPEED; extern const char* g_varTOWFUEL; extern const char* g_varVISIBILITY; extern const char* g_varCAMERALOCATION; diff --git a/LEGO1/lego/legoomni/include/towtrack.h b/LEGO1/lego/legoomni/include/towtrack.h index ebcefb54..3d9c7a1a 100644 --- a/LEGO1/lego/legoomni/include/towtrack.h +++ b/LEGO1/lego/legoomni/include/towtrack.h @@ -48,8 +48,8 @@ class TowTrackMissionState : public LegoState { // TowTrackMissionState::`scalar deleting destructor' undefined4 m_unk0x08; // 0x08 - undefined4 m_unk0x0c; // 0x0c - MxU8 m_unk0x10; // 0x10 + MxS32 m_unk0x0c; // 0x0c + MxBool m_unk0x10; // 0x10 MxS16 m_unk0x12; // 0x12 MxS16 m_unk0x14; // 0x14 MxS16 m_unk0x16; // 0x16 @@ -84,7 +84,7 @@ class TowTrack : public IslePathActor { MxLong Notify(MxParam& p_param) override; // vtable+0x04 MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 - void VTable0x70(float p_float) override; // vtable+0x70 + void VTable0x70(float p_time) override; // vtable+0x70 MxLong HandleClick() override; // vtable+0xcc MxLong HandleControl(LegoControlManagerNotificationParam& p_param) override; // vtable+0xd4 MxLong HandleEndAnim(LegoEndAnimNotificationParam& p_param) override; // vtable+0xd8 @@ -101,6 +101,8 @@ class TowTrack : public IslePathActor { // TowTrack::`scalar deleting destructor' private: + void FUN_1004dcf0(IsleScript::Script); + undefined4 m_unk0x160; // 0x160 TowTrackMissionState* m_state; // 0x164 MxS16 m_unk0x168; // 0x168 @@ -109,7 +111,7 @@ class TowTrack : public IslePathActor { MxS16 m_unk0x16e; // 0x16e MxS32 m_unk0x170; // 0x170 MxS32 m_unk0x174; // 0x174 - MxFloat m_unk0x178; // 0x178 + MxFloat m_fuel; // 0x178 MxFloat m_time; // 0x17c }; diff --git a/LEGO1/lego/legoomni/src/actors/towtrack.cpp b/LEGO1/lego/legoomni/src/actors/towtrack.cpp index 05cf5fcb..dd9a0d9b 100644 --- a/LEGO1/lego/legoomni/src/actors/towtrack.cpp +++ b/LEGO1/lego/legoomni/src/actors/towtrack.cpp @@ -1,7 +1,9 @@ #include "towtrack.h" +#include "isle_actions.h" #include "legocontrolmanager.h" #include "legogamestate.h" +#include "legonavcontroller.h" #include "legovariables.h" #include "legoworld.h" #include "misc.h" @@ -23,7 +25,7 @@ TowTrack::TowTrack() m_unk0x16e = 0; m_unk0x174 = -1; m_maxLinearVel = 40.0; - m_unk0x178 = 1.0; + m_fuel = 1.0; } // FUNCTION: LEGO1 0x1004c970 @@ -54,15 +56,39 @@ MxResult TowTrack::Create(MxDSAction& p_dsAction) } VariableTable()->SetVariable(g_varTOWFUEL, "1.0"); - m_unk0x178 = 1.0; + m_fuel = 1.0; m_time = Timer()->GetTime(); return result; } -// STUB: LEGO1 0x1004cb10 -void TowTrack::VTable0x70(float p_float) +// FUNCTION: LEGO1 0x1004cb10 +void TowTrack::VTable0x70(float p_time) { - // TODO + IslePathActor::VTable0x70(p_time); + + if (UserActor() == this) { + char buf[200]; + float speed = abs(m_worldSpeed); + float maxLinearVel = NavController()->GetMaxLinearVel(); + + sprintf(buf, "%g", speed / maxLinearVel); + VariableTable()->SetVariable(g_varTOWSPEED, buf); + + m_fuel += (p_time - m_time) * -3.333333333e-06f; + if (m_fuel < 0) { + m_fuel = 0; + } + + m_time = p_time; + + sprintf(buf, "%g", m_fuel); + VariableTable()->SetVariable(g_varTOWFUEL, buf); + + if (p_time - m_state->m_unk0x0c > 100000.0f && m_state->m_unk0x08 == 1 && !m_state->m_unk0x10) { + FUN_1004dcf0(IsleScript::c_Avo909In_PlayWav); + m_state->m_unk0x10 = TRUE; + } + } } // FUNCTION: LEGO1 0x1004cc40 @@ -139,6 +165,12 @@ void TowTrack::FUN_1004dbe0() // TODO } +// STUB: LEGO1 0x1004dcf0 +void TowTrack::FUN_1004dcf0(IsleScript::Script) +{ + // TODO +} + // FUNCTION: LEGO1 0x1004dd30 TowTrackMissionState::TowTrackMissionState() { @@ -149,7 +181,7 @@ TowTrackMissionState::TowTrackMissionState() m_unk0x18 = 0; m_unk0x0c = 0; m_unk0x1a = 0; - m_unk0x10 = 0; + m_unk0x10 = FALSE; m_score1 = 0; m_score2 = 0; m_score3 = 0; diff --git a/LEGO1/lego/legoomni/src/common/legovariables.cpp b/LEGO1/lego/legoomni/src/common/legovariables.cpp index 54569743..da6b30fd 100644 --- a/LEGO1/lego/legoomni/src/common/legovariables.cpp +++ b/LEGO1/lego/legoomni/src/common/legovariables.cpp @@ -48,6 +48,10 @@ const char* g_varAMBULSPEED = "ambulSPEED"; // STRING: LEGO1 0x100f39a0 const char* g_varAMBULFUEL = "ambulFUEL"; +// GLOBAL: LEGO1 0x100f43b0 +// STRING: LEGO1 0x100f43a4 +const char* g_varTOWSPEED = "towSPEED"; + // GLOBAL: LEGO1 0x100f43b4 // STRING: LEGO1 0x100f439c const char* g_varTOWFUEL = "towFUEL"; From afa5b90117b2f363d9931ac5437942c5848650e6 Mon Sep 17 00:00:00 2001 From: jonschz <17198703+jonschz@users.noreply.github.com> Date: Sun, 7 Jul 2024 14:10:46 +0200 Subject: [PATCH 05/11] Implement `LegoRaceCar::FUN_10012ff0()`, refactoring (#1063) * Implement `LegoRaceCar::FUN_10012ff0()`, refactor based on BETA10 * Add BETA10 annotations * Rename functions and variables based on BETA10 assertions * Address issues raised by linter * Rename variable, add BETA10 vtables * Rename legoracecar files to legoracers --------- Co-authored-by: jonschz --- CMakeLists.txt | 2 +- LEGO1/lego/legoomni/include/legoanimactor.h | 4 ++ .../include/{legoracecar.h => legoracers.h} | 15 +++-- LEGO1/lego/legoomni/include/legoworld.h | 2 + .../src/common/legoanimationmanager.cpp | 2 +- .../legoomni/src/common/legoobjectfactory.cpp | 2 +- LEGO1/lego/legoomni/src/common/misc.cpp | 2 + .../src/entity/legocameracontroller.cpp | 1 + .../lego/legoomni/src/paths/legoanimactor.cpp | 2 + .../race/{legoracecar.cpp => legoracers.cpp} | 62 +++++++++++++++++-- .../legoomni/src/video/legoanimpresenter.cpp | 4 +- LEGO1/lego/sources/anim/legoanim.cpp | 10 +-- LEGO1/lego/sources/anim/legoanim.h | 9 ++- LEGO1/lego/sources/geom/legoweedge.h | 3 + LEGO1/mxgeometry/mxmatrix.h | 1 + LEGO1/realtime/matrix.h | 1 + LEGO1/realtime/orientableroi.cpp | 1 + LEGO1/realtime/orientableroi.h | 1 + 18 files changed, 102 insertions(+), 22 deletions(-) rename LEGO1/lego/legoomni/include/{legoracecar.h => legoracers.h} (85%) rename LEGO1/lego/legoomni/src/race/{legoracecar.cpp => legoracers.cpp} (69%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 08e4424a..5e9a675c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -373,7 +373,7 @@ add_library(lego1 SHARED LEGO1/lego/legoomni/src/race/jetskirace.cpp LEGO1/lego/legoomni/src/race/legorace.cpp LEGO1/lego/legoomni/src/race/legoraceactor.cpp - LEGO1/lego/legoomni/src/race/legoracecar.cpp + LEGO1/lego/legoomni/src/race/legoracers.cpp LEGO1/lego/legoomni/src/race/legoracemap.cpp LEGO1/lego/legoomni/src/race/raceskel.cpp LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp diff --git a/LEGO1/lego/legoomni/include/legoanimactor.h b/LEGO1/lego/legoomni/include/legoanimactor.h index e2843c3d..72f6bc1c 100644 --- a/LEGO1/lego/legoomni/include/legoanimactor.h +++ b/LEGO1/lego/legoomni/include/legoanimactor.h @@ -15,6 +15,10 @@ struct LegoAnimActorStruct { float GetUnknown0x00() { return m_unk0x00; } + // FUNCTION: BETA10 0x10012210 + LegoAnim* GetAnimTreePtr() { return m_AnimTreePtr; } + + // TODO: Possibly private float m_unk0x00; // 0x00 LegoAnim* m_AnimTreePtr; // 0x04 LegoROI** m_roiMap; // 0x08 diff --git a/LEGO1/lego/legoomni/include/legoracecar.h b/LEGO1/lego/legoomni/include/legoracers.h similarity index 85% rename from LEGO1/lego/legoomni/include/legoracecar.h rename to LEGO1/lego/legoomni/include/legoracers.h index d85e7d7b..290a849f 100644 --- a/LEGO1/lego/legoomni/include/legoracecar.h +++ b/LEGO1/lego/legoomni/include/legoracers.h @@ -1,5 +1,5 @@ -#ifndef LEGORACECAR_H -#define LEGORACECAR_H +#ifndef LEGORACERS_H +#define LEGORACERS_H #include "legocarraceactor.h" #include "legoracemap.h" @@ -15,6 +15,11 @@ struct EdgeReference { // VTABLE: LEGO1 0x100d58b8 LegoPathActor // VTABLE: LEGO1 0x100d5984 LegoRaceMap // VTABLE: LEGO1 0x100d5988 LegoCarRaceActor +// VTABLE: BETA10 0x101be6ec LegoRaceActor +// VTABLE: BETA10 0x101be6f0 LegoAnimActor +// VTABLE: BETA10 0x101be708 LegoPathActor +// VTABLE: BETA10 0x101be7f8 LegoRaceMap +// VTABLE: BETA10 0x101be800 LegoCarRaceActor // SIZE 0x200 class LegoRaceCar : public LegoCarRaceActor, public LegoRaceMap { public: @@ -60,8 +65,8 @@ class LegoRaceCar : public LegoCarRaceActor, public LegoRaceMap { // LegoRaceCar::`scalar deleting destructor' private: - undefined m_unk0x54; // 0x54 - undefined4 m_unk0x58; // 0x58 + undefined m_userState; // 0x54 + float m_unk0x58; // 0x58 Mx3DPointFloat m_unk0x5c; // 0x5c LegoAnimActorStruct* m_unk0x70; // 0x70 LegoAnimActorStruct* m_unk0x74; // 0x74 @@ -72,4 +77,4 @@ class LegoRaceCar : public LegoCarRaceActor, public LegoRaceMap { static const EdgeReference* g_pEdgeReferences; }; -#endif // LEGORACECAR_H +#endif // LEGORACERS_H diff --git a/LEGO1/lego/legoomni/include/legoworld.h b/LEGO1/lego/legoomni/include/legoworld.h index 8cec279c..d248ab5b 100644 --- a/LEGO1/lego/legoomni/include/legoworld.h +++ b/LEGO1/lego/legoomni/include/legoworld.h @@ -97,7 +97,9 @@ class LegoWorld : public LegoEntity { MxCore* Find(const char* p_class, const char* p_name); MxCore* Find(const MxAtomId& p_atom, MxS32 p_entityId); + // FUNCTION: BETA10 0x1002b4f0 LegoCameraController* GetCamera() { return m_cameraController; } + LegoEntityList* GetEntityList() { return m_entityList; } MxS32 GetWorldId() { return m_worldId; } MxBool GetUnknown0xd0Empty() { return m_set0xd0.empty(); } diff --git a/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp b/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp index fa136321..fb8b39d0 100644 --- a/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp +++ b/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp @@ -1220,7 +1220,7 @@ void LegoAnimationManager::FUN_10061010(MxBool p_und) if (tranInfo->m_presenter->GetPresenter() != NULL && (anim = tranInfo->m_presenter->GetPresenter()->GetAnimation()) != NULL && - anim->GetScene() != NULL) { + anim->GetCamAnim() != NULL) { if (flags & LegoTranInfo::c_bit2) { BackgroundAudioManager()->RaiseVolume(); tranInfo->m_flags &= ~LegoTranInfo::c_bit2; diff --git a/LEGO1/lego/legoomni/src/common/legoobjectfactory.cpp b/LEGO1/lego/legoomni/src/common/legoobjectfactory.cpp index fca0c0cb..00f88397 100644 --- a/LEGO1/lego/legoomni/src/common/legoobjectfactory.cpp +++ b/LEGO1/lego/legoomni/src/common/legoobjectfactory.cpp @@ -57,7 +57,7 @@ #include "legopathactor.h" #include "legopathpresenter.h" #include "legophonemepresenter.h" -#include "legoracecar.h" +#include "legoracers.h" #include "legotexturepresenter.h" #include "legoworld.h" #include "legoworldpresenter.h" diff --git a/LEGO1/lego/legoomni/src/common/misc.cpp b/LEGO1/lego/legoomni/src/common/misc.cpp index 29cc4cd6..6d879aa1 100644 --- a/LEGO1/lego/legoomni/src/common/misc.cpp +++ b/LEGO1/lego/legoomni/src/common/misc.cpp @@ -73,8 +73,10 @@ LegoPathActor* UserActor() } // FUNCTION: LEGO1 0x100157a0 +// FUNCTION: BETA10 0x100e4a46 LegoWorld* CurrentWorld() { + assert(LegoOmni::GetInstance()); return LegoOmni::GetInstance()->GetCurrentWorld(); } diff --git a/LEGO1/lego/legoomni/src/entity/legocameracontroller.cpp b/LEGO1/lego/legoomni/src/entity/legocameracontroller.cpp index 3db91002..bd757bd5 100644 --- a/LEGO1/lego/legoomni/src/entity/legocameracontroller.cpp +++ b/LEGO1/lego/legoomni/src/entity/legocameracontroller.cpp @@ -140,6 +140,7 @@ void LegoCameraController::FUN_10012320(float p_angle) } // FUNCTION: LEGO1 0x100123e0 +// FUNCTION: BETA10 0x10068cb2 void LegoCameraController::FUN_100123e0(const Matrix4& p_transform, MxU32 p_und) { if (m_lego3DView != NULL) { diff --git a/LEGO1/lego/legoomni/src/paths/legoanimactor.cpp b/LEGO1/lego/legoomni/src/paths/legoanimactor.cpp index 70c73fe2..eaad8ba9 100644 --- a/LEGO1/lego/legoomni/src/paths/legoanimactor.cpp +++ b/LEGO1/lego/legoomni/src/paths/legoanimactor.cpp @@ -29,8 +29,10 @@ LegoAnimActorStruct::~LegoAnimActorStruct() } // FUNCTION: LEGO1 0x1001c130 +// FUNCTION: BETA10 0x1003df5f float LegoAnimActorStruct::GetDuration() { + assert(m_AnimTreePtr); return m_AnimTreePtr->GetDuration(); } diff --git a/LEGO1/lego/legoomni/src/race/legoracecar.cpp b/LEGO1/lego/legoomni/src/race/legoracers.cpp similarity index 69% rename from LEGO1/lego/legoomni/src/race/legoracecar.cpp rename to LEGO1/lego/legoomni/src/race/legoracers.cpp index 2a2b2a7e..2a4e2185 100644 --- a/LEGO1/lego/legoomni/src/race/legoracecar.cpp +++ b/LEGO1/lego/legoomni/src/race/legoracers.cpp @@ -1,6 +1,8 @@ -#include "legoracecar.h" +#include "legoracers.h" +#include "anim/legoanim.h" #include "define.h" +#include "legocameracontroller.h" #include "legorace.h" #include "misc.h" #include "mxmisc.h" @@ -44,7 +46,7 @@ const EdgeReference* LegoRaceCar::g_pEdgeReferences = g_edgeReferences; // FUNCTION: LEGO1 0x10012950 LegoRaceCar::LegoRaceCar() { - m_unk0x54 = 0; + m_userState = 0; m_unk0x70 = 0; m_unk0x74 = 0; m_unk0x5c.Clear(); @@ -131,10 +133,60 @@ void LegoRaceCar::ParseAction(char* p_extra) } } -// STUB: LEGO1 0x10012ff0 -void LegoRaceCar::FUN_10012ff0(float) +// FUNCTION: LEGO1 0x10012ff0 +// FUNCTION: BETA10 0x100cb60e +void LegoRaceCar::FUN_10012ff0(float p_param) { - // TODO + LegoAnimActorStruct* a; // called `a` in BETA10 + float deltaTime; + + if (m_userState == 2) { + a = m_unk0x70; + } + else { + // TODO: Possibly an enum? + const char legoracecarKick2 = 4; // original name: LEGORACECAR_KICK2 + assert(m_userState == legoracecarKick2); + a = m_unk0x74; + } + + assert(a && a->GetAnimTreePtr() && a->GetAnimTreePtr()->GetCamAnim()); + + if (a->GetAnimTreePtr()) { + deltaTime = p_param - m_unk0x58; + + if (a->GetDuration() <= deltaTime || deltaTime < 0.0) { + if (m_userState == 2) { + LegoEdge** edges = m_unk0x78->GetEdges(); + m_destEdge = (LegoUnknown100db7f4*) (edges[2]); + m_boundary = m_unk0x78; + } + else { + LegoEdge** edges = m_unk0x78->GetEdges(); + m_destEdge = (LegoUnknown100db7f4*) (edges[1]); + m_boundary = m_unk0x7c; + } + + m_userState = 0; + } + else if (a->GetAnimTreePtr()->GetCamAnim()) { + MxMatrix transformationMatrix; + + LegoWorld* r = CurrentWorld(); // called `r` in BETA10 + assert(r); + + transformationMatrix.SetIdentity(); + + // Possible bug in the original code: The first argument is not initialized + a->GetAnimTreePtr()->GetCamAnim()->FUN_1009f490(deltaTime, transformationMatrix); + + if (r->GetCamera()) { + r->GetCamera()->FUN_100123e0(transformationMatrix, 0); + } + + m_roi->FUN_100a58f0(transformationMatrix); + } + } } // STUB: LEGO1 0x10013130 diff --git a/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp b/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp index 723a1a30..faebd3d4 100644 --- a/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp +++ b/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp @@ -922,9 +922,9 @@ void LegoAnimPresenter::FUN_1006b9a0(LegoAnim* p_anim, MxLong p_time, Matrix4* p } } - if (p_anim->GetScene() != NULL) { + if (p_anim->GetCamAnim() != NULL) { MxMatrix transform(mat); - p_anim->GetScene()->FUN_1009f490(p_time, transform); + p_anim->GetCamAnim()->FUN_1009f490(p_time, transform); if (m_currentWorld != NULL && m_currentWorld->GetCamera() != NULL) { m_currentWorld->GetCamera()->FUN_100123e0(transform, 0); diff --git a/LEGO1/lego/sources/anim/legoanim.cpp b/LEGO1/lego/sources/anim/legoanim.cpp index 45844ca9..77801f61 100644 --- a/LEGO1/lego/sources/anim/legoanim.cpp +++ b/LEGO1/lego/sources/anim/legoanim.cpp @@ -785,7 +785,7 @@ LegoAnim::LegoAnim() m_duration = 0; m_actors = NULL; m_numActors = 0; - m_scene = NULL; + m_camAnim = NULL; } // FUNCTION: LEGO1 0x100a0bc0 @@ -799,8 +799,8 @@ LegoAnim::~LegoAnim() delete[] m_actors; } - if (m_scene != NULL) { - delete m_scene; + if (m_camAnim != NULL) { + delete m_camAnim; } } @@ -845,9 +845,9 @@ LegoResult LegoAnim::Read(LegoStorage* p_storage, LegoS32 p_parseScene) } if (p_parseScene) { - m_scene = new LegoAnimScene(); + m_camAnim = new LegoAnimScene(); - result = m_scene->Read(p_storage); + result = m_camAnim->Read(p_storage); if (result != SUCCESS) { goto done; diff --git a/LEGO1/lego/sources/anim/legoanim.h b/LEGO1/lego/sources/anim/legoanim.h index a7f7ee72..1a861eb6 100644 --- a/LEGO1/lego/sources/anim/legoanim.h +++ b/LEGO1/lego/sources/anim/legoanim.h @@ -208,6 +208,7 @@ struct LegoAnimActorEntry { undefined4 m_unk0x04; // 0x04 }; +// TODO: Possibly called `LegoCameraAnim(ation)`? // SIZE 0x24 class LegoAnimScene { public: @@ -242,7 +243,10 @@ class LegoAnim : public LegoTree { public: LegoAnim(); ~LegoAnim() override; + + // FUNCTION: BETA10 0x100284c0 LegoTime GetDuration() { return m_duration; } + LegoU32 GetNumActors() { return m_numActors; } LegoResult Write(LegoStorage* p_storage) override; // vtable+0x08 virtual LegoResult Read(LegoStorage* p_storage, LegoS32 p_parseScene); // vtable+0x10 @@ -250,7 +254,8 @@ class LegoAnim : public LegoTree { const LegoChar* GetActorName(LegoU32 p_index); undefined4 GetActorUnknown0x04(LegoU32 p_index); - LegoAnimScene* GetScene() { return m_scene; } + // FUNCTION: BETA10 0x1005abf0 + LegoAnimScene* GetCamAnim() { return m_camAnim; } // SYNTHETIC: LEGO1 0x100a0ba0 // LegoAnim::`scalar deleting destructor' @@ -259,7 +264,7 @@ class LegoAnim : public LegoTree { LegoTime m_duration; // 0x08 LegoAnimActorEntry* m_actors; // 0x0c LegoU32 m_numActors; // 0x10 - LegoAnimScene* m_scene; // 0x14 + LegoAnimScene* m_camAnim; // 0x14 // FUNCTION: LEGO1 0x100a1040 LegoTreeNodeData* CreateData() override { return new LegoAnimNodeData(); } // vtable+0x0c diff --git a/LEGO1/lego/sources/geom/legoweedge.h b/LEGO1/lego/sources/geom/legoweedge.h index c5a8b83d..74dc6a45 100644 --- a/LEGO1/lego/sources/geom/legoweedge.h +++ b/LEGO1/lego/sources/geom/legoweedge.h @@ -16,7 +16,10 @@ class LegoWEEdge { virtual LegoResult VTable0x04(); // vtable+0x04 LegoU8 GetNumEdges() { return m_numEdges; } + + // FUNCTION: BETA10 0x1001cc30 LegoEdge** GetEdges() { return m_edges; } + LegoU32 IsEqual(LegoWEEdge& p_other) { return this == &p_other; } void SetEdges(LegoEdge** p_edges, LegoU8 p_numEdges) diff --git a/LEGO1/mxgeometry/mxmatrix.h b/LEGO1/mxgeometry/mxmatrix.h index a33d92b9..1b8bbfbc 100644 --- a/LEGO1/mxgeometry/mxmatrix.h +++ b/LEGO1/mxgeometry/mxmatrix.h @@ -4,6 +4,7 @@ #include "realtime/matrix.h" // VTABLE: LEGO1 0x100d4300 +// VTABLE: BETA10 0x101b82e0 // SIZE 0x48 class MxMatrix : public Matrix4 { public: diff --git a/LEGO1/realtime/matrix.h b/LEGO1/realtime/matrix.h index a63b69d6..92c7ac7d 100644 --- a/LEGO1/realtime/matrix.h +++ b/LEGO1/realtime/matrix.h @@ -13,6 +13,7 @@ struct UnknownMatrixType { // The class needs to undergo a very careful refactoring to fix that (no matches should break). // VTABLE: LEGO1 0x100d4350 +// VTABLE: BETA10 0x101b8340 // SIZE 0x08 class Matrix4 { public: diff --git a/LEGO1/realtime/orientableroi.cpp b/LEGO1/realtime/orientableroi.cpp index 21a6b75a..451df324 100644 --- a/LEGO1/realtime/orientableroi.cpp +++ b/LEGO1/realtime/orientableroi.cpp @@ -98,6 +98,7 @@ void OrientableROI::GetLocalTransform(Matrix4& p_transform) } // FUNCTION: LEGO1 0x100a58f0 +// FUNCTION: BETA10 0x10167b77 void OrientableROI::FUN_100a58f0(const Matrix4& p_transform) { m_local2world = p_transform; diff --git a/LEGO1/realtime/orientableroi.h b/LEGO1/realtime/orientableroi.h index b707bbe3..25e09a5d 100644 --- a/LEGO1/realtime/orientableroi.h +++ b/LEGO1/realtime/orientableroi.h @@ -47,6 +47,7 @@ class OrientableROI : public ROI { void SetParentROI(OrientableROI* p_parentROI) { m_parentROI = p_parentROI; } + // FUNCTION: BETA10 0x10168800 void ToggleUnknown0xd8(BOOL p_enable) { if (p_enable) { From 4a861faca3ee37aa26e581e2c58f6afcf285b1bd Mon Sep 17 00:00:00 2001 From: jonschz <17198703+jonschz@users.noreply.github.com> Date: Mon, 8 Jul 2024 23:52:50 +0200 Subject: [PATCH 06/11] Refactor file names based on BETA10 (#1064) * Refactor file names based on BETA10 * Extract LegoDeviceEnumerate to dedicated file * Fix compiler errors * Migrate contiguous block of code to `LegoDeviceEnumerate` --------- Co-authored-by: jonschz --- CMakeLists.txt | 4 +- CONFIG/MainDlg.cpp | 6 +- CONFIG/config.cpp | 1 + .../include/{act3actor.h => act3actors.h} | 9 +- LEGO1/lego/legoomni/include/act3brickster.h | 2 +- LEGO1/lego/legoomni/include/act3cop.h | 2 +- .../actors/{act3actor.cpp => act3actors.cpp} | 2 +- .../legoomni/src/common/legoobjectfactory.cpp | 2 +- .../legoomni/src/video/legovideomanager.cpp | 1 + LEGO1/mxdirectx/legodxinfo.cpp | 373 ++++++++++++++++++ LEGO1/mxdirectx/legodxinfo.h | 32 ++ LEGO1/mxdirectx/mxdirectxinfo.cpp | 367 ----------------- LEGO1/mxdirectx/mxdirectxinfo.h | 28 +- 13 files changed, 424 insertions(+), 405 deletions(-) rename LEGO1/lego/legoomni/include/{act3actor.h => act3actors.h} (78%) rename LEGO1/lego/legoomni/src/actors/{act3actor.cpp => act3actors.cpp} (92%) create mode 100644 LEGO1/mxdirectx/legodxinfo.cpp create mode 100644 LEGO1/mxdirectx/legodxinfo.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e9a675c..8ed6f3a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -131,6 +131,7 @@ add_library(mxdirectx STATIC LEGO1/mxdirectx/mxdirect3d.cpp LEGO1/mxdirectx/mxdirectdraw.cpp LEGO1/mxdirectx/mxdirectxinfo.cpp + LEGO1/mxdirectx/legodxinfo.cpp ) register_lego1_target(mxdirectx) set_property(TARGET mxdirectx PROPERTY ARCHIVE_OUTPUT_NAME "MxDirectX$<$:d>") @@ -288,7 +289,7 @@ add_library(lego1 SHARED LEGO1/define.cpp LEGO1/lego/legoomni/src/actors/act2actor.cpp LEGO1/lego/legoomni/src/actors/act2genactor.cpp - LEGO1/lego/legoomni/src/actors/act3actor.cpp + LEGO1/lego/legoomni/src/actors/act3actors.cpp LEGO1/lego/legoomni/src/actors/act3brickster.cpp LEGO1/lego/legoomni/src/actors/act3cop.cpp LEGO1/lego/legoomni/src/actors/act3shark.cpp @@ -466,6 +467,7 @@ endif() if (ISLE_BUILD_CONFIG) add_executable(config WIN32 LEGO1/mxdirectx/mxdirectxinfo.cpp + LEGO1/mxdirectx/legodxinfo.cpp CONFIG/config.cpp CONFIG/ConfigCommandLineInfo.cpp CONFIG/AboutDlg.cpp diff --git a/CONFIG/MainDlg.cpp b/CONFIG/MainDlg.cpp index da0b5d17..7ae5393e 100644 --- a/CONFIG/MainDlg.cpp +++ b/CONFIG/MainDlg.cpp @@ -4,7 +4,7 @@ #include "config.h" #include "res/resource.h" -#include +#include DECOMP_SIZE_ASSERT(CDialog, 0x60) DECOMP_SIZE_ASSERT(CMainDialog, 0x70) @@ -57,7 +57,7 @@ BOOL CMainDialog::OnInitDialog() } SendMessage(WM_SETICON, ICON_BIG, (LPARAM) m_icon); SendMessage(WM_SETICON, ICON_SMALL, (LPARAM) m_icon); - MxDeviceEnumerate* enumerator = currentConfigApp->m_device_enumerator; + LegoDeviceEnumerate* enumerator = currentConfigApp->m_device_enumerator; enumerator->FUN_1009d210(); m_modified = currentConfigApp->ReadRegisterSettings(); CWnd* list_3d_devices = GetDlgItem(IDC_LIST_3DDEVICES); @@ -131,7 +131,7 @@ HCURSOR CMainDialog::OnQueryDragIcon() // FUNCTION: CONFIG 0x00404240 void CMainDialog::OnList3DevicesSelectionChanged() { - MxDeviceEnumerate* device_enumerator = currentConfigApp->m_device_enumerator; + LegoDeviceEnumerate* device_enumerator = currentConfigApp->m_device_enumerator; int selected = ::SendMessage(GetDlgItem(IDC_LIST_3DDEVICES)->m_hWnd, LB_GETCURSEL, 0, 0); device_enumerator->GetDevice(selected, currentConfigApp->m_driver, currentConfigApp->m_device); if (currentConfigApp->GetHardwareDeviceColorModel()) { diff --git a/CONFIG/config.cpp b/CONFIG/config.cpp index 59c03332..d4457b55 100644 --- a/CONFIG/config.cpp +++ b/CONFIG/config.cpp @@ -5,6 +5,7 @@ #include "detectdx5.h" #include // _chdir +#include #include #include // _spawnl diff --git a/LEGO1/lego/legoomni/include/act3actor.h b/LEGO1/lego/legoomni/include/act3actors.h similarity index 78% rename from LEGO1/lego/legoomni/include/act3actor.h rename to LEGO1/lego/legoomni/include/act3actors.h index b71939e0..ac955816 100644 --- a/LEGO1/lego/legoomni/include/act3actor.h +++ b/LEGO1/lego/legoomni/include/act3actors.h @@ -1,10 +1,13 @@ -#ifndef ACT3ACTOR_H -#define ACT3ACTOR_H +#ifndef ACT3ACTORS_H +#define ACT3ACTORS_H #include "legoanimactor.h" +// File name verified by multiple assertions, e.g. BETA10 0x10018391 + // VTABLE: LEGO1 0x100d7668 LegoPathActor // VTABLE: LEGO1 0x100d7738 LegoAnimActor +// VTABLE: BETA10 0x101b8a98 LegoPathActor // SIZE 0x178 class Act3Actor : public LegoAnimActor { public: @@ -30,4 +33,4 @@ class Act3Actor : public LegoAnimActor { undefined4 m_unk0x1c; // 0x1c }; -#endif // ACT3ACTOR_H +#endif // ACT3ACTORS_H diff --git a/LEGO1/lego/legoomni/include/act3brickster.h b/LEGO1/lego/legoomni/include/act3brickster.h index f9066d3c..c84b8dd7 100644 --- a/LEGO1/lego/legoomni/include/act3brickster.h +++ b/LEGO1/lego/legoomni/include/act3brickster.h @@ -1,7 +1,7 @@ #ifndef ACT3BRICKSTER_H #define ACT3BRICKSTER_H -#include "act3actor.h" +#include "act3actors.h" // VTABLE: LEGO1 0x100d7838 LegoPathActor // VTABLE: LEGO1 0x100d7908 LegoAnimActor diff --git a/LEGO1/lego/legoomni/include/act3cop.h b/LEGO1/lego/legoomni/include/act3cop.h index 29ac65b6..a720b84c 100644 --- a/LEGO1/lego/legoomni/include/act3cop.h +++ b/LEGO1/lego/legoomni/include/act3cop.h @@ -1,7 +1,7 @@ #ifndef ACT3COP_H #define ACT3COP_H -#include "act3actor.h" +#include "act3actors.h" // VTABLE: LEGO1 0x100d7750 LegoPathActor // VTABLE: LEGO1 0x100d7820 LegoAnimActor diff --git a/LEGO1/lego/legoomni/src/actors/act3actor.cpp b/LEGO1/lego/legoomni/src/actors/act3actors.cpp similarity index 92% rename from LEGO1/lego/legoomni/src/actors/act3actor.cpp rename to LEGO1/lego/legoomni/src/actors/act3actors.cpp index 5ae24f14..01359090 100644 --- a/LEGO1/lego/legoomni/src/actors/act3actor.cpp +++ b/LEGO1/lego/legoomni/src/actors/act3actors.cpp @@ -1,4 +1,4 @@ -#include "act3actor.h" +#include "act3actors.h" DECOMP_SIZE_ASSERT(Act3Actor, 0x178) diff --git a/LEGO1/lego/legoomni/src/common/legoobjectfactory.cpp b/LEGO1/lego/legoomni/src/common/legoobjectfactory.cpp index 00f88397..6bbae1fa 100644 --- a/LEGO1/lego/legoomni/src/common/legoobjectfactory.cpp +++ b/LEGO1/lego/legoomni/src/common/legoobjectfactory.cpp @@ -5,7 +5,7 @@ #include "act2genactor.h" #include "act2policestation.h" #include "act3.h" -#include "act3actor.h" +#include "act3actors.h" #include "act3brickster.h" #include "act3cop.h" #include "act3shark.h" diff --git a/LEGO1/lego/legoomni/src/video/legovideomanager.cpp b/LEGO1/lego/legoomni/src/video/legovideomanager.cpp index 0eae0878..21147b1f 100644 --- a/LEGO1/lego/legoomni/src/video/legovideomanager.cpp +++ b/LEGO1/lego/legoomni/src/video/legovideomanager.cpp @@ -4,6 +4,7 @@ #include "legoinputmanager.h" #include "legomain.h" #include "misc.h" +#include "mxdirectx/legodxinfo.h" #include "mxdirectx/mxdirect3d.h" #include "mxdirectx/mxstopwatch.h" #include "mxdisplaysurface.h" diff --git a/LEGO1/mxdirectx/legodxinfo.cpp b/LEGO1/mxdirectx/legodxinfo.cpp new file mode 100644 index 00000000..eb511f2b --- /dev/null +++ b/LEGO1/mxdirectx/legodxinfo.cpp @@ -0,0 +1,373 @@ +#include "legodxinfo.h" + +#include +#include // for vsprintf + +// File name validated by BETA10 0x1011cba3; directory unknown + +// FUNCTION: CONFIG 0x00402560 +// FUNCTION: LEGO1 0x1009ce60 +// FUNCTION: BETA10 0x1011c7e0 +int LegoDeviceEnumerate::ParseDeviceName(const char* p_deviceId) +{ + if (!IsInitialized()) { + return -1; + } + + int unknown = -1; + int num = -1; + int hex[4]; + + if (sscanf(p_deviceId, "%d 0x%x 0x%x 0x%x 0x%x", &num, &hex[0], &hex[1], &hex[2], &hex[3]) != 5) { + return -1; + } + + if (num < 0) { + return -1; + } + + GUID guid; + memcpy(&guid, hex, sizeof(guid)); + + int result = ProcessDeviceBytes(num, guid); + + if (result < 0) { + result = ProcessDeviceBytes(-1, guid); + } + + return result; +} + +// FUNCTION: CONFIG 0x00402620 +// FUNCTION: LEGO1 0x1009cf20 +// FUNCTION: BETA10 0x1011c8b3 +int LegoDeviceEnumerate::ProcessDeviceBytes(int p_deviceNum, GUID& p_guid) +{ + if (!IsInitialized()) { + return -1; + } + + int i = 0; + int j = 0; + + static_assert(sizeof(GUID4) == sizeof(GUID), "Equal size"); + + GUID4 deviceGuid; + memcpy(&deviceGuid, &p_guid, sizeof(GUID4)); + + for (list::iterator it = m_list.begin(); it != m_list.end(); it++, i++) { + if (p_deviceNum >= 0 && p_deviceNum < i) { + return -1; + } + + GUID4 compareGuid; + MxDriver& driver = *it; + for (list::iterator it2 = driver.m_devices.begin(); it2 != driver.m_devices.end(); it2++) { + Direct3DDeviceInfo& md3d = *it2; + assert(md3d.m_guid); + + memcpy(&compareGuid, md3d.m_guid, sizeof(GUID4)); + + if (GUID4::Compare(compareGuid, deviceGuid) && i == p_deviceNum) { + return j; + } + + j++; + } + } + + return -1; +} + +// FUNCTION: CONFIG 0x00402730 +// FUNCTION: LEGO1 0x1009d030 +// FUNCTION: BETA10 0x1011ca54 +int LegoDeviceEnumerate::GetDevice(int p_deviceNum, MxDriver*& p_driver, Direct3DDeviceInfo*& p_device) +{ + if (p_deviceNum < 0 || !IsInitialized()) { + return -1; + } + + int i = 0; + + for (list::iterator it = m_list.begin(); it != m_list.end(); it++) { + p_driver = &*it; + + for (list::iterator it2 = p_driver->m_devices.begin(); it2 != p_driver->m_devices.end(); + it2++) { + if (i == p_deviceNum) { + p_device = &*it2; + return 0; + } + i++; + } + } + + return -1; +} + +// FUNCTION: CONFIG 0x004027d0 +// FUNCTION: BETA10 0x1011cb70 +int LegoDeviceEnumerate::FormatDeviceName(char* p_buffer, const MxDriver* p_ddInfo, const Direct3DDeviceInfo* p_d3dInfo) + const +{ + int number = 0; + assert(p_ddInfo && p_d3dInfo); + + for (list::const_iterator it = m_list.begin(); it != m_list.end(); it++, number++) { + if (&(*it) == p_ddInfo) { + GUID4 guid; + memcpy(&guid, p_d3dInfo->m_guid, sizeof(GUID4)); + + sprintf(p_buffer, "%d 0x%x 0x%x 0x%x 0x%x", number, guid.m_data1, guid.m_data2, guid.m_data3, guid.m_data4); + return 0; + } + } + + return -1; +} + +// FUNCTION: BETA10 0x1011cc65 +int LegoDeviceEnumerate::BETA_1011cc65(int p_idx, char* p_buffer) +{ + if (p_idx < 0 || !IsInitialized()) { + return -1; + } + + int i = 0; + int j = 0; + + for (list::iterator it = m_list.begin(); it != m_list.end(); it++, i++) { + MxDriver& driver = *it; + for (list::iterator it2 = driver.m_devices.begin(); it2 != driver.m_devices.end(); it2++) { + + if (j == p_idx) { + GUID4 guid; + memcpy(&guid, &((Direct3DDeviceInfo&) *it2).m_guid, sizeof(GUID4)); + sprintf(p_buffer, "%d 0x%x 0x%x 0x%x 0x%x", i, guid.m_data1, guid.m_data2, guid.m_data3, guid.m_data4); + return 0; + } + + j++; + } + } + + return -1; +} + +// FUNCTION: CONFIG 0x00402860 +// FUNCTION: LEGO1 0x1009d0d0 +// FUNCTION: BETA10 0x1011cdb4 +int LegoDeviceEnumerate::FUN_1009d0d0() +{ + if (!IsInitialized()) { + return -1; + } + + if (m_list.size() == 0) { + return -1; + } + + int i = 0; + int j = 0; + int k = -1; + int cpu_mmx = SupportsMMX(); + + for (list::iterator it = m_list.begin(); it != m_list.end(); it++, i++) { + + MxDriver& driver = *it; + for (list::iterator it2 = driver.m_devices.begin(); it2 != driver.m_devices.end(); it2++) { + if ((*it2).m_HWDesc.dcmColorModel) { + return j; + } + else { + if (cpu_mmx && (*it2).m_HELDesc.dcmColorModel == D3DCOLOR_RGB && i == 0) { + k = j; + } + else if ((*it2).m_HELDesc.dcmColorModel == D3DCOLOR_MONO && i == 0 && k < 0) { + k = j; + } + } + + j++; + } + } + + return k; +} + +// FUNCTION: CONFIG 0x00402930 +// FUNCTION: LEGO1 0x1009d1a0 +// FUNCTION: BETA10 0x1011cf54 +int LegoDeviceEnumerate::SupportsMMX() +{ + if (!SupportsCPUID()) { + return 0; + } + int supports_mmx; +#ifdef _MSC_VER + __asm { + mov eax, 0x0 ; EAX=0: Highest Function Parameter and Manufacturer ID +#if _MSC_VER > 1100 + cpuid ; Run CPUID +#else + __emit 0x0f + __emit 0xa2 +#endif + mov eax, 0x1 ; EAX=1: Processor Info and Feature Bits (unused) +#if _MSC_VER > 1100 + cpuid ; Run CPUID +#else + __emit 0x0f + __emit 0xa2 +#endif + xor eax, eax ; Zero EAX register + bt edx, 0x17 ; Test bit 0x17 (23): MMX instructions (64-bit SIMD) (Store in CF) + adc eax, eax ; Add with carry: EAX = EAX + EAX + CF = CF + mov supports_mmx, eax ; Save eax into C variable + } +#else + __asm__("movl $0x0, %%eax\n\t" // EAX=0: Highest Function Parameter and Manufacturer ID + "cpuid\n\t" // Run CPUID\n" + "mov $0x1, %%eax\n\t" // EAX=1: Processor Info and Feature Bits (unused) + "cpuid\n\t" // Run CPUID + "xorl %%eax, %%eax\n\t" // Zero EAX register + "btl $0x15, %%edx\n\t" // Test bit 0x17 (23): MMX instructions (64-bit SIMD) (Store in CF) + "adc %%eax, %%eax" // Add with carry: EAX = EAX + EAX + CF = CF + : "=a"(supports_mmx) // supports_mmx == EAX + ); +#endif + return supports_mmx; +} + +// FUNCTION: CONFIG 0x00402970 +// FUNCTION: LEGO1 0x1009d1e0 +// FUNCTION: BETA10 0x1011cf97 +int LegoDeviceEnumerate::SupportsCPUID() +{ + int has_cpuid; +#ifdef _MSC_VER +#if defined(_M_IX86) + __asm { + xor eax, eax ; Zero EAX register + pushfd ; Push EFLAGS register value on the stack + or dword ptr[esp], 0x200000 ; Set bit 0x200000: Able to use CPUID instruction (Pentium+) + popfd ; Write the updated value into the EFLAGS register + pushfd ; Push EFLAGS register value on the stack (again) + btr dword ptr[esp], 0x15 ; Test bit 0x15 (21) and reset (set CF) + adc eax, eax ; Add with carry: EAX = EAX + EAX + CF = CF + popfd ; Push EFLAGS register value on the stack (again, and makes sure the stack remains the same) + mov has_cpuid, eax ; Save eax into C variable + } +#elif defined(_M_X64) + has_cpuid = 1; +#else + has_cpuid = 0; +#endif +#else +#if defined(__i386__) + __asm__("xorl %%eax, %%eax\n\t" // Zero EAX register + "pushfl\n\t" // Push EFLAGS register value on the stack + "orl $0x200000, (%%esp)\n\t" // Set bit 0x200000: Able to use CPUID instruction (Pentium+) + "popfl\n\t" // Write the updated value into the EFLAGS register + "pushfl\n\t" // Push EFLAGS register value on the stack (again) + "btrl $0x15, (%%esp)\n\t" // Test bit 0x15 (21) and reset (set CF) + "adc %%eax, %%eax\n\t" // Add with carry: EAX = EAX + EAX + CF = CF + "popfl" // Push EFLAGS register value on the stack (again, and makes sure the stack remains the same) + : "=a"(has_cpuid) // has_cpuid == EAX + ); +#elif defined(__x86_64__) || defined(__amd64__) + has_cpuid = 1; +#else + has_cpuid = 0; +#endif +#endif + return has_cpuid; +} + +// FUNCTION: CONFIG 0x004029a0 +// FUNCTION: LEGO1 0x1009d210 +// FUNCTION: BETA10 0x1011cfc4 +int LegoDeviceEnumerate::FUN_1009d210() +{ + if (!IsInitialized()) { + return -1; + } + + for (list::iterator it = m_list.begin(); it != m_list.end();) { + if (!DriverSupportsRequiredDisplayMode(*it)) { + m_list.erase(it++); + continue; + } + + MxDriver& driver = *it; + + for (list::iterator it2 = driver.m_devices.begin(); it2 != driver.m_devices.end();) { + if (!FUN_1009d3d0(*it2)) { + driver.m_devices.erase(it2++); + } + else { + it2++; + } + } + + if (!driver.m_devices.size()) { + m_list.erase(it++); + } + else { + it++; + } + } + + if (!m_list.size()) { + return -1; + } + + return 0; +} + +// FUNCTION: CONFIG 0x00402b00 +// FUNCTION: LEGO1 0x1009d370 +// FUNCTION: BETA10 0x1011d176 +unsigned char LegoDeviceEnumerate::DriverSupportsRequiredDisplayMode(MxDriver& p_driver) +{ + for (list::iterator it = p_driver.m_displayModes.begin(); it != p_driver.m_displayModes.end(); + it++) { + if ((*it).m_width == 640 && (*it).m_height == 480) { + if ((*it).m_bitsPerPixel == 8 || (*it).m_bitsPerPixel == 16) { + return TRUE; + } + } + } + + return FALSE; +} + +// FUNCTION: CONFIG 0x00402b60 +// FUNCTION: LEGO1 0x1009d3d0 +// FUNCTION: BETA10 0x1011d235 +unsigned char LegoDeviceEnumerate::FUN_1009d3d0(Direct3DDeviceInfo& p_device) +{ + if (m_list.size() <= 0) { + return FALSE; + } + + if (p_device.m_HWDesc.dcmColorModel) { + if (p_device.m_HWDesc.dwDeviceZBufferBitDepth & DDBD_16 && + p_device.m_HWDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) { + return TRUE; + } + else { + return FALSE; + } + } + + MxDriver& front = m_list.front(); + for (list::iterator it = front.m_devices.begin(); it != front.m_devices.end(); it++) { + if ((&*it) == &p_device) { + return TRUE; + } + } + + return FALSE; +} diff --git a/LEGO1/mxdirectx/legodxinfo.h b/LEGO1/mxdirectx/legodxinfo.h new file mode 100644 index 00000000..2888c02c --- /dev/null +++ b/LEGO1/mxdirectx/legodxinfo.h @@ -0,0 +1,32 @@ +#ifndef LEGODXINFO_H +#define LEGODXINFO_H + +#include "mxdirectxinfo.h" + +// VTABLE: CONFIG 0x4060e4 +// VTABLE: LEGO1 0x100d9cc8 +// VTABLE: BETA10 0x101befb4 +// SIZE 0x14 +class LegoDeviceEnumerate : public MxDeviceEnumerate { +public: + int ParseDeviceName(const char* p_deviceId); + int ProcessDeviceBytes(int p_deviceNum, GUID& p_guid); + int GetDevice(int p_deviceNum, MxDriver*& p_driver, Direct3DDeviceInfo*& p_device); + int FormatDeviceName(char* p_buffer, const MxDriver* p_ddInfo, const Direct3DDeviceInfo* p_d3dInfo) const; + int BETA_1011cc65(int p_idx, char* p_buffer); + int FUN_1009d0d0(); + static int SupportsMMX(); + static int SupportsCPUID(); + int FUN_1009d210(); + unsigned char DriverSupportsRequiredDisplayMode(MxDriver& p_driver); + unsigned char FUN_1009d3d0(Direct3DDeviceInfo& p_device); + + // SYNTHETIC: BETA10 0x100d8d10 + // LegoDeviceEnumerate::LegoDeviceEnumerate + + // SYNTHETIC: LEGO1 0x1007b590 + // SYNTHETIC: BETA10 0x100d8da0 + // LegoDeviceEnumerate::~LegoDeviceEnumerate +}; + +#endif // LEGODXINFO_H diff --git a/LEGO1/mxdirectx/mxdirectxinfo.cpp b/LEGO1/mxdirectx/mxdirectxinfo.cpp index dded6e04..4d2950e3 100644 --- a/LEGO1/mxdirectx/mxdirectxinfo.cpp +++ b/LEGO1/mxdirectx/mxdirectxinfo.cpp @@ -570,373 +570,6 @@ const char* MxDeviceEnumerate::EnumerateErrorToString(HRESULT p_error) } } -// FUNCTION: CONFIG 0x00402560 -// FUNCTION: LEGO1 0x1009ce60 -// FUNCTION: BETA10 0x1011c7e0 -int MxDeviceEnumerate::ParseDeviceName(const char* p_deviceId) -{ - if (!IsInitialized()) { - return -1; - } - - int unknown = -1; - int num = -1; - int hex[4]; - - if (sscanf(p_deviceId, "%d 0x%x 0x%x 0x%x 0x%x", &num, &hex[0], &hex[1], &hex[2], &hex[3]) != 5) { - return -1; - } - - if (num < 0) { - return -1; - } - - GUID guid; - memcpy(&guid, hex, sizeof(guid)); - - int result = ProcessDeviceBytes(num, guid); - - if (result < 0) { - result = ProcessDeviceBytes(-1, guid); - } - - return result; -} - -// FUNCTION: CONFIG 0x00402620 -// FUNCTION: LEGO1 0x1009cf20 -// FUNCTION: BETA10 0x1011c8b3 -int MxDeviceEnumerate::ProcessDeviceBytes(int p_deviceNum, GUID& p_guid) -{ - if (!IsInitialized()) { - return -1; - } - - int i = 0; - int j = 0; - - static_assert(sizeof(GUID4) == sizeof(GUID), "Equal size"); - - GUID4 deviceGuid; - memcpy(&deviceGuid, &p_guid, sizeof(GUID4)); - - for (list::iterator it = m_list.begin(); it != m_list.end(); it++, i++) { - if (p_deviceNum >= 0 && p_deviceNum < i) { - return -1; - } - - GUID4 compareGuid; - MxDriver& driver = *it; - for (list::iterator it2 = driver.m_devices.begin(); it2 != driver.m_devices.end(); it2++) { - Direct3DDeviceInfo& md3d = *it2; - assert(md3d.m_guid); - - memcpy(&compareGuid, md3d.m_guid, sizeof(GUID4)); - - if (GUID4::Compare(compareGuid, deviceGuid) && i == p_deviceNum) { - return j; - } - - j++; - } - } - - return -1; -} - -// FUNCTION: CONFIG 0x00402730 -// FUNCTION: LEGO1 0x1009d030 -// FUNCTION: BETA10 0x1011ca54 -int MxDeviceEnumerate::GetDevice(int p_deviceNum, MxDriver*& p_driver, Direct3DDeviceInfo*& p_device) -{ - if (p_deviceNum < 0 || !IsInitialized()) { - return -1; - } - - int i = 0; - - for (list::iterator it = m_list.begin(); it != m_list.end(); it++) { - p_driver = &*it; - - for (list::iterator it2 = p_driver->m_devices.begin(); it2 != p_driver->m_devices.end(); - it2++) { - if (i == p_deviceNum) { - p_device = &*it2; - return 0; - } - i++; - } - } - - return -1; -} - -// FUNCTION: CONFIG 0x004027d0 -// FUNCTION: BETA10 0x1011cb70 -int MxDeviceEnumerate::FormatDeviceName(char* p_buffer, const MxDriver* p_ddInfo, const Direct3DDeviceInfo* p_d3dInfo) - const -{ - int number = 0; - assert(p_ddInfo && p_d3dInfo); - - for (list::const_iterator it = m_list.begin(); it != m_list.end(); it++, number++) { - if (&(*it) == p_ddInfo) { - GUID4 guid; - memcpy(&guid, p_d3dInfo->m_guid, sizeof(GUID4)); - - sprintf(p_buffer, "%d 0x%x 0x%x 0x%x 0x%x", number, guid.m_data1, guid.m_data2, guid.m_data3, guid.m_data4); - return 0; - } - } - - return -1; -} - -// FUNCTION: BETA10 0x1011cc65 -int MxDeviceEnumerate::BETA_1011cc65(int p_idx, char* p_buffer) -{ - if (p_idx < 0 || !IsInitialized()) { - return -1; - } - - int i = 0; - int j = 0; - - for (list::iterator it = m_list.begin(); it != m_list.end(); it++, i++) { - MxDriver& driver = *it; - for (list::iterator it2 = driver.m_devices.begin(); it2 != driver.m_devices.end(); it2++) { - - if (j == p_idx) { - GUID4 guid; - memcpy(&guid, &((Direct3DDeviceInfo&) *it2).m_guid, sizeof(GUID4)); - sprintf(p_buffer, "%d 0x%x 0x%x 0x%x 0x%x", i, guid.m_data1, guid.m_data2, guid.m_data3, guid.m_data4); - return 0; - } - - j++; - } - } - - return -1; -} - -// FUNCTION: CONFIG 0x00402860 -// FUNCTION: LEGO1 0x1009d0d0 -// FUNCTION: BETA10 0x1011cdb4 -int MxDeviceEnumerate::FUN_1009d0d0() -{ - if (!IsInitialized()) { - return -1; - } - - if (m_list.size() == 0) { - return -1; - } - - int i = 0; - int j = 0; - int k = -1; - int cpu_mmx = SupportsMMX(); - - for (list::iterator it = m_list.begin(); it != m_list.end(); it++, i++) { - - MxDriver& driver = *it; - for (list::iterator it2 = driver.m_devices.begin(); it2 != driver.m_devices.end(); it2++) { - if ((*it2).m_HWDesc.dcmColorModel) { - return j; - } - else { - if (cpu_mmx && (*it2).m_HELDesc.dcmColorModel == D3DCOLOR_RGB && i == 0) { - k = j; - } - else if ((*it2).m_HELDesc.dcmColorModel == D3DCOLOR_MONO && i == 0 && k < 0) { - k = j; - } - } - - j++; - } - } - - return k; -} - -// FUNCTION: CONFIG 0x00402930 -// FUNCTION: LEGO1 0x1009d1a0 -// FUNCTION: BETA10 0x1011cf54 -int MxDeviceEnumerate::SupportsMMX() -{ - if (!SupportsCPUID()) { - return 0; - } - int supports_mmx; -#ifdef _MSC_VER - __asm { - mov eax, 0x0 ; EAX=0: Highest Function Parameter and Manufacturer ID -#if _MSC_VER > 1100 - cpuid ; Run CPUID -#else - __emit 0x0f - __emit 0xa2 -#endif - mov eax, 0x1 ; EAX=1: Processor Info and Feature Bits (unused) -#if _MSC_VER > 1100 - cpuid ; Run CPUID -#else - __emit 0x0f - __emit 0xa2 -#endif - xor eax, eax ; Zero EAX register - bt edx, 0x17 ; Test bit 0x17 (23): MMX instructions (64-bit SIMD) (Store in CF) - adc eax, eax ; Add with carry: EAX = EAX + EAX + CF = CF - mov supports_mmx, eax ; Save eax into C variable - } -#else - __asm__("movl $0x0, %%eax\n\t" // EAX=0: Highest Function Parameter and Manufacturer ID - "cpuid\n\t" // Run CPUID\n" - "mov $0x1, %%eax\n\t" // EAX=1: Processor Info and Feature Bits (unused) - "cpuid\n\t" // Run CPUID - "xorl %%eax, %%eax\n\t" // Zero EAX register - "btl $0x15, %%edx\n\t" // Test bit 0x17 (23): MMX instructions (64-bit SIMD) (Store in CF) - "adc %%eax, %%eax" // Add with carry: EAX = EAX + EAX + CF = CF - : "=a"(supports_mmx) // supports_mmx == EAX - ); -#endif - return supports_mmx; -} - -// FUNCTION: CONFIG 0x00402970 -// FUNCTION: LEGO1 0x1009d1e0 -// FUNCTION: BETA10 0x1011cf97 -int MxDeviceEnumerate::SupportsCPUID() -{ - int has_cpuid; -#ifdef _MSC_VER -#if defined(_M_IX86) - __asm { - xor eax, eax ; Zero EAX register - pushfd ; Push EFLAGS register value on the stack - or dword ptr[esp], 0x200000 ; Set bit 0x200000: Able to use CPUID instruction (Pentium+) - popfd ; Write the updated value into the EFLAGS register - pushfd ; Push EFLAGS register value on the stack (again) - btr dword ptr[esp], 0x15 ; Test bit 0x15 (21) and reset (set CF) - adc eax, eax ; Add with carry: EAX = EAX + EAX + CF = CF - popfd ; Push EFLAGS register value on the stack (again, and makes sure the stack remains the same) - mov has_cpuid, eax ; Save eax into C variable - } -#elif defined(_M_X64) - has_cpuid = 1; -#else - has_cpuid = 0; -#endif -#else -#if defined(__i386__) - __asm__("xorl %%eax, %%eax\n\t" // Zero EAX register - "pushfl\n\t" // Push EFLAGS register value on the stack - "orl $0x200000, (%%esp)\n\t" // Set bit 0x200000: Able to use CPUID instruction (Pentium+) - "popfl\n\t" // Write the updated value into the EFLAGS register - "pushfl\n\t" // Push EFLAGS register value on the stack (again) - "btrl $0x15, (%%esp)\n\t" // Test bit 0x15 (21) and reset (set CF) - "adc %%eax, %%eax\n\t" // Add with carry: EAX = EAX + EAX + CF = CF - "popfl" // Push EFLAGS register value on the stack (again, and makes sure the stack remains the same) - : "=a"(has_cpuid) // has_cpuid == EAX - ); -#elif defined(__x86_64__) || defined(__amd64__) - has_cpuid = 1; -#else - has_cpuid = 0; -#endif -#endif - return has_cpuid; -} - -// FUNCTION: CONFIG 0x004029a0 -// FUNCTION: LEGO1 0x1009d210 -// FUNCTION: BETA10 0x1011cfc4 -int MxDeviceEnumerate::FUN_1009d210() -{ - if (!IsInitialized()) { - return -1; - } - - for (list::iterator it = m_list.begin(); it != m_list.end();) { - if (!DriverSupportsRequiredDisplayMode(*it)) { - m_list.erase(it++); - continue; - } - - MxDriver& driver = *it; - - for (list::iterator it2 = driver.m_devices.begin(); it2 != driver.m_devices.end();) { - if (!FUN_1009d3d0(*it2)) { - driver.m_devices.erase(it2++); - } - else { - it2++; - } - } - - if (!driver.m_devices.size()) { - m_list.erase(it++); - } - else { - it++; - } - } - - if (!m_list.size()) { - return -1; - } - - return 0; -} - -// FUNCTION: CONFIG 0x00402b00 -// FUNCTION: LEGO1 0x1009d370 -// FUNCTION: BETA10 0x1011d176 -unsigned char MxDeviceEnumerate::DriverSupportsRequiredDisplayMode(MxDriver& p_driver) -{ - for (list::iterator it = p_driver.m_displayModes.begin(); it != p_driver.m_displayModes.end(); - it++) { - if ((*it).m_width == 640 && (*it).m_height == 480) { - if ((*it).m_bitsPerPixel == 8 || (*it).m_bitsPerPixel == 16) { - return TRUE; - } - } - } - - return FALSE; -} - -// FUNCTION: CONFIG 0x00402b60 -// FUNCTION: LEGO1 0x1009d3d0 -// FUNCTION: BETA10 0x1011d235 -unsigned char MxDeviceEnumerate::FUN_1009d3d0(Direct3DDeviceInfo& p_device) -{ - if (m_list.size() <= 0) { - return FALSE; - } - - if (p_device.m_HWDesc.dcmColorModel) { - if (p_device.m_HWDesc.dwDeviceZBufferBitDepth & DDBD_16 && - p_device.m_HWDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) { - return TRUE; - } - else { - return FALSE; - } - } - - MxDriver& front = m_list.front(); - for (list::iterator it = front.m_devices.begin(); it != front.m_devices.end(); it++) { - if ((&*it) == &p_device) { - return TRUE; - } - } - - return FALSE; -} - // FUNCTION: LEGO1 0x1009efb0 // FUNCTION: BETA10 0x10122ee2 DeviceModesInfo::DeviceModesInfo() diff --git a/LEGO1/mxdirectx/mxdirectxinfo.h b/LEGO1/mxdirectx/mxdirectxinfo.h index e585cd1e..0371b276 100644 --- a/LEGO1/mxdirectx/mxdirectxinfo.h +++ b/LEGO1/mxdirectx/mxdirectxinfo.h @@ -203,17 +203,6 @@ class MxDeviceEnumerate { LPD3DDEVICEDESC p_HELDesc ); const char* EnumerateErrorToString(HRESULT p_error); - int ParseDeviceName(const char* p_deviceId); - int ProcessDeviceBytes(int p_deviceNum, GUID& p_guid); - int GetDevice(int p_deviceNum, MxDriver*& p_driver, Direct3DDeviceInfo*& p_device); - int FormatDeviceName(char* p_buffer, const MxDriver* p_ddInfo, const Direct3DDeviceInfo* p_d3dInfo) const; - int BETA_1011cc65(int p_idx, char* p_buffer); - - int FUN_1009d0d0(); - int FUN_1009d210(); - unsigned char DriverSupportsRequiredDisplayMode(MxDriver& p_driver); - unsigned char FUN_1009d3d0(Direct3DDeviceInfo& p_device); - static void BuildErrorString(const char*, ...); static BOOL CALLBACK DirectDrawEnumerateCallback(LPGUID p_guid, LPSTR p_driverDesc, LPSTR p_driverName, LPVOID p_context); @@ -226,8 +215,6 @@ class MxDeviceEnumerate { LPD3DDEVICEDESC p_HELDesc, LPVOID p_context ); - static int SupportsMMX(); - static int SupportsCPUID(); friend class MxDirect3D; @@ -251,24 +238,11 @@ class MxDeviceEnumerate { // FUNCTION: BETA10 0x1011d320 unsigned char IsInitialized() const { return m_initialized; } -private: +protected: list m_list; // 0x04 unsigned char m_initialized; // 0x10 }; -// VTABLE: CONFIG 0x4060e4 -// VTABLE: LEGO1 0x100d9cc8 -// VTABLE: BETA10 0x101befb4 -// SIZE 0x14 -class LegoDeviceEnumerate : public MxDeviceEnumerate {}; - -// SYNTHETIC: BETA10 0x100d8d10 -// LegoDeviceEnumerate::LegoDeviceEnumerate - -// SYNTHETIC: LEGO1 0x1007b590 -// SYNTHETIC: BETA10 0x100d8da0 -// LegoDeviceEnumerate::~LegoDeviceEnumerate - // TEMPLATE: BETA10 0x1011c1b0 // list >::iterator::operator* From 0760e4e7d72f47d1630fbf1cb192313f9fc7c550 Mon Sep 17 00:00:00 2001 From: MS Date: Tue, 16 Jul 2024 22:23:10 -0400 Subject: [PATCH 07/11] Option to disable decomp asserts in MSVC (#1066) --- CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ed6f3a6..a775dc2e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,6 +66,7 @@ option(ISLE_BUILD_APP "Build ISLE.EXE application" ON) cmake_dependent_option(ISLE_BUILD_CONFIG "Build CONFIG.EXE application" ON "NOT MINGW" OFF) option(ISLE_USE_SMARTHEAP "Build with SmartHeap" ${MSVC_FOR_DECOMP}) option(ISLE_USE_DX5 "Build with internal DirectX 5 SDK" ON) +option(ISLE_DECOMP_ASSERT "Assert struct size" ${MSVC_FOR_DECOMP}) cmake_dependent_option(ISLE_USE_DX5_LIBS "Build with internal DirectX 5 SDK Libraries" ON ISLE_USE_DX5 OFF) add_cxx_warning(parentheses) @@ -512,7 +513,8 @@ if (MSVC) endif() endif() -if (MSVC_FOR_DECOMP) +if (ISLE_DECOMP_ASSERT) + message(STATUS "Decomp asserts enabled") foreach(tgt IN LISTS lego1_targets) target_compile_definitions(${tgt} PRIVATE "ENABLE_DECOMP_ASSERTS") endforeach() From 210376f2724b2482ce5ab547f300ca42b0583063 Mon Sep 17 00:00:00 2001 From: jonschz <17198703+jonschz@users.noreply.github.com> Date: Wed, 17 Jul 2024 16:03:02 +0200 Subject: [PATCH 08/11] Implement `LegoRaceCar::HandleSkeletonKicks` and dependents (#1065) * Implement `LegoRaceCar::HandleSkeletonKicks` and dependents * Fix typo * Spike to fix array comparisons (needs refactor) * Refactor: Dedicated method for array element matching * Address review comments * Reformat with new version of black * Apply more review comments * Address more review comments --------- Co-authored-by: jonschz --- LEGO1/lego/legoomni/include/carrace.h | 3 + LEGO1/lego/legoomni/include/legoracers.h | 22 ++++- LEGO1/lego/legoomni/include/raceskel.h | 4 +- LEGO1/lego/legoomni/src/race/legoracers.cpp | 81 ++++++++++++++++--- LEGO1/lego/legoomni/src/race/raceskel.cpp | 12 +++ LEGO1/lego/sources/geom/legowegedge.h | 2 + tools/isledecomp/isledecomp/compare/core.py | 67 ++++++++++++++- .../isledecomp/isledecomp/cvdump/analysis.py | 5 +- 8 files changed, 179 insertions(+), 17 deletions(-) diff --git a/LEGO1/lego/legoomni/include/carrace.h b/LEGO1/lego/legoomni/include/carrace.h index fd33c536..5a43f420 100644 --- a/LEGO1/lego/legoomni/include/carrace.h +++ b/LEGO1/lego/legoomni/include/carrace.h @@ -52,6 +52,9 @@ class CarRace : public LegoRace { MxLong HandleEndAction(MxEndActionNotificationParam&) override; // vtable+0x74 MxLong HandleType0Notification(MxNotificationParam&) override; // vtable+0x78 + // FUNCTION: BETA10 0x100cd060 + undefined4 GetUnk0x150() { return m_unk0x150; } + // SYNTHETIC: LEGO1 0x10016c70 // CarRace::`scalar deleting destructor' diff --git a/LEGO1/lego/legoomni/include/legoracers.h b/LEGO1/lego/legoomni/include/legoracers.h index 290a849f..d66349a5 100644 --- a/LEGO1/lego/legoomni/include/legoracers.h +++ b/LEGO1/lego/legoomni/include/legoracers.h @@ -4,12 +4,24 @@ #include "legocarraceactor.h" #include "legoracemap.h" +#define LEGORACECAR_UNKNOWN_STATE 0 +#define LEGORACECAR_KICK1 2 // name guessed +#define LEGORACECAR_KICK2 4 // name validated by BETA10 0x100cb659 + // SIZE 0x08 struct EdgeReference { const char* m_name; // 0x00 LegoPathBoundary* m_data; // 0x04 }; +// SIZE 0x10 +struct SkeletonKickPhase { + EdgeReference* m_edgeRef; // 0x00 + float m_lower; // 0x04 + float m_upper; // 0x08 + MxU8 m_userState; // 0x0c +}; + // VTABLE: LEGO1 0x100d58a0 LegoRaceActor // VTABLE: LEGO1 0x100d58a8 LegoAnimActor // VTABLE: LEGO1 0x100d58b8 LegoPathActor @@ -41,7 +53,7 @@ class LegoRaceCar : public LegoCarRaceActor, public LegoRaceMap { return !strcmp(p_name, LegoRaceCar::ClassName()) || LegoCarRaceActor::IsA(p_name); } - void ParseAction(char*) override; // vtable+0x20 + void ParseAction(char* p_extra) override; // vtable+0x20 void SetWorldSpeed(MxFloat p_worldSpeed) override; // vtable+0x30 MxU32 VTable0x6c( LegoPathBoundary* p_boundary, @@ -58,8 +70,8 @@ class LegoRaceCar : public LegoCarRaceActor, public LegoRaceMap { MxResult VTable0x9c() override; // vtable+0x9c virtual void SetMaxLinearVelocity(float p_maxLinearVelocity); - virtual void FUN_10012ff0(float); - virtual MxBool FUN_10013130(float); + virtual void FUN_10012ff0(float p_param); + virtual MxU32 HandleSkeletonKicks(float p_param1); // SYNTHETIC: LEGO1 0x10014240 // LegoRaceCar::`scalar deleting destructor' @@ -74,7 +86,9 @@ class LegoRaceCar : public LegoCarRaceActor, public LegoRaceMap { LegoPathBoundary* m_unk0x7c; // 0x7c static EdgeReference g_edgeReferences[]; - static const EdgeReference* g_pEdgeReferences; + static const SkeletonKickPhase g_skeletonKickPhases[]; // TODO: better name + + static const char* g_soundSkel3; }; #endif // LEGORACERS_H diff --git a/LEGO1/lego/legoomni/include/raceskel.h b/LEGO1/lego/legoomni/include/raceskel.h index 6d9a270b..fca57dde 100644 --- a/LEGO1/lego/legoomni/include/raceskel.h +++ b/LEGO1/lego/legoomni/include/raceskel.h @@ -12,8 +12,10 @@ class RaceSkel : public LegoAnimActor { public: RaceSkel(); + void GetCurrentAnimData(float* p_outCurAnimPosition, float* p_outCurAnimDuration); + private: - undefined4 m_unk0x1c; // 0x1c + float m_animPosition; // 0x1c }; #endif // RACESKEL_H diff --git a/LEGO1/lego/legoomni/src/race/legoracers.cpp b/LEGO1/lego/legoomni/src/race/legoracers.cpp index 2a4e2185..720ea13c 100644 --- a/LEGO1/lego/legoomni/src/race/legoracers.cpp +++ b/LEGO1/lego/legoomni/src/race/legoracers.cpp @@ -1,15 +1,21 @@ #include "legoracers.h" #include "anim/legoanim.h" +#include "carrace.h" #include "define.h" +#include "legocachesoundmanager.h" #include "legocameracontroller.h" #include "legorace.h" +#include "legosoundmanager.h" #include "misc.h" +#include "mxdebug.h" #include "mxmisc.h" #include "mxnotificationmanager.h" #include "mxutilities.h" +#include "raceskel.h" DECOMP_SIZE_ASSERT(EdgeReference, 0x08) +DECOMP_SIZE_ASSERT(SkeletonKickPhase, 0x10) DECOMP_SIZE_ASSERT(LegoRaceCar, 0x200) // GLOBAL: LEGO1 0x100f0a20 @@ -41,7 +47,24 @@ EdgeReference LegoRaceCar::g_edgeReferences[] = { }; // GLOBAL: LEGO1 0x100f0a50 -const EdgeReference* LegoRaceCar::g_pEdgeReferences = g_edgeReferences; +const SkeletonKickPhase LegoRaceCar::g_skeletonKickPhases[] = { + {&LegoRaceCar::g_edgeReferences[0], 0.1, 0.2, LEGORACECAR_KICK2}, + {&LegoRaceCar::g_edgeReferences[1], 0.2, 0.3, LEGORACECAR_KICK2}, + {&LegoRaceCar::g_edgeReferences[2], 0.3, 0.4, LEGORACECAR_KICK2}, + {&LegoRaceCar::g_edgeReferences[2], 0.6, 0.7, LEGORACECAR_KICK1}, + {&LegoRaceCar::g_edgeReferences[1], 0.7, 0.8, LEGORACECAR_KICK1}, + {&LegoRaceCar::g_edgeReferences[0], 0.8, 0.9, LEGORACECAR_KICK1}, + {&LegoRaceCar::g_edgeReferences[3], 0.1, 0.2, LEGORACECAR_KICK1}, + {&LegoRaceCar::g_edgeReferences[4], 0.2, 0.3, LEGORACECAR_KICK1}, + {&LegoRaceCar::g_edgeReferences[5], 0.3, 0.4, LEGORACECAR_KICK1}, + {&LegoRaceCar::g_edgeReferences[5], 0.6, 0.7, LEGORACECAR_KICK2}, + {&LegoRaceCar::g_edgeReferences[4], 0.7, 0.8, LEGORACECAR_KICK2}, + {&LegoRaceCar::g_edgeReferences[3], 0.8, 0.9, LEGORACECAR_KICK2}, +}; + +// GLOBAL: LEGO1 0x100f0b70 +// STRING: LEGO1 0x100f08bc +const char* LegoRaceCar::g_soundSkel3 = "skel3"; // FUNCTION: LEGO1 0x10012950 LegoRaceCar::LegoRaceCar() @@ -140,13 +163,11 @@ void LegoRaceCar::FUN_10012ff0(float p_param) LegoAnimActorStruct* a; // called `a` in BETA10 float deltaTime; - if (m_userState == 2) { + if (m_userState == LEGORACECAR_KICK1) { a = m_unk0x70; } else { - // TODO: Possibly an enum? - const char legoracecarKick2 = 4; // original name: LEGORACECAR_KICK2 - assert(m_userState == legoracecarKick2); + assert(m_userState == LEGORACECAR_KICK2); a = m_unk0x74; } @@ -156,7 +177,7 @@ void LegoRaceCar::FUN_10012ff0(float p_param) deltaTime = p_param - m_unk0x58; if (a->GetDuration() <= deltaTime || deltaTime < 0.0) { - if (m_userState == 2) { + if (m_userState == LEGORACECAR_KICK1) { LegoEdge** edges = m_unk0x78->GetEdges(); m_destEdge = (LegoUnknown100db7f4*) (edges[2]); m_boundary = m_unk0x78; @@ -167,7 +188,7 @@ void LegoRaceCar::FUN_10012ff0(float p_param) m_boundary = m_unk0x7c; } - m_userState = 0; + m_userState = LEGORACECAR_UNKNOWN_STATE; } else if (a->GetAnimTreePtr()->GetCamAnim()) { MxMatrix transformationMatrix; @@ -189,10 +210,50 @@ void LegoRaceCar::FUN_10012ff0(float p_param) } } -// STUB: LEGO1 0x10013130 -MxBool LegoRaceCar::FUN_10013130(float) +// FUNCTION: LEGO1 0x10013130 +// FUNCTION: BETA10 0x100cce50 +MxU32 LegoRaceCar::HandleSkeletonKicks(float p_param1) { - // TODO + const SkeletonKickPhase* current = g_skeletonKickPhases; + + // TODO: Type is guesswork so far + CarRace* r = (CarRace*) CurrentWorld(); // called `r` in BETA10 + assert(r); + + RaceSkel* s = (RaceSkel*) r->GetUnk0x150(); // called `s` in BETA10 + assert(s); + + float skeletonCurAnimPosition; + float skeletonCurAnimDuration; + + s->GetCurrentAnimData(&skeletonCurAnimPosition, &skeletonCurAnimDuration); + + float skeletonCurAnimPhase = skeletonCurAnimPosition / skeletonCurAnimDuration; + + for (MxS32 i = 0; i < sizeOfArray(g_skeletonKickPhases); i++) { + if (m_boundary == current->m_edgeRef->m_data && current->m_lower <= skeletonCurAnimPhase && + skeletonCurAnimPhase <= current->m_upper) { + m_userState = current->m_userState; + } + current = ¤t[1]; + } + + if (m_userState != LEGORACECAR_KICK1 && m_userState != LEGORACECAR_KICK2) { + 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, + skeletonCurAnimPhase + ); + return FALSE; + } + + m_unk0x58 = p_param1; + SoundManager()->GetCacheSoundManager()->Play(g_soundSkel3, NULL, FALSE); + return TRUE; } diff --git a/LEGO1/lego/legoomni/src/race/raceskel.cpp b/LEGO1/lego/legoomni/src/race/raceskel.cpp index 5ef950e2..dd7e87f3 100644 --- a/LEGO1/lego/legoomni/src/race/raceskel.cpp +++ b/LEGO1/lego/legoomni/src/race/raceskel.cpp @@ -1,5 +1,7 @@ #include "raceskel.h" +#include + DECOMP_SIZE_ASSERT(RaceSkel, 0x178) // STUB: LEGO1 0x100719b0 @@ -7,3 +9,13 @@ RaceSkel::RaceSkel() { // TODO } + +// FUNCTION: LEGO1 0x10071cb0 +// FUNCTION: BETA10 0x100f158b +void RaceSkel::GetCurrentAnimData(float* p_outCurAnimPosition, float* p_outCurAnimDuration) +{ + *p_outCurAnimPosition = m_animPosition; + + assert(m_curAnim >= 0); + *p_outCurAnimDuration = m_animMaps[m_curAnim]->GetDuration(); +} diff --git a/LEGO1/lego/sources/geom/legowegedge.h b/LEGO1/lego/sources/geom/legowegedge.h index 716f830f..23bdf340 100644 --- a/LEGO1/lego/sources/geom/legowegedge.h +++ b/LEGO1/lego/sources/geom/legowegedge.h @@ -43,6 +43,8 @@ class LegoWEGEdge : public LegoWEEdge { LegoU32 GetFlag0x10() { return m_flags & c_bit5 ? FALSE : TRUE; } Mx4DPointFloat* GetUnknown0x14() { return &m_unk0x14; } Mx4DPointFloat* GetEdgeNormal(int index) { return &m_edgeNormals[index]; } + + // FUNCTION: BETA10 0x1001c9b0 LegoChar* GetName() { return m_name; } void SetFlag0x10(LegoU32 p_disable) diff --git a/tools/isledecomp/isledecomp/compare/core.py b/tools/isledecomp/isledecomp/compare/core.py index 1587ef81..3cf827e9 100644 --- a/tools/isledecomp/isledecomp/compare/core.py +++ b/tools/isledecomp/isledecomp/compare/core.py @@ -8,6 +8,7 @@ from isledecomp.bin import Bin as IsleBin, InvalidVirtualAddressError from isledecomp.cvdump.demangler import demangle_string_const from isledecomp.cvdump import Cvdump, CvdumpAnalysis +from isledecomp.cvdump.types import scalar_type_pointer from isledecomp.parser import DecompCodebase from isledecomp.dir import walk_source_dir from isledecomp.types import SymbolType @@ -220,7 +221,8 @@ def orig_bin_checker(addr: int) -> bool: var.offset, var.name, var.parent_function ) else: - self._db.match_variable(var.offset, var.name) + if self._db.match_variable(var.offset, var.name): + self._check_if_array_and_match_elements(var.offset, var.name) for tbl in codebase.iter_vtables(): self._db.match_vtable(tbl.offset, tbl.name, tbl.base_class) @@ -245,6 +247,69 @@ def orig_bin_checker(addr: int) -> bool: self._db.match_string(string.offset, string.name) + def _check_if_array_and_match_elements(self, orig_addr: int, name: str): + """ + Checks if the global variable at `orig_addr` is an array. + If yes, adds a match for all its elements. If it is an array of structs, all fields in that struct are also matched. + Note that there is no recursion, so an array of arrays would not be handled entirely. + This step is necessary e.g. for `0x100f0a20` (LegoRacers.cpp). + """ + + def _add_match_in_array( + name: str, type_id: str, orig_addr: int, recomp_addr: int + ): + self._db.set_recomp_symbol( + recomp_addr, + SymbolType.POINTER if scalar_type_pointer(type_id) else SymbolType.DATA, + name, + name, + # we only need the matches when they are referenced elsewhere, hence we don't need the size + size=None, + ) + self._db.set_pair(orig_addr, recomp_addr) + + matchinfo = self._db.get_by_orig(orig_addr) + if matchinfo is None or matchinfo.recomp_addr is None: + return + recomp_addr = matchinfo.recomp_addr + + node = next( + (x for x in self.cvdump_analysis.nodes if x.addr == recomp_addr), + None, + ) + if node is None or node.data_type is None: + return + + if not node.data_type.key.startswith("0x"): + # scalar type, so clearly not an array + return + + data_type = self.cv.types.keys[node.data_type.key.lower()] + + if data_type["type"] == "LF_ARRAY": + array_element_type = self.cv.types.get(data_type["array_type"]) + + assert node.data_type.members is not None + + for array_element in node.data_type.members: + orig_element_base_addr = orig_addr + array_element.offset + recomp_element_base_addr = recomp_addr + array_element.offset + if array_element_type.members is None: + _add_match_in_array( + f"{name}{array_element.name}", + array_element_type.key, + orig_element_base_addr, + recomp_element_base_addr, + ) + else: + for member in array_element_type.members: + _add_match_in_array( + f"{name}{array_element.name}.{member.name}", + array_element_type.key, + orig_element_base_addr + member.offset, + recomp_element_base_addr + member.offset, + ) + def _find_original_strings(self): """Go to the original binary and look for the specified string constants to find a match. This is a (relatively) expensive operation so we only diff --git a/tools/isledecomp/isledecomp/cvdump/analysis.py b/tools/isledecomp/isledecomp/cvdump/analysis.py index 40ef292e..e030035e 100644 --- a/tools/isledecomp/isledecomp/cvdump/analysis.py +++ b/tools/isledecomp/isledecomp/cvdump/analysis.py @@ -5,7 +5,7 @@ from isledecomp.types import SymbolType from .parser import CvdumpParser from .demangler import demangle_string_const, demangle_vtable -from .types import CvdumpKeyError, CvdumpIntegrityError +from .types import CvdumpKeyError, CvdumpIntegrityError, TypeInfo class CvdumpNode: @@ -35,6 +35,8 @@ class CvdumpNode: section_contribution: Optional[int] = None addr: Optional[int] = None symbol_entry: Optional[SymbolsEntry] = None + # Preliminary - only used for non-static variables at the moment + data_type: Optional[TypeInfo] = None def __init__(self, section: int, offset: int) -> None: self.section = section @@ -127,6 +129,7 @@ def __init__(self, parser: CvdumpParser): # get information for built-in "T_" types. g_info = parser.types.get(glo.type) node_dict[key].confirmed_size = g_info.size + node_dict[key].data_type = g_info # Previously we set the symbol type to POINTER here if # the variable was known to be a pointer. We can derive this # information later when it's time to compare the variable, From bc9abdc823537792c0dcbb65a377aa085fc1f5d1 Mon Sep 17 00:00:00 2001 From: jonschz <17198703+jonschz@users.noreply.github.com> Date: Thu, 18 Jul 2024 22:20:59 +0200 Subject: [PATCH 09/11] More legoracers functions (#1067) * Implement/match LegoRaceCar::VTable0x70 * Fix datacmp errors * minor fix * Fix naming issue * Address review comments, part 1 * Address review comments, part 2 --------- Co-authored-by: jonschz --- .../lego/legoomni/include/legocarraceactor.h | 2 +- LEGO1/lego/legoomni/include/legoracers.h | 10 ++- .../legoomni/src/entity/legocarraceactor.cpp | 2 +- LEGO1/lego/legoomni/src/race/legoracers.cpp | 75 ++++++++++++++++++- 4 files changed, 81 insertions(+), 8 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legocarraceactor.h b/LEGO1/lego/legoomni/include/legocarraceactor.h index 35c099d2..e68a2afc 100644 --- a/LEGO1/lego/legoomni/include/legocarraceactor.h +++ b/LEGO1/lego/legoomni/include/legocarraceactor.h @@ -38,7 +38,7 @@ class LegoCarRaceActor : public virtual LegoRaceActor { override; // vtable+0x98 MxResult VTable0x9c() override; // vtable+0x9c - virtual void FUN_10080590(); + virtual void FUN_10080590(float); // FUNCTION: LEGO1 0x10012bb0 virtual void FUN_10012bb0(float p_unk0x14) { m_unk0x14 = p_unk0x14; } diff --git a/LEGO1/lego/legoomni/include/legoracers.h b/LEGO1/lego/legoomni/include/legoracers.h index d66349a5..f460a050 100644 --- a/LEGO1/lego/legoomni/include/legoracers.h +++ b/LEGO1/lego/legoomni/include/legoracers.h @@ -4,7 +4,8 @@ #include "legocarraceactor.h" #include "legoracemap.h" -#define LEGORACECAR_UNKNOWN_STATE 0 +#define LEGORACECAR_UNKNOWN_0 0 +#define LEGORACECAR_UNKNOWN_1 1 #define LEGORACECAR_KICK1 2 // name guessed #define LEGORACECAR_KICK2 4 // name validated by BETA10 0x100cb659 @@ -86,9 +87,12 @@ class LegoRaceCar : public LegoCarRaceActor, public LegoRaceMap { LegoPathBoundary* m_unk0x7c; // 0x7c static EdgeReference g_edgeReferences[]; - static const SkeletonKickPhase g_skeletonKickPhases[]; // TODO: better name - + static const SkeletonKickPhase g_skeletonKickPhases[]; + static const char* g_strSpeedCopy; + static const char* g_srt001ra; static const char* g_soundSkel3; + static MxS32 g_unk0x100f0b88; + static MxBool g_unk0x100f0b8c; }; #endif // LEGORACERS_H diff --git a/LEGO1/lego/legoomni/src/entity/legocarraceactor.cpp b/LEGO1/lego/legoomni/src/entity/legocarraceactor.cpp index c36040b9..b74a652b 100644 --- a/LEGO1/lego/legoomni/src/entity/legocarraceactor.cpp +++ b/LEGO1/lego/legoomni/src/entity/legocarraceactor.cpp @@ -28,7 +28,7 @@ LegoCarRaceActor::LegoCarRaceActor() } // STUB: LEGO1 0x10080590 -void LegoCarRaceActor::FUN_10080590() +void LegoCarRaceActor::FUN_10080590(float) { } diff --git a/LEGO1/lego/legoomni/src/race/legoracers.cpp b/LEGO1/lego/legoomni/src/race/legoracers.cpp index 720ea13c..c5e227fa 100644 --- a/LEGO1/lego/legoomni/src/race/legoracers.cpp +++ b/LEGO1/lego/legoomni/src/race/legoracers.cpp @@ -5,6 +5,7 @@ #include "define.h" #include "legocachesoundmanager.h" #include "legocameracontroller.h" +#include "legonavcontroller.h" #include "legorace.h" #include "legosoundmanager.h" #include "misc.h" @@ -12,6 +13,7 @@ #include "mxmisc.h" #include "mxnotificationmanager.h" #include "mxutilities.h" +#include "mxvariabletable.h" #include "raceskel.h" DECOMP_SIZE_ASSERT(EdgeReference, 0x08) @@ -62,10 +64,26 @@ const SkeletonKickPhase LegoRaceCar::g_skeletonKickPhases[] = { {&LegoRaceCar::g_edgeReferences[3], 0.8, 0.9, LEGORACECAR_KICK2}, }; +// GLOBAL: LEGO1 0x100f0b10 +// STRING: LEGO1 0x100f09cc +const char* LegoRaceCar::g_strSpeedCopy = "SPEED"; + +// GLOBAL: LEGO1 0x100f0b6c +// STRING: LEGO1 0x100f08c4 +const char* LegoRaceCar::g_srt001ra = "srt001ra"; + // GLOBAL: LEGO1 0x100f0b70 // STRING: LEGO1 0x100f08bc const char* LegoRaceCar::g_soundSkel3 = "skel3"; +// GLOBAL: LEGO1 0x100f0b88 +// GLOBAL: BETA10 0x101f5f94 +MxS32 LegoRaceCar::g_unk0x100f0b88 = 0; + +// GLOBAL: LEGO1 0x100f0b8c +// GLOBAL: BETA10 0x101f5f98 +MxBool LegoRaceCar::g_unk0x100f0b8c = TRUE; + // FUNCTION: LEGO1 0x10012950 LegoRaceCar::LegoRaceCar() { @@ -188,7 +206,7 @@ void LegoRaceCar::FUN_10012ff0(float p_param) m_boundary = m_unk0x7c; } - m_userState = LEGORACECAR_UNKNOWN_STATE; + m_userState = LEGORACECAR_UNKNOWN_0; } else if (a->GetAnimTreePtr()->GetCamAnim()) { MxMatrix transformationMatrix; @@ -257,10 +275,61 @@ MxU32 LegoRaceCar::HandleSkeletonKicks(float p_param1) return TRUE; } -// STUB: LEGO1 0x100131f0 +// FUNCTION: LEGO1 0x100131f0 +// FUNCTION: BETA10 0x100cb88a void LegoRaceCar::VTable0x70(float p_float) { - // TODO + if (m_userNavFlag && (m_userState == LEGORACECAR_KICK1 || m_userState == LEGORACECAR_KICK2)) { + FUN_10012ff0(p_float); + return; + } + + LegoCarRaceActor::VTable0x70(p_float); + + if (m_userNavFlag && m_userState == LEGORACECAR_UNKNOWN_1) { + if (HandleSkeletonKicks(p_float)) { + return; + } + } + + if (LegoCarRaceActor::m_unk0x0c == 1) { + FUN_1005d4b0(); + + if (!m_userNavFlag) { + FUN_10080590(p_float); + return; + } + + float absoluteSpeed = abs(m_worldSpeed); + float maximumSpeed = NavController()->GetMaxLinearVel(); + char buffer[200]; + + sprintf(buffer, "%g", absoluteSpeed / maximumSpeed); + + VariableTable()->SetVariable(g_strSpeedCopy, buffer); + + if (m_sound) { + // pitches up the engine sound based on the velocity + if (absoluteSpeed > 0.83 * maximumSpeed) { + m_frequencyFactor = 1.9f; + } + else { + // this value seems to simulate RPM based on the gear + MxS32 gearRpmFactor = (MxS32) (6.0 * absoluteSpeed) % 100; + m_frequencyFactor = gearRpmFactor / 80.0 + 0.7; + } + } + + if (absoluteSpeed != 0.0f) { + g_unk0x100f0b88 = p_float; + g_unk0x100f0b8c = FALSE; + } + + if (p_float - g_unk0x100f0b88 > 5000.0f && !g_unk0x100f0b8c) { + SoundManager()->GetCacheSoundManager()->Play(g_srt001ra, NULL, 0); + g_unk0x100f0b8c = TRUE; + } + } } // STUB: LEGO1 0x100133c0 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 10/11] 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 @@ class LegoEntity : public MxEntity { 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 @@ class LegoPathActor : public LegoActor { 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 @@ class LegoRaceCar : public LegoCarRaceActor, public LegoRaceMap { 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 @@ class LegoROI : public ViewROI { ); 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 @@ class MxMatrix : public Matrix4 { 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 @@ class MxTimer : public MxCore { 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 @@ class OrientableROI : public ROI { 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]; } From f436b9365b90fc4a5edd16f34b7fe559bca072f8 Mon Sep 17 00:00:00 2001 From: jonschz <17198703+jonschz@users.noreply.github.com> Date: Sat, 27 Jul 2024 18:24:36 +0200 Subject: [PATCH 11/11] Implement/match the rest of `LegoRaceCar`, BETA10 improvements (#1069) * Implement/match the rest of `LegoRaceCar` * Add BETA10 annotations and improvements * Undo incorrect change * Add synthetic vbase destructors --------- Co-authored-by: jonschz --- .../lego/legoomni/include/legocarraceactor.h | 3 + LEGO1/lego/legoomni/include/legoentity.h | 1 + LEGO1/lego/legoomni/include/legoraceactor.h | 3 + LEGO1/lego/legoomni/include/legoracemap.h | 3 + LEGO1/lego/legoomni/include/legoracers.h | 29 ++-- .../lego/legoomni/src/paths/legopathactor.cpp | 1 + LEGO1/lego/legoomni/src/race/legoracers.cpp | 136 ++++++++++++------ 7 files changed, 126 insertions(+), 50 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legocarraceactor.h b/LEGO1/lego/legoomni/include/legocarraceactor.h index e68a2afc..6f1c72f4 100644 --- a/LEGO1/lego/legoomni/include/legocarraceactor.h +++ b/LEGO1/lego/legoomni/include/legocarraceactor.h @@ -60,6 +60,9 @@ class LegoCarRaceActor : public virtual LegoRaceActor { virtual void VTable0x1c(); // vtable+0x1c + // SYNTHETIC: LEGO1 0x10012c30 + // LegoCarRaceActor::`vbase destructor' + // SYNTHETIC: LEGO1 0x10081620 // LegoCarRaceActor::`scalar deleting destructor' diff --git a/LEGO1/lego/legoomni/include/legoentity.h b/LEGO1/lego/legoomni/include/legoentity.h index 4fb01d61..115ed813 100644 --- a/LEGO1/lego/legoomni/include/legoentity.h +++ b/LEGO1/lego/legoomni/include/legoentity.h @@ -62,6 +62,7 @@ class LegoEntity : public MxEntity { virtual void ResetWorldTransform(MxBool p_cameraFlag); // vtable+0x2c // FUNCTION: LEGO1 0x10001090 + // FUNCTION: BETA10 0x10013260 virtual void SetWorldSpeed(MxFloat p_worldSpeed) { m_worldSpeed = p_worldSpeed; } // vtable+0x30 virtual void ClickSound(MxBool p_und); // vtable+0x34 diff --git a/LEGO1/lego/legoomni/include/legoraceactor.h b/LEGO1/lego/legoomni/include/legoraceactor.h index 50d4a016..57325256 100644 --- a/LEGO1/lego/legoomni/include/legoraceactor.h +++ b/LEGO1/lego/legoomni/include/legoraceactor.h @@ -33,6 +33,9 @@ class LegoRaceActor : public virtual LegoAnimActor { // FUNCTION: LEGO1 0x10014aa0 virtual MxResult FUN_10014aa0() { return SUCCESS; } + // SYNTHETIC: LEGO1 0x10012c10 + // LegoRaceActor::`vbase destructor' + // SYNTHETIC: LEGO1 0x10014ac0 // LegoRaceActor::`scalar deleting destructor' diff --git a/LEGO1/lego/legoomni/include/legoracemap.h b/LEGO1/lego/legoomni/include/legoracemap.h index 99625dd9..3cbd7739 100644 --- a/LEGO1/lego/legoomni/include/legoracemap.h +++ b/LEGO1/lego/legoomni/include/legoracemap.h @@ -21,6 +21,9 @@ class LegoRaceMap : public virtual LegoRaceActor { // LegoRaceMap vtable virtual void FUN_1005d4b0(); // vtable+0x00 + // SYNTHETIC: LEGO1 0x10012c50 + // LegoRaceMap::`vbase destructor' + // SYNTHETIC: LEGO1 0x1005d5d0 // LegoRaceMap::`scalar deleting destructor' diff --git a/LEGO1/lego/legoomni/include/legoracers.h b/LEGO1/lego/legoomni/include/legoracers.h index ab5310a7..d20de8a7 100644 --- a/LEGO1/lego/legoomni/include/legoracers.h +++ b/LEGO1/lego/legoomni/include/legoracers.h @@ -11,8 +11,9 @@ // SIZE 0x08 struct EdgeReference { - const char* m_name; // 0x00 - LegoPathBoundary* m_data; // 0x04 + const char* m_name; // 0x00 + // name verified by BETA10 0x100cbee6 + LegoPathBoundary* m_b; // 0x04 }; // SIZE 0x10 @@ -78,15 +79,23 @@ class LegoRaceCar : public LegoCarRaceActor, public LegoRaceMap { // LegoRaceCar::`scalar deleting destructor' private: - undefined m_userState; // 0x54 - float m_unk0x58; // 0x58 - Mx3DPointFloat m_unk0x5c; // 0x5c - LegoAnimActorStruct* m_unk0x70; // 0x70 - LegoAnimActorStruct* m_unk0x74; // 0x74 - LegoPathBoundary* m_unk0x78; // 0x78 - LegoPathBoundary* m_unk0x7c; // 0x7c + undefined m_userState; // 0x54 + float m_unk0x58; // 0x58 + Mx3DPointFloat m_unk0x5c; // 0x5c + + // Names verified by BETA10 0x100cb4a9 + LegoAnimActorStruct* m_skelKick1Anim; // 0x70 + LegoAnimActorStruct* m_skelKick2Anim; // 0x74 + + // Name verified by BETA10 0x100cb4f0 + LegoPathBoundary* m_kick1B; // 0x78 + + // Name verified by BETA10 0x100cb537 + LegoPathBoundary* m_kick2B; // 0x7c + + // name verified by BETA10 0x100cbee6 + static EdgeReference g_skBMap[]; - static EdgeReference g_edgeReferences[]; static const SkeletonKickPhase g_skeletonKickPhases[]; static const char* g_strSpeed; static const char* g_srtsl18to29[]; diff --git a/LEGO1/lego/legoomni/src/paths/legopathactor.cpp b/LEGO1/lego/legoomni/src/paths/legopathactor.cpp index c374ab5e..239f704f 100644 --- a/LEGO1/lego/legoomni/src/paths/legopathactor.cpp +++ b/LEGO1/lego/legoomni/src/paths/legopathactor.cpp @@ -33,6 +33,7 @@ DECOMP_SIZE_ASSERT(LegoPathEdgeContainer, 0x3c) const char* g_strHIT_WALL_SOUND = "HIT_WALL_SOUND"; // GLOBAL: LEGO1 0x100f3308 +// GLOBAL: BETA10 0x101f1e1c MxLong g_unk0x100f3308 = 0; // FUNCTION: LEGO1 0x1002d700 diff --git a/LEGO1/lego/legoomni/src/race/legoracers.cpp b/LEGO1/lego/legoomni/src/race/legoracers.cpp index 355f3b79..5bebe2da 100644 --- a/LEGO1/lego/legoomni/src/race/legoracers.cpp +++ b/LEGO1/lego/legoomni/src/race/legoracers.cpp @@ -22,7 +22,8 @@ DECOMP_SIZE_ASSERT(SkeletonKickPhase, 0x10) DECOMP_SIZE_ASSERT(LegoRaceCar, 0x200) // GLOBAL: LEGO1 0x100f0a20 -EdgeReference LegoRaceCar::g_edgeReferences[] = { +// GLOBAL: BETA10 0x101f5e34 +EdgeReference LegoRaceCar::g_skBMap[] = { {// STRING: LEGO1 0x100f0a10 "EDG03_772", NULL @@ -50,19 +51,20 @@ EdgeReference LegoRaceCar::g_edgeReferences[] = { }; // GLOBAL: LEGO1 0x100f0a50 +// GLOBAL: BETA10 0x101f5e60 const SkeletonKickPhase LegoRaceCar::g_skeletonKickPhases[] = { - {&LegoRaceCar::g_edgeReferences[0], 0.1, 0.2, LEGORACECAR_KICK2}, - {&LegoRaceCar::g_edgeReferences[1], 0.2, 0.3, LEGORACECAR_KICK2}, - {&LegoRaceCar::g_edgeReferences[2], 0.3, 0.4, LEGORACECAR_KICK2}, - {&LegoRaceCar::g_edgeReferences[2], 0.6, 0.7, LEGORACECAR_KICK1}, - {&LegoRaceCar::g_edgeReferences[1], 0.7, 0.8, LEGORACECAR_KICK1}, - {&LegoRaceCar::g_edgeReferences[0], 0.8, 0.9, LEGORACECAR_KICK1}, - {&LegoRaceCar::g_edgeReferences[3], 0.1, 0.2, LEGORACECAR_KICK1}, - {&LegoRaceCar::g_edgeReferences[4], 0.2, 0.3, LEGORACECAR_KICK1}, - {&LegoRaceCar::g_edgeReferences[5], 0.3, 0.4, LEGORACECAR_KICK1}, - {&LegoRaceCar::g_edgeReferences[5], 0.6, 0.7, LEGORACECAR_KICK2}, - {&LegoRaceCar::g_edgeReferences[4], 0.7, 0.8, LEGORACECAR_KICK2}, - {&LegoRaceCar::g_edgeReferences[3], 0.8, 0.9, LEGORACECAR_KICK2}, + {&LegoRaceCar::g_skBMap[0], 0.1, 0.2, LEGORACECAR_KICK2}, + {&LegoRaceCar::g_skBMap[1], 0.2, 0.3, LEGORACECAR_KICK2}, + {&LegoRaceCar::g_skBMap[2], 0.3, 0.4, LEGORACECAR_KICK2}, + {&LegoRaceCar::g_skBMap[2], 0.6, 0.7, LEGORACECAR_KICK1}, + {&LegoRaceCar::g_skBMap[1], 0.7, 0.8, LEGORACECAR_KICK1}, + {&LegoRaceCar::g_skBMap[0], 0.8, 0.9, LEGORACECAR_KICK1}, + {&LegoRaceCar::g_skBMap[3], 0.1, 0.2, LEGORACECAR_KICK1}, + {&LegoRaceCar::g_skBMap[4], 0.2, 0.3, LEGORACECAR_KICK1}, + {&LegoRaceCar::g_skBMap[5], 0.3, 0.4, LEGORACECAR_KICK1}, + {&LegoRaceCar::g_skBMap[5], 0.6, 0.7, LEGORACECAR_KICK2}, + {&LegoRaceCar::g_skBMap[4], 0.7, 0.8, LEGORACECAR_KICK2}, + {&LegoRaceCar::g_skBMap[3], 0.8, 0.9, LEGORACECAR_KICK2}, }; // GLOBAL: LEGO1 0x100f0b10 @@ -70,6 +72,7 @@ const SkeletonKickPhase LegoRaceCar::g_skeletonKickPhases[] = { const char* LegoRaceCar::g_strSpeed = "SPEED"; // GLOBAL: LEGO1 0x100f0b18 +// GLOBAL: BETA10 0x101f5f28 const char* LegoRaceCar::g_srtsl18to29[] = { "srt018sl", "srt019sl", @@ -86,12 +89,15 @@ const char* LegoRaceCar::g_srtsl18to29[] = { }; // GLOBAL: LEGO1 0x100f0b48 +// GLOBAL: BETA10 0x101f5f58 const char* LegoRaceCar::g_srtsl6to10[] = {"srt006sl", "srt007sl", "srt008sl", "srt009sl", "srt010sl"}; // GLOBAL: LEGO1 0x100f0b5c +// GLOBAL: BETA10 0x101f5f6c const char* LegoRaceCar::g_emptySoundKeyList[] = {NULL}; // GLOBAL: LEGO1 0x100f0b60 +// GLOBAL: BETA10 0x101f5f70 const char* LegoRaceCar::g_srtrh[] = {"srt004rh", "srt005rh", "srt006rh"}; // GLOBAL: LEGO1 0x100f0b6c @@ -103,18 +109,23 @@ const char* LegoRaceCar::g_srt001ra = "srt001ra"; const char* LegoRaceCar::g_soundSkel3 = "skel3"; // GLOBAL: LEGO1 0x100f0b74 +// GLOBAL: BETA10 0x101f5f80 MxU32 LegoRaceCar::g_srtsl18to29Index = 0; // GLOBAL: LEGO1 0x100f0b78 +// GLOBAL: BETA10 0x101f5f84 MxU32 LegoRaceCar::g_srtsl6to10Index = 0; // GLOBAL: LEGO1 0x100f0b7c +// GLOBAL: BETA10 0x101f5f88 MxU32 LegoRaceCar::g_emptySoundKeyListIndex = 0; // GLOBAL: LEGO1 0x100f0b80 +// GLOBAL: BETA10 0x101f5f8c MxU32 LegoRaceCar::g_srtrhIndex = 0; // GLOBAL: LEGO1 0x100f0b84 +// GLOBAL: BETA10 0x101f5f90 MxLong LegoRaceCar::g_timeLastSoundPlayed = 0; // GLOBAL: LEGO1 0x100f0b88 @@ -127,18 +138,19 @@ MxBool LegoRaceCar::g_unk0x100f0b8c = TRUE; // Initialized at LEGO1 0x10012db0 // GLOBAL: LEGO1 0x10102af0 +// GLOBAL: BETA10 0x102114c0 Mx3DPointFloat LegoRaceCar::g_unk0x10102af0 = Mx3DPointFloat(0.0f, 2.0f, 0.0f); // FUNCTION: LEGO1 0x10012950 LegoRaceCar::LegoRaceCar() { m_userState = 0; - m_unk0x70 = 0; - m_unk0x74 = 0; + m_skelKick1Anim = 0; + m_skelKick2Anim = 0; m_unk0x5c.Clear(); m_unk0x58 = 0; - m_unk0x78 = 0; - m_unk0x7c = 0; + m_kick1B = 0; + m_kick2B = 0; NotificationManager()->Register(this); } @@ -155,6 +167,7 @@ MxLong LegoRaceCar::Notify(MxParam& p_param) } // FUNCTION: LEGO1 0x10012e60 +// FUNCTION: BETA10 0x100cb191 void LegoRaceCar::SetWorldSpeed(MxFloat p_worldSpeed) { if (!m_userNavFlag) { @@ -164,11 +177,12 @@ void LegoRaceCar::SetWorldSpeed(MxFloat p_worldSpeed) LegoAnimActor::SetWorldSpeed(p_worldSpeed); } else { - m_worldSpeed = p_worldSpeed; + LegoEntity::SetWorldSpeed(p_worldSpeed); } } // FUNCTION: LEGO1 0x10012ea0 +// FUNCTION: BETA10 0x100cb220 void LegoRaceCar::SetMaxLinearVelocity(float p_maxLinearVelocity) { if (p_maxLinearVelocity < 0) { @@ -182,6 +196,7 @@ void LegoRaceCar::SetMaxLinearVelocity(float p_maxLinearVelocity) } // FUNCTION: LEGO1 0x10012ef0 +// FUNCTION: BETA10 0x100cb2aa void LegoRaceCar::ParseAction(char* p_extra) { char buffer[256]; @@ -195,26 +210,36 @@ void LegoRaceCar::ParseAction(char* p_extra) } if (m_userNavFlag) { - for (MxU32 i = 0; i < m_animMaps.size(); i++) { + MxS32 i; + + for (i = 0; i < m_animMaps.size(); i++) { + // It appears that the implementation in BETA10 does not use this variable LegoAnimActorStruct* animMap = m_animMaps[i]; if (animMap->m_unk0x00 == -1.0f) { - m_unk0x70 = animMap; + m_skelKick1Anim = animMap; } else if (animMap->m_unk0x00 == -2.0f) { - m_unk0x74 = animMap; + m_skelKick2Anim = animMap; } } + assert(m_skelKick1Anim && m_skelKick2Anim); + // STRING: LEGO1 0x100f0bc4 const char* edge0344 = "EDG03_44"; - m_unk0x78 = currentWorld->FindPathBoundary(edge0344); + m_kick1B = currentWorld->FindPathBoundary(edge0344); + assert(m_kick1B); + // STRING: LEGO1 0x100f0bb8 const char* edge0354 = "EDG03_54"; - m_unk0x7c = currentWorld->FindPathBoundary(edge0354); + m_kick2B = currentWorld->FindPathBoundary(edge0354); + assert(m_kick2B); - for (MxS32 j = 0; j < sizeOfArray(g_edgeReferences); j++) { - g_edgeReferences[j].m_data = currentWorld->FindPathBoundary(g_edgeReferences[j].m_name); + for (i = 0; i < sizeOfArray(g_skBMap); i++) { + assert(g_skBMap[i].m_name); + g_skBMap[i].m_b = currentWorld->FindPathBoundary(g_skBMap[i].m_name); + assert(g_skBMap[i].m_b); } } } @@ -227,11 +252,11 @@ void LegoRaceCar::FUN_10012ff0(float p_param) float deltaTime; if (m_userState == LEGORACECAR_KICK1) { - a = m_unk0x70; + a = m_skelKick1Anim; } else { assert(m_userState == LEGORACECAR_KICK2); - a = m_unk0x74; + a = m_skelKick2Anim; } assert(a && a->GetAnimTreePtr() && a->GetAnimTreePtr()->GetCamAnim()); @@ -241,14 +266,14 @@ void LegoRaceCar::FUN_10012ff0(float p_param) if (a->GetDuration() <= deltaTime || deltaTime < 0.0) { if (m_userState == LEGORACECAR_KICK1) { - LegoEdge** edges = m_unk0x78->GetEdges(); + LegoEdge** edges = m_kick1B->GetEdges(); m_destEdge = (LegoUnknown100db7f4*) (edges[2]); - m_boundary = m_unk0x78; + m_boundary = m_kick1B; } else { - LegoEdge** edges = m_unk0x78->GetEdges(); + LegoEdge** edges = m_kick1B->GetEdges(); m_destEdge = (LegoUnknown100db7f4*) (edges[1]); - m_boundary = m_unk0x7c; + m_boundary = m_kick2B; } m_userState = LEGORACECAR_UNKNOWN_0; @@ -294,7 +319,7 @@ MxU32 LegoRaceCar::HandleSkeletonKicks(float p_param1) float skeletonCurAnimPhase = skeletonCurAnimPosition / skeletonCurAnimDuration; for (MxS32 i = 0; i < sizeOfArray(g_skeletonKickPhases); i++) { - if (m_boundary == current->m_edgeRef->m_data && current->m_lower <= skeletonCurAnimPhase && + if (m_boundary == current->m_edgeRef->m_b && current->m_lower <= skeletonCurAnimPhase && skeletonCurAnimPhase <= current->m_upper) { m_userState = current->m_userState; } @@ -451,14 +476,45 @@ MxResult LegoRaceCar::VTable0x94(LegoPathActor* p_actor, MxBool p_bool) return SUCCESS; } -// STUB: LEGO1 0x10013600 +// FUNCTION: LEGO1 0x10013600 +// FUNCTION: BETA10 0x100cbe60 MxResult LegoRaceCar::VTable0x9c() { - // TODO - return SUCCESS; + MxResult result; + + if (m_userNavFlag) { + result = LegoCarRaceActor::VTable0x9c(); + + if (m_boundary) { + MxS32 bVar2 = 0; + + for (MxS32 i = 0; i < sizeOfArray(g_skBMap); i++) { + assert(g_skBMap[i].m_b); + if (m_boundary == g_skBMap[i].m_b) { + bVar2 = 1; + break; + } + } + + if (m_userState == LEGORACECAR_UNKNOWN_1) { + if (!bVar2) { + m_userState = LEGORACECAR_UNKNOWN_0; + } + } + else { + m_userState = LEGORACECAR_UNKNOWN_1; + } + } + } + else { + result = LegoCarRaceActor::VTable0x9c(); + } + + return result; } -// STUB: LEGO1 0x10014500 +// FUNCTION: LEGO1 0x10014500 +// FUNCTION: BETA10 0x100cd5e0 MxU32 LegoRaceCar::VTable0x6c( LegoPathBoundary* p_boundary, Vector3& p_v1, @@ -468,12 +524,12 @@ MxU32 LegoRaceCar::VTable0x6c( Vector3& p_v3 ) { - // TODO - return 0; + return LegoCarRaceActor::VTable0x6c(p_boundary, p_v1, p_v2, p_f1, p_f2, p_v3); } -// STUB: LEGO1 0x10014560 +// FUNCTION: LEGO1 0x10014560 +// FUNCTION: BETA10 0x100cd660 void LegoRaceCar::SwitchBoundary(LegoPathBoundary*& p_boundary, LegoUnknown100db7f4*& p_edge, float& p_unk0xe4) { - // TODO + LegoCarRaceActor::SwitchBoundary(p_boundary, p_edge, p_unk0xe4); }