1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-04 21:40:03 +00:00

Reset current animation states in a consistent way

This commit is contained in:
Alexei Kotov 2022-06-13 16:14:19 +03:00
parent dd42a69ca5
commit 0a38c3ab78
2 changed files with 85 additions and 97 deletions

View File

@ -271,6 +271,52 @@ std::string CharacterController::chooseRandomGroup (const std::string& prefix, i
return prefix + std::to_string(roll); return prefix + std::to_string(roll);
} }
void CharacterController::clearStateAnimation(std::string &anim) const
{
if (anim.empty())
return;
if (mAnimation)
mAnimation->disable(anim);
anim.clear();
}
void CharacterController::resetCurrentJumpState()
{
clearStateAnimation(mCurrentJump);
mJumpState = JumpState_None;
}
void CharacterController::resetCurrentMovementState()
{
clearStateAnimation(mCurrentMovement);
mMovementState = CharState_None;
}
void CharacterController::resetCurrentIdleState()
{
clearStateAnimation(mCurrentIdle);
mIdleState = CharState_None;
}
void CharacterController::resetCurrentHitState()
{
clearStateAnimation(mCurrentHit);
mHitState = CharState_None;
}
void CharacterController::resetCurrentWeaponState()
{
clearStateAnimation(mCurrentWeapon);
mUpperBodyState = UpperCharState_Nothing;
}
void CharacterController::resetCurrentDeathState()
{
clearStateAnimation(mCurrentDeath);
mDeathState = CharState_None;
}
void CharacterController::refreshHitRecoilAnims(CharacterState& idle) void CharacterController::refreshHitRecoilAnims(CharacterState& idle)
{ {
auto& charClass = mPtr.getClass(); auto& charClass = mPtr.getClass();
@ -361,11 +407,7 @@ void CharacterController::refreshHitRecoilAnims(CharacterState& idle)
// Cancel upper body animations // Cancel upper body animations
if (isKnockedOut() || isKnockedDown()) if (isKnockedOut() || isKnockedDown())
{ {
if (!mCurrentWeapon.empty()) clearStateAnimation(mCurrentWeapon);
{
mAnimation->disable(mCurrentWeapon);
mCurrentWeapon.clear();
}
if (mUpperBodyState > UpperCharState_WeapEquiped) if (mUpperBodyState > UpperCharState_WeapEquiped)
{ {
mUpperBodyState = UpperCharState_WeapEquiped; mUpperBodyState = UpperCharState_WeapEquiped;
@ -390,12 +432,7 @@ void CharacterController::refreshJumpAnims(const std::string& weapShortGroup, Ju
if (jump == JumpState_None) if (jump == JumpState_None)
{ {
if (!mCurrentJump.empty()) resetCurrentJumpState();
{
mAnimation->disable(mCurrentJump);
mCurrentJump.clear();
}
mJumpState = JumpState_None;
return; return;
} }
@ -416,12 +453,7 @@ void CharacterController::refreshJumpAnims(const std::string& weapShortGroup, Ju
bool startAtLoop = (jump == mJumpState); bool startAtLoop = (jump == mJumpState);
mJumpState = jump; mJumpState = jump;
clearStateAnimation(mCurrentJump);
if (!mCurrentJump.empty())
{
mAnimation->disable(mCurrentJump);
mCurrentJump.clear();
}
if (!mAnimation->hasAnimation(jumpAnimName)) if (!mAnimation->hasAnimation(jumpAnimName))
return; return;
@ -539,12 +571,7 @@ void CharacterController::refreshMovementAnims(const std::string& weapShortGroup
if (movementAnimName.empty()) if (movementAnimName.empty())
{ {
if (!mCurrentMovement.empty()) resetCurrentMovementState();
{
mAnimation->disable(mCurrentMovement);
mCurrentMovement.clear();
}
mMovementState = CharState_None;
return; return;
} }
@ -592,12 +619,7 @@ void CharacterController::refreshMovementAnims(const std::string& weapShortGroup
if (!mAnimation->hasAnimation(movementAnimName)) if (!mAnimation->hasAnimation(movementAnimName))
{ {
if (!mCurrentMovement.empty()) resetCurrentMovementState();
{
mAnimation->disable(mCurrentMovement);
mCurrentMovement.clear();
}
mMovementState = CharState_None;
return; return;
} }
} }
@ -611,9 +633,7 @@ void CharacterController::refreshMovementAnims(const std::string& weapShortGroup
mMovementAnimationControlled = true; mMovementAnimationControlled = true;
if (!mCurrentMovement.empty()) clearStateAnimation(mCurrentMovement);
mAnimation->disable(mCurrentMovement);
mCurrentMovement = movementAnimName; mCurrentMovement = movementAnimName;
// Reset idle if we actually play movement animations excepts of these cases: // Reset idle if we actually play movement animations excepts of these cases:
@ -621,12 +641,7 @@ 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)
if (!isTurning() && movemask == MWRender::Animation::BlendMask_All) if (!isTurning() && movemask == MWRender::Animation::BlendMask_All)
{ {
if (!mCurrentIdle.empty()) resetCurrentIdleState();
{
mAnimation->disable(mCurrentIdle);
mCurrentIdle.clear();
}
mIdleState = CharState_None;
idle = CharState_None; idle = CharState_None;
} }
@ -695,12 +710,7 @@ void CharacterController::refreshIdleAnims(const std::string& weapShortGroup, Ch
if (idleGroup.empty()) if (idleGroup.empty())
{ {
if (mCurrentIdle.empty()) resetCurrentIdleState();
{
mAnimation->disable(mCurrentIdle);
mCurrentIdle.clear();
}
mIdleState = CharState_None;
return; return;
} }
@ -719,26 +729,17 @@ void CharacterController::refreshIdleAnims(const std::string& weapShortGroup, Ch
if (!mAnimation->hasAnimation(idleGroup)) if (!mAnimation->hasAnimation(idleGroup))
{ {
if (mCurrentIdle.empty()) resetCurrentIdleState();
{
mAnimation->disable(mCurrentIdle);
mCurrentIdle.clear();
}
mIdleState = CharState_None;
return; return;
} }
float startPoint = 0.f; float startPoint = 0.f;
if (!mCurrentIdle.empty()) // There is no need to restart anim if the new and old anims are the same.
{ // Just update the number of loops.
// There is no need to restart anim if the new and old anims are the same. if (mCurrentIdle == idleGroup)
// Just update the number of loops. mAnimation->getInfo(mCurrentIdle, &startPoint);
if (mCurrentIdle == idleGroup)
mAnimation->getInfo(mCurrentIdle, &startPoint);
mAnimation->disable(mCurrentIdle);
}
clearStateAnimation(mCurrentIdle);
mCurrentIdle = idleGroup; mCurrentIdle = idleGroup;
mAnimation->play(mCurrentIdle, priority, MWRender::Animation::BlendMask_All, false, 1.0f, "start", "stop", startPoint, numLoops, true); mAnimation->play(mCurrentIdle, priority, MWRender::Animation::BlendMask_All, false, 1.0f, "start", "stop", startPoint, numLoops, true);
} }
@ -781,21 +782,11 @@ void CharacterController::playDeath(float startpoint, CharacterState death)
// For dead actors, refreshCurrentAnims is no longer called, so we need to disable the movement state manually. // For dead actors, refreshCurrentAnims is no longer called, so we need to disable the movement state manually.
// Note that these animations wouldn't actually be visible (due to the Death animation's priority being higher). // Note that these animations wouldn't actually be visible (due to the Death animation's priority being higher).
// However, they could still trigger text keys, such as Hit events, or sounds. // However, they could still trigger text keys, such as Hit events, or sounds.
mMovementState = CharState_None; resetCurrentMovementState();
mAnimation->disable(mCurrentMovement); resetCurrentWeaponState();
mCurrentMovement.clear(); resetCurrentHitState();
mUpperBodyState = UpperCharState_Nothing; resetCurrentIdleState();
mAnimation->disable(mCurrentWeapon); resetCurrentJumpState();
mCurrentWeapon.clear();
mHitState = CharState_None;
mAnimation->disable(mCurrentHit);
mCurrentHit.clear();
mIdleState = CharState_None;
mAnimation->disable(mCurrentIdle);
mCurrentIdle.clear();
mJumpState = JumpState_None;
mAnimation->disable(mCurrentJump);
mCurrentJump.clear();
mMovementAnimationControlled = true; mMovementAnimationControlled = true;
mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::BlendMask_All, mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::BlendMask_All,
@ -1184,9 +1175,9 @@ bool CharacterController::updateState(CharacterState idle)
if (isStillWeapon && mWeaponType != weaptype && mUpperBodyState > UpperCharState_WeapEquiped) if (isStillWeapon && mWeaponType != weaptype && mUpperBodyState > UpperCharState_WeapEquiped)
{ {
forcestateupdate = true; forcestateupdate = true;
clearStateAnimation(mCurrentWeapon);
mUpperBodyState = UpperCharState_WeapEquiped; mUpperBodyState = UpperCharState_WeapEquiped;
setAttackingOrSpell(false); setAttackingOrSpell(false);
mAnimation->disable(mCurrentWeapon);
mAnimation->showWeapons(true); mAnimation->showWeapons(true);
stats.setAttackingOrSpell(false); stats.setAttackingOrSpell(false);
} }
@ -1256,7 +1247,7 @@ bool CharacterController::updateState(CharacterState idle)
if (!isStillWeapon) if (!isStillWeapon)
{ {
mAnimation->disable(mCurrentWeapon); clearStateAnimation(mCurrentWeapon);
if (weaptype != ESM::Weapon::None) if (weaptype != ESM::Weapon::None)
{ {
mAnimation->showWeapons(false); mAnimation->showWeapons(false);
@ -1304,8 +1295,7 @@ bool CharacterController::updateState(CharacterState idle)
// Make sure that we disabled unequipping animation // Make sure that we disabled unequipping animation
if (mUpperBodyState == UpperCharState_UnEquipingWeap) if (mUpperBodyState == UpperCharState_UnEquipingWeap)
{ {
mUpperBodyState = UpperCharState_Nothing; resetCurrentWeaponState();
mAnimation->disable(mCurrentWeapon);
mWeaponType = ESM::Weapon::None; mWeaponType = ESM::Weapon::None;
mCurrentWeapon = getWeaponAnimation(mWeaponType); mCurrentWeapon = getWeaponAnimation(mWeaponType);
} }
@ -1347,7 +1337,7 @@ bool CharacterController::updateState(CharacterState idle)
if (!ammunition && mUpperBodyState > UpperCharState_WeapEquiped) if (!ammunition && mUpperBodyState > UpperCharState_WeapEquiped)
{ {
mAnimation->disable(mCurrentWeapon); clearStateAnimation(mCurrentWeapon);
mUpperBodyState = UpperCharState_WeapEquiped; mUpperBodyState = UpperCharState_WeapEquiped;
} }
} }
@ -1572,8 +1562,7 @@ bool CharacterController::updateState(CharacterState idle)
idle != CharState_IdleSneak && idle != CharState_IdleSwim && idle != CharState_IdleSneak && idle != CharState_IdleSwim &&
mIdleState != CharState_IdleSneak && mIdleState != CharState_IdleSwim) mIdleState != CharState_IdleSneak && mIdleState != CharState_IdleSwim)
{ {
mAnimation->disable(mCurrentIdle); resetCurrentIdleState();
mIdleState = CharState_None;
} }
animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete); animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete);
@ -1629,7 +1618,7 @@ bool CharacterController::updateState(CharacterState idle)
if (mWeaponType > ESM::Weapon::None) if (mWeaponType > ESM::Weapon::None)
mAnimation->showWeapons(true); mAnimation->showWeapons(true);
} }
mAnimation->disable(mCurrentWeapon); clearStateAnimation(mCurrentWeapon);
} }
} }
@ -1766,7 +1755,7 @@ bool CharacterController::updateState(CharacterState idle)
} }
else if(complete >= 1.0f && isRandomAttackAnimation(mCurrentWeapon)) else if(complete >= 1.0f && isRandomAttackAnimation(mCurrentWeapon))
{ {
mAnimation->disable(mCurrentWeapon); clearStateAnimation(mCurrentWeapon);
mUpperBodyState = UpperCharState_WeapEquiped; mUpperBodyState = UpperCharState_WeapEquiped;
} }
@ -2086,7 +2075,7 @@ void CharacterController::update(float duration)
vec.z() = 0.0f; vec.z() = 0.0f;
// We should reset idle animation during landing // We should reset idle animation during landing
mAnimation->disable(mCurrentIdle); clearStateAnimation(mCurrentIdle);
float height = cls.getCreatureStats(mPtr).land(isPlayer); float height = cls.getCreatureStats(mPtr).land(isPlayer);
float healthLost = getFallDamage(mPtr, height); float healthLost = getFallDamage(mPtr, height);
@ -2429,8 +2418,7 @@ void CharacterController::unpersistAnimationState()
complete = (time - start) / (stop - start); complete = (time - start) / (stop - start);
} }
mAnimation->disable(mCurrentIdle); clearStateAnimation(mCurrentIdle);
mCurrentIdle.clear();
mIdleState = CharState_SpecialIdle; mIdleState = CharState_SpecialIdle;
bool loopfallback = (mAnimQueue.front().mGroup.compare(0,4,"idle") == 0); bool loopfallback = (mAnimQueue.front().mGroup.compare(0,4,"idle") == 0);
@ -2480,8 +2468,7 @@ bool CharacterController::playGroup(const std::string &groupname, int mode, int
{ {
clearAnimQueue(persist); clearAnimQueue(persist);
mAnimation->disable(mCurrentIdle); clearStateAnimation(mCurrentIdle);
mCurrentIdle.clear();
mIdleState = CharState_SpecialIdle; mIdleState = CharState_SpecialIdle;
bool loopfallback = (entry.mGroup.compare(0,4,"idle") == 0); bool loopfallback = (entry.mGroup.compare(0,4,"idle") == 0);
@ -2575,11 +2562,7 @@ CharacterController::KillResult CharacterController::kill()
if (mDeathState == CharState_None) if (mDeathState == CharState_None)
{ {
playRandomDeath(); playRandomDeath();
resetCurrentIdleState();
mAnimation->disable(mCurrentIdle);
mIdleState = CharState_None;
mCurrentIdle.clear();
return Result_DeathAnimStarted; return Result_DeathAnimStarted;
} }
@ -2599,10 +2582,7 @@ void CharacterController::resurrect()
if(mDeathState == CharState_None) if(mDeathState == CharState_None)
return; return;
if(mAnimation) resetCurrentDeathState();
mAnimation->disable(mCurrentDeath);
mCurrentDeath.clear();
mDeathState = CharState_None;
mWeaponType = ESM::Weapon::None; mWeaponType = ESM::Weapon::None;
} }

View File

@ -197,6 +197,14 @@ class CharacterController : public MWRender::Animation::TextKeyListener
std::string getMovementBasedAttackType() const; std::string getMovementBasedAttackType() const;
void clearStateAnimation(std::string &anim) const;
void resetCurrentJumpState();
void resetCurrentMovementState();
void resetCurrentIdleState();
void resetCurrentHitState();
void resetCurrentWeaponState();
void resetCurrentDeathState();
void refreshCurrentAnims(CharacterState idle, CharacterState movement, JumpingState jump, bool force=false); void refreshCurrentAnims(CharacterState idle, CharacterState movement, JumpingState jump, bool force=false);
void refreshHitRecoilAnims(CharacterState& idle); void refreshHitRecoilAnims(CharacterState& idle);
void refreshJumpAnims(const std::string& weapShortGroup, JumpingState jump, CharacterState& idle, bool force=false); void refreshJumpAnims(const std::string& weapShortGroup, JumpingState jump, CharacterState& idle, bool force=false);