From 8752f78fa45ebd1212cd2874ed0e105739369c23 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Tue, 11 Jan 2022 21:03:10 +0100 Subject: [PATCH 1/4] Remove weaponless, non-biped distinction --- CHANGELOG.md | 1 + apps/openmw/mwmechanics/character.cpp | 106 +------------------------- apps/openmw/mwmechanics/character.hpp | 1 - 3 files changed, 4 insertions(+), 104 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2baee6552..710d0bff12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ Bug #4700: Editor: Incorrect command implementation Bug #4744: Invisible particles must still be processed Bug #4949: Incorrect particle lighting + Bug #5054: Non-biped creatures don't use spellcast equip/unequip animations Bug #5088: Sky abruptly changes direction during certain weather transitions Bug #5100: Persuasion doesn't always clamp the resulting disposition Bug #5120: Scripted object spawning updates physics system diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 0f8e2ebd97..820bfad07b 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -707,9 +707,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat if (mPtr.getClass().isActor()) refreshHitRecoilAnims(idle); - std::string weap; - if (mPtr.getClass().hasInventoryStore(mPtr)) - weap = getWeaponType(mWeaponType)->mShortGroup; + std::string weap = getWeaponType(mWeaponType)->mShortGroup; refreshJumpAnims(weap, jump, idle, force); refreshMovementAnims(weap, movement, idle, force); @@ -1119,97 +1117,6 @@ void CharacterController::updateIdleStormState(bool inwater) } } -bool CharacterController::updateCreatureState() -{ - const MWWorld::Class &cls = mPtr.getClass(); - CreatureStats &stats = cls.getCreatureStats(mPtr); - - int weapType = ESM::Weapon::None; - if(stats.getDrawState() == DrawState_Weapon) - weapType = ESM::Weapon::HandToHand; - else if (stats.getDrawState() == DrawState_Spell) - weapType = ESM::Weapon::Spell; - - if (weapType != mWeaponType) - { - mWeaponType = weapType; - if (mAnimation->isPlaying(mCurrentWeapon)) - mAnimation->disable(mCurrentWeapon); - } - - if(getAttackingOrSpell()) - { - if(mUpperBodyState == UpperCharState_Nothing && mHitState == CharState_None) - { - MWBase::Environment::get().getWorld()->breakInvisibility(mPtr); - - std::string startKey = "start"; - std::string stopKey = "stop"; - if (weapType == ESM::Weapon::Spell) - { - const std::string spellid = stats.getSpells().getSelectedSpell(); - bool canCast = mCastingManualSpell || MWBase::Environment::get().getWorld()->startSpellCast(mPtr); - - if (!spellid.empty() && canCast) - { - MWMechanics::CastSpell cast(mPtr, nullptr, false, mCastingManualSpell); - cast.playSpellCastingEffects(spellid, false); - - if (!mAnimation->hasAnimation("spellcast")) - { - MWBase::Environment::get().getWorld()->castSpell(mPtr, mCastingManualSpell); // No "release" text key to use, so cast immediately - mCastingManualSpell = false; - } - else - { - const ESM::Spell *spell = MWBase::Environment::get().getWorld()->getStore().get().find(spellid); - const ESM::ENAMstruct &effectentry = spell->mEffects.mList.at(0); - - switch(effectentry.mRange) - { - case 0: mAttackType = "self"; break; - case 1: mAttackType = "touch"; break; - case 2: mAttackType = "target"; break; - } - - startKey = mAttackType + " " + startKey; - stopKey = mAttackType + " " + stopKey; - mCurrentWeapon = "spellcast"; - } - } - else - mCurrentWeapon = ""; - } - - if (weapType != ESM::Weapon::Spell || !mAnimation->hasAnimation("spellcast")) // Not all creatures have a dedicated spellcast animation - { - mCurrentWeapon = chooseRandomAttackAnimation(); - } - - if (!mCurrentWeapon.empty()) - { - mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::BlendMask_All, true, - 1, startKey, stopKey, - 0.0f, 0); - mUpperBodyState = UpperCharState_StartToMinAttack; - - mAttackStrength = std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability()); - - if (weapType == ESM::Weapon::HandToHand) - playSwishSound(0.0f); - } - } - - setAttackingOrSpell(false); - } - - bool animPlaying = mAnimation->getInfo(mCurrentWeapon); - if (!animPlaying) - mUpperBodyState = UpperCharState_Nothing; - return false; -} - bool CharacterController::updateCarriedLeftVisible(const int weaptype) const { // Shields/torches shouldn't be visible during any operation involving two hands @@ -2346,11 +2253,7 @@ void CharacterController::update(float duration) if (!mSkipAnim) { - // bipedal means hand-to-hand could be used (which is handled in updateWeaponState). an existing InventoryStore means an actual weapon could be used. - if(cls.isBipedal(mPtr) || cls.hasInventoryStore(mPtr)) - forcestateupdate = updateWeaponState(idlestate) || forcestateupdate; - else - forcestateupdate = updateCreatureState() || forcestateupdate; + forcestateupdate = updateWeaponState(idlestate) || forcestateupdate; refreshCurrentAnims(idlestate, movestate, jumpstate, forcestateupdate); updateIdleStormState(inwater); @@ -2879,10 +2782,7 @@ bool CharacterController::readyToStartAttack() const if (mHitState != CharState_None && mHitState != CharState_Block) return false; - if (mPtr.getClass().hasInventoryStore(mPtr) || mPtr.getClass().isBipedal(mPtr)) - return mUpperBodyState == UpperCharState_WeapEquiped; - else - return mUpperBodyState == UpperCharState_Nothing; + return mUpperBodyState == UpperCharState_WeapEquiped; } float CharacterController::getAttackStrength() const diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 1647980541..8c410bba25 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -206,7 +206,6 @@ class CharacterController : public MWRender::Animation::TextKeyListener void clearAnimQueue(bool clearPersistAnims = false); bool updateWeaponState(CharacterState& idle); - bool updateCreatureState(); void updateIdleStormState(bool inwater); std::string chooseRandomAttackAnimation() const; From 5ebcd37da109629041502cf630e76946b0b4c153 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 5 Feb 2022 19:07:44 +0100 Subject: [PATCH 2/4] Rename method and restore swish sounds --- apps/openmw/mwmechanics/character.cpp | 16 ++++++++++------ apps/openmw/mwmechanics/character.hpp | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 820bfad07b..815f3b30cb 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1125,7 +1125,7 @@ bool CharacterController::updateCarriedLeftVisible(const int weaptype) const return mAnimation->updateCarriedLeftVisible(weaptype); } -bool CharacterController::updateWeaponState(CharacterState& idle) +bool CharacterController::updateState(CharacterState& idle) { const MWWorld::Class &cls = mPtr.getClass(); CreatureStats &stats = cls.getCreatureStats(mPtr); @@ -1363,20 +1363,24 @@ bool CharacterController::updateWeaponState(CharacterState& idle) ESM::WeaponType::Class weapclass = getWeaponType(mWeaponType)->mWeaponClass; if(getAttackingOrSpell()) { - MWWorld::Ptr player = getPlayer(); - bool resetIdle = ammunition; if(mUpperBodyState == UpperCharState_WeapEquiped && (mHitState == CharState_None || mHitState == CharState_Block)) { MWBase::Environment::get().getWorld()->breakInvisibility(mPtr); mAttackStrength = 0; - // Randomize attacks for non-bipedal creatures with Weapon flag + // Randomize attacks for non-bipedal creatures if (mPtr.getClass().getType() == ESM::Creature::sRecordId && !mPtr.getClass().isBipedal(mPtr) && (!mAnimation->hasAnimation(mCurrentWeapon) || isRandomAttackAnimation(mCurrentWeapon))) { mCurrentWeapon = chooseRandomAttackAnimation(); + if (!mPtr.getClass().hasInventoryStore(mPtr)) + { + mAttackStrength = std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability()); + if (mWeaponType == ESM::Weapon::HandToHand) + playSwishSound(0.0f); + } } if(mWeaponType == ESM::Weapon::Spell) @@ -1384,7 +1388,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle) // Unset casting flag, otherwise pressing the mouse button down would // continue casting every frame if there is no animation setAttackingOrSpell(false); - if (mPtr == player) + if (mPtr == getPlayer()) { // For the player, set the spell we want to cast // This has to be done at the start of the casting animation, @@ -2253,7 +2257,7 @@ void CharacterController::update(float duration) if (!mSkipAnim) { - forcestateupdate = updateWeaponState(idlestate) || forcestateupdate; + forcestateupdate = updateState(idlestate) || forcestateupdate; refreshCurrentAnims(idlestate, movestate, jumpstate, forcestateupdate); updateIdleStormState(inwater); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 8c410bba25..1a0fd42fba 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -205,7 +205,7 @@ class CharacterController : public MWRender::Animation::TextKeyListener void clearAnimQueue(bool clearPersistAnims = false); - bool updateWeaponState(CharacterState& idle); + bool updateState(CharacterState& idle); void updateIdleStormState(bool inwater); std::string chooseRandomAttackAnimation() const; From 020e0b2ea5c5da26322119df8196c2a1ca5ab1c9 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sat, 5 Feb 2022 22:50:04 +0100 Subject: [PATCH 3/4] Don't allow non-bipedal actors to play hand-to-hand animations --- apps/openmw/mwmechanics/character.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 815f3b30cb..3ea09569ba 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -435,6 +435,8 @@ std::string CharacterController::getWeaponAnimation(int weaponType) const else if (isRealWeapon) weaponGroup = oneHandFallback; } + else if (weaponType == ESM::Weapon::HandToHand && !mPtr.getClass().isBipedal(mPtr)) + return "attack1"; return weaponGroup; } @@ -1293,7 +1295,7 @@ bool CharacterController::updateState(CharacterState& idle) } mWeaponType = weaptype; - mCurrentWeapon = getWeaponAnimation(mWeaponType); + mCurrentWeapon = weapgroup; if(!upSoundId.empty() && !isStillWeapon) { @@ -1376,11 +1378,7 @@ bool CharacterController::updateState(CharacterState& idle) { mCurrentWeapon = chooseRandomAttackAnimation(); if (!mPtr.getClass().hasInventoryStore(mPtr)) - { mAttackStrength = std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability()); - if (mWeaponType == ESM::Weapon::HandToHand) - playSwishSound(0.0f); - } } if(mWeaponType == ESM::Weapon::Spell) @@ -1561,7 +1559,11 @@ bool CharacterController::updateState(CharacterState& idle) weapSpeed, startKey, stopKey, 0.0f, 0); if(mAnimation->getCurrentTime(mCurrentWeapon) != -1.f) + { mUpperBodyState = UpperCharState_StartToMinAttack; + if (mWeaponType == ESM::Weapon::HandToHand && !mPtr.getClass().isBipedal(mPtr)) + playSwishSound(0.0f); + } } } From 4657060d2caef27f3a7d67fb8995c969dc8a7440 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sun, 6 Feb 2022 11:08:47 +0100 Subject: [PATCH 4/4] Extend swish and strength changes to all random attacks --- apps/openmw/mwmechanics/character.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 3ea09569ba..90a175af51 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1377,8 +1377,6 @@ bool CharacterController::updateState(CharacterState& idle) (!mAnimation->hasAnimation(mCurrentWeapon) || isRandomAttackAnimation(mCurrentWeapon))) { mCurrentWeapon = chooseRandomAttackAnimation(); - if (!mPtr.getClass().hasInventoryStore(mPtr)) - mAttackStrength = std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability()); } if(mWeaponType == ESM::Weapon::Spell) @@ -1561,8 +1559,11 @@ bool CharacterController::updateState(CharacterState& idle) if(mAnimation->getCurrentTime(mCurrentWeapon) != -1.f) { mUpperBodyState = UpperCharState_StartToMinAttack; - if (mWeaponType == ESM::Weapon::HandToHand && !mPtr.getClass().isBipedal(mPtr)) + if (isRandomAttackAnimation(mCurrentWeapon)) + { + mAttackStrength = std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability()); playSwishSound(0.0f); + } } } }