From 9723912ee094d21f7a857001eaa655929c8b4c64 Mon Sep 17 00:00:00 2001 From: Alexei Dobrohotov Date: Fri, 11 Aug 2023 01:26:34 +0300 Subject: [PATCH] Evaluate the attack early for non-biped attacks with no hit key (#7524) --- apps/openmw/mwmechanics/character.cpp | 44 ++++++++++++++++++--------- apps/openmw/mwmechanics/character.hpp | 2 ++ 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 992c048c5a..823dd0f598 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1115,8 +1115,12 @@ namespace MWMechanics } ++hitKey; } - if (!hasHitKey && mAttackStrength != -1.f) + if (!hasHitKey) { + // State update doesn't expect the start key to be the hit key, + // so we have to do this early. + prepareHit(); + if (groupname == "attack1" || groupname == "swimattack1") charClass.hit( mPtr, mAttackStrength, ESM::Weapon::AT_Chop, mAttackVictim, mAttackHitPos, mAttackSuccess); @@ -1126,7 +1130,6 @@ namespace MWMechanics else if (groupname == "attack3" || groupname == "swimattack3") charClass.hit( mPtr, mAttackStrength, ESM::Weapon::AT_Thrust, mAttackVictim, mAttackHitPos, mAttackSuccess); - mAttackStrength = -1.f; } } else if (action == "shoot attach") @@ -1219,6 +1222,25 @@ namespace MWMechanics (mAnimation->getCurrentTime(mCurrentWeapon) - minAttackTime) / (maxAttackTime - minAttackTime), 0.f, 1.f); } + void CharacterController::prepareHit() + { + if (mAttackStrength != -1.f) + return; + + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + mAttackStrength = calculateWindUp(); + if (mAttackStrength == -1.f) + mAttackStrength = std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability(prng)); + ESM::WeaponType::Class weapclass = getWeaponType(mWeaponType)->mWeaponClass; + if (weapclass != ESM::WeaponType::Ranged && weapclass != ESM::WeaponType::Thrown) + { + mAttackSuccess = mPtr.getClass().evaluateHit(mPtr, mAttackVictim, mAttackHitPos); + if (!mAttackSuccess) + mAttackStrength = 0.f; + playSwishSound(); + } + } + bool CharacterController::updateWeaponState() { const auto world = MWBase::Environment::get().getWorld(); @@ -1641,8 +1663,6 @@ namespace MWMechanics stopKey = mAttackType + " max attack"; } - mAnimation->play(mCurrentWeapon, priorityWeapon, MWRender::Animation::BlendMask_All, false, - weapSpeed, startKey, stopKey, 0.0f, 0); mUpperBodyState = UpperBodyState::AttackWindUp; // Reset the attack results when the attack starts. @@ -1651,6 +1671,9 @@ namespace MWMechanics mAttackSuccess = false; mAttackVictim = MWWorld::Ptr(); mAttackHitPos = osg::Vec3f(); + + mAnimation->play(mCurrentWeapon, priorityWeapon, MWRender::Animation::BlendMask_All, false, + weapSpeed, startKey, stopKey, 0.0f, 0); } } @@ -1688,18 +1711,11 @@ namespace MWMechanics sndMgr->playSound3D(target, ESM::RefId::stringRefId(resultSound), 1.0f, 1.0f); } } + // Evaluate the attack results and play the swish sound. + // Attack animations with no hit key do this earlier. else { - mAttackStrength = calculateWindUp(); - if (mAttackStrength == -1.f) - mAttackStrength = std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability(prng)); - if (weapclass != ESM::WeaponType::Ranged && weapclass != ESM::WeaponType::Thrown) - { - mAttackSuccess = cls.evaluateHit(mPtr, mAttackVictim, mAttackHitPos); - if (!mAttackSuccess) - mAttackStrength = 0.f; - playSwishSound(); - } + prepareHit(); } if (mWeaponType == ESM::Weapon::PickProbe || isRandomAttackAnimation(mCurrentWeapon)) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 2fc1b1de8e..5a676e3f6d 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -242,6 +242,8 @@ namespace MWMechanics bool getAttackingOrSpell() const; void setAttackingOrSpell(bool attackingOrSpell) const; + void prepareHit(); + public: CharacterController(const MWWorld::Ptr& ptr, MWRender::Animation* anim); virtual ~CharacterController();