Add CBodyStateInfo

Former-commit-id: 5161698bef
This commit is contained in:
Henrique Gemignani Passos Lima 2022-10-25 18:43:42 +03:00
parent f57880f218
commit d6b660c936
13 changed files with 398 additions and 175 deletions

File diff suppressed because it is too large Load Diff

View File

@ -183,7 +183,7 @@ LIBS = [
"MetroidPrime/ScriptObjects/CHUDBillboardEffect",
"MetroidPrime/Enemies/CFlickerBat",
"MetroidPrime/BodyState/CBodyStateCmdMgr",
"MetroidPrime/BodyState/CBodyStateInfo",
["MetroidPrime/BodyState/CBodyStateInfo", False],
"MetroidPrime/BodyState/CBSAttack",
"MetroidPrime/BodyState/CBSDie",
"MetroidPrime/BodyState/CBSFall",

View File

@ -67,6 +67,8 @@ private:
class CPASAnimState {
public:
CPASAnimParm GetAnimParmData(int, unsigned int) const;
pas::EAnimationState GetStateId() const { return x0_id; }
private:
pas::EAnimationState x0_id;

View File

@ -12,13 +12,23 @@ class CPASAnimParmData;
class CRandom16;
class CPASDatabase {
private:
rstl::vector< CPASAnimState > x0_states;
int x10_defaultState;
public:
const CPASAnimState* GetAnimState(int) const;
rstl::pair< float, int > FindBestAnimation(const CPASAnimParmData&, CRandom16&, int) const;
size_t GetNumAnimStates() const; // { return x0_states.size(); }
const CPASAnimState* GetAnimStateByIndex(int index) const; /* {
if (index >= x0_states.size()) {
return nullptr;
}
return &x0_states[index];
}*/
private:
rstl::vector< CPASAnimState > x0_states;
int x10_defaultState;
};
CHECK_SIZEOF(CPASDatabase, 0x14)

View File

@ -171,6 +171,17 @@ enum EWallHangState {
};
} // namespace pas
enum EBodyType {
kBT_Invalid,
kBT_BiPedal,
kBT_Restricted,
kBT_Flyer,
kBT_Pitchable,
kBT_RestrictedFlyer,
kBT_WallWalker,
kBT_NewFlyer
};
enum EBodyStateCmd {
kBSC_Getup,
kBSC_Step,

View File

@ -0,0 +1,23 @@
#ifndef _CABSAIM
#define _CABSAIM
#include "MetroidPrime/BodyState/CAdditiveBodyState.hpp"
class CABSAim : public CAdditiveBodyState {
bool x4_needsIdle;
int x8_anims[4];
float x18_angles[4];
float x28_hWeight;
float x2c_hWeightVel;
float x30_vWeight;
float x34_vWeightVel;
pas::EAnimationState GetBodyStateTransition(float dt, CBodyController& bc) const;
public:
CABSAim();
void Start(CBodyController& bc, CStateManager& mgr) override;
pas::EAnimationState UpdateBody(float dt, CBodyController& bc, CStateManager& mgr) override;
void Shutdown(CBodyController& bc) override;
};
#endif // _CABSAIM

View File

@ -0,0 +1,21 @@
#ifndef _CABSREACTION
#define _CABSREACTION
#include "MetroidPrime/BodyState/CAdditiveBodyState.hpp"
class CABSReaction : public CAdditiveBodyState {
float x4_weight;
s32 x8_anim;
pas::EAdditiveReactionType xc_type;
bool x10_active;
pas::EAnimationState GetBodyStateTransition(float dt, CBodyController& bc) const;
void StopAnimation(CBodyController& bc);
public:
CABSReaction();
void Start(CBodyController& bc, CStateManager& mgr) override;
pas::EAnimationState UpdateBody(float dt, CBodyController& bc, CStateManager& mgr) override;
void Shutdown(CBodyController& bc) override { StopAnimation(bc); }
};
#endif // _CABSREACTION

View File

@ -0,0 +1,28 @@
#ifndef _CBSLOCOMOTION
#define _CBSLOCOMOTION
#include "MetroidPrime/BodyState/CBodyState.hpp"
#include "rstl/pair.hpp"
class CBSLocomotion : public CBodyState {
protected:
pas::ELocomotionType x4_locomotionType;
float GetStartVelocityMagnitude(const CBodyController& bc) const;
void ReStartBodyState(CBodyController& bc, bool maintainVel);
float ComputeWeightPercentage(const rstl::pair<int, float>& a, const rstl::pair<int, float>& b, float f) const;
public:
bool IsMoving() const override = 0;
bool CanShoot() const override { return true; }
void Start(CBodyController& bc, CStateManager& mgr) override;
pas::EAnimationState UpdateBody(float dt, CBodyController& bc, CStateManager& mgr) override;
void Shutdown(CBodyController& bc) override;
virtual bool IsPitchable() const { return false; }
virtual float GetLocomotionSpeed(pas::ELocomotionType type, pas::ELocomotionAnim anim) const = 0;
virtual float ApplyLocomotionPhysics(float dt, CBodyController& bc);
virtual float UpdateLocomotionAnimation(float dt, float velMag, CBodyController& bc, bool init) = 0;
virtual pas::EAnimationState GetBodyStateTransition(float dt, CBodyController& bc);
};
#endif // _CBSLOCOMOTION

View File

@ -2,6 +2,9 @@
#define _CBODYCONTROLLER
#include "MetroidPrime/BodyState/CBodyStateCmdMgr.hpp"
#include "MetroidPrime/BodyState/CBodyStateInfo.hpp"
#include "Kyoto/Math/CQuaternion.hpp"
class CActor;
class CPASDatabase;
@ -22,16 +25,16 @@ public:
void SetCurrentAnimation(const CAnimPlaybackParms& parms, bool loop, bool noTrans);
bool IsAnimationOver() const { return x300_24_animationOver; }
pas::ELocomotionType GetLocomotionType() const { return x2ec_locomotionType; }
private:
CActor& x0_actor;
CBodyStateCmdMgr x4_cmdMgr;
uchar x2a4_pad[0x54];
// CBodyStateInfo x2a4_bodyStateInfo;
// CQuaternion x2dc_rot;
// pas::ELocomotionType x2ec_locomotionType ;
// pas::EFallState x2f0_fallState ;
// EBodyType x2f4_bodyType;
CBodyStateInfo x2a4_bodyStateInfo;
CQuaternion x2dc_rot;
pas::ELocomotionType x2ec_locomotionType ;
pas::EFallState x2f0_fallState ;
EBodyType x2f4_bodyType;
int x2f8_curAnim ;
float x2fc_turnSpeed;
bool x300_24_animationOver : 1;

View File

@ -0,0 +1,55 @@
#ifndef _CBODYSTATEINFO
#define _CBODYSTATEINFO
#include "Kyoto/Animation/CharacterCommon.hpp"
#include "rstl/map.hpp"
#include "rstl/auto_ptr.hpp"
#include "rstl/vector.hpp"
class CAdditiveBodyState;
class CBodyController;
class CBodyState;
class CActor;
class CBodyStateInfo {
public:
CBodyStateInfo(CActor& actor, EBodyType type);
~CBodyStateInfo();
float GetMaximumPitch() const { return x30_maxPitch; }
void SetMaximumPitch(float pitch) { x30_maxPitch = pitch; }
bool GetLocoAnimChangeAtEndOfAnimOnly() const { return x34_24_changeLocoAtEndOfAnimOnly; }
void SetLocoAnimChangeAtEndOfAnimOnly(bool s) { x34_24_changeLocoAtEndOfAnimOnly = s; }
pas::EAnimationState GetCurrentStateId() const { return x14_state; }
pas::EAnimationState GetCurrentAdditiveStateId() const { return x2c_additiveState; }
void SetState(pas::EAnimationState s);
const CBodyState* GetCurrentState() const;
CBodyState* GetCurrentState();
bool ApplyHeadTracking() const;
void SetAdditiveState(pas::EAnimationState s);
CAdditiveBodyState* GetCurrentAdditiveState();
float GetMaxSpeed() const;
float GetLocomotionSpeed(pas::ELocomotionAnim anim) const;
private:
friend class CBodyController;
rstl::map< int, CBodyState* > x0_stateMap;
pas::EAnimationState x14_state;
CBodyController* x18_bodyController;
rstl::vector< rstl::pair< int, rstl::auto_ptr< CAdditiveBodyState > > > x1c_additiveStates;
pas::EAnimationState x2c_additiveState;
float x30_maxPitch;
bool x34_24_changeLocoAtEndOfAnimOnly : 1;
CBodyState* SetupRestrictedFlyerBodyStates(int stateId, CActor& actor);
CBodyState* SetupNewFlyerBodyStates(int stateId, CActor& actor);
CBodyState* SetupWallWalkerBodyStates(int stateId, CActor& actor);
CBodyState* SetupFlyerBodyStates(int stateId, CActor& actor);
CBodyState* SetupPitchableFlyerBodyStates(int, CActor&);
CBodyState* SetupRestrictedBodyStates(int stateId, CActor& actor);
CBodyState* SetupBiPedalBodyStates(int stateId, CActor& actor);
};
#endif // _CBODYSTATEINFO

View File

@ -23,7 +23,7 @@ public:
rstl::vector< CAssetId > x30_elsc;
};
const CPASDatabase& GetPASDatabase() const; // { return x30_pasDatabase; }
const CPASDatabase& GetPASDatabase() const { return x30_pasDatabase; }
private:
ushort x0_tableCount;

View File

@ -54,11 +54,9 @@ private:
node* get_right() { return mRight; }
void set_right(node* n) { mRight = n; }
};
struct header {
node* mLeftmost;
node* mRightmost;
node* mRootNode;
class header {
public:
header() : mLeftmost(nullptr), mRightmost(nullptr), mRootNode(nullptr) {}
void set_root(node* n) { mRootNode = n; }
void set_leftmost(node* n) { mLeftmost = n; }
void set_rightmost(node* n) { mRightmost = n; }
@ -66,6 +64,11 @@ private:
node* get_root() const { return mRootNode; }
node* get_leftmost() const { return mLeftmost; }
node* get_rightmost() const { return mRightmost; }
private:
node* mLeftmost;
node* mRightmost;
node* mRootNode;
};
public:
@ -103,6 +106,9 @@ public:
iterator(node* node, const header* header, bool b) : const_iterator(node, header, b) {}
};
red_black_tree() : x0_(0), x1_(0), x4_count(0) {}
~red_black_tree() { clear(); }
iterator insert_into(node* n, const P& item);
iterator insert(const P& item) { return insert_into(x8_header.get_root(), item); }
@ -119,7 +125,7 @@ public:
node* n = x8_header.get_root();
node* needle = nullptr;
while (n != nullptr) {
if (!x1_cmp(x2_selector(*n->get_value()), key)) {
if (!x2_cmp(x3_selector(*n->get_value()), key)) {
needle = n;
n = n->get_left();
} else {
@ -127,7 +133,7 @@ public:
}
}
bool noResult = false;
if (needle == nullptr || x1_cmp(key, x2_selector(*needle->get_value()))) {
if (needle == nullptr || x2_cmp(key, x3_selector(*needle->get_value()))) {
noResult = true;
}
if (noResult) {
@ -137,7 +143,6 @@ public:
}
void clear() {
// x0_allocator.deallocate(x10_rootNode);
node* root = x8_header.get_root();
if (root != nullptr) {
free_node_and_sub_nodes(root);
@ -148,18 +153,17 @@ public:
x4_count = 0;
}
~red_black_tree() { clear(); }
private:
Alloc x0_allocator;
Cmp x1_cmp;
S x2_selector;
uchar x0_;
uchar x1_;
Cmp x2_cmp;
S x3_selector;
int x4_count;
header x8_header;
node* create_node(node* left, node* right, node* parent, node_color color, const P& value) {
node* n;
x0_allocator.allocate(n, 1);
Alloc::allocate(n, 1);
new (n) node(left, right, parent, color, value);
return n;
}
@ -176,7 +180,7 @@ private:
void free_node(node* n) {
n->~node();
x0_allocator.deallocate(n);
Alloc::deallocate(n);
}
void rebalance(node* n) { rbtree_rebalance(&x8_header, n); }
@ -199,8 +203,8 @@ red_black_tree< T, P, U, S, Cmp, Alloc >::insert_into(node* n, const P& item) {
} else {
node* newNode = nullptr;
while (newNode == nullptr) {
bool firstComp = x1_cmp(x2_selector(*n->get_value()), x2_selector(item));
if (!firstComp && !x1_cmp(x2_selector(item), x2_selector(*n->get_value()))) {
bool firstComp = x2_cmp(x3_selector(*n->get_value()), x3_selector(item));
if (!firstComp && !x2_cmp(x3_selector(item), x3_selector(*n->get_value()))) {
return iterator(n, &x8_header, kUnknownValueEqualKey);
}
if (firstComp) {

View File

@ -0,0 +1,213 @@
#include "MetroidPrime/BodyState/CBodyStateInfo.hpp"
#include "MetroidPrime/BodyState/CABSAim.hpp"
#include "MetroidPrime/BodyState/CABSFlinch.hpp"
#include "MetroidPrime/BodyState/CABSIdle.hpp"
#include "MetroidPrime/BodyState/CABSReaction.hpp"
#include "MetroidPrime/BodyState/CBodyController.hpp"
#include "MetroidPrime/BodyState/CBSLocomotion.hpp"
#include "MetroidPrime/BodyState/CBSSlide.hpp"
#include "MetroidPrime/CActor.hpp"
#include "MetroidPrime/CAnimData.hpp"
#include "MetroidPrime/CModelData.hpp"
#include "Kyoto/Animation/CPASDatabase.hpp"
#include "Kyoto/Math/CloseEnough.hpp"
CBodyStateInfo::CBodyStateInfo(CActor& actor, EBodyType type)
: x14_state(pas::kAS_Invalid)
, x18_bodyController(nullptr)
, x2c_additiveState(pas::kAS_AdditiveIdle)
, x30_maxPitch(0.0f)
, x34_24_changeLocoAtEndOfAnimOnly(false)
{
const CPASDatabase& pasDatabase =
actor.GetModelData()->GetAnimationData()->GetCharacterInfo().GetPASDatabase();
for (size_t i = 0; i < pasDatabase.GetNumAnimStates(); ++i) {
const CPASAnimState* state = pasDatabase.GetAnimStateByIndex(i);
CBodyState* bs;
switch (type) {
case kBT_BiPedal:
bs = SetupBiPedalBodyStates(state->GetStateId(), actor);
break;
case kBT_Restricted:
bs = SetupRestrictedBodyStates(state->GetStateId(), actor);
break;
case kBT_Flyer:
bs = SetupFlyerBodyStates(state->GetStateId(), actor);
break;
case kBT_Pitchable:
bs = SetupPitchableFlyerBodyStates(state->GetStateId(), actor);
break;
case kBT_WallWalker:
bs = SetupWallWalkerBodyStates(state->GetStateId(), actor);
break;
case kBT_NewFlyer:
bs = SetupNewFlyerBodyStates(state->GetStateId(), actor);
break;
case kBT_RestrictedFlyer:
bs = SetupRestrictedFlyerBodyStates(state->GetStateId(), actor);
break;
default:
bs = SetupRestrictedBodyStates(state->GetStateId(), actor);
break;
}
if (bs)
x0_stateMap.insert(rstl::pair< int, CBodyState* >(state->GetStateId(), bs));
}
x1c_additiveStates.reserve(4);
x1c_additiveStates.push_back(rstl::pair< int, rstl::auto_ptr< CAdditiveBodyState > >(
pas::kAS_AdditiveIdle, new CABSIdle()));
x1c_additiveStates.push_back(
rstl::pair< int, rstl::auto_ptr< CAdditiveBodyState > >(pas::kAS_AdditiveAim, new CABSAim()));
x1c_additiveStates.push_back(rstl::pair< int, rstl::auto_ptr< CAdditiveBodyState > >(
pas::kAS_AdditiveIdle, new CABSFlinch()));
x1c_additiveStates.push_back(rstl::pair< int, rstl::auto_ptr< CAdditiveBodyState > >(
pas::kAS_AdditiveReaction, new CABSReaction()));
}
CBodyStateInfo::~CBodyStateInfo() {
for (rstl::map< int, CBodyState* >::const_iterator it = x0_stateMap.begin();
it != x0_stateMap.end(); ++it) {
delete it->second;
}
}
void CBodyStateInfo::SetState(pas::EAnimationState s) {
rstl::map< int, CBodyState* >::const_iterator search = x0_stateMap.find(s);
if (search != x0_stateMap.end()) {
x14_state = s;
}
}
const CBodyState* CBodyStateInfo::GetCurrentState() const {
rstl::map< int, CBodyState* >::const_iterator search = x0_stateMap.find(x14_state);
// if (search == x0_stateMap.end())
// return nullptr;
return search->second;
}
CBodyState* CBodyStateInfo::GetCurrentState() {
rstl::map< int, CBodyState* >::const_iterator search = x0_stateMap.find(x14_state);
// if (search == x0_stateMap.end())
// return nullptr;
return search->second;
}
bool CBodyStateInfo::ApplyHeadTracking() const {
if (x14_state != pas::kAS_Invalid)
return GetCurrentState()->ApplyHeadTracking();
return false;
}
void CBodyStateInfo::SetAdditiveState(pas::EAnimationState s) {
for (int i = 0; i < x1c_additiveStates.size(); ++i) {
if (s == x1c_additiveStates[i].first) {
x2c_additiveState = s;
return;
}
}
}
CAdditiveBodyState* CBodyStateInfo::GetCurrentAdditiveState() {
CAdditiveBodyState* result = nullptr;
for (int i = 0; i < x1c_additiveStates.size(); ++i) {
const rstl::pair< int, rstl::auto_ptr< CAdditiveBodyState > >& it = x1c_additiveStates[i];
if (x2c_additiveState == x1c_additiveStates[i].first) {
result = x1c_additiveStates[i].second.get();
break;
}
}
return result;
}
float CBodyStateInfo::GetMaxSpeed() const {
float ret = GetLocomotionSpeed(pas::kLA_Run);
if (close_enough(ret, 0.f)) {
for (int i = 0; i <= pas::kLA_StrafeDown; ++i) {
float tmp = GetLocomotionSpeed(pas::ELocomotionAnim(i));
if (tmp > ret)
ret = tmp;
}
}
return ret;
}
float CBodyStateInfo::GetLocomotionSpeed(pas::ELocomotionAnim anim) const {
rstl::map< int, CBodyState* >::const_iterator search = x0_stateMap.find(pas::kAS_Locomotion);
if (search != x0_stateMap.end() && search->second && x18_bodyController) {
const CBSLocomotion& bs = static_cast< const CBSLocomotion& >(*search->second);
return bs.GetLocomotionSpeed(x18_bodyController->GetLocomotionType(), anim);
}
return 0.f;
}
CBodyState* CBodyStateInfo::SetupBiPedalBodyStates(int stateId, CActor& actor) {
switch (stateId) {
// case pas::kAS_Fall:
// return new CBSFall();
// case pas::kAS_Getup:
// return new CBSGetup();
// case pas::kAS_LieOnGround:
// return new CBSLieOnGround(actor);
// case pas::kAS_Step:
// return new CBSStep();
// case pas::kAS_Death:
// return new CBSDie();
// case pas::kAS_Locomotion:
// return new CBSBiPedLocomotion(actor);
// case pas::kAS_KnockBack:
// return new CBSKnockBack();
// case pas::kAS_MeleeAttack:
// return new CBSAttack();
// case pas::kAS_ProjectileAttack:
// return new CBSProjectileAttack();
// case pas::kAS_LoopAttack:
// return new CBSLoopAttack();
// case pas::kAS_Turn:
// return new CBSTurn();
// case pas::kAS_LoopReaction:
// return new CBSLoopReaction();
// case pas::kAS_GroundHit:
// return new CBSGroundHit();
// case pas::kAS_Generate:
// return new CBSGenerate();
// case pas::kAS_Jump:
// return new CBSJump();
// case pas::kAS_Hurled:
// return new CBSHurled();
case pas::kAS_Slide:
return new CBSSlide();
// case pas::kAS_Taunt:
// return new CBSTaunt();
// case pas::kAS_Scripted:
// return new CBSScripted();
// case pas::kAS_Cover:
// return new CBSCover();
// case pas::kAS_WallHang:
// return new CBSWallHang();
default:
return nullptr;
}
}
CBodyState* CBodyStateInfo::SetupRestrictedBodyStates(int stateId, CActor& actor) {
return nullptr;
}
CBodyState* CBodyStateInfo::SetupFlyerBodyStates(int stateId, CActor& actor) { return nullptr; }
CBodyState* CBodyStateInfo::SetupPitchableFlyerBodyStates(int, CActor&) { return nullptr; }
CBodyState* CBodyStateInfo::SetupWallWalkerBodyStates(int stateId, CActor& actor) {
return nullptr;
}
CBodyState* CBodyStateInfo::SetupNewFlyerBodyStates(int stateId, CActor& actor) { return nullptr; }
CBodyState* CBodyStateInfo::SetupRestrictedFlyerBodyStates(int stateId, CActor& actor) {
return nullptr;
}