From d1a29300f0c6bad8671ce64fc10755c7af4e84c8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 31 Dec 2014 16:59:21 +0100 Subject: [PATCH] Handle bipedal creatures not using weapons (Fixes #2238) --- apps/openmw/mwmechanics/character.cpp | 131 +++++++++++++++----------- 1 file changed, 78 insertions(+), 53 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 23ff9afff..9f88d1573 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -296,7 +296,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat } const WeaponInfo *weap = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(mWeaponType)); - if (!mPtr.getClass().hasInventoryStore(mPtr)) + if (!mPtr.getClass().isBipedal(mPtr)) weap = sWeaponTypeListEnd; if(force || idle != mIdleState) @@ -870,10 +870,26 @@ bool CharacterController::updateWeaponState() const MWWorld::Class &cls = mPtr.getClass(); CreatureStats &stats = cls.getCreatureStats(mPtr); WeaponType weaptype = WeapType_None; - MWWorld::InventoryStore &inv = cls.getInventoryStore(mPtr); - MWWorld::ContainerStoreIterator weapon = getActiveWeapon(stats, inv, &weaptype); + if(stats.getDrawState() == DrawState_Weapon) + weaptype = WeapType_HandToHand; + else if (stats.getDrawState() == DrawState_Spell) + weaptype = WeapType_Spell; + const bool isWerewolf = cls.isNpc() && cls.getNpcStats(mPtr).isWerewolf(); + std::string soundid; + if (mPtr.getClass().hasInventoryStore(mPtr)) + { + MWWorld::InventoryStore &inv = cls.getInventoryStore(mPtr); + MWWorld::ContainerStoreIterator weapon = getActiveWeapon(stats, inv, &weaptype); + if(weapon != inv.end() && !(weaptype == WeapType_None && mWeaponType == WeapType_Spell)) + { + soundid = (weaptype == WeapType_None) ? + weapon->getClass().getDownSoundId(*weapon) : + weapon->getClass().getUpSoundId(*weapon); + } + } + bool forcestateupdate = false; if(weaptype != mWeaponType && mHitState != CharState_KnockDown) { @@ -913,16 +929,10 @@ bool CharacterController::updateWeaponState() } } - if(weapon != inv.end() && !(weaptype == WeapType_None && mWeaponType == WeapType_Spell)) + if(!soundid.empty()) { - std::string soundid = (weaptype == WeapType_None) ? - weapon->getClass().getDownSoundId(*weapon) : - weapon->getClass().getUpSoundId(*weapon); - if(!soundid.empty()) - { - MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - sndMgr->playSound3D(mPtr, soundid, 1.0f, 1.0f); - } + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); + sndMgr->playSound3D(mPtr, soundid, 1.0f, 1.0f); } mWeaponType = weaptype; @@ -945,22 +955,28 @@ bool CharacterController::updateWeaponState() sndMgr->stopSound3D(mPtr, "WolfRun"); } - bool isWeapon = (weapon != inv.end() && weapon->getTypeName() == typeid(ESM::Weapon).name()); - float weapSpeed = 1.0f; - if(isWeapon) - weapSpeed = weapon->get()->mBase->mData.mSpeed; - // Cancel attack if we no longer have ammunition bool ammunition = true; - MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition); - if (mWeaponType == WeapType_Crossbow) - ammunition = (ammo != inv.end() && ammo->get()->mBase->mData.mType == ESM::Weapon::Bolt); - else if (mWeaponType == WeapType_BowAndArrow) - ammunition = (ammo != inv.end() && ammo->get()->mBase->mData.mType == ESM::Weapon::Arrow); - if (!ammunition && mUpperBodyState > UpperCharState_WeapEquiped) + bool isWeapon = false; + float weapSpeed = 1.f; + if (mPtr.getClass().hasInventoryStore(mPtr)) { - mAnimation->disable(mCurrentWeapon); - mUpperBodyState = UpperCharState_WeapEquiped; + MWWorld::InventoryStore &inv = cls.getInventoryStore(mPtr); + MWWorld::ContainerStoreIterator weapon = getActiveWeapon(stats, inv, &weaptype); + isWeapon = (weapon != inv.end() && weapon->getTypeName() == typeid(ESM::Weapon).name()); + if(isWeapon) + weapSpeed = weapon->get()->mBase->mData.mSpeed; + + MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition); + if (mWeaponType == WeapType_Crossbow) + ammunition = (ammo != inv.end() && ammo->get()->mBase->mData.mType == ESM::Weapon::Bolt); + else if (mWeaponType == WeapType_BowAndArrow) + ammunition = (ammo != inv.end() && ammo->get()->mBase->mData.mType == ESM::Weapon::Arrow); + if (!ammunition && mUpperBodyState > UpperCharState_WeapEquiped) + { + mAnimation->disable(mCurrentWeapon); + mUpperBodyState = UpperCharState_WeapEquiped; + } } float complete; @@ -1001,15 +1017,14 @@ bool CharacterController::updateWeaponState() const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Hands"); if (mAnimation->getNode("Left Hand")) - { mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Left Hand", effect->mParticle); - mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Right Hand", effect->mParticle); - } else - { mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 L Hand", effect->mParticle); + + if (mAnimation->getNode("Right Hand")) + mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Right Hand", effect->mParticle); + else mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 R Hand", effect->mParticle); - } switch(effectentry.mRange) { @@ -1024,14 +1039,20 @@ bool CharacterController::updateWeaponState() 0.0f, 0); mUpperBodyState = UpperCharState_CastingSpell; } - if (inv.getSelectedEnchantItem() != inv.end()) + if (mPtr.getClass().hasInventoryStore(mPtr)) { - // Enchanted items cast immediately (no animation) - MWBase::Environment::get().getWorld()->castSpell(mPtr); + MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr); + if (inv.getSelectedEnchantItem() != inv.end()) + { + // Enchanted items cast immediately (no animation) + MWBase::Environment::get().getWorld()->castSpell(mPtr); + } } + } else if(mWeaponType == WeapType_PickProbe) { + MWWorld::ContainerStoreIterator weapon = mPtr.getClass().getInventoryStore(mPtr).getSlot(MWWorld::InventoryStore::Slot_CarriedRight); MWWorld::Ptr item = *weapon; // TODO: this will only work for the player, and needs to be fixed if NPCs should ever use lockpicks/probes. MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getFacedObject(); @@ -1063,7 +1084,10 @@ bool CharacterController::updateWeaponState() { if(isWeapon && mPtr.getRefData().getHandle() == "player" && Settings::Manager::getBool("best attack", "Game")) + { + MWWorld::ContainerStoreIterator weapon = mPtr.getClass().getInventoryStore(mPtr).getSlot(MWWorld::InventoryStore::Slot_CarriedRight); mAttackType = getBestAttack(weapon->get()->mBase); + } else determineAttackType(); } @@ -1283,17 +1307,21 @@ bool CharacterController::updateWeaponState() } } - MWWorld::ContainerStoreIterator torch = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); - if(torch != inv.end() && torch->getTypeName() == typeid(ESM::Light).name() - && updateCarriedLeftVisible(mWeaponType)) - + if (mPtr.getClass().hasInventoryStore(mPtr)) { - mAnimation->play("torch", Priority_Torch, MWRender::Animation::Group_LeftArm, - false, 1.0f, "start", "stop", 0.0f, (~(size_t)0), true); - } - else if (mAnimation->isPlaying("torch")) - { - mAnimation->disable("torch"); + MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr); + MWWorld::ContainerStoreIterator torch = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); + if(torch != inv.end() && torch->getTypeName() == typeid(ESM::Light).name() + && updateCarriedLeftVisible(mWeaponType)) + + { + mAnimation->play("torch", Priority_Torch, MWRender::Animation::Group_LeftArm, + false, 1.0f, "start", "stop", 0.0f, (~(size_t)0), true); + } + else if (mAnimation->isPlaying("torch")) + { + mAnimation->disable("torch"); + } } return forcestateupdate; @@ -1607,7 +1635,7 @@ void CharacterController::update(float duration) } } - if(cls.hasInventoryStore(mPtr)) + if(cls.isBipedal(mPtr)) forcestateupdate = updateWeaponState() || forcestateupdate; else forcestateupdate = updateCreatureState() || forcestateupdate; @@ -1839,15 +1867,12 @@ void CharacterController::determineAttackType() { float *move = mPtr.getClass().getMovementSettings(mPtr).mPosition; - if(mPtr.getClass().hasInventoryStore(mPtr)) - { - if (move[1] && !move[0]) // forward-backward - mAttackType = "thrust"; - else if (move[0] && !move[1]) //sideway - mAttackType = "slash"; - else - mAttackType = "chop"; - } + if (move[1] && !move[0]) // forward-backward + mAttackType = "thrust"; + else if (move[0] && !move[1]) //sideway + mAttackType = "slash"; + else + mAttackType = "chop"; } bool CharacterController::isReadyToBlock() const