diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5a5b258e..d53dac46 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -139,7 +139,7 @@ jobs: run: | reccmp-reccmp -S CONFIGPROGRESS.SVG --svg-icon assets/config.png --target CONFIG | tee CONFIGPROGRESS.TXT reccmp-reccmp -S ISLEPROGRESS.SVG --svg-icon assets/isle.png --target ISLE | tee ISLEPROGRESS.TXT - reccmp-reccmp -S LEGO1PROGRESS.SVG -T 4332 --svg-icon assets/lego1.png --target LEGO1 | tee LEGO1PROGRESS.TXT + reccmp-reccmp -S LEGO1PROGRESS.SVG -T 4340 --svg-icon assets/lego1.png --target LEGO1 | tee LEGO1PROGRESS.TXT - name: Compare Accuracy With Current Master shell: bash diff --git a/LEGO1/lego/legoomni/include/act3.h b/LEGO1/lego/legoomni/include/act3.h index 4b6e86ac..2abc9a51 100644 --- a/LEGO1/lego/legoomni/include/act3.h +++ b/LEGO1/lego/legoomni/include/act3.h @@ -122,12 +122,16 @@ class Act3 : public LegoWorld { void RemoveDonut(Act3Ammo& p_p); MxResult ShootPizza(LegoPathController* p_controller, Vector3& p_location, Vector3& p_direction, Vector3& p_up); MxResult ShootDonut(LegoPathController* p_controller, Vector3& p_location, Vector3& p_direction, Vector3& p_up); + void FUN_10072ad0(undefined4 p_param1); + MxResult FUN_10073360(Act3Ammo& p_ammo, const Vector3& p_param2); + MxResult FUN_10073390(Act3Ammo& p_ammo, const Vector3& p_param2); void SetBrickster(Act3Brickster* p_brickster); void FUN_10073400(); void FUN_10073430(); void GoodEnding(const Matrix4& p_destination); - // BETA indicates that the actors access certain members directly. + // BETA indicates that the following classes access certain members directly. + friend class Act3Ammo; friend class Act3Brickster; friend class Act3Cop; friend class Act3Shark; diff --git a/LEGO1/lego/legoomni/include/act3actors.h b/LEGO1/lego/legoomni/include/act3actors.h index 5b66ab65..545b6480 100644 --- a/LEGO1/lego/legoomni/include/act3actors.h +++ b/LEGO1/lego/legoomni/include/act3actors.h @@ -58,7 +58,8 @@ class Act3Cop : public Act3Actor { void SetUnknown0x20(MxFloat p_unk0x20) { m_unk0x20 = p_unk0x20; } - void FUN_10040360(); + MxResult FUN_10040350(Act3Ammo& p_ammo, const Vector3&); + MxResult FUN_10040360(); // SYNTHETIC: LEGO1 0x10043120 // Act3Cop::`scalar deleting destructor' @@ -95,6 +96,7 @@ class Act3Brickster : public Act3Actor { void SetUnknown0x24(MxFloat p_unk0x24) { m_unk0x24 = p_unk0x24; } void SetUnknown0x50(MxFloat p_unk0x50) { m_unk0x50 = p_unk0x50; } + MxResult FUN_100417a0(Act3Ammo& p_ammo, const Vector3&); MxResult FUN_100417c0(); // SYNTHETIC: LEGO1 0x10043250 diff --git a/LEGO1/lego/legoomni/include/act3ammo.h b/LEGO1/lego/legoomni/include/act3ammo.h index 006d7424..8beac5be 100644 --- a/LEGO1/lego/legoomni/include/act3ammo.h +++ b/LEGO1/lego/legoomni/include/act3ammo.h @@ -47,6 +47,9 @@ class Act3Ammo : public LegoPathActor { // FUNCTION: BETA10 0x1001fc80 MxU32 IsPizza() { return m_ammoFlag & c_pizza; } + // FUNCTION: BETA10 0x10021d60 + MxU32 IsDonut() { return m_ammoFlag & c_donut; } + // FUNCTION: BETA10 0x1001fcb0 void SetBit4(MxBool p_bit4) { @@ -58,6 +61,9 @@ class Act3Ammo : public LegoPathActor { } } + // FUNCTION: BETA10 0x10021d90 + MxU32 IsBit4() { return m_ammoFlag & c_bit4; } + void SetBit5(MxBool p_bit5) { if (p_bit5) { @@ -75,7 +81,7 @@ class Act3Ammo : public LegoPathActor { void SetUnknown0x158(MxFloat p_unk0x158) { m_unk0x158 = p_unk0x158; } MxResult Remove(); - MxResult Create(Act3* p_a3, MxU32 p_isPizza, MxS32 p_index); + MxResult Create(Act3* p_world, MxU32 p_isPizza, MxS32 p_index); MxResult FUN_10053b40(Vector3& p_srcLoc, Vector3& p_srcDir, Vector3& p_srcUp); MxResult FUN_10053cb0(LegoPathController* p_p, LegoPathBoundary* p_boundary, MxFloat p_unk0x19c); MxResult FUN_10053d30(LegoPathController* p_p, MxFloat p_unk0x19c); @@ -84,9 +90,13 @@ class Act3Ammo : public LegoPathActor { // Act3Ammo::`scalar deleting destructor' private: + MxResult FUN_10053db0(float p_param1, const Matrix4& p_param2); + + static Mx3DPointFloat g_unk0x10104f08; + MxU16 m_ammoFlag; // 0x154 MxFloat m_unk0x158; // 0x158 - Act3* m_a3; // 0x15c + Act3* m_world; // 0x15c Mx3DPointFloat m_eq[3]; // 0x160 MxFloat m_unk0x19c; // 0x19c }; diff --git a/LEGO1/lego/legoomni/src/actors/act3actors.cpp b/LEGO1/lego/legoomni/src/actors/act3actors.cpp index e7395fbd..96f5c113 100644 --- a/LEGO1/lego/legoomni/src/actors/act3actors.cpp +++ b/LEGO1/lego/legoomni/src/actors/act3actors.cpp @@ -120,13 +120,13 @@ MxResult Act3Cop::HitActor(LegoPathActor* p_actor, MxBool p_bool) LegoROI* roi = p_actor->GetROI(); if (p_bool && !strncmp(roi->GetName(), "dammo", 5)) { - MxS32 count = -1; - if (sscanf(roi->GetName(), "dammo%d", &count) != 1) { + MxS32 index = -1; + if (sscanf(roi->GetName(), "dammo%d", &index) != 1) { assert(0); } assert(m_world); - ((Act3*) m_world)->EatDonut(count); + ((Act3*) m_world)->EatDonut(index); m_unk0x20 = m_lastTime + 2000; SetWorldSpeed(6.0); @@ -161,11 +161,19 @@ void Act3Cop::Animate(float p_time) // TODO } +// FUNCTION: LEGO1 0x10040350 +// FUNCTION: BETA10 0x10018c4a +MxResult Act3Cop::FUN_10040350(Act3Ammo& p_ammo, const Vector3&) +{ + return FUN_10040360(); +} + // STUB: LEGO1 0x10040360 // STUB: BETA10 0x10018c6a -void Act3Cop::FUN_10040360() +MxResult Act3Cop::FUN_10040360() { // TODO + return SUCCESS; } // FUNCTION: LEGO1 0x10040d20 @@ -248,15 +256,15 @@ MxResult Act3Brickster::HitActor(LegoPathActor* p_actor, MxBool p_bool) if (a3->m_cop1->GetROI() != r && a3->m_cop2->GetROI() != r) { if (!strncmp(r->GetName(), "pammo", 5)) { - MxS32 count = -1; - if (sscanf(r->GetName(), "pammo%d", &count) != 1) { + MxS32 index = -1; + if (sscanf(r->GetName(), "pammo%d", &index) != 1) { assert(0); } assert(m_world); - if (a3->m_pizzas[count].IsValid() && !a3->m_pizzas[count].IsBit5()) { - a3->EatPizza(count); + if (a3->m_pizzas[index].IsValid() && !a3->m_pizzas[index].IsBit5()) { + a3->EatPizza(index); } m_unk0x38 = 2; @@ -270,6 +278,17 @@ MxResult Act3Brickster::HitActor(LegoPathActor* p_actor, MxBool p_bool) return SUCCESS; } +// FUNCTION: LEGO1 0x100417a0 +// FUNCTION: BETA10 0x1001a3cf +MxResult Act3Brickster::FUN_100417a0(Act3Ammo& p_ammo, const Vector3&) +{ + if (m_unk0x58 < 8) { + return FUN_100417c0(); + } + + return SUCCESS; +} + // STUB: LEGO1 0x100417c0 // STUB: BETA10 0x1001a407 MxResult Act3Brickster::FUN_100417c0() diff --git a/LEGO1/lego/legoomni/src/actors/act3ammo.cpp b/LEGO1/lego/legoomni/src/actors/act3ammo.cpp index a2bfdb2c..71a55972 100644 --- a/LEGO1/lego/legoomni/src/actors/act3ammo.cpp +++ b/LEGO1/lego/legoomni/src/actors/act3ammo.cpp @@ -1,5 +1,7 @@ #include "act3ammo.h" +#include "act3.h" +#include "act3actors.h" #include "legocachesoundmanager.h" #include "legocharactermanager.h" #include "legopathboundary.h" @@ -13,12 +15,16 @@ DECOMP_SIZE_ASSERT(Act3Ammo, 0x1a0) +// Initialized at LEGO1 0x100537c0 +// GLOBAL: LEGO1 0x10104f08 +Mx3DPointFloat Act3Ammo::g_unk0x10104f08 = Mx3DPointFloat(0.0, 5.0, 0.0); + // FUNCTION: LEGO1 0x100537f0 // FUNCTION: BETA10 0x1001d648 Act3Ammo::Act3Ammo() { m_ammoFlag = 0; - m_a3 = NULL; + m_world = NULL; } // FUNCTION: LEGO1 0x100538a0 @@ -62,7 +68,7 @@ MxResult Act3Ammo::Remove() // FUNCTION: LEGO1 0x10053980 // FUNCTION: BETA10 0x1001d8b3 -MxResult Act3Ammo::Create(Act3* p_a3, MxU32 p_isPizza, MxS32 p_index) +MxResult Act3Ammo::Create(Act3* p_world, MxU32 p_isPizza, MxS32 p_index) { assert(m_ammoFlag); char name[12]; @@ -96,7 +102,7 @@ MxResult Act3Ammo::Create(Act3* p_a3, MxU32 p_isPizza, MxS32 p_index) assert(m_roi); } - m_a3 = p_a3; + m_world = p_world; SetValid(TRUE); return SUCCESS; } @@ -190,9 +196,245 @@ MxResult Act3Ammo::FUN_10053d30(LegoPathController* p_p, MxFloat p_unk0x19c) return SUCCESS; } -// STUB: LEGO1 0x10054050 -// STUB: BETA10 0x1001e362 -void Act3Ammo::Animate(float p_time) +// STUB: LEGO1 0x10053db0 +// STUB: BETA10 0x1001e0f0 +MxResult Act3Ammo::FUN_10053db0(float p_param1, const Matrix4& p_param2) { // TODO + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10054050 +// FUNCTION: BETA10 0x1001e362 +void Act3Ammo::Animate(float p_time) +{ + assert(IsValid()); + + switch (m_actorState & c_maxState) { + case c_initial: + case c_one: + break; + case c_two: + m_unk0x158 = p_time + 2000.0f; + m_actorState = c_three; + return; + case c_three: + MxMatrix transform; + Vector3 positionRef(transform[3]); + + transform = m_roi->GetLocal2World(); + + if (m_unk0x158 > p_time) { + Mx3DPointFloat position; + + position = positionRef; + positionRef.Clear(); + transform.RotateX(0.6); + positionRef = position; + m_roi->FUN_100a58f0(transform); + m_roi->VTable0x14(); + return; + } + else { + m_actorState = c_initial; + m_unk0x158 = 0; + + positionRef -= g_unk0x10104f08; + m_roi->FUN_100a58f0(transform); + m_roi->VTable0x14(); + return; + } + } + + if (m_worldSpeed <= 0.0f) { + return; + } + + if (m_lastTime < 0.0f) { + m_lastTime = p_time; + m_unk0x7c = 0.0f; + } + + MxMatrix local104; + MxMatrix local60; + + float f = (m_BADuration - m_unk0x7c) / m_worldSpeed + m_lastTime; + + undefined4 localb4 = 0; + undefined4 localbc = 0; + MxU32 local14 = FALSE; + MxU32 localb8 = FALSE; + + if (f >= p_time) { + m_actorTime = (p_time - m_lastTime) * m_worldSpeed + m_actorTime; + m_unk0x7c = (p_time - m_lastTime) * m_worldSpeed + m_unk0x7c; + m_lastTime = p_time; + } + else { + localb8 = TRUE; + m_unk0x7c = m_BADuration; + m_lastTime = p_time; + } + + local104.SetIdentity(); + + MxResult r = FUN_10053db0((m_unk0x7c / m_BADuration) * m_unk0x19c, local104); + assert(r == 0); // SUCCESS + + local60.SetIdentity(); + + if (IsPizza()) { + local60.Scale(2.0f, 2.0f, 2.0f); + } + else { + local60.Scale(5.0f, 5.0f, 5.0f); + } + + if (localb8) { + if (m_boundary != NULL) { + Vector3 local17c(local104[0]); + Vector3 local184(local104[1]); + Vector3 local174(local104[2]); + + if (IsPizza()) { + local184 = *m_boundary->GetUnknown0x14(); + local17c[0] = 1.0f; + local17c[1] = local17c[2] = 0.0f; + local174.EqualsCross(&local17c, &local184); + local174.Unitize(); + local17c.EqualsCross(&local184, &local174); + } + else { + local17c = *m_boundary->GetUnknown0x14(); + local184[0] = 1.0f; + local184[1] = local184[2] = 0.0f; + local174.EqualsCross(&local17c, &local184); + local174.Unitize(); + local184.EqualsCross(&local174, &local17c); + } + } + + m_actorState = c_initial; + } + else { + local60.RotateX(m_actorTime / 10.0f); + local60.RotateY(m_actorTime / 6.0f); + } + + MxMatrix localb0(local104); + local104.Product(local60, localb0); + m_roi->FUN_100a58f0(local104); + m_roi->VTable0x14(); + + if (m_BADuration <= m_unk0x7c) { + m_worldSpeed = 0.0f; + } + + Vector3 local68(local104[3]); + + if (localb8) { + if (IsBit4()) { + if (IsPizza()) { + m_world->RemovePizza(*this); + m_world->FUN_10072ad0(2); + } + else { + m_world->RemoveDonut(*this); + m_world->FUN_10072ad0(4); + } + } + else { + if (IsPizza()) { + assert(SoundManager()->GetCacheSoundManager()); + SoundManager()->GetCacheSoundManager()->Play("stickpz", NULL, FALSE); + } + else { + assert(SoundManager()->GetCacheSoundManager()); + SoundManager()->GetCacheSoundManager()->Play("stickdn", NULL, FALSE); + } + + LegoPathActorSet& plpas = m_boundary->GetActors(); + LegoPathActorSet lpas(plpas); + + for (LegoPathActorSet::iterator itpa = lpas.begin(); itpa != lpas.end(); itpa++) { + if (plpas.find(*itpa) != plpas.end() && this != *itpa) { + LegoROI* r = (*itpa)->GetROI(); + assert(r); + + if (!strncmp(r->GetName(), "pammo", 5)) { + Mx3DPointFloat local1c8; + Mx3DPointFloat local1b4; + + local1c8 = r->GetLocal2World()[3]; + local1b4 = m_roi->GetLocal2World()[3]; + + local1b4 -= local1c8; + + float radius = r->GetWorldBoundingSphere().Radius(); + if (local1b4.LenSquared() <= radius * radius) { + MxS32 index = -1; + if (sscanf(r->GetName(), "pammo%d", &index) != 1) { + assert(0); + } + + assert(m_world); + + if (m_world->m_pizzas[index].IsValid() && !m_world->m_pizzas[index].IsBit5()) { + m_world->EatPizza(index); + m_world->m_brickster->FUN_100417c0(); + } + + if (IsDonut()) { + assert(SoundManager()->GetCacheSoundManager()); + SoundManager()->GetCacheSoundManager()->Play("dnhitpz", NULL, FALSE); + m_world->RemoveDonut(*this); + local14 = TRUE; + break; + } + } + } + else if (!strncmp(r->GetName(), "dammo", 5)) { + Mx3DPointFloat local1f8; + Mx3DPointFloat local1e4; + + local1f8 = r->GetLocal2World()[3]; + local1e4 = m_roi->GetLocal2World()[3]; + + local1e4 -= local1f8; + + float radius = r->GetWorldBoundingSphere().Radius(); + if (local1e4.LenSquared() <= radius * radius) { + MxS32 index = -1; + if (sscanf(r->GetName(), "dammo%d", &index) != 1) { + assert(0); + } + + assert(m_world); + + m_world->EatDonut(index); + + if (IsPizza()) { + assert(SoundManager()->GetCacheSoundManager()); + SoundManager()->GetCacheSoundManager()->Play("pzhitdn", NULL, FALSE); + m_world->RemovePizza(*this); + local14 = TRUE; + break; + } + } + } + } + } + + if (!local14) { + if (IsPizza()) { + m_world->FUN_10073360(*this, local68); + } + else { + m_world->FUN_10073390(*this, local68); + } + + m_worldSpeed = -1.0f; + } + } + } } diff --git a/LEGO1/lego/legoomni/src/worlds/act3.cpp b/LEGO1/lego/legoomni/src/worlds/act3.cpp index c8da9436..233bde61 100644 --- a/LEGO1/lego/legoomni/src/worlds/act3.cpp +++ b/LEGO1/lego/legoomni/src/worlds/act3.cpp @@ -30,6 +30,9 @@ DECOMP_SIZE_ASSERT(Act3State, 0x0c) DECOMP_SIZE_ASSERT(Act3ListElement, 0x0c) DECOMP_SIZE_ASSERT(Act3List, 0x10) +// GLOBAL: LEGO1 0x100f7814 +MxU8 g_unk0x100f7814 = 0; + // GLOBAL: LEGO1 0x100d95e8 Act3Script::Script g_unk0x100d95e8[] = {Act3Script::c_tlp053in_RunAnim, Act3Script::c_tlp064la_RunAnim, Act3Script::c_tlp068in_RunAnim}; @@ -333,6 +336,13 @@ MxResult Act3::ShootDonut(LegoPathController* p_controller, Vector3& p_location, return FAILURE; } +// STUB: LEGO1 0x10072ad0 +// STUB: BETA10 0x10015eec +void Act3::FUN_10072ad0(undefined4 p_param1) +{ + // TODO +} + // FUNCTION: LEGO1 0x10072c30 // FUNCTION: BETA10 0x100160fb MxResult Act3::Create(MxDSAction& p_dsAction) @@ -563,6 +573,34 @@ MxResult Act3::Tickle() return SUCCESS; } +// FUNCTION: LEGO1 0x10073360 +// FUNCTION: BETA10 0x100169d5 +MxResult Act3::FUN_10073360(Act3Ammo& p_ammo, const Vector3& p_param2) +{ + assert(m_brickster); + m_brickster->FUN_100417a0(p_ammo, p_param2); + FUN_10072ad0(1); + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10073390 +// FUNCTION: BETA10 0x10016a40 +MxResult Act3::FUN_10073390(Act3Ammo& p_ammo, const Vector3& p_param2) +{ + assert(m_cop1 && m_cop2); + + if (!(g_unk0x100f7814 & 1)) { + m_cop1->FUN_10040350(p_ammo, p_param2); + } + else { + m_cop2->FUN_10040350(p_ammo, p_param2); + } + + FUN_10072ad0(3); + g_unk0x100f7814++; + return SUCCESS; +} + // FUNCTION: LEGO1 0x100733f0 // FUNCTION: BETA10 0x10016ba2 void Act3::SetBrickster(Act3Brickster* p_brickster) diff --git a/LEGO1/realtime/matrix.h b/LEGO1/realtime/matrix.h index 729239e2..b0ace048 100644 --- a/LEGO1/realtime/matrix.h +++ b/LEGO1/realtime/matrix.h @@ -130,6 +130,7 @@ class Matrix4 { inline virtual int FromQuaternion(const Vector4& p_vec); // vtable+0x44 // FUNCTION: LEGO1 0x100a0ff0 + // FUNCTION: BETA10 0x1001fe60 void Scale(const float& p_x, const float& p_y, const float& p_z) { for (int i = 0; i < 4; i++) {