1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-27 03:35:27 +00:00

Map movement animation groups with a switch

This commit is contained in:
Alexei Kotov 2022-06-12 02:25:09 +03:00
parent f47e64b0f8
commit 31d636ea20

View File

@ -105,6 +105,47 @@ MWMechanics::CharacterState runStateToWalkState (MWMechanics::CharacterState sta
return ret; return ret;
} }
// Converts a movement state to its equivalent base animation group as long as it is a movement state.
std::string movementStateToAnimGroup(MWMechanics::CharacterState state)
{
using namespace MWMechanics;
switch (state)
{
case CharState_WalkForward: return "walkforward";
case CharState_WalkBack: return "walkback";
case CharState_WalkLeft: return "walkleft";
case CharState_WalkRight: return "walkright";
case CharState_SwimWalkForward: return "swimwalkforward";
case CharState_SwimWalkBack: return "swimwalkback";
case CharState_SwimWalkLeft: return "swimwalkleft";
case CharState_SwimWalkRight: return "swimwalkright";
case CharState_RunForward: return "runforward";
case CharState_RunBack: return "runback";
case CharState_RunLeft: return "runleft";
case CharState_RunRight: return "runright";
case CharState_SwimRunForward: return "swimrunforward";
case CharState_SwimRunBack: return "swimrunback";
case CharState_SwimRunLeft: return "swimrunleft";
case CharState_SwimRunRight: return "swimrunright";
case CharState_SneakForward: return "sneakforward";
case CharState_SneakBack: return "sneakback";
case CharState_SneakLeft: return "sneakleft";
case CharState_SneakRight: return "sneakright";
case CharState_Jump: return "jump";
case CharState_TurnLeft: return "turnleft";
case CharState_TurnRight: return "turnright";
case CharState_SwimTurnLeft: return "swimturnleft";
case CharState_SwimTurnRight: return "swimturnright";
default: return {};
}
}
float getFallDamage(const MWWorld::Ptr& ptr, float fallHeight) float getFallDamage(const MWWorld::Ptr& ptr, float fallHeight)
{ {
MWBase::World *world = MWBase::Environment::get().getWorld(); MWBase::World *world = MWBase::Environment::get().getWorld();
@ -139,58 +180,6 @@ float getFallDamage(const MWWorld::Ptr& ptr, float fallHeight)
namespace MWMechanics namespace MWMechanics
{ {
struct StateInfo {
CharacterState state;
const char groupname[32];
};
static const StateInfo sMovementList[] = {
{ CharState_WalkForward, "walkforward" },
{ CharState_WalkBack, "walkback" },
{ CharState_WalkLeft, "walkleft" },
{ CharState_WalkRight, "walkright" },
{ CharState_SwimWalkForward, "swimwalkforward" },
{ CharState_SwimWalkBack, "swimwalkback" },
{ CharState_SwimWalkLeft, "swimwalkleft" },
{ CharState_SwimWalkRight, "swimwalkright" },
{ CharState_RunForward, "runforward" },
{ CharState_RunBack, "runback" },
{ CharState_RunLeft, "runleft" },
{ CharState_RunRight, "runright" },
{ CharState_SwimRunForward, "swimrunforward" },
{ CharState_SwimRunBack, "swimrunback" },
{ CharState_SwimRunLeft, "swimrunleft" },
{ CharState_SwimRunRight, "swimrunright" },
{ CharState_SneakForward, "sneakforward" },
{ CharState_SneakBack, "sneakback" },
{ CharState_SneakLeft, "sneakleft" },
{ CharState_SneakRight, "sneakright" },
{ CharState_Jump, "jump" },
{ CharState_TurnLeft, "turnleft" },
{ CharState_TurnRight, "turnright" },
{ CharState_SwimTurnLeft, "swimturnleft" },
{ CharState_SwimTurnRight, "swimturnright" },
};
static const StateInfo *sMovementListEnd = &sMovementList[sizeof(sMovementList)/sizeof(sMovementList[0])];
class FindCharState {
CharacterState state;
public:
FindCharState(CharacterState _state) : state(_state) { }
bool operator()(const StateInfo &info) const
{ return info.state == state; }
};
std::string CharacterController::chooseRandomGroup (const std::string& prefix, int* num) const std::string CharacterController::chooseRandomGroup (const std::string& prefix, int* num) const
{ {
auto& prng = MWBase::Environment::get().getWorld()->getPrng(); auto& prng = MWBase::Environment::get().getWorld()->getPrng();
@ -492,33 +481,25 @@ void CharacterController::refreshMovementAnims(const std::string& weapShortGroup
// 2. When we use a fallback animation for lower body since movement animation for given weapon is missing (e.g. for crossbows and spellcasting) // 2. When we use a fallback animation for lower body since movement animation for given weapon is missing (e.g. for crossbows and spellcasting)
bool resetIdle = (movement != CharState_None && !isTurning()); bool resetIdle = (movement != CharState_None && !isTurning());
std::string movementAnimName; std::string movementAnimName = movementStateToAnimGroup(movement);
MWRender::Animation::BlendMask movemask; MWRender::Animation::BlendMask movemask = MWRender::Animation::BlendMask_All;
const StateInfo *movestate;
movemask = MWRender::Animation::BlendMask_All; if (!movementAnimName.empty())
movestate = std::find_if(sMovementList, sMovementListEnd, FindCharState(movement));
if(movestate != sMovementListEnd)
{ {
movementAnimName = movestate->groupname;
if(!weapShortGroup.empty()) if(!weapShortGroup.empty())
{ {
std::string::size_type swimpos = movementAnimName.find("swim"); std::string::size_type swimpos = movementAnimName.find("swim");
if (swimpos == std::string::npos) if (swimpos == std::string::npos)
{ {
std::string weapMovementAnimName;
if (mWeaponType == ESM::Weapon::Spell && (movement == CharState_TurnLeft || movement == CharState_TurnRight)) // Spellcasting stance turning is a special case if (mWeaponType == ESM::Weapon::Spell && (movement == CharState_TurnLeft || movement == CharState_TurnRight)) // Spellcasting stance turning is a special case
movementAnimName = weapShortGroup + movementAnimName; weapMovementAnimName = weapShortGroup + movementAnimName;
else else
movementAnimName += weapShortGroup; weapMovementAnimName = movementAnimName + weapShortGroup;
}
if(!mAnimation->hasAnimation(movementAnimName)) if (!mAnimation->hasAnimation(weapMovementAnimName))
{
movementAnimName = movestate->groupname;
if (swimpos == std::string::npos)
{ {
movementAnimName = fallbackShortWeaponGroup(movementAnimName, &movemask); weapMovementAnimName = fallbackShortWeaponGroup(movementAnimName, &movemask);
// If we apply movement only for lower body, do not reset idle animations. // If we apply movement only for lower body, do not reset idle animations.
// For upper body there will be idle animation. // For upper body there will be idle animation.
if (movemask == MWRender::Animation::BlendMask_LowerBody && idle == CharState_None) if (movemask == MWRender::Animation::BlendMask_LowerBody && idle == CharState_None)
@ -527,6 +508,8 @@ void CharacterController::refreshMovementAnims(const std::string& weapShortGroup
if (movemask == MWRender::Animation::BlendMask_LowerBody) if (movemask == MWRender::Animation::BlendMask_LowerBody)
resetIdle = false; resetIdle = false;
} }
movementAnimName = weapMovementAnimName;
} }
} }
} }
@ -534,7 +517,7 @@ void CharacterController::refreshMovementAnims(const std::string& weapShortGroup
if(force || movement != mMovementState) if(force || movement != mMovementState)
{ {
mMovementState = movement; mMovementState = movement;
if(movestate != sMovementListEnd) if (!movementAnimName.empty())
{ {
if(!mAnimation->hasAnimation(movementAnimName)) if(!mAnimation->hasAnimation(movementAnimName))
{ {
@ -595,14 +578,12 @@ void CharacterController::refreshMovementAnims(const std::string& weapShortGroup
// For non-flying creatures, MW uses the Walk animation to calculate the animation velocity // For non-flying creatures, MW uses the Walk animation to calculate the animation velocity
// even if we are running. This must be replicated, otherwise the observed speed would differ drastically. // even if we are running. This must be replicated, otherwise the observed speed would differ drastically.
std::string anim = mCurrentMovement;
mAdjustMovementAnimSpeed = true; mAdjustMovementAnimSpeed = true;
if (mPtr.getClass().getType() == ESM::Creature::sRecordId if (mPtr.getClass().getType() == ESM::Creature::sRecordId
&& !(mPtr.get<ESM::Creature>()->mBase->mFlags & ESM::Creature::Flies)) && !(mPtr.get<ESM::Creature>()->mBase->mFlags & ESM::Creature::Flies))
{ {
CharacterState walkState = runStateToWalkState(mMovementState); CharacterState walkState = runStateToWalkState(mMovementState);
const StateInfo *stateinfo = std::find_if(sMovementList, sMovementListEnd, FindCharState(walkState)); std::string anim = movementStateToAnimGroup(walkState);
anim = stateinfo->groupname;
mMovementAnimSpeed = mAnimation->getVelocity(anim); mMovementAnimSpeed = mAnimation->getVelocity(anim);
if (mMovementAnimSpeed <= 1.0f) if (mMovementAnimSpeed <= 1.0f)
@ -618,7 +599,7 @@ void CharacterController::refreshMovementAnims(const std::string& weapShortGroup
} }
else else
{ {
mMovementAnimSpeed = mAnimation->getVelocity(anim); mMovementAnimSpeed = mAnimation->getVelocity(mCurrentMovement);
if (mMovementAnimSpeed <= 1.0f) if (mMovementAnimSpeed <= 1.0f)
{ {