From 0d11dd1476818a77c1fa15dbd24e49b097ad8427 Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Sun, 20 Sep 2020 14:25:46 -0700 Subject: [PATCH] Finish CMetroidPrimeEssence imps --- Runtime/Collision/CGameCollision.cpp | 17 +++ Runtime/Collision/CGameCollision.hpp | 3 + Runtime/Collision/CMaterialFilter.hpp | 3 + Runtime/MP1/World/CMetroidPrimeEssence.cpp | 163 +++++++++++++++++---- Runtime/MP1/World/CMetroidPrimeEssence.hpp | 12 +- Runtime/MP1/World/CShockWave.hpp | 3 +- 6 files changed, 164 insertions(+), 37 deletions(-) diff --git a/Runtime/Collision/CGameCollision.cpp b/Runtime/Collision/CGameCollision.cpp index 8352be196..068e73cd4 100644 --- a/Runtime/Collision/CGameCollision.cpp +++ b/Runtime/Collision/CGameCollision.cpp @@ -682,6 +682,23 @@ bool CGameCollision::DetectDynamicCollisionMoving(const CCollisionPrimitive& pri return ret; } +bool CGameCollision::DetectCollision(const CStateManager& mgr, const CCollisionPrimitive& prim, const zeus::CTransform& xf, + const CMaterialFilter& filter, const rstl::reserved_vector& nearList, + TUniqueId& idOut, CCollisionInfoList& infoOut) { + bool ret = false; + CMaterialList exclude = filter.ExcludeList(); + if (!exclude.HasMaterial(EMaterialTypes::Occluder) && DetectStaticCollision(mgr, prim, xf, filter, infoOut)) { + ret = true; + } + + TUniqueId tmpId = kInvalidUniqueId; + if (DetectDynamicCollision(prim, xf, nearList, tmpId, infoOut, mgr)) { + ret = true; + idOut = tmpId; + } + return ret; +} + void CGameCollision::MakeCollisionCallbacks(CStateManager& mgr, CPhysicsActor& actor, TUniqueId id, const CCollisionInfoList& list) { actor.CollidedWith(id, list, mgr); diff --git a/Runtime/Collision/CGameCollision.hpp b/Runtime/Collision/CGameCollision.hpp index ac3b9e292..d03f604e7 100644 --- a/Runtime/Collision/CGameCollision.hpp +++ b/Runtime/Collision/CGameCollision.hpp @@ -105,6 +105,9 @@ public: const rstl::reserved_vector& nearList, const zeus::CVector3f& vec, TUniqueId& idOut, CCollisionInfo& infoOut, double& d, const CStateManager& mgr); + static bool DetectCollision(const CStateManager& mgr, const CCollisionPrimitive& prim, const zeus::CTransform& xf, + const CMaterialFilter& filter, const rstl::reserved_vector& nearList, + TUniqueId& idOut, CCollisionInfoList& infoOut); static void MakeCollisionCallbacks(CStateManager& mgr, CPhysicsActor& actor, TUniqueId id, const CCollisionInfoList& list); static void SendScriptMessages(CStateManager& mgr, CActor& a0, CActor* a1, const CCollisionInfoList& list); diff --git a/Runtime/Collision/CMaterialFilter.hpp b/Runtime/Collision/CMaterialFilter.hpp index 198c43bbd..32c521f2c 100644 --- a/Runtime/Collision/CMaterialFilter.hpp +++ b/Runtime/Collision/CMaterialFilter.hpp @@ -35,6 +35,9 @@ public: constexpr const CMaterialList& GetExcludeList() const noexcept { return x8_exclude; } constexpr CMaterialList& IncludeList() noexcept { return x0_include; } constexpr CMaterialList& ExcludeList() noexcept { return x8_exclude; } + const CMaterialList& IncludeList() const noexcept { return x0_include; } + const CMaterialList& ExcludeList() const noexcept { return x8_exclude; } + constexpr bool Passes(const CMaterialList& list) const noexcept { switch (x10_type) { diff --git a/Runtime/MP1/World/CMetroidPrimeEssence.cpp b/Runtime/MP1/World/CMetroidPrimeEssence.cpp index 071e25fa7..a02523000 100644 --- a/Runtime/MP1/World/CMetroidPrimeEssence.cpp +++ b/Runtime/MP1/World/CMetroidPrimeEssence.cpp @@ -4,13 +4,15 @@ #include "Runtime/CStateManager.hpp" #include "Runtime/Collision/CCollisionActor.hpp" #include "Runtime/Collision/CCollisionActorManager.hpp" +#include "Runtime/Collision/CGameCollision.hpp" #include "Runtime/GameGlobalObjects.hpp" +#include "Runtime/Graphics/CBooRenderer.hpp" #include "Runtime/Weapon/CGameProjectile.hpp" #include "Runtime/World/CGameArea.hpp" #include "Runtime/World/CPatternedInfo.hpp" #include "Runtime/World/CPlayer.hpp" +#include "Runtime/World/CScriptWaypoint.hpp" #include "Runtime/World/CWorld.hpp" -#include "Runtime/Graphics/CBooRenderer.hpp" #include "DataSpec/DNAMP1/SFX/MetroidPrime.h" @@ -39,7 +41,10 @@ CMetroidPrimeEssence::CMetroidPrimeEssence(urde::TUniqueId uid, std::string_view , x664_(electric) , x698_(dInfo) , x6b4_(xf.origin) -, x70c_(CSfxManager::TranslateSFXID(w1)) {} +, x70c_(CSfxManager::TranslateSFXID(w1)) { + CreateShadow(false); + MakeThermalColdAndHot(); +} void CMetroidPrimeEssence::Think(float dt, CStateManager& mgr) { if (!GetActive()) { @@ -112,7 +117,7 @@ void CMetroidPrimeEssence::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId o } case EScriptObjectMessage::InitializedInArea: { x574_searchPath.SetArea(mgr.GetWorld()->GetArea(GetAreaIdAlways())->GetPostConstructed()->x10bc_pathArea); - x704_ = GetWaypointForState(mgr, EScriptObjectState::Play, EScriptObjectMessage::Activate); + x704_bossUtilityWaypointId = GetWaypointForState(mgr, EScriptObjectState::Play, EScriptObjectMessage::Activate); break; } case EScriptObjectMessage::Damage: { @@ -170,6 +175,42 @@ zeus::CVector3f CMetroidPrimeEssence::GetAimPosition(const CStateManager& mgr, f void CMetroidPrimeEssence::DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType type, float dt) { + + switch (type) { + case EUserEventType::EggLay: { + if (x70e_29_ && x6d8_ != 0 && x6e4_ < x6f8_) { + const float ang1 = zeus::degToRad(22.5f) * mgr.GetActiveRandom()->Range(-1, 1); + const float ang2 = zeus::degToRad(45.0f) * mgr.GetActiveRandom()->Range(-1, 1); + zeus::CVector3f pos = + x668_ * zeus::CVector3f{2.f * -std::sin(ang1), (2.f * (2.f * std::cos(ang1)) * std::sin(ang2)), + 2.f * ((2.f * std::cos(ang1)) * std::cos(ang2))}; + if (TCastToPtr wp = mgr.ObjectById(x704_bossUtilityWaypointId)) { + wp->SetTransform(zeus::lookAt(pos, mgr.GetPlayer().GetTranslation())); + if (sub8027e870(wp->GetTransform(), mgr)) { + SendScriptMsgs(EScriptObjectState::Zero, mgr, EScriptObjectMessage::None); + } + } + } + return; + } + case EUserEventType::BeginAction: { + SShockWaveData data(x660_, x698_, 2.f, x664_, x70c_); + // TODO: Need to fix CElementGen accessing null ParticleAccessParameters + // data.SetSpeedIncrease(180.f); + DropShockwave(mgr, data); + ShakeCamera(mgr, 1.f); + return; + } + case EUserEventType::Activate: { + sub8027d824(mgr); + return; + } + case EUserEventType::Deactivate: + x70e_27_ = false; + [[fallthrough]]; + default: + break; + } CPatterned::DoUserAnimEvent(mgr, node, type, dt); } @@ -178,8 +219,8 @@ void CMetroidPrimeEssence::Death(CStateManager& mgr, const zeus::CVector3f& dire return; } - sub8027ee88(mgr); - sub8027d790(mgr, false); + KillAiInArea(mgr); + SetParticleEffectState(mgr, false); if (TCastToPtr colAct = mgr.ObjectById(x706_lockOnTargetCollider)) { colAct->AddMaterial(EMaterialTypes::ProjectilePassthrough, mgr); } @@ -197,7 +238,7 @@ void CMetroidPrimeEssence::Dead(CStateManager& mgr, EStateMsg msg, float dt) { void CMetroidPrimeEssence::PathFind(CStateManager& mgr, EStateMsg msg, float dt) { CPatterned::PathFind(mgr, msg, dt); if (msg == EStateMsg::Update) { - sub8027cb40(GetTranslation()); + sub8027cb40(mgr.GetPlayer().GetTranslation()); } } @@ -207,19 +248,21 @@ void CMetroidPrimeEssence::Halt(CStateManager& mgr, EStateMsg msg, float dt) { void CMetroidPrimeEssence::Generate(CStateManager& mgr, EStateMsg msg, float dt) { if (msg == EStateMsg::Activate) { - zeus::CTransform xf = zeus::lookAt(GetTranslation(), mgr.GetPlayer().GetTranslation()); + zeus::CVector3f lookPos = mgr.GetPlayer().GetTranslation(); + lookPos.z() = GetTranslation().z(); + zeus::CTransform xf = zeus::lookAt(GetTranslation(), lookPos); xf.origin = GetTranslation(); SetTransform(xf); } else if (msg == EStateMsg::Deactivate) { mgr.SetBossParams(GetUniqueId(), GetHealthInfo(mgr)->GetHP(), 91); - sub8027d790(mgr, true); + SetParticleEffectState(mgr, true); } } void CMetroidPrimeEssence::JumpBack(CStateManager& mgr, EStateMsg msg, float dt) { if (msg == EStateMsg::Activate) { x32c_animState = EAnimState::Ready; - x700_ = sub8027cfd4(mgr, 1); + x700_ = sub8027cfd4(mgr, true); } else if (msg == EStateMsg::Update) { TryCommand(mgr, pas::EAnimationState::Step, &CPatterned::TryStep, x700_); } else if (msg == EStateMsg::Deactivate) { @@ -291,7 +334,7 @@ void CMetroidPrimeEssence::TelegraphAttack(CStateManager& mgr, EStateMsg msg, fl void CMetroidPrimeEssence::Dodge(CStateManager& mgr, EStateMsg msg, float dt) { if (msg == EStateMsg::Activate) { x32c_animState = EAnimState::Ready; - x700_ = sub8027cfd4(mgr, 0); + x700_ = sub8027cfd4(mgr, false); } else if (msg == EStateMsg::Update) { TryCommand(mgr, pas::EAnimationState::Step, &CPatterned::TryStep, x700_); } else if (msg == EStateMsg::Deactivate) { @@ -408,21 +451,19 @@ void CMetroidPrimeEssence::sub8027cee0(CStateManager& mgr) { } } -u32 CMetroidPrimeEssence::sub8027cfd4(CStateManager& mgr, u32 w1) { +u32 CMetroidPrimeEssence::sub8027cfd4(CStateManager& mgr, bool w1) { + size_t startIndex = static_cast(!w1); zeus::CTransform xf = GetTargetTransform(mgr); - u32 uVar1 = zeus::countLeadingZeros(w1); - uVar1 >>= 5; - std::array vec; - const zeus::CVector3f* dir = &vec[uVar1]; - vec[0] = -xf.frontVector(); - vec[1] = -xf.rightVector(); - u32 uVar5 = 1 << uVar1; - for (size_t i = uVar1; i < 3; ++i) { - CRayCastResult res = mgr.RayStaticIntersection(xf.origin, *dir, 20.f, CMaterialFilter::skPassEverything); + std::array directions; + directions[0] = -xf.frontVector(); + directions[2] = xf.rightVector(); + directions[1] = -directions[2]; + u32 uVar5 = 1 << size_t(startIndex); + for (size_t i = size_t(startIndex); i < 3; ++i) { + CRayCastResult res = mgr.RayStaticIntersection(xf.origin, directions[i], 20.f, CMaterialFilter::skPassEverything); if (res.IsInvalid()) { uVar5 |= 1 << i; } - ++dir; } u32 uVar3 = 0; @@ -438,7 +479,7 @@ u32 CMetroidPrimeEssence::sub8027cfd4(CStateManager& mgr, u32 w1) { } else if (numBits < 2) { uVar3 = uVar5 >> 1; } else if (numBits == 3) { - uVar3 = mgr.GetActiveRandom()->Range(uVar1, 2); + uVar3 = mgr.GetActiveRandom()->Range(startIndex, 2); } } @@ -482,17 +523,79 @@ void CMetroidPrimeEssence::ShakeCamera(CStateManager& mgr, float f1) { mgr.GetCameraManager()->AddCameraShaker(CCameraShakeData(0.5f, mag), true); } -void CMetroidPrimeEssence::sub8027d52c(CStateManager& mgr, const SShockWaveData& shockWaveData) {} +void CMetroidPrimeEssence::DropShockwave(CStateManager& mgr, const SShockWaveData& shockWaveData) { + CRayCastResult res = RayStaticIntersection(mgr); + if (res.IsInvalid()) { + return; + } -CRayCastResult CMetroidPrimeEssence::sub8027d704(CStateManager& mgr) { return CRayCastResult(); } + mgr.AddObject(new CShockWave(mgr.AllocateUniqueId(), "Shockwave", CEntityInfo(GetAreaIdAlways(), NullConnectionList), + zeus::CTransform::Translate(res.GetPoint()), GetUniqueId(), shockWaveData, 1.5f, 0.5f)); +} -void CMetroidPrimeEssence::sub8027d790(CStateManager& mgr, bool active) {} +CRayCastResult CMetroidPrimeEssence::RayStaticIntersection(CStateManager& mgr) { + return mgr.RayStaticIntersection(GetTranslation(), -zeus::skUp, 30.f, CMaterialFilter::skPassEverything); +} -void CMetroidPrimeEssence::sub8027d824(CStateManager& mgr) {} +void CMetroidPrimeEssence::SetParticleEffectState(CStateManager& mgr, bool active) { + GetModelData()->GetAnimationData()->SetParticleEffectState("Eyes"sv, active, mgr); + GetModelData()->GetAnimationData()->SetParticleEffectState("Head"sv, active, mgr); +} -bool CMetroidPrimeEssence::sub8027e870(const zeus::CTransform& xf, CStateManager& mgr) { return false; } +void CMetroidPrimeEssence::sub8027d824(CStateManager& mgr) { + CRayCastResult res = RayStaticIntersection(mgr); + if (res.IsInvalid()) { + return; + } -void CMetroidPrimeEssence::sub8027ee88(CStateManager& mgr) {} + x668_ = zeus::CTransform::Translate(res.GetPoint()); + if (TCastToPtr wp = mgr.ObjectById(x704_bossUtilityWaypointId)) { + wp->SetTransform(x668_); + SendScriptMsgs(EScriptObjectState::AboutToMassivelyDie, mgr, EScriptObjectMessage::None); + x70e_29_ = true; + } +} + +bool CMetroidPrimeEssence::sub8027e870(const zeus::CTransform& xf, CStateManager& mgr) { + rstl::reserved_vector nearList; + mgr.BuildNearList(nearList, {xf.origin - 2.f, xf.origin + 2.f}, CMaterialFilter::MakeInclude(EMaterialTypes::AIBlock), + this); + + CCollidableSphere sphere({zeus::skZero3f, 2.f}, CMaterialList(EMaterialTypes::Solid, EMaterialTypes::AIBlock)); + CCollisionInfoList infoList; + TUniqueId tmpId = kInvalidUniqueId; + CGameCollision::DetectCollision( + mgr, sphere, xf, + CMaterialFilter::MakeIncludeExclude( + {EMaterialTypes ::Solid, EMaterialTypes ::Player, EMaterialTypes ::Character, EMaterialTypes ::AIBlock}, + {EMaterialTypes ::ProjectilePassthrough}), + nearList, tmpId, infoList); + + if (infoList.GetCount() >= 1) { + return false; + } + + if (TCastToPtr colAct = mgr.ObjectById(x706_lockOnTargetCollider)) { + zeus::CVector3f direction = (xf.origin - colAct->GetTranslation()).normalized(); + CRayCastResult res = + mgr.RayStaticIntersection(colAct->GetTranslation(), direction, direction.magnitude(), + CMaterialFilter::MakeExclude({EMaterialTypes::ProjectilePassthrough})); + if (res.IsInvalid()) { + return true; + } + } + return false; +} + +void CMetroidPrimeEssence::KillAiInArea(CStateManager& mgr) { + for (auto* ent : mgr.GetListeningAiObjectList()) { + if (TCastToPtr ai = ent) { + if (ai != this && ai->GetActive() && ai->GetAreaIdAlways() == GetAreaIdAlways()) { + static_cast(ai.GetPtr())->MassiveDeath(mgr); + } + } + } +} void CMetroidPrimeEssence::CountListeningAi(CStateManager& mgr) { x6e0_ = 0; @@ -511,7 +614,7 @@ void CMetroidPrimeEssence::UpdatePhase(float dt, CStateManager& mgr) { GetModelData()->SetScale(zeus::CVector3f((x6cc_ - x6d0_) + x6d0_)); if (!x70e_28_) { AddMaterial(EMaterialTypes::Orbit, EMaterialTypes::Target, mgr); - sub8027d790(mgr, true); + SetParticleEffectState(mgr, true); x70e_28_ = true; } } else { @@ -519,7 +622,7 @@ void CMetroidPrimeEssence::UpdatePhase(float dt, CStateManager& mgr) { GetModelData()->SetScale(zeus::CVector3f((x6cc_ - x6d0_) + x6d0_)); if (x70e_28_) { RemoveMaterial(EMaterialTypes::Orbit, EMaterialTypes::Target, mgr); - sub8027d790(mgr, false); + SetParticleEffectState(mgr, false); x70e_28_ = false; } } diff --git a/Runtime/MP1/World/CMetroidPrimeEssence.hpp b/Runtime/MP1/World/CMetroidPrimeEssence.hpp index 03b5840d1..93dfe9624 100644 --- a/Runtime/MP1/World/CMetroidPrimeEssence.hpp +++ b/Runtime/MP1/World/CMetroidPrimeEssence.hpp @@ -35,7 +35,7 @@ class CMetroidPrimeEssence : public CPatterned { u32 x6f8_ = 2; u32 x6fc_ = 0; u32 x700_ = 1; - TUniqueId x704_ = kInvalidUniqueId; + TUniqueId x704_bossUtilityWaypointId = kInvalidUniqueId; TUniqueId x706_lockOnTargetCollider = kInvalidUniqueId; CSfxHandle x708_; s16 x70c_; @@ -53,16 +53,16 @@ class CMetroidPrimeEssence : public CPatterned { zeus::CTransform GetTargetTransform(CStateManager& mgr); void sub8027ce5c(float f1); void sub8027cee0(CStateManager& mgr); - u32 sub8027cfd4(CStateManager& mgr, u32 w1); + u32 sub8027cfd4(CStateManager& mgr, bool w1); void DoPhaseTransition(CStateManager& mgr); u32 sub8027d428() { return 2; /* Decided by fair dice roll, guaranteed to be random */} void ShakeCamera(CStateManager& mgr, float f1); - void sub8027d52c(CStateManager& mgr, const SShockWaveData& shockWaveData); - CRayCastResult sub8027d704(CStateManager& mgr); - void sub8027d790(CStateManager& mgr, bool active); + void DropShockwave(CStateManager& mgr, const SShockWaveData& shockWaveData); + CRayCastResult RayStaticIntersection(CStateManager& mgr); + void SetParticleEffectState(CStateManager& mgr, bool active); void sub8027d824(CStateManager& mgr); bool sub8027e870(const zeus::CTransform& xf, CStateManager& mgr); - void sub8027ee88(CStateManager& mgr); + void KillAiInArea(CStateManager& mgr); void CountListeningAi(CStateManager& mgr); void UpdatePhase(float dt, CStateManager& mgr); void UpdateHealth(CStateManager& mgr); diff --git a/Runtime/MP1/World/CShockWave.hpp b/Runtime/MP1/World/CShockWave.hpp index 4eddadbec..fd5fc35ed 100644 --- a/Runtime/MP1/World/CShockWave.hpp +++ b/Runtime/MP1/World/CShockWave.hpp @@ -1,8 +1,8 @@ #pragma once +#include "Runtime/Particle/CElementGen.hpp" #include "Runtime/World/CActor.hpp" #include "Runtime/World/CDamageInfo.hpp" -#include "Runtime/Particle/CElementGen.hpp" namespace urde::MP1 { struct SShockWaveData { @@ -31,6 +31,7 @@ public: [[nodiscard]] float GetWidthPercent() const { return x28_widthPercent; } [[nodiscard]] float GetInitialExpansionSpeed() const { return x2c_initialExpansionSpeed; } [[nodiscard]] float GetSpeedIncrease() const { return x30_speedIncrease; } + void SetSpeedIncrease(float speed) { x30_speedIncrease = speed; } [[nodiscard]] CAssetId GetWeaponDescId() const { return x34_weaponDesc; } [[nodiscard]] u16 GetElectrocuteSfx() const { return x38_electrocuteSfx; } };