diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fd166c72c..c1755c42d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -167,6 +167,7 @@ Bug #5182: OnPCEquip doesn't trigger on skipped beast race attempts to equip something not equippable by beasts Bug #5186: Equipped item enchantments don't affect creatures Bug #5190: On-strike enchantments can be applied to and used with non-projectile ranged weapons + Bug #5196: Dwarven ghosts do not use idle animations Feature #1774: Handle AvoidNode Feature #2229: Improve pathfinding AI Feature #3025: Analogue gamepad movement controls diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 4b9287f31a..60da8b27dd 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -477,6 +477,11 @@ void CharacterController::refreshMovementAnims(const std::string& weapShortGroup if (movement == mMovementState && idle == mIdleState && !force) return; + // Reset idle if we actually play movement animations excepts of these cases: + // 1. When we play turning animations + // 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()); + std::string movementAnimName; MWRender::Animation::BlendMask movemask; const StateInfo *movestate; @@ -508,14 +513,9 @@ void CharacterController::refreshMovementAnims(const std::string& weapShortGroup // For upper body there will be idle animation. if (movemask == MWRender::Animation::BlendMask_LowerBody && idle == CharState_None) idle = CharState_Idle; - } - else if (idle == CharState_None) - { - // In the 1st-person mode use ground idle animations as fallback - if (mPtr == getPlayer() && MWBase::Environment::get().getWorld()->isFirstPerson()) - idle = CharState_Idle; - else - idle = CharState_IdleSwim; + + if (movemask == MWRender::Animation::BlendMask_LowerBody) + resetIdle = false; } } } @@ -538,7 +538,11 @@ void CharacterController::refreshMovementAnims(const std::string& weapShortGroup if(mAnimation->hasAnimation(weapMovementAnimName)) movementAnimName = weapMovementAnimName; else + { movementAnimName = fallbackShortWeaponGroup(movementAnimName, &movemask); + if (movemask == MWRender::Animation::BlendMask_LowerBody) + resetIdle = false; + } } } @@ -565,6 +569,10 @@ void CharacterController::refreshMovementAnims(const std::string& weapShortGroup mMovementAnimationControlled = true; mAnimation->disable(mCurrentMovement); + + if (!mAnimation->hasAnimation(movementAnimName)) + movementAnimName.clear(); + mCurrentMovement = movementAnimName; if(!mCurrentMovement.empty()) { @@ -607,7 +615,12 @@ void CharacterController::refreshMovementAnims(const std::string& weapShortGroup mAnimation->play(mCurrentMovement, Priority_Movement, movemask, false, 1.f, "start", "stop", startpoint, ~0ul, true); + + if (resetIdle) + mAnimation->disable(mCurrentIdle); } + else + mMovementState = CharState_None; } } @@ -2217,10 +2230,7 @@ void CharacterController::update(float duration, bool animationOnly) if(mAnimQueue.empty() || inwater || sneak) { - // Note: turning animations should not interrupt idle ones - if (movestate != CharState_None && !isTurning()) - idlestate = CharState_None; - else if (inwater) + if (inwater) idlestate = CharState_IdleSwim; else if (sneak && !inJump) idlestate = CharState_IdleSneak;