#include "Runtime/Character/CAdditiveBodyState.hpp" #include "Runtime/CStateManager.hpp" #include "Runtime/Character/CBodyController.hpp" #include "Runtime/Character/CAnimTreeNode.hpp" #include "Runtime/Character/CPASDatabase.hpp" #include "Runtime/Character/CPASAnimParmData.hpp" namespace metaforce { void CABSAim::Start(CBodyController& bc, CStateManager& mgr) { // const CBCAdditiveAimCmd* cmd = // static_cast(bc.GetCommandMgr().GetCmd(EBodyStateCmd::AdditiveAim)); const CPASAnimState* aimState = bc.GetPASDatabase().GetAnimState(pas::EAnimationState::AdditiveAim); // Left, Right, Up, Down for (size_t i = 0; i < x8_anims.size(); ++i) { const CPASAnimParmData parms(pas::EAnimationState::AdditiveAim, CPASAnimParm::FromEnum(s32(i))); const std::pair best = bc.GetPASDatabase().FindBestAnimation(parms, *mgr.GetActiveRandom(), -1); x8_anims[i] = best.second; x18_angles[i] = zeus::degToRad(aimState->GetAnimParmData(x8_anims[i], 1).GetReal32Value()); } const CAnimData& animData = *bc.GetOwner().GetModelData()->GetAnimationData(); x28_hWeight = -animData.GetAdditiveAnimationWeight(x8_anims[0]); x28_hWeight += animData.GetAdditiveAnimationWeight(x8_anims[1]); x30_vWeight = -animData.GetAdditiveAnimationWeight(x8_anims[2]); x30_vWeight += animData.GetAdditiveAnimationWeight(x8_anims[3]); x4_needsIdle = false; if (bc.GetCommandMgr().GetCmd(EBodyStateCmd::AdditiveIdle)) x4_needsIdle = true; } pas::EAnimationState CABSAim::GetBodyStateTransition(float dt, CBodyController& bc) const { if (bc.GetCommandMgr().GetCmd(EBodyStateCmd::AdditiveReaction)) return pas::EAnimationState::AdditiveReaction; if (bc.GetCommandMgr().GetCmd(EBodyStateCmd::AdditiveFlinch)) return pas::EAnimationState::AdditiveFlinch; if (bc.GetCommandMgr().GetCmd(EBodyStateCmd::AdditiveIdle) || x4_needsIdle) return pas::EAnimationState::AdditiveIdle; return pas::EAnimationState::Invalid; } pas::EAnimationState CABSAim::UpdateBody(float dt, CBodyController& bc, CStateManager& mgr) { const pas::EAnimationState st = GetBodyStateTransition(dt, bc); if (st == pas::EAnimationState::Invalid) { const zeus::CVector3f& target = bc.GetCommandMgr().GetAdditiveTargetVector(); if (target.canBeNormalized()) { CAnimData& animData = *bc.GetOwner().GetModelData()->GetAnimationData(); float hAngle = zeus::clamp(-x18_angles[0], std::atan2(target.x(), target.y()), x18_angles[1]); hAngle *= 0.63661975f; hAngle = zeus::clamp(-3.f, (hAngle - x28_hWeight) * 0.25f / dt, 3.f); x2c_hWeightVel += dt * zeus::clamp(-10.f, (hAngle - x2c_hWeightVel) / dt, 10.f); float hypotenuse = std::sqrt(target.y() * target.y() + target.x() * target.x()); float vAngle = zeus::clamp(-x18_angles[3], std::atan2(target.z(), hypotenuse), x18_angles[2]); vAngle *= 0.63661975f; vAngle = zeus::clamp(-3.f, (vAngle - x30_vWeight) * 0.25f / dt, 3.f); x34_vWeightVel += dt * zeus::clamp(-10.f, (vAngle - x34_vWeightVel) / dt, 10.f); float newHWeight = dt * x2c_hWeightVel + x28_hWeight; if (newHWeight != x28_hWeight) { if (std::fabs(x28_hWeight) > 0.f && x28_hWeight * newHWeight <= 0.f) animData.DelAdditiveAnimation(x8_anims[x28_hWeight < 0.f ? 0 : 1]); float absWeight = std::fabs(newHWeight); if (absWeight > 0.f) animData.AddAdditiveAnimation(x8_anims[newHWeight < 0.f ? 0 : 1], absWeight, false, false); } float newVWeight = dt * x34_vWeightVel + x30_vWeight; if (newVWeight != x30_vWeight) { if (std::fabs(x30_vWeight) > 0.f && x30_vWeight * newVWeight <= 0.f) animData.DelAdditiveAnimation(x8_anims[x30_vWeight > 0.f ? 2 : 3]); float absWeight = std::fabs(newVWeight); if (absWeight > 0.f) animData.AddAdditiveAnimation(x8_anims[newVWeight > 0.f ? 2 : 3], absWeight, false, false); } x28_hWeight = newHWeight; x30_vWeight = newVWeight; } } return st; } void CABSAim::Shutdown(CBodyController& bc) { CAnimData& animData = *bc.GetOwner().GetModelData()->GetAnimationData(); if (x28_hWeight != 0.f) animData.DelAdditiveAnimation(x8_anims[x28_hWeight < 0.f ? 0 : 1]); if (x30_vWeight != 0.f) animData.DelAdditiveAnimation(x8_anims[x30_vWeight > 0.f ? 2 : 3]); } void CABSFlinch::Start(CBodyController& bc, CStateManager& mgr) { const CBCAdditiveFlinchCmd* cmd = static_cast(bc.GetCommandMgr().GetCmd(EBodyStateCmd::AdditiveFlinch)); x4_weight = cmd->GetWeight(); CPASAnimParmData parms(pas::EAnimationState::AdditiveFlinch); std::pair best = bc.GetPASDatabase().FindBestAnimation(parms, *mgr.GetActiveRandom(), -1); x8_anim = best.second; CAnimData& animData = *bc.GetOwner().GetModelData()->GetAnimationData(); animData.AddAdditiveAnimation(x8_anim, x4_weight, false, true); } pas::EAnimationState CABSFlinch::GetBodyStateTransition(float dt, CBodyController& bc) const { if (bc.GetCommandMgr().GetCmd(EBodyStateCmd::AdditiveReaction)) return pas::EAnimationState::AdditiveReaction; return pas::EAnimationState::Invalid; } pas::EAnimationState CABSFlinch::UpdateBody(float dt, CBodyController& bc, CStateManager& mgr) { const pas::EAnimationState st = GetBodyStateTransition(dt, bc); if (st == pas::EAnimationState::Invalid) { CAnimData& animData = *bc.GetOwner().GetModelData()->GetAnimationData(); CCharAnimTime rem = animData.GetAdditiveAnimationTree(x8_anim)->VGetTimeRemaining(); if (std::fabs(rem.GetSeconds()) < 0.00001f) return pas::EAnimationState::AdditiveIdle; } return st; } pas::EAnimationState CABSIdle::GetBodyStateTransition(float dt, CBodyController& bc) const { if (bc.GetCommandMgr().GetCmd(EBodyStateCmd::AdditiveReaction)) return pas::EAnimationState::AdditiveReaction; if (bc.GetCommandMgr().GetCmd(EBodyStateCmd::AdditiveFlinch)) return pas::EAnimationState::AdditiveFlinch; if (bc.GetCommandMgr().GetCmd(EBodyStateCmd::AdditiveAim)) return pas::EAnimationState::AdditiveAim; return pas::EAnimationState::Invalid; } pas::EAnimationState CABSIdle::UpdateBody(float dt, CBodyController& bc, CStateManager& mgr) { return GetBodyStateTransition(dt, bc); } void CABSReaction::Start(CBodyController& bc, CStateManager& mgr) { const CBCAdditiveReactionCmd* cmd = static_cast(bc.GetCommandMgr().GetCmd(EBodyStateCmd::AdditiveReaction)); x4_weight = cmd->GetWeight(); xc_type = cmd->GetType(); x10_active = cmd->GetIsActive(); CPASAnimParmData parms(pas::EAnimationState::AdditiveReaction, CPASAnimParm::FromEnum(s32(xc_type))); std::pair best = bc.GetPASDatabase().FindBestAnimation(parms, *mgr.GetActiveRandom(), -1); x8_anim = best.second; if (x8_anim != -1) { CAnimData& animData = *bc.GetOwner().GetModelData()->GetAnimationData(); animData.AddAdditiveAnimation(x8_anim, x4_weight, x10_active, false); } } pas::EAnimationState CABSReaction::GetBodyStateTransition(float dt, CBodyController& bc) const { if (bc.GetCommandMgr().GetCmd(EBodyStateCmd::AdditiveReaction) && xc_type == pas::EAdditiveReactionType::IceBreakout) return pas::EAnimationState::AdditiveReaction; return pas::EAnimationState::Invalid; } pas::EAnimationState CABSReaction::UpdateBody(float dt, CBodyController& bc, CStateManager& mgr) { const pas::EAnimationState st = GetBodyStateTransition(dt, bc); if (st == pas::EAnimationState::Invalid) { if (x8_anim == -1) return pas::EAnimationState::AdditiveIdle; CAnimData& animData = *bc.GetOwner().GetModelData()->GetAnimationData(); if (x10_active) { if (bc.GetCommandMgr().GetCmd(EBodyStateCmd::StopReaction)) { StopAnimation(bc); bc.GetOwner().RemoveEmitter(); return pas::EAnimationState::AdditiveIdle; } } else { if (animData.IsAdditiveAnimationAdded(x8_anim)) { CCharAnimTime rem = animData.GetAdditiveAnimationTree(x8_anim)->VGetTimeRemaining(); if (std::fabs(rem.GetSeconds()) < 0.00001f) { StopAnimation(bc); return pas::EAnimationState::AdditiveIdle; } } else { return pas::EAnimationState::AdditiveIdle; } } } return st; } void CABSReaction::StopAnimation(CBodyController& bc) { if (x8_anim != -1) { CAnimData& animData = *bc.GetOwner().GetModelData()->GetAnimationData(); animData.DelAdditiveAnimation(x8_anim); x8_anim = -1; } } } // namespace metaforce