From 83055d527df86ffab01c50be2a8abe2a2b3516e4 Mon Sep 17 00:00:00 2001 From: Henrique Gemignani Passos Lima Date: Fri, 28 Oct 2022 19:12:27 +0300 Subject: [PATCH] Add CBSKnockBack Former-commit-id: 3344af40bfc9bbad540f0e5e9f0c14a1f48f21e3 --- asm/MetroidPrime/BodyState/CBSKnockBack.s | 12 +-- configure.py | 2 +- .../MetroidPrime/BodyState/CBSKnockBack.hpp | 24 +++++ src/MetroidPrime/BodyState/CBSFall.cpp | 3 +- src/MetroidPrime/BodyState/CBSGroundHit.cpp | 8 +- src/MetroidPrime/BodyState/CBSKnockBack.cpp | 94 +++++++++++++++++++ 6 files changed, 130 insertions(+), 13 deletions(-) create mode 100644 include/MetroidPrime/BodyState/CBSKnockBack.hpp create mode 100644 src/MetroidPrime/BodyState/CBSKnockBack.cpp diff --git a/asm/MetroidPrime/BodyState/CBSKnockBack.s b/asm/MetroidPrime/BodyState/CBSKnockBack.s index a41ab194..f9197733 100644 --- a/asm/MetroidPrime/BodyState/CBSKnockBack.s +++ b/asm/MetroidPrime/BodyState/CBSKnockBack.s @@ -3,8 +3,8 @@ .section .data .balign 8 -.global lbl_803E1450 -lbl_803E1450: +.global __vt__12CBSKnockBack +__vt__12CBSKnockBack: # ROM: 0x3DE450 .4byte 0 .4byte 0 @@ -31,8 +31,8 @@ __dt__12CBSKnockBackFv: /* 80136208 00133168 93 E1 00 0C */ stw r31, 0xc(r1) /* 8013620C 0013316C 7C 7F 1B 79 */ or. r31, r3, r3 /* 80136210 00133170 41 82 00 30 */ beq lbl_80136240 -/* 80136214 00133174 3C 60 80 3E */ lis r3, lbl_803E1450@ha -/* 80136218 00133178 38 03 14 50 */ addi r0, r3, lbl_803E1450@l +/* 80136214 00133174 3C 60 80 3E */ lis r3, __vt__12CBSKnockBack@ha +/* 80136218 00133178 38 03 14 50 */ addi r0, r3, __vt__12CBSKnockBack@l /* 8013621C 0013317C 90 1F 00 00 */ stw r0, 0(r31) /* 80136220 00133180 41 82 00 10 */ beq lbl_80136230 /* 80136224 00133184 3C 60 80 3E */ lis r3, __vt__10CBodyState@ha @@ -430,11 +430,11 @@ lbl_80136784: .global __ct__12CBSKnockBackFv __ct__12CBSKnockBackFv: /* 801367A0 00133700 3C A0 80 3E */ lis r5, __vt__10CBodyState@ha -/* 801367A4 00133704 3C 80 80 3E */ lis r4, lbl_803E1450@ha +/* 801367A4 00133704 3C 80 80 3E */ lis r4, __vt__12CBSKnockBack@ha /* 801367A8 00133708 38 A5 13 18 */ addi r5, r5, __vt__10CBodyState@l /* 801367AC 0013370C C0 02 99 FC */ lfs f0, lbl_805AB71C@sda21(r2) /* 801367B0 00133710 90 A3 00 00 */ stw r5, 0(r3) -/* 801367B4 00133714 38 04 14 50 */ addi r0, r4, lbl_803E1450@l +/* 801367B4 00133714 38 04 14 50 */ addi r0, r4, __vt__12CBSKnockBack@l /* 801367B8 00133718 90 03 00 00 */ stw r0, 0(r3) /* 801367BC 0013371C D0 03 00 04 */ stfs f0, 4(r3) /* 801367C0 00133720 D0 03 00 08 */ stfs f0, 8(r3) diff --git a/configure.py b/configure.py index c8b7e22b..12a158ca 100755 --- a/configure.py +++ b/configure.py @@ -188,7 +188,7 @@ LIBS = [ ["MetroidPrime/BodyState/CBSDie", True], ["MetroidPrime/BodyState/CBSFall", False], ["MetroidPrime/BodyState/CBSGetup", True], - "MetroidPrime/BodyState/CBSKnockBack", + ["MetroidPrime/BodyState/CBSKnockBack", False], ["MetroidPrime/BodyState/CBSLieOnGround", True], "MetroidPrime/BodyState/CBSLocomotion", ["MetroidPrime/BodyState/CBSStep", True], diff --git a/include/MetroidPrime/BodyState/CBSKnockBack.hpp b/include/MetroidPrime/BodyState/CBSKnockBack.hpp new file mode 100644 index 00000000..c4e5f045 --- /dev/null +++ b/include/MetroidPrime/BodyState/CBSKnockBack.hpp @@ -0,0 +1,24 @@ +#ifndef _CBSKNOCKBACK +#define _CBSKNOCKBACK + +#include "MetroidPrime/BodyState/CBodyState.hpp" + +class CBSKnockBack : public CBodyState { +public: + CBSKnockBack(); + ~CBSKnockBack(); + + void Start(CBodyController& bc, CStateManager& mgr) override; + pas::EAnimationState UpdateBody(float dt, CBodyController& bc, CStateManager& mgr) override; + void Shutdown(CBodyController&) override; + bool IsMoving() const override; + +private: + float x4_curTime; + float x8_rotateSpeed; + float xc_remTime; + + pas::EAnimationState GetBodyStateTransition(float dt, CBodyController& bc); +}; + +#endif // _CBSKNOCKBACK diff --git a/src/MetroidPrime/BodyState/CBSFall.cpp b/src/MetroidPrime/BodyState/CBSFall.cpp index 68d59df4..ed55d190 100644 --- a/src/MetroidPrime/BodyState/CBSFall.cpp +++ b/src/MetroidPrime/BodyState/CBSFall.cpp @@ -10,7 +10,6 @@ #include "Kyoto/Math/CAbsAngle.hpp" #include "Kyoto/Math/CRelAngle.hpp" - #include "math.h" #include "rstl/math.hpp" @@ -43,7 +42,7 @@ void CBSFall::Start(CBodyController& bc, CStateManager& mgr) { float minAngle = rstl::min_val(delta1, delta2); // There's a missing `if (delta1 < 0) { delta1 += M_2PIF; }` here // But it's not exactly delta1, but a temporary from inside the FromRadians call?! - // Same problem in CBSGroundHit + // Same problem in CBSGroundHit and CBSKnockBack const float flippedAngle = (delta1 > M_PIF) ? -minAngle : minAngle; x8_remTime = 0.15f * bc.GetAnimTimeRemaining(); x4_rotateSpeed = (x8_remTime > FLT_EPSILON) ? flippedAngle / x8_remTime : flippedAngle; diff --git a/src/MetroidPrime/BodyState/CBSGroundHit.cpp b/src/MetroidPrime/BodyState/CBSGroundHit.cpp index 9a4c80d8..3217b179 100644 --- a/src/MetroidPrime/BodyState/CBSGroundHit.cpp +++ b/src/MetroidPrime/BodyState/CBSGroundHit.cpp @@ -32,10 +32,10 @@ void CBSGroundHit::Start(CBodyController& bc, CStateManager& mgr) { const CAnimPlaybackParms playParms(best.second, -1, 1.f, true); bc.SetCurrentAnimation(playParms, false, false); - const CPASAnimState* groundHitState = db.GetAnimState(pas::kAS_GroundHit); - CPASAnimParm parm2(groundHitState->GetAnimParmData(best.second, 2)); + const CPASAnimState* animState = db.GetAnimState(pas::kAS_GroundHit); + CPASAnimParm parm2(animState->GetAnimParmData(best.second, 2)); if (!parm2.GetBoolValue()) { - CPASAnimParm parm1(groundHitState->GetAnimParmData(best.second, 1)); + CPASAnimParm parm1(animState->GetAnimParmData(best.second, 1)); float knockdownAngle = parm1.GetReal32Value(); float delta1 = CAbsAngle::FromRadians(angle.AsRadians() - CRelAngle::FromDegrees(knockdownAngle).AsRadians()) @@ -52,7 +52,7 @@ void CBSGroundHit::Start(CBodyController& bc, CStateManager& mgr) { x8_remTime = 0.f; x4_rotateSpeed = 0.f; } - CPASAnimParm parm3(groundHitState->GetAnimParmData(best.second, 3)); + CPASAnimParm parm3(animState->GetAnimParmData(best.second, 3)); xc_fallState = pas::EFallState(parm3.GetEnumValue()); } diff --git a/src/MetroidPrime/BodyState/CBSKnockBack.cpp b/src/MetroidPrime/BodyState/CBSKnockBack.cpp new file mode 100644 index 00000000..440bafad --- /dev/null +++ b/src/MetroidPrime/BodyState/CBSKnockBack.cpp @@ -0,0 +1,94 @@ +#include "MetroidPrime/BodyState/CBSKnockBack.hpp" + +#include "MetroidPrime/BodyState/CBodyController.hpp" +#include "MetroidPrime/CActor.hpp" +#include "MetroidPrime/CAnimPlaybackParms.hpp" +#include "MetroidPrime/CStateManager.hpp" + +#include "Kyoto/Animation/CPASAnimParmData.hpp" +#include "Kyoto/Animation/CPASDatabase.hpp" +#include "Kyoto/Math/CAbsAngle.hpp" +#include "Kyoto/Math/CRelAngle.hpp" + +#include "math.h" +#include "rstl/math.hpp" + +CBSKnockBack::CBSKnockBack() : x4_curTime(0.f), x8_rotateSpeed(0.f), xc_remTime(0.f) {} + +void CBSKnockBack::Start(CBodyController& bc, CStateManager& mgr) { + const CBCKnockBackCmd* cmd = static_cast(bc.CommandMgr().GetCmd(kBSC_KnockBack)); + + CVector3f localDir = bc.GetOwner().GetTransform().TransposeRotate(cmd->GetHitDirection()); + CAbsAngle angle = CAbsAngle::FromRadians(atan2(localDir.GetY(), localDir.GetX())); + + const CPASDatabase& db = bc.GetPASDatabase(); + + const CPASAnimParmData parms(pas::kAS_KnockBack, CPASAnimParm::FromReal32(angle.AsDegrees()), + CPASAnimParm::FromEnum(cmd->GetHitSeverity())); + const rstl::pair best = db.FindBestAnimation(parms, *mgr.Random(), -1); + + const CAnimPlaybackParms playParms(best.second, -1, 1.f, true); + bc.SetCurrentAnimation(playParms, false, false); + const CPASAnimState* animState = db.GetAnimState(pas::kAS_KnockBack); + + CPASAnimParm parm2(animState->GetAnimParmData(best.second, 2)); + if (!parm2.GetBoolValue()) { + CPASAnimParm parm0(animState->GetAnimParmData(best.second, 0)); + float knockdownAngle = parm0.GetReal32Value(); + float delta1 = CAbsAngle::FromRadians(angle.AsRadians() - + CRelAngle::FromDegrees(knockdownAngle).AsRadians()) + .AsRadians(); + float delta2 = CAbsAngle::FromRadians(CRelAngle::FromDegrees(knockdownAngle).AsRadians() - + angle.AsRadians()) + .AsRadians(); + float minAngle = rstl::min_val(delta1, delta2); + // There's missing code here. Same problem in CBSFall, see there for details + const float flippedAngle = (delta1 > M_PIF) ? -minAngle : minAngle; + xc_remTime = 0.15f * bc.GetAnimTimeRemaining(); + x8_rotateSpeed = (xc_remTime > FLT_EPSILON) ? flippedAngle / xc_remTime : flippedAngle; + } else { + xc_remTime = 0.f; + x8_rotateSpeed = 0.f; + } + x4_curTime = 0.f; +} + +pas::EAnimationState CBSKnockBack::UpdateBody(float dt, CBodyController& bc, + CStateManager& mgr) override { + const pas::EAnimationState st = GetBodyStateTransition(dt, bc); + if (st == pas::kAS_Invalid) { + x4_curTime += dt; + if (xc_remTime > 0.f) { + bc.SetDeltaRotation(CQuaternion::ZRotation(CRelAngle::FromRadians(x8_rotateSpeed * dt))); + xc_remTime -= dt; + } + } + return st; +} + +void CBSKnockBack::Shutdown(CBodyController&) override {} + +pas::EAnimationState CBSKnockBack::GetBodyStateTransition(float dt, CBodyController& bc) { + CBodyStateCmdMgr& commandMgr = bc.CommandMgr(); + + if (commandMgr.GetCmd(kBSC_Hurled)) { + return pas::kAS_Hurled; + } + if (commandMgr.GetCmd(kBSC_KnockDown)) { + return pas::kAS_Fall; + } + if (commandMgr.GetCmd(kBSC_LoopHitReaction)) { + return pas::kAS_LoopReaction; + } + if (commandMgr.GetCmd(kBSC_KnockBack) && x4_curTime > 0.2f) { + return pas::kAS_KnockBack; + } + if (bc.IsAnimationOver()) { + return pas::kAS_Locomotion; + } + return pas::kAS_Invalid; +} + +bool CBSKnockBack::IsMoving() const override { return true; } + +CBSKnockBack::~CBSKnockBack() {}