From 07def56326a40edeef72dfb9ea4f59bb22b89917 Mon Sep 17 00:00:00 2001 From: jonschz <17198703+jonschz@users.noreply.github.com> Date: Mon, 9 Dec 2024 22:05:08 +0100 Subject: [PATCH] Implement `Act2Actor::VTable0x70` (#1201) * Implement draft of `Act2Actor::VTable0x70` * Fix CI errors * Implement `Act2Actor::FUN_100199f0` * WIP: cleanup * Address review comments * Run formatter --------- Co-authored-by: jonschz <jonschz@users.noreply.github.com> --- LEGO1/lego/legoomni/include/act2actor.h | 13 +- LEGO1/lego/legoomni/include/legoact2.h | 19 +- LEGO1/lego/legoomni/src/actors/act2actor.cpp | 282 +++++++++++++++++- LEGO1/lego/legoomni/src/entity/legoworld.cpp | 1 + LEGO1/lego/legoomni/src/main/legomain.cpp | 4 +- .../lego/legoomni/src/paths/legoanimactor.cpp | 5 +- .../lego/legoomni/src/paths/legopathactor.cpp | 1 + .../legoomni/src/video/legoanimpresenter.cpp | 1 + LEGO1/lego/legoomni/src/worlds/legoact2.cpp | 14 + LEGO1/lego/sources/3dmanager/lego3dview.h | 2 +- LEGO1/mxgeometry/mxmatrix.h | 1 + LEGO1/viewmanager/viewmanager.h | 2 + 12 files changed, 325 insertions(+), 20 deletions(-) diff --git a/LEGO1/lego/legoomni/include/act2actor.h b/LEGO1/lego/legoomni/include/act2actor.h index cf8ed507..905743fb 100644 --- a/LEGO1/lego/legoomni/include/act2actor.h +++ b/LEGO1/lego/legoomni/include/act2actor.h @@ -28,8 +28,11 @@ class Act2Actor : public LegoAnimActor { MxS32 VTable0xa0() override; // vtable+0xa0 void FUN_10018980(); + void FUN_10019250(MxFloat p_speed, MxFloat p_param2); void FUN_10019520(); void FUN_10019560(); + undefined4 FUN_10019700(MxFloat p_param); + void FUN_100199f0(MxS8 p_param); void FUN_100192a0(undefined4 p_param); // SYNTHETIC: LEGO1 0x1001a0a0 @@ -44,16 +47,16 @@ class Act2Actor : public LegoAnimActor { MxS8 m_unk0x1d; // 0x1d undefined m_unk0x1e; // 0x1e MxBool m_unk0x1f; // 0x1f - undefined4 m_unk0x20; // 0x20 - undefined4 m_unk0x24; // 0x24 + MxFloat m_unk0x20; // 0x20 + MxFloat m_unk0x24; // 0x24 MxS8 m_unk0x28; // 0x28 - undefined4 m_unk0x2c; // 0x2c - undefined4 m_unk0x30; // 0x30 + MxFloat m_unk0x2c; // 0x2c + MxFloat m_unk0x30; // 0x30 LegoAnimActorStruct* m_shootAnim; // 0x34 LegoCacheSound* m_unk0x38; // 0x38 undefined4 m_unk0x3c; // 0x3c undefined m_unk0x40; // 0x40 - undefined4 m_unk0x44; // 0x44 + MxFloat m_unk0x44; // 0x44 MxS8 m_unk0x48; // 0x48 undefined4 m_unk0x4c; // 0x4c }; diff --git a/LEGO1/lego/legoomni/include/legoact2.h b/LEGO1/lego/legoomni/include/legoact2.h index 797b2249..e43c3a7a 100644 --- a/LEGO1/lego/legoomni/include/legoact2.h +++ b/LEGO1/lego/legoomni/include/legoact2.h @@ -68,6 +68,17 @@ class LegoAct2 : public LegoWorld { void SetUnknown0x1138(Act2Actor* p_unk0x1138) { m_unk0x1138 = p_unk0x1138; } void SetDestLocation(LegoGameState::Area p_destLocation) { m_destLocation = p_destLocation; } + MxResult FUN_100516b0(); + void FUN_100517b0(); + MxResult FUN_10052560( + Act2mainScript::Script p_objectId, + MxBool p_param2, + MxBool p_param3, + Mx3DPointFloat* p_location, + Mx3DPointFloat* p_direction, + Mx3DPointFloat* p_param6 + ); + // SYNTHETIC: LEGO1 0x1004fe20 // LegoAct2::`scalar deleting destructor' @@ -83,14 +94,6 @@ class LegoAct2 : public LegoWorld { void SpawnBricks(); void FUN_10051fa0(MxS32 p_param1); void FUN_100521f0(MxS32 p_param1); - MxResult FUN_10052560( - Act2mainScript::Script p_objectId, - MxBool p_param2, - MxBool p_param3, - Mx3DPointFloat* p_location, - Mx3DPointFloat* p_direction, - Mx3DPointFloat* p_param6 - ); MxResult FUN_10052800(); Act2Brick m_bricks[10]; // 0x00f8 diff --git a/LEGO1/lego/legoomni/src/actors/act2actor.cpp b/LEGO1/lego/legoomni/src/actors/act2actor.cpp index 1d29f18b..f70788d5 100644 --- a/LEGO1/lego/legoomni/src/actors/act2actor.cpp +++ b/LEGO1/lego/legoomni/src/actors/act2actor.cpp @@ -1,11 +1,19 @@ #include "act2actor.h" +#include "3dmanager/lego3dmanager.h" +#include "act2main_actions.h" +#include "legoact2.h" #include "legocachesoundmanager.h" #include "legopathcontroller.h" #include "legopathedgecontainer.h" #include "legosoundmanager.h" +#include "legovideomanager.h" +#include "legoworld.h" #include "misc.h" #include "roi/legoroi.h" +#include "viewmanager/viewmanager.h" + +#include <vec.h> DECOMP_SIZE_ASSERT(Act2Actor, 0x1a8) DECOMP_SIZE_ASSERT(Act2Actor::UnknownListStructure, 0x20) @@ -26,6 +34,21 @@ Act2Actor::UnknownListStructure g_unk0x100f0db8[] = { {{-44.6, 0.1, 45.3}, {0.95, 0.0, -0.3}, "edg00_154", FALSE}, }; +// GLOBAL: LEGO1 0x100f0f1c +MxFloat g_unk0x100f0f1c = 0.0f; + +// GLOBAL: LEGO1 0x10102b1c +// GLOBAL: BETA10 0x10209f60 +undefined4 g_nextHeadWavIndex = 0; + +// GLOBAL: LEGO1 0x10102b20 +// GLOBAL: BETA10 0x10209f64 +undefined4 g_nextBehindWavIndex = 0; + +// GLOBAL: LEGO1 0x10102b24 +// GLOBAL: BETA10 0x10209f68 +undefined4 g_nextInterruptWavIndex = 0; + // FUNCTION: LEGO1 0x100187e0 // FUNCTION: BETA10 0x1000c7fb Act2Actor::Act2Actor() @@ -115,11 +138,186 @@ MxResult Act2Actor::VTable0x9c() } } -// STUB: LEGO1 0x10018c30 -// STUB: BETA10 0x1000cb52 +// FUNCTION: LEGO1 0x10018c30 +// FUNCTION: BETA10 0x1000cb52 void Act2Actor::VTable0x70(float p_time) { - // TODO + int dummy1; // for BETA10, not sure what it is being used for + +#ifdef NDEBUG + MxFloat local48float = 0.0f; + if (g_unk0x100f0f1c != 0.0f) { + local48float = p_time - g_unk0x100f0f1c; + } + + g_unk0x100f0f1c = p_time; +#endif + + LegoAnimActor::VTable0x70(p_time); + + if (m_unk0x44 != 0.0f && m_unk0x44 < p_time) { + SetWorldSpeed(m_unk0x28); + } + + if (m_unk0x1f) { + if (m_unk0x20 > 600.0f) { + m_unk0x1f = FALSE; + m_unk0x20 = 0; + } + else { +#ifdef NDEBUG + m_unk0x20 += local48float; +#endif + MxMatrix matrix = m_roi->GetLocal2World(); + matrix[3][1] += 3.0f; + m_roi->UpdateTransformationRelativeToParent(matrix); + +#ifdef NDEBUG + LegoROI* brickstrROI = FindROI("brickstr"); + MxMatrix brickstrMatrix = brickstrROI->GetLocal2World(); + brickstrMatrix[3][1] += 3.0f; + brickstrROI->UpdateTransformationRelativeToParent(brickstrMatrix); +#endif + return; + } + } + + if (!m_grec) { + if (m_unk0x1e == 2) { + m_unk0x1e = 0; + m_unk0x2c = m_shootAnim->GetDuration() + p_time; + m_unk0x30 = m_unk0x2c - 1300.0f; + SetWorldSpeed(0); + m_unk0x1c = FALSE; + } + else if (m_unk0x1e == 1) { + FindROI("pwrbrik")->SetVisibility(FALSE); + FindROI("debrick")->SetVisibility(FALSE); + FindROI("ray")->SetVisibility(FALSE); + m_unk0x4c = 0; + m_unk0x1e = 2; + VTable0xa0(); + FUN_10019250(m_unk0x28 + 3, p_time + 3000.0f); + } + else if (m_unk0x1e == 0) { + if (m_unk0x40) { + m_unk0x40 = 0; + m_unk0x2c = m_shootAnim->GetDuration() + p_time; + m_unk0x30 = m_unk0x2c - 1300.0f; + } + + if (FUN_10019700(p_time) == 1) { + return; + } + } + else if (m_unk0x1e == 5) { + FindROI("brickstr")->SetVisibility(FALSE); + GetROI()->SetVisibility(FALSE); + CurrentWorld()->RemoveActor(this); + return; + } +#ifdef NDEBUG + else if (m_unk0x1e == 4) { + if (m_worldSpeed == 0.0f) { + return; + } + + SetWorldSpeed(0.0f); + ((LegoAct2*) CurrentWorld())->FUN_100517b0(); + return; + } +#endif + } + + if (m_unk0x1e == 5 || m_unk0x1e == 4) { + return; + } + + if (m_unk0x1e == 3) { + if (p_time - m_unk0x24 > 600.0f) { + m_unk0x1e = 2; + FUN_10019250(m_unk0x28 + 4, p_time + 15000.0f); + } + } + else { + LegoROI* roiPepper = FindROI("pepper"); + + if (roiPepper) { + ViewManager* vm = VideoManager()->Get3DManager()->GetLego3DView()->GetViewManager(); + assert(vm); + + MxU32 inFrustum = vm->IsBoundingBoxInFrustum(m_roi->GetWorldBoundingBox()); + + if (inFrustum) { + Mx3DPointFloat local18(roiPepper->GetWorldDirection()); + Mx3DPointFloat local30(m_roi->GetWorldPosition()); + Mx3DPointFloat local60(roiPepper->GetWorldPosition()); + local30 -= local60; + local30.Unitize(); + + MxFloat dotproduct = local18.Dot(&local30, &local18); + + if (dotproduct >= 0.0) { + const MxFloat* pepperWorldPosition = roiPepper->GetWorldPosition(); + const MxFloat* worldPosition = m_roi->GetWorldPosition(); + + MxFloat distance1 = DISTSQRD3(pepperWorldPosition, worldPosition); + + if (distance1 < 75.0f) { + if (!m_unk0x1c) { + m_unk0x1c = 1; + + if (!m_unk0x1e) { + FUN_100199f0(2); + m_unk0x1e = 1; + } + else { + LegoROI* childROI = m_roi->FindChildROI("windsd", m_roi); + const MxFloat* childPosition = childROI->GetWorldPosition(); + MxFloat distance2 = DISTSQRD3(pepperWorldPosition, childPosition); + + childROI = m_roi->FindChildROI("reardr", m_roi); + childPosition = childROI->GetWorldPosition(); + MxFloat distance3 = DISTSQRD3(pepperWorldPosition, childPosition); + + if (distance3 > distance2) { + FUN_100199f0(0); + } + else +#ifdef NDEBUG + if (p_time - m_unk0x24 > 3000.0f) { +#endif + SetWorldSpeed(m_unk0x28 - 1); + m_unk0x1e = 3; + m_unk0x24 = p_time; + + if (!((LegoAct2*) CurrentWorld())->FUN_100516b0()) { + FUN_100199f0(1); + } +#ifdef NDEBUG + } +#endif + } + } + } + else { + if (m_unk0x1c) { + m_unk0x1c = 0; + } + } + } + } + } + } +} + +// FUNCTION: LEGO1 0x10019250 +// FUNCTION: BETA10 0x1000d45c +void Act2Actor::FUN_10019250(MxFloat p_speed, MxFloat p_param2) +{ + // The arguments have been changed from BETA10 to LEGO1 + SetWorldSpeed(p_speed); + m_unk0x44 = p_param2; } // FUNCTION: LEGO1 0x10019280 @@ -298,6 +496,84 @@ MxS32 Act2Actor::VTable0xa0() } } +// STUB: LEGO1 0x10019700 +// STUB: BETA10 0x1000dd27 +undefined4 Act2Actor::FUN_10019700(MxFloat p_param) +{ + // TODO + return 0; +} + +// FUNCTION: LEGO1 0x100199f0 +// FUNCTION: BETA10 0x1000e11a +void Act2Actor::FUN_100199f0(MxS8 p_param) +{ + switch (p_param) { + case 0: + switch (g_nextHeadWavIndex) { + case 0: + ((LegoAct2*) CurrentWorld()) + ->FUN_10052560(Act2mainScript::c_VOhead0_PlayWav, FALSE, FALSE, NULL, NULL, NULL); + + g_nextHeadWavIndex++; + break; + default: + ((LegoAct2*) CurrentWorld()) + ->FUN_10052560(Act2mainScript::c_VOhead1_PlayWav, FALSE, FALSE, NULL, NULL, NULL); + g_nextHeadWavIndex = 0; + break; + } + break; + case 1: + switch (g_nextBehindWavIndex) { + case 0: + ((LegoAct2*) CurrentWorld()) + ->FUN_10052560(Act2mainScript::c_VObehind0_PlayWav, FALSE, TRUE, NULL, NULL, NULL); + g_nextBehindWavIndex++; + break; + case 1: + ((LegoAct2*) CurrentWorld()) + ->FUN_10052560(Act2mainScript::c_VObehind1_PlayWav, FALSE, TRUE, NULL, NULL, NULL); + g_nextBehindWavIndex++; + break; + case 2: + ((LegoAct2*) CurrentWorld()) + ->FUN_10052560(Act2mainScript::c_VObehind2_PlayWav, FALSE, TRUE, NULL, NULL, NULL); + g_nextBehindWavIndex++; + break; + default: + ((LegoAct2*) CurrentWorld()) + ->FUN_10052560(Act2mainScript::c_VObehind3_PlayWav, FALSE, TRUE, NULL, NULL, NULL); + g_nextBehindWavIndex = 0; + break; + } + break; + case 2: + switch (g_nextInterruptWavIndex) { + case 0: + ((LegoAct2*) CurrentWorld()) + ->FUN_10052560(Act2mainScript::c_VOinterrupt0_PlayWav, FALSE, FALSE, NULL, NULL, NULL); + g_nextInterruptWavIndex++; + break; + case 1: + ((LegoAct2*) CurrentWorld()) + ->FUN_10052560(Act2mainScript::c_VOinterrupt1_PlayWav, FALSE, FALSE, NULL, NULL, NULL); + g_nextInterruptWavIndex++; + break; + case 2: + ((LegoAct2*) CurrentWorld()) + ->FUN_10052560(Act2mainScript::c_VOinterrupt2_PlayWav, FALSE, FALSE, NULL, NULL, NULL); + g_nextInterruptWavIndex++; + break; + default: + ((LegoAct2*) CurrentWorld()) + ->FUN_10052560(Act2mainScript::c_VOinterrupt3_PlayWav, FALSE, FALSE, NULL, NULL, NULL); + g_nextInterruptWavIndex = 0; + break; + } + } +} + // FUNCTION: LEGO1 0x1001a180 MxS32 Act2Actor::VTable0x68(Vector3& p_v1, Vector3& p_v2, Vector3& p_v3) { diff --git a/LEGO1/lego/legoomni/src/entity/legoworld.cpp b/LEGO1/lego/legoomni/src/entity/legoworld.cpp index 88023db9..2dbcce2e 100644 --- a/LEGO1/lego/legoomni/src/entity/legoworld.cpp +++ b/LEGO1/lego/legoomni/src/entity/legoworld.cpp @@ -339,6 +339,7 @@ MxResult LegoWorld::PlaceActor( } // FUNCTION: LEGO1 0x1001fc80 +// FUNCTION: BETA10 0x100da4bf void LegoWorld::RemoveActor(LegoPathActor* p_actor) { LegoPathControllerListCursor cursor(&m_list0x68); diff --git a/LEGO1/lego/legoomni/src/main/legomain.cpp b/LEGO1/lego/legoomni/src/main/legomain.cpp index 7fc35185..4a751ab7 100644 --- a/LEGO1/lego/legoomni/src/main/legomain.cpp +++ b/LEGO1/lego/legoomni/src/main/legomain.cpp @@ -408,8 +408,8 @@ void LegoOmni::DeleteObject(MxDSAction& p_dsAction) // FUNCTION: BETA10 0x1008ea6d LegoROI* LegoOmni::FindROI(const char* p_name) { - ViewManager* viewManager = GetVideoManager()->Get3DManager()->GetLego3DView()->GetViewManager(); - const CompoundObject& rois = viewManager->GetROIs(); + const CompoundObject& rois = + ((LegoVideoManager*) m_videoManager)->Get3DManager()->GetLego3DView()->GetViewManager()->GetROIs(); if (p_name != NULL && *p_name != '\0' && rois.size() > 0) { for (CompoundObject::const_iterator it = rois.begin(); it != rois.end(); it++) { diff --git a/LEGO1/lego/legoomni/src/paths/legoanimactor.cpp b/LEGO1/lego/legoomni/src/paths/legoanimactor.cpp index 6001212b..234bf344 100644 --- a/LEGO1/lego/legoomni/src/paths/legoanimactor.cpp +++ b/LEGO1/lego/legoomni/src/paths/legoanimactor.cpp @@ -30,7 +30,7 @@ LegoAnimActorStruct::~LegoAnimActorStruct() } // FUNCTION: LEGO1 0x1001c130 -// FUNCTION: BETA10 0x1003df5f +// FUNCTION: BETA10 0x1003df3a float LegoAnimActorStruct::GetDuration() { assert(m_AnimTreePtr); @@ -70,8 +70,11 @@ void LegoAnimActor::VTable0x74(Matrix4& p_transform) } // FUNCTION: LEGO1 0x1001c290 +// FUNCTION: BETA10 0x1003e144 void LegoAnimActor::VTable0x70(float p_time) { + assert(m_roi); + if (m_lastTime == 0) { m_lastTime = p_time - 1.0f; } diff --git a/LEGO1/lego/legoomni/src/paths/legopathactor.cpp b/LEGO1/lego/legoomni/src/paths/legopathactor.cpp index 1d5bb959..3c859936 100644 --- a/LEGO1/lego/legoomni/src/paths/legopathactor.cpp +++ b/LEGO1/lego/legoomni/src/paths/legopathactor.cpp @@ -380,6 +380,7 @@ void LegoPathActor::VTable0x74(Matrix4& p_transform) } // FUNCTION: LEGO1 0x1002e790 +// FUNCTION: BETA10 0x100af208 void LegoPathActor::VTable0x70(float p_time) { MxMatrix transform; diff --git a/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp b/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp index 15140eca..c827043f 100644 --- a/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp +++ b/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp @@ -289,6 +289,7 @@ void LegoAnimPresenter::FUN_100692b0() } // FUNCTION: LEGO1 0x100695c0 +// FUNCTION: BETA10 0x1004f359 void LegoAnimPresenter::FUN_100695c0() { m_unk0x70 = new LegoROIList(); diff --git a/LEGO1/lego/legoomni/src/worlds/legoact2.cpp b/LEGO1/lego/legoomni/src/worlds/legoact2.cpp index 9119eb1b..f25a77ab 100644 --- a/LEGO1/lego/legoomni/src/worlds/legoact2.cpp +++ b/LEGO1/lego/legoomni/src/worlds/legoact2.cpp @@ -659,6 +659,20 @@ MxLong LegoAct2::HandlePathStruct(LegoPathStructNotificationParam& p_param) return 0; } +// STUB: LEGO1 0x100516b0 +// STUB: BETA10 0x1003bcbc +MxResult LegoAct2::FUN_100516b0() +{ + // TODO + return SUCCESS; +} + +// STUB: LEGO1 0x100517b0 +void LegoAct2::FUN_100517b0() +{ + // TODO +} + // FUNCTION: LEGO1 0x10051840 void LegoAct2::PlayMusic(JukeboxScript::Script p_objectId) { diff --git a/LEGO1/lego/sources/3dmanager/lego3dview.h b/LEGO1/lego/sources/3dmanager/lego3dview.h index 9e0f69eb..1f878a53 100644 --- a/LEGO1/lego/sources/3dmanager/lego3dview.h +++ b/LEGO1/lego/sources/3dmanager/lego3dview.h @@ -46,7 +46,7 @@ class Lego3DView : public LegoView1 { // // Lego3DView implementation -// FUNCTION: BETA10 0x100576b0 +// FUNCTION: BETA10 0x10011810 inline ViewManager* Lego3DView::GetViewManager() { return m_pViewManager; diff --git a/LEGO1/mxgeometry/mxmatrix.h b/LEGO1/mxgeometry/mxmatrix.h index 55a17da1..9f1aa59f 100644 --- a/LEGO1/mxgeometry/mxmatrix.h +++ b/LEGO1/mxgeometry/mxmatrix.h @@ -13,6 +13,7 @@ class MxMatrix : public Matrix4 { MxMatrix() : Matrix4(m_elements) {} // FUNCTION: LEGO1 0x10032770 + // FUNCTION: BETA10 0x1001ff30 MxMatrix(const MxMatrix& p_matrix) : Matrix4(m_elements) { Equals(p_matrix); } // FUNCTION: BETA10 0x1000fc20 diff --git a/LEGO1/viewmanager/viewmanager.h b/LEGO1/viewmanager/viewmanager.h index 92236873..051fe0fa 100644 --- a/LEGO1/viewmanager/viewmanager.h +++ b/LEGO1/viewmanager/viewmanager.h @@ -39,7 +39,9 @@ class ViewManager { inline static int CalculateLODLevel(float p_und1, float p_und2, ViewROI* p_roi); inline static int IsROIVisibleAtLOD(ViewROI* p_roi); + // FUNCTION: BETA10 0x100576b0 const CompoundObject& GetROIs() { return rois; } + void Add(ViewROI* p_roi) { rois.push_back(p_roi); } // SYNTHETIC: LEGO1 0x100a6000