#include "Runtime/MP1/World/CPuddleSpore.hpp" #include "Runtime/CSimplePool.hpp" #include "Runtime/CStateManager.hpp" #include "Runtime/GameGlobalObjects.hpp" #include "Runtime/Collision/CGameCollision.hpp" #include "Runtime/Weapon/CEnergyProjectile.hpp" #include "Runtime/Weapon/CGameProjectile.hpp" #include "Runtime/World/CPatternedInfo.hpp" #include "Runtime/World/CPlayer.hpp" #include "Runtime/World/CScriptWater.hpp" #include "TCastTo.hpp" // Generated file, do not modify include path namespace metaforce::MP1 { constexpr u32 kEyeCount = 16; constexpr std::array kEyeLocators{ "Glow_1_LCTR"sv, "Glow_2_LCTR"sv, "Glow_3_LCTR"sv, "Glow_4_LCTR"sv, "Glow_5_LCTR"sv, "Glow_6_LCTR"sv, "Glow_7_LCTR"sv, "Glow_8_LCTR"sv, "Glow_9_LCTR"sv, "Glow_10_LCTR"sv, "Glow_11_LCTR"sv, "Glow_12_LCTR"sv, "Glow_13_LCTR"sv, "Glow_14_LCTR"sv, "Glow_15_LCTR"sv, "Glow_16_LCTR"sv, }; CPuddleSpore::CPuddleSpore(TUniqueId uid, std::string_view name, EFlavorType flavor, const CEntityInfo& info, const zeus::CTransform& xf, CModelData&& mData, const CPatternedInfo& pInfo, EColliderType colType, CAssetId glowFx, float f1, float f2, float f3, float f4, float f5, const CActorParameters& actParms, CAssetId weapon, const CDamageInfo& dInfo) : CPatterned(ECharacter::PuddleSpore, uid, name, flavor, info, xf, std::move(mData), pInfo, EMovementType::Flyer, colType, EBodyType::Restricted, actParms, EKnockBackVariant::Medium) , x570_(f1) , x574_(f2) , x578_(f3) , x57c_(f4) , x580_(f5) , x584_bodyOrigin(pInfo.GetBodyOrigin()) , x590_halfExtent(pInfo.GetHalfExtent()) , x594_height(pInfo.GetHeight()) , x5a0_(CalculateBoundingBox(), GetMaterialList()) , x5d0_(g_SimplePool->GetObj({SBIG('PART'), glowFx})) , x5ec_projectileInfo(weapon, dInfo) { x5dc_elemGens.reserve(kEyeCount); for (u32 i = 0; i < kEyeCount; ++i) x5dc_elemGens.emplace_back(std::make_unique(x5d0_)); x5ec_projectileInfo.Token().Lock(); x460_knockBackController.SetAutoResetImpulse(false); } zeus::CAABox CPuddleSpore::CalculateBoundingBox() const { auto aaBox = GetBaseBoundingBox(); return {{(-x590_halfExtent + x584_bodyOrigin.x()) * 0.05f + (aaBox.min.x() * 0.95f), (-x590_halfExtent + x584_bodyOrigin.y()) * 0.05f + (aaBox.min.y() * 0.95f), (x598_ + x584_bodyOrigin.z()) * 0.05f + (aaBox.min.z() * 0.95f)}, {(x590_halfExtent + x584_bodyOrigin.x()) * 0.05f + (aaBox.max.x() * 0.95f), (x590_halfExtent + x584_bodyOrigin.y()) * 0.05f + (aaBox.max.y() * 0.95f), (x594_height * x59c_ + x598_ + x584_bodyOrigin.z()) * 0.05f + (aaBox.max.z() * 0.95f)}}; } void CPuddleSpore::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) { if (msg == EScriptObjectMessage::InvulnDamage) return; if (msg == EScriptObjectMessage::Registered) x450_bodyController->Activate(mgr); CPatterned::AcceptScriptMsg(msg, uid, mgr); } bool CPuddleSpore::HitShell(const zeus::CVector3f& point) const { if (x5c8_ != 1) return true; float distance = GetTransform().upVector().dot(zeus::CUnitVector3f(point - GetBoundingBox().center())); return (distance <= -0.5f || distance >= 0.5f); } void CPuddleSpore::KnockPlayer(CStateManager& mgr, float arg) { auto selfBox = GetBoundingBox(); auto playerBox = mgr.GetPlayer().GetBoundingBox(); if (selfBox.max.z() < ((playerBox.min.z() + playerBox.max.z()) * .5f) && playerBox.min.x() <= selfBox.max.x() && playerBox.min.y() <= selfBox.max.y() && selfBox.min.x() <= playerBox.max.x() && selfBox.min.y() <= playerBox.max.y() && playerBox.min.z() - selfBox.max.z() < 0.2f) { const float scale = mgr.GetPlayer().GetMorphballTransitionState() == CPlayer::EPlayerMorphBallState::Morphed ? 1.5f : 1.f; mgr.GetPlayer().ApplyImpulseWR(scale * (arg * mgr.GetPlayer().GetMass()) * x34_transform.rotate({1.f, 0.f, 0.3f}), {}); mgr.GetPlayer().SetMoveState(CPlayer::EPlayerMovementState::ApplyJump, mgr); } } void CPuddleSpore::UpdateBoundingState(const zeus::CAABox& box, CStateManager& mgr, float dt) { SetBoundingBox(box); x5a0_ = CCollidableAABox(box, x68_material); zeus::CAABox plBox; CPlayer& player = mgr.GetPlayer(); zeus::CAABox selfBox = GetBoundingBox(); if (player.GetMorphballTransitionState() == CPlayer::EPlayerMorphBallState::Morphed) { const float ballRad = player.GetMorphBall()->GetBallRadius(); zeus::CVector3f ballOffset = (player.GetTranslation() + zeus::CVector3f{0.f, 0.f, ballRad}); plBox = zeus::CAABox(ballOffset - ballRad, ballOffset + ballRad); } else { plBox = player.GetBoundingBox(); } if (selfBox.intersects(plBox)) { float bias = (x5c8_ == 2 ? FLT_EPSILON : -FLT_EPSILON) + (selfBox.max.z() - plBox.min.z()); if (bias > 0.f && selfBox.max.z() < plBox.max.z()) { bool hadGroundColliderMat = player.GetMaterialList().HasMaterial(EMaterialTypes::GroundCollider); if (hadGroundColliderMat) { player.RemoveMaterial(EMaterialTypes::GroundCollider, mgr); } player.RemoveMaterial(EMaterialTypes::Player, mgr); CPhysicsState state = player.GetPhysicsState(); player.MoveToOR(bias * zeus::CVector3f{0.f, 0.f, 1.f}, dt); CGameCollision::Move(mgr, player, dt, nullptr); state.SetTranslation(player.GetTranslation()); player.SetPhysicsState(state); if (hadGroundColliderMat) { player.AddMaterial(EMaterialTypes::GroundCollider, mgr); } player.AddMaterial(EMaterialTypes::Player, mgr); } } } void CPuddleSpore::PreThink(float dt, CStateManager& mgr) { if (x5c8_ == 2) AddMaterial(EMaterialTypes::SolidCharacter, mgr); else RemoveMaterial(EMaterialTypes::SolidCharacter, mgr); UpdateBoundingState(CalculateBoundingBox(), mgr, dt); CPatterned::PreThink(dt, mgr); } void CPuddleSpore::Think(float dt, CStateManager& mgr) { if (x614_25) x56c_ += dt; if (x614_24) x568_ += dt; HealthInfo(mgr)->SetHP(1000000.0f); float t = (x56c_ / x570_) - 1.f >= -0.f ? 1.f : x56c_ / x570_; zeus::CColor modColor = zeus::CColor::lerp(zeus::skWhite, zeus::CColor(1.f, 1.f, 1.f, 0.f), t); for (size_t i = 0; i < kEyeCount; ++i) { const auto& elemGen = x5dc_elemGens[i]; elemGen->SetModulationColor(modColor); elemGen->SetTranslation(GetLctrTransform(kEyeLocators[i]).origin); elemGen->Update(dt); } CPatterned::Think(dt, mgr); } void CPuddleSpore::Render(CStateManager& mgr) { CPatterned::Render(mgr); if (x56c_ > 0.01f) { for (const auto& elemGen : x5dc_elemGens) elemGen->Render(GetActorLights()); } } void CPuddleSpore::Touch(CActor& act, CStateManager& mgr) { if (!x400_25_alive) return; if (TCastToPtr proj = act) { if (proj->GetOwnerId() == mgr.GetPlayer().GetUniqueId()) x400_24_hitByPlayerProjectile = !HitShell(proj->GetTranslation()); } } void CPuddleSpore::FluidFXThink(EFluidState fState, CScriptWater& water, CStateManager& mgr) { if (fState != EFluidState::InFluid) return; CFluidPlaneManager* planeManager = mgr.GetFluidPlaneManager(); if (planeManager->GetLastRippleDeltaTime(GetUniqueId()) >= 2.9f) { zeus::CVector3f point = GetTranslation(); point.z() = float(water.GetTriggerBoundsWR().max.z()); water.GetFluidPlane().AddRipple(2.f, GetUniqueId(), point, water, mgr); } } void CPuddleSpore::DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType type, float dt) { if (type == EUserEventType::Projectile) { CProjectileInfo* projInfo = GetProjectileInfo(); if (projInfo->Token() && projInfo->Token().IsLocked() && mgr.CanCreateProjectile(GetUniqueId(), EWeaponType::AI, 16)) { mgr.AddObject(new CEnergyProjectile( true, projInfo->Token(), EWeaponType::AI, GetLctrTransform(node.GetLocatorName()), EMaterialTypes::Character, projInfo->GetDamage(), mgr.AllocateUniqueId(), GetAreaIdAlways(), GetUniqueId(), kInvalidUniqueId, EProjectileAttrib::None, false, zeus::skOne3f, {}, 0xFFFF, false)); } } else { CPatterned::DoUserAnimEvent(mgr, node, type, dt); } } bool CPuddleSpore::ShouldTurn(CStateManager& mgr, float) { auto selfBox = GetBoundingBox(); auto plBox = mgr.GetPlayer().GetBoundingBox(); if (((plBox.min.z() + plBox.max.z()) * 0.5f) <= selfBox.max.z() || selfBox.max.x() < plBox.min.x() || selfBox.max.y() < plBox.min.y() || plBox.max.x() < selfBox.min.x() || plBox.max.y() < selfBox.min.y() || mgr.GetPlayer().GetMorphballTransitionState() != CPlayer::EPlayerMorphBallState::Morphed) { return x578_ <= x568_; } return true; } void CPuddleSpore::InActive(CStateManager&, EStateMsg msg, float) { if (msg == EStateMsg::Activate) { x450_bodyController->SetLocomotionType(pas::ELocomotionType::Relaxed); x56c_ = 0.f; x598_ = -1.f; } } void CPuddleSpore::Active(CStateManager&, EStateMsg msg, float) { if (msg == EStateMsg::Activate) { x450_bodyController->SetLocomotionType(pas::ELocomotionType::Lurk); x568_ = 0.f; x56c_ = 0.f; x598_ = 0.f; x614_24 = true; x614_25 = true; } else if (msg == EStateMsg::Deactivate) { x614_24 = false; x614_25 = false; } } void CPuddleSpore::Run(CStateManager& mgr, EStateMsg msg, float) { if (msg == EStateMsg::Activate) { x5c8_ = 1; x5cc_ = 0; x568_ = 0.f; x614_24 = false; x598_ = 0.f; x59c_ = 1.5f; } else if (msg == EStateMsg::Update) { if (x5cc_ == 0) { if (x450_bodyController->GetBodyStateInfo().GetCurrentStateId() == pas::EAnimationState::LoopReaction) { x5cc_ = 1; x614_24 = true; } else { x450_bodyController->GetCommandMgr().DeliverCmd(CBCLoopReactionCmd(pas::EReactionType::Zero)); } } else if (x5cc_ == 1 && x450_bodyController->GetBodyStateInfo().GetCurrentStateId() == pas::EAnimationState::LoopReaction) { x5cc_ = 2; } } else if (msg == EStateMsg::Deactivate) { x450_bodyController->GetCommandMgr().DeliverCmd(CBodyStateCmd(EBodyStateCmd::ExitState)); x5c8_ = 0; x59c_ = 1.f; x614_24 = false; } } void CPuddleSpore::TurnAround(CStateManager& mgr, EStateMsg msg, float) { if (msg == EStateMsg::Activate) { x568_ = 0.f; x56c_ = 0.f; x400_24_hitByPlayerProjectile = false; x598_ = -2.5f; x5c8_ = 2; x5cc_ = 0; x614_24 = false; } else if (msg == EStateMsg::Update) { if (x5cc_ == 0) { if (x450_bodyController->GetBodyStateInfo().GetCurrentStateId() == pas::EAnimationState::LieOnGround) { x5cc_ = 1; x614_24 = true; } else { x450_bodyController->GetCommandMgr().DeliverCmd(CBCKnockDownCmd({1.f, 0.f, 0.f}, pas::ESeverity::One)); } } else if (x5cc_ == 1 && x450_bodyController->GetBodyStateInfo().GetCurrentStateId() != pas::EAnimationState::LieOnGround) { x5cc_ = 2; } } else if (msg == EStateMsg::Deactivate) { x614_24 = false; } } void CPuddleSpore::GetUp(CStateManager& mgr, EStateMsg msg, float) { if (msg == EStateMsg::Activate) { x450_bodyController->GetCommandMgr().DeliverCmd(CBCGetupCmd(pas::EGetupType::Zero)); KnockPlayer(mgr, x580_); x56c_ = 0.f; x598_ = -1.f; x5cc_ = 0; } else if (msg == EStateMsg::Update) { KnockPlayer(mgr, x580_ * 0.25f); if (x5cc_ == 0) { x450_bodyController->GetCommandMgr().DeliverCmd(CBCGetupCmd(pas::EGetupType::Zero)); if (x450_bodyController->GetBodyStateInfo().GetCurrentStateId() == pas::EAnimationState::Getup) x5cc_ = 1; } else if (x5cc_ == 1 && x450_bodyController->GetBodyStateInfo().GetCurrentStateId() != pas::EAnimationState::Getup) { x5cc_ = 1; } } else if (msg == EStateMsg::Deactivate) { x5c8_ = 0; } } void CPuddleSpore::Attack(CStateManager& mgr, EStateMsg msg, float) { if (msg == EStateMsg::Activate) { x32c_animState = EAnimState::Ready; x598_ = 0.f; } else if (msg == EStateMsg::Update) { TryCommand(mgr, pas::EAnimationState::MeleeAttack, &CPatterned::TryMeleeAttack, 1); } else if (msg == EStateMsg::Deactivate) { x32c_animState = EAnimState::NotReady; } } } // namespace metaforce::MP1