From fa65c8981a963224ed86480bb54fe16d3ea244e1 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Sat, 11 Oct 2014 21:05:12 +0200 Subject: [PATCH] Issue #1887: Equipped items do not emit sounds Played sound items are based on parts not inserted items. Signed-off-by: Lukasz Gromanowski --- apps/openmw/mwrender/npcanimation.cpp | 165 +++++++++---------------- apps/openmw/mwrender/npcanimation.hpp | 8 +- apps/openmw/mwworld/inventorystore.cpp | 23 ++-- apps/openmw/mwworld/inventorystore.hpp | 13 +- 4 files changed, 73 insertions(+), 136 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 6e8640377..0b1dcc270 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -173,7 +173,7 @@ const NpcAnimation::PartBoneMap NpcAnimation::sPartList = createPartListMap(); NpcAnimation::~NpcAnimation() { if (!mListenerDisabled) - mPtr.getClass().getInventoryStore(mPtr).setListener(NULL, mPtr); + mInv.setListener(NULL, mPtr); } @@ -188,7 +188,8 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, int v mAlpha(1.f), mNpcType(Type_Normal), mUnequipping(false), - mFirstEquip(true) + mFirstEquip(true), + mInv(ptr.getClass().getInventoryStore(ptr)) { mNpc = mPtr.get()->mBase; @@ -202,7 +203,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, int v } if (!disableListener) - mPtr.getClass().getInventoryStore(mPtr).setListener(this, mPtr); + mInv.setListener(this, mPtr); updateNpcBase(); } @@ -299,7 +300,6 @@ void NpcAnimation::updateParts() { mAlpha = 1.f; const MWWorld::Class &cls = mPtr.getClass(); - MWWorld::InventoryStore &inv = cls.getInventoryStore(mPtr); NpcType curType = Type_Normal; if (cls.getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Vampirism).getMagnitude() > 0) @@ -338,11 +338,11 @@ void NpcAnimation::updateParts() for(size_t i = 0;i < slotlistsize && mViewMode != VM_HeadOnly;i++) { - MWWorld::ContainerStoreIterator store = inv.getSlot(slotlist[i].mSlot); + MWWorld::ContainerStoreIterator store = mInv.getSlot(slotlist[i].mSlot); removePartGroup(slotlist[i].mSlot); - if(store == inv.end()) + if(store == mInv.end()) continue; if(slotlist[i].mSlot == MWWorld::InventoryStore::Slot_Helmet) @@ -395,14 +395,14 @@ void NpcAnimation::updateParts() if(mPartPriorities[ESM::PRT_Shield] < 1) { - MWWorld::ContainerStoreIterator store = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); + MWWorld::ContainerStoreIterator store = mInv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); MWWorld::Ptr part; - if(store != inv.end() && (part=*store).getTypeName() == typeid(ESM::Light).name()) + if(store != mInv.end() && (part=*store).getTypeName() == typeid(ESM::Light).name()) { const ESM::Light *light = part.get()->mBase; addOrReplaceIndividualPart(ESM::PRT_Shield, MWWorld::InventoryStore::Slot_CarriedLeft, 1, "meshes\\"+light->mModel); - addExtraLight(mInsert->getCreator(), mObjectParts[ESM::PRT_Shield], light); + addExtraLight(mInsert->getCreator(), mObjectParts[ESM::PRT_Shield].first, light); } } @@ -606,13 +606,13 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) for(size_t i = 0;i < ESM::PRT_Count;i++) { - if (mObjectParts[i].isNull()) + if (mObjectParts[i].first.isNull()) continue; - std::vector >::iterator ctrl(mObjectParts[i]->mControllers.begin()); - for(;ctrl != mObjectParts[i]->mControllers.end();++ctrl) + std::vector >::iterator ctrl(mObjectParts[i].first->mControllers.begin()); + for(;ctrl != mObjectParts[i].first->mControllers.end();++ctrl) ctrl->update(); - Ogre::Entity *ent = mObjectParts[i]->mSkelBase; + Ogre::Entity *ent = mObjectParts[i].first->mSkelBase; if(!ent) continue; updateSkeletonInstance(baseinst, ent->getSkeleton()); ent->getAllAnimationStates()->_notifyDirty(); @@ -626,7 +626,12 @@ void NpcAnimation::removeIndividualPart(ESM::PartReferenceType type) mPartPriorities[type] = 0; mPartslots[type] = -1; - mObjectParts[type].setNull(); + mObjectParts[type].first.setNull(); + if (!mObjectParts[type].second.empty()) + { + MWBase::Environment::get().getSoundManager()->stopSound3D(mPtr, mObjectParts[type].second); + mObjectParts[type].second.clear(); + } } void NpcAnimation::reserveIndividualPart(ESM::PartReferenceType type, int group, int priority) @@ -657,13 +662,25 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g mPartslots[type] = group; mPartPriorities[type] = priority; - mObjectParts[type] = insertBoundedPart(mesh, group, sPartList.at(type), enchantedGlow, glowColor); - if(mObjectParts[type]->mSkelBase) + std::string soundId; + MWWorld::ContainerStoreIterator csi = mInv.getSlot(group < 0 ? MWWorld::InventoryStore::Slot_Helmet : group); + if (csi != mInv.end() && csi->getTypeName() == typeid(ESM::Light).name()) { - Ogre::SkeletonInstance *skel = mObjectParts[type]->mSkelBase->getSkeleton(); - if(mObjectParts[type]->mSkelBase->isParentTagPoint()) + soundId = csi->get()->mBase->mSound; + } + mObjectParts[type] = std::make_pair(insertBoundedPart(mesh, group, sPartList.at(type), enchantedGlow, glowColor), soundId); + if (!soundId.empty()) + { + MWBase::Environment::get().getSoundManager()->playSound3D(mPtr, soundId, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, + MWBase::SoundManager::Play_Loop); + } + + if(mObjectParts[type].first->mSkelBase) + { + Ogre::SkeletonInstance *skel = mObjectParts[type].first->mSkelBase->getSkeleton(); + if(mObjectParts[type].first->mSkelBase->isParentTagPoint()) { - Ogre::Node *root = mObjectParts[type]->mSkelBase->getParentNode(); + Ogre::Node *root = mObjectParts[type].first->mSkelBase->getParentNode(); if(skel->hasBone("BoneOffset")) { Ogre::Bone *offset = skel->getBone("BoneOffset"); @@ -682,8 +699,8 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g updateSkeletonInstance(mSkelBase->getSkeleton(), skel); } - std::vector >::iterator ctrl(mObjectParts[type]->mControllers.begin()); - for(;ctrl != mObjectParts[type]->mControllers.end();++ctrl) + std::vector >::iterator ctrl(mObjectParts[type].first->mControllers.begin()); + for(;ctrl != mObjectParts[type].first->mControllers.end();++ctrl) { if(ctrl->getSource().isNull()) { @@ -692,7 +709,7 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g if (type == ESM::PRT_Head) { ctrl->setSource(mHeadAnimationTime); - const NifOgre::TextKeyMap& keys = mObjectParts[type]->mTextKeys; + const NifOgre::TextKeyMap& keys = mObjectParts[type].first->mTextKeys; for (NifOgre::TextKeyMap::const_iterator it = keys.begin(); it != keys.end(); ++it) { if (Misc::StringUtils::ciEqual(it->second, "talk: start")) @@ -762,9 +779,8 @@ void NpcAnimation::showWeapons(bool showWeapon) mShowWeapons = showWeapon; if(showWeapon) { - MWWorld::InventoryStore &inv = mPtr.getClass().getInventoryStore(mPtr); - MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); - if(weapon != inv.end()) + MWWorld::ContainerStoreIterator weapon = mInv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); + if(weapon != mInv.end()) { Ogre::Vector3 glowColor = getEnchantmentColor(*weapon); std::string mesh = weapon->getClass().getModel(*weapon); @@ -775,8 +791,8 @@ void NpcAnimation::showWeapons(bool showWeapon) if (weapon->getTypeName() == typeid(ESM::Weapon).name() && weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) { - MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition); - if (ammo != inv.end() && ammo->get()->mBase->mData.mType == ESM::Weapon::Bolt) + MWWorld::ContainerStoreIterator ammo = mInv.getSlot(MWWorld::InventoryStore::Slot_Ammunition); + if (ammo != mInv.end() && ammo->get()->mBase->mData.mType == ESM::Weapon::Bolt) attachArrow(); else mAmmunition.setNull(); @@ -795,10 +811,9 @@ void NpcAnimation::showWeapons(bool showWeapon) void NpcAnimation::showCarriedLeft(bool show) { mShowCarriedLeft = show; - MWWorld::InventoryStore &inv = mPtr.getClass().getInventoryStore(mPtr); - MWWorld::ContainerStoreIterator iter = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); - if(show && iter != inv.end()) + MWWorld::ContainerStoreIterator iter = mInv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); + if(show && iter != mInv.end()) { Ogre::Vector3 glowColor = getEnchantmentColor(*iter); std::string mesh = iter->getClass().getModel(*iter); @@ -806,7 +821,7 @@ void NpcAnimation::showCarriedLeft(bool show) mesh, !iter->getClass().getEnchantment(*iter).empty(), &glowColor)) { if (iter->getTypeName() == typeid(ESM::Light).name()) - addExtraLight(mInsert->getCreator(), mObjectParts[ESM::PRT_Shield], iter->get()->mBase); + addExtraLight(mInsert->getCreator(), mObjectParts[ESM::PRT_Shield].first, iter->get()->mBase); } } else @@ -869,14 +884,14 @@ void NpcAnimation::setAlpha(float alpha) for (int i=0; imEntities.size(); ++j) + for (unsigned int j=0; jmEntities.size(); ++j) { - Ogre::Entity* ent = mObjectParts[i]->mEntities[j]; - if (ent != mObjectParts[i]->mSkelBase) - applyAlpha(alpha, ent, mObjectParts[i]); + Ogre::Entity* ent = mObjectParts[i].first->mEntities[j]; + if (ent != mObjectParts[i].first->mSkelBase) + applyAlpha(alpha, ent, mObjectParts[i].first); } } } @@ -891,9 +906,9 @@ void NpcAnimation::preRender(Ogre::Camera *camera) Animation::preRender(camera); for (int i=0; irotateBillboardNodes(camera); + mObjectParts[i].first->rotateBillboardNodes(camera); } } @@ -930,79 +945,9 @@ void NpcAnimation::applyAlpha(float alpha, Ogre::Entity *ent, NifOgre::ObjectSce } } -void NpcAnimation::equipmentChanged(const MWWorld::Ptr& actor, const MWWorld::Ptr& item, InventoryStoreListener::State state) +void NpcAnimation::equipmentChanged() { - if (actor.getRefData().getHandle() == "player") - { - std::string soundId; - - MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - - if (state == InventoryStoreListener::EQUIP - || state == InventoryStoreListener::UNEQUIP) - { - if (item.getTypeName() == typeid(ESM::Light).name()) - { - soundId = item.get()->mBase->mSound; - } - - if (!soundId.empty()) - { - if (state == InventoryStoreListener::EQUIP) - { - sndMgr->playSound3D(mPtr, soundId, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, - MWBase::SoundManager::Play_Loop); - } - else - { - sndMgr->stopSound3D(mPtr, soundId); - } - } - } - else if (state == InventoryStoreListener::AUTOEQUIP) - { - const MWWorld::Class &cls = mPtr.getClass(); - MWWorld::InventoryStore &inv = cls.getInventoryStore(mPtr); - for (int i = MWWorld::InventoryStore::Slot_Helmet; i < MWWorld::InventoryStore::Slots; ++i) - { - MWWorld::ContainerStoreIterator store = inv.getSlot(i); - - if (store != inv.end() && store->getTypeName() == typeid(ESM::Light).name()) - { - soundId = store->get()->mBase->mSound; - } - - if (!soundId.empty()) - { - sndMgr->playSound3D(mPtr, soundId, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, - MWBase::SoundManager::Play_Loop); - } - } - } - } - - /** - * AUTOEQUIP is triggered just after setting listener (ie. when game is loaded from savegame), - * but not all things are initialized yet, so we have to check it (mFirstEquip variable) - * and skip one call to updateParts() method. - * - * Also call to updateParts() method will be called only once if inventory.unequipAll() - * was called (mUnequipping == true). - */ - if (state == InventoryStoreListener::UNEQUIPALL_BEGIN) - mUnequipping = true; - else if (state == InventoryStoreListener::UNEQUIPALL_END) - mUnequipping = false; - - if (!mUnequipping && !mFirstEquip) - { - updateParts(); - } - - if (mFirstEquip && state == InventoryStoreListener::AUTOEQUIP) - { - mFirstEquip = false; - } + updateParts(); } } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 83f85abe0..827859b04 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -51,7 +51,7 @@ public: class NpcAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener { public: - virtual void equipmentChanged(const MWWorld::Ptr& actor, const MWWorld::Ptr& item, InventoryStoreListener::State state); + virtual void equipmentChanged(); virtual void permanentEffectAdded(const ESM::MagicEffect *magicEffect, bool isNew, bool playSound); public: @@ -69,7 +69,7 @@ private: bool mListenerDisabled; // Bounded Parts - NifOgre::ObjectScenePtr mObjectParts[ESM::PRT_Count]; + std::pair mObjectParts[ESM::PRT_Count]; const ESM::NPC *mNpc; std::string mHeadModel; @@ -100,6 +100,8 @@ private: bool mUnequipping; bool mFirstEquip; + MWWorld::InventoryStore& mInv; + void updateNpcBase(); NifOgre::ObjectScenePtr insertBoundedPart(const std::string &model, int group, const std::string &bonename, @@ -148,7 +150,7 @@ public: virtual void releaseArrow(); // WeaponAnimation - virtual NifOgre::ObjectScenePtr getWeapon() { return mObjectParts[ESM::PRT_Weapon]; } + virtual NifOgre::ObjectScenePtr getWeapon() { return mObjectParts[ESM::PRT_Weapon].first; } virtual void showWeapon(bool show) { showWeapons(show); } virtual void configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot); diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index db58af32a..2988066e0 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -146,18 +146,20 @@ void MWWorld::InventoryStore::equip (int slot, const ContainerStoreIterator& ite flagAsModified(); - fireEquipmentChangedEvent(actor, *iterator, InventoryStoreListener::EQUIP); + fireEquipmentChangedEvent(); updateMagicEffects(actor); } void MWWorld::InventoryStore::unequipAll(const MWWorld::Ptr& actor) { - fireEquipmentChangedEvent(actor, MWWorld::Ptr(), InventoryStoreListener::UNEQUIPALL_BEGIN); + mUpdatesEnabled = false; for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot) unequipSlot(slot, actor); - fireEquipmentChangedEvent(actor, MWWorld::Ptr(), InventoryStoreListener::UNEQUIPALL_END); + mUpdatesEnabled = true; + + fireEquipmentChangedEvent(); updateMagicEffects(actor); } @@ -203,8 +205,9 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) if (!Misc::StringUtils::ciEqual(test.getCellRef().getOwner(), actor.getCellRef().getRefId()) && (actor.getClass().getScript(actor).empty() || !actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion"))) + { continue; - + } int testSkill = test.getClass().getEquipmentSkill (test); std::pair, bool> itemsSlots = @@ -288,7 +291,7 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) if (changed) { mSlots.swap (slots_); - fireEquipmentChangedEvent(actor, MWWorld::Ptr(), InventoryStoreListener::AUTOEQUIP); + fireEquipmentChangedEvent(); updateMagicEffects(actor); flagAsModified(); } @@ -521,7 +524,7 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipSlot(int slot, c } } - fireEquipmentChangedEvent(actor, *it, InventoryStoreListener::UNEQUIP); + fireEquipmentChangedEvent(); updateMagicEffects(actor); return retval; @@ -546,18 +549,14 @@ void MWWorld::InventoryStore::setListener(InventoryStoreListener *listener, cons { mListener = listener; updateMagicEffects(actor); - if (mListener != NULL) - { - mListener->equipmentChanged(actor, MWWorld::Ptr(), InventoryStoreListener::AUTOEQUIP); - } } -void MWWorld::InventoryStore::fireEquipmentChangedEvent(const MWWorld::Ptr& actor, const MWWorld::Ptr& item, InventoryStoreListener::State state) +void MWWorld::InventoryStore::fireEquipmentChangedEvent() { if (!mUpdatesEnabled) return; if (mListener) - mListener->equipmentChanged(actor, item, state); + mListener->equipmentChanged(); } void MWWorld::InventoryStore::visitEffectSources(MWMechanics::EffectSourceVisitor &visitor) diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index fb6d2919b..41caae4e5 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -20,19 +20,10 @@ namespace MWWorld class InventoryStoreListener { public: - enum State - { - EQUIP, - AUTOEQUIP, - UNEQUIP, - UNEQUIPALL_BEGIN, - UNEQUIPALL_END - }; - /** * Fired when items are equipped or unequipped */ - virtual void equipmentChanged (const MWWorld::Ptr& /*actor*/, const MWWorld::Ptr& /*item*/, State /*state*/) {} + virtual void equipmentChanged () {} /** * @param effect @@ -118,7 +109,7 @@ namespace MWWorld void updateMagicEffects(const Ptr& actor); void updateRechargingItems(); - void fireEquipmentChangedEvent(const MWWorld::Ptr& actor, const MWWorld::Ptr& item, InventoryStoreListener::State state); + void fireEquipmentChangedEvent(); virtual int getSlot (const MWWorld::LiveCellRefBase& ref) const; ///< Return inventory slot that \a ref is in or -1 (if \a ref is not in a slot).