mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-04-01 20:06:41 +00:00
Use an inventory store listener for animation parts and VFX update instead of updating them directly. Slightly more flexible, reduces InventoryStore dependencies and solves a crash during character creation due to the preview doll's animation not being registered in World.
This commit is contained in:
parent
427de69b79
commit
00af6b5617
8 changed files with 131 additions and 78 deletions
|
@ -71,7 +71,7 @@ namespace MWRender
|
||||||
mNode = renderRoot->createChildSceneNode();
|
mNode = renderRoot->createChildSceneNode();
|
||||||
|
|
||||||
mAnimation = new NpcAnimation(mCharacter, mNode,
|
mAnimation = new NpcAnimation(mCharacter, mNode,
|
||||||
0, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal));
|
0, true, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal));
|
||||||
mAnimation->updateParts();
|
mAnimation->updateParts();
|
||||||
|
|
||||||
Ogre::Vector3 scale = mNode->getScale();
|
Ogre::Vector3 scale = mNode->getScale();
|
||||||
|
@ -102,7 +102,6 @@ namespace MWRender
|
||||||
{
|
{
|
||||||
if (mSceneMgr)
|
if (mSceneMgr)
|
||||||
{
|
{
|
||||||
//Ogre::TextureManager::getSingleton().remove(mName);
|
|
||||||
mSceneMgr->destroyAllCameras();
|
mSceneMgr->destroyAllCameras();
|
||||||
delete mAnimation;
|
delete mAnimation;
|
||||||
Ogre::Root::getSingleton().destroySceneManager(mSceneMgr);
|
Ogre::Root::getSingleton().destroySceneManager(mSceneMgr);
|
||||||
|
@ -114,7 +113,7 @@ namespace MWRender
|
||||||
assert(mAnimation);
|
assert(mAnimation);
|
||||||
delete mAnimation;
|
delete mAnimation;
|
||||||
mAnimation = new NpcAnimation(mCharacter, mNode,
|
mAnimation = new NpcAnimation(mCharacter, mNode,
|
||||||
0, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal));
|
0, true, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal));
|
||||||
mAnimation->updateParts();
|
mAnimation->updateParts();
|
||||||
|
|
||||||
float scale=1.f;
|
float scale=1.f;
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/mechanicsmanager.hpp"
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
|
#include "../mwbase/soundmanager.hpp"
|
||||||
|
|
||||||
#include "renderconst.hpp"
|
#include "renderconst.hpp"
|
||||||
#include "camera.hpp"
|
#include "camera.hpp"
|
||||||
|
@ -58,17 +59,19 @@ const NpcAnimation::PartBoneMap NpcAnimation::sPartList = createPartListMap();
|
||||||
|
|
||||||
NpcAnimation::~NpcAnimation()
|
NpcAnimation::~NpcAnimation()
|
||||||
{
|
{
|
||||||
|
if (!mListenerDisabled)
|
||||||
|
mPtr.getClass().getInventoryStore(mPtr).setListener(NULL);
|
||||||
|
|
||||||
Ogre::SceneManager *sceneMgr = mInsert->getCreator();
|
Ogre::SceneManager *sceneMgr = mInsert->getCreator();
|
||||||
for(size_t i = 0;i < ESM::PRT_Count;i++)
|
for(size_t i = 0;i < ESM::PRT_Count;i++)
|
||||||
destroyObjectList(sceneMgr, mObjectParts[i]);
|
destroyObjectList(sceneMgr, mObjectParts[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, int visibilityFlags, ViewMode viewMode)
|
NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, int visibilityFlags, bool disableListener, ViewMode viewMode)
|
||||||
: Animation(ptr, node),
|
: Animation(ptr, node),
|
||||||
mStateID(-1),
|
|
||||||
mVisibilityFlags(visibilityFlags),
|
mVisibilityFlags(visibilityFlags),
|
||||||
|
mListenerDisabled(disableListener),
|
||||||
mViewMode(viewMode),
|
mViewMode(viewMode),
|
||||||
mShowWeapons(false),
|
mShowWeapons(false),
|
||||||
mFirstPersonOffset(0.f, 0.f, 0.f)
|
mFirstPersonOffset(0.f, 0.f, 0.f)
|
||||||
|
@ -80,6 +83,11 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, int v
|
||||||
mPartslots[i] = -1; //each slot is empty
|
mPartslots[i] = -1; //each slot is empty
|
||||||
mPartPriorities[i] = 0;
|
mPartPriorities[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!disableListener)
|
||||||
|
mPtr.getClass().getInventoryStore(mPtr).setListener(this);
|
||||||
|
|
||||||
|
updateNpcBase();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode)
|
void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode)
|
||||||
|
@ -162,13 +170,6 @@ void NpcAnimation::updateNpcBase()
|
||||||
|
|
||||||
void NpcAnimation::updateParts()
|
void NpcAnimation::updateParts()
|
||||||
{
|
{
|
||||||
if (!mSkelBase)
|
|
||||||
{
|
|
||||||
// First update?
|
|
||||||
updateNpcBase();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const MWWorld::Class &cls = MWWorld::Class::get(mPtr);
|
const MWWorld::Class &cls = MWWorld::Class::get(mPtr);
|
||||||
MWWorld::InventoryStore &inv = cls.getInventoryStore(mPtr);
|
MWWorld::InventoryStore &inv = cls.getInventoryStore(mPtr);
|
||||||
|
|
||||||
|
@ -417,9 +418,6 @@ NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, in
|
||||||
|
|
||||||
Ogre::Vector3 NpcAnimation::runAnimation(float timepassed)
|
Ogre::Vector3 NpcAnimation::runAnimation(float timepassed)
|
||||||
{
|
{
|
||||||
if (!mSkelBase)
|
|
||||||
updateNpcBase();
|
|
||||||
|
|
||||||
Ogre::Vector3 ret = Animation::runAnimation(timepassed);
|
Ogre::Vector3 ret = Animation::runAnimation(timepassed);
|
||||||
|
|
||||||
Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton();
|
Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton();
|
||||||
|
@ -586,4 +584,32 @@ void NpcAnimation::showWeapons(bool showWeapon)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NpcAnimation::permanentEffectAdded(const ESM::MagicEffect *magicEffect, bool isNew, bool playSound)
|
||||||
|
{
|
||||||
|
// During first auto equip, we don't play any sounds.
|
||||||
|
// Basically we don't want sounds when the actor is first loaded,
|
||||||
|
// the items should appear as if they'd always been equipped.
|
||||||
|
if (playSound)
|
||||||
|
{
|
||||||
|
static const std::string schools[] = {
|
||||||
|
"alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration"
|
||||||
|
};
|
||||||
|
|
||||||
|
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||||
|
if(!magicEffect->mHitSound.empty())
|
||||||
|
sndMgr->playSound3D(mPtr, magicEffect->mHitSound, 1.0f, 1.0f);
|
||||||
|
else
|
||||||
|
sndMgr->playSound3D(mPtr, schools[magicEffect->mData.mSchool]+" hit", 1.0f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!magicEffect->mHit.empty())
|
||||||
|
{
|
||||||
|
const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().find (magicEffect->mHit);
|
||||||
|
bool loop = magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx;
|
||||||
|
// Don't play particle VFX unless the effect is new or it should be looping.
|
||||||
|
if (isNew || loop)
|
||||||
|
addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,23 +3,22 @@
|
||||||
|
|
||||||
#include "animation.hpp"
|
#include "animation.hpp"
|
||||||
|
|
||||||
#include "../mwworld/containerstore.hpp"
|
#include "../mwworld/inventorystore.hpp"
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
struct NPC;
|
struct NPC;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWWorld
|
|
||||||
{
|
|
||||||
class InventoryStore;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
{
|
{
|
||||||
|
|
||||||
class NpcAnimation : public Animation
|
class NpcAnimation : public Animation, public MWWorld::InventoryStoreListener
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
virtual void equipmentChanged() { updateParts(); }
|
||||||
|
virtual void permanentEffectAdded(const ESM::MagicEffect *magicEffect, bool isNew, bool playSound);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef std::map<ESM::PartReferenceType,std::string> PartBoneMap;
|
typedef std::map<ESM::PartReferenceType,std::string> PartBoneMap;
|
||||||
|
|
||||||
|
@ -32,7 +31,7 @@ public:
|
||||||
private:
|
private:
|
||||||
static const PartBoneMap sPartList;
|
static const PartBoneMap sPartList;
|
||||||
|
|
||||||
int mStateID;
|
bool mListenerDisabled;
|
||||||
|
|
||||||
// Bounded Parts
|
// Bounded Parts
|
||||||
NifOgre::ObjectList mObjectParts[ESM::PRT_Count];
|
NifOgre::ObjectList mObjectParts[ESM::PRT_Count];
|
||||||
|
@ -62,7 +61,17 @@ private:
|
||||||
void addPartGroup(int group, int priority, const std::vector<ESM::PartReference> &parts);
|
void addPartGroup(int group, int priority, const std::vector<ESM::PartReference> &parts);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, int visibilityFlags,
|
/**
|
||||||
|
* @param ptr
|
||||||
|
* @param node
|
||||||
|
* @param visibilityFlags
|
||||||
|
* @param disableListener Don't listen for equipment changes and magic effects. InventoryStore only supports
|
||||||
|
* one listener at a time, so you shouldn't do this if creating several NpcAnimations
|
||||||
|
* for the same Ptr, eg preview dolls for the player.
|
||||||
|
* Those need to be manually rendered anyway.
|
||||||
|
* @param viewMode
|
||||||
|
*/
|
||||||
|
NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, int visibilityFlags, bool disableListener = false,
|
||||||
ViewMode viewMode=VM_Normal);
|
ViewMode viewMode=VM_Normal);
|
||||||
virtual ~NpcAnimation();
|
virtual ~NpcAnimation();
|
||||||
|
|
||||||
|
|
|
@ -135,7 +135,10 @@ namespace MWScript
|
||||||
|
|
||||||
MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr);
|
MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr);
|
||||||
|
|
||||||
std::string itemName = "";
|
std::string itemName;
|
||||||
|
for (MWWorld::ContainerStoreIterator iter(store.begin()); iter != store.end(); ++iter)
|
||||||
|
if (Misc::StringUtils::ciEqual(iter->getCellRef().mRefID, item))
|
||||||
|
itemName = iter->getClass().getName(*iter);
|
||||||
|
|
||||||
int numRemoved = store.remove(item, count, ptr);
|
int numRemoved = store.remove(item, count, ptr);
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ namespace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MWWorld::ContainerStore::ContainerStore() : mStateId (0), mCachedWeight (0), mWeightUpToDate (false) {}
|
MWWorld::ContainerStore::ContainerStore() : mCachedWeight (0), mWeightUpToDate (false) {}
|
||||||
|
|
||||||
MWWorld::ContainerStore::~ContainerStore() {}
|
MWWorld::ContainerStore::~ContainerStore() {}
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,6 @@ namespace MWWorld
|
||||||
MWWorld::CellRefList<ESM::Probe> probes;
|
MWWorld::CellRefList<ESM::Probe> probes;
|
||||||
MWWorld::CellRefList<ESM::Repair> repairs;
|
MWWorld::CellRefList<ESM::Repair> repairs;
|
||||||
MWWorld::CellRefList<ESM::Weapon> weapons;
|
MWWorld::CellRefList<ESM::Weapon> weapons;
|
||||||
int mStateId;
|
|
||||||
mutable float mCachedWeight;
|
mutable float mCachedWeight;
|
||||||
mutable bool mWeightUpToDate;
|
mutable bool mWeightUpToDate;
|
||||||
ContainerStoreIterator addImp (const Ptr& ptr);
|
ContainerStoreIterator addImp (const Ptr& ptr);
|
||||||
|
|
|
@ -9,9 +9,6 @@
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
#include "../mwbase/soundmanager.hpp"
|
|
||||||
|
|
||||||
#include "../mwrender/animation.hpp"
|
|
||||||
|
|
||||||
#include "../mwmechanics/npcstats.hpp"
|
#include "../mwmechanics/npcstats.hpp"
|
||||||
|
|
||||||
|
@ -46,6 +43,7 @@ MWWorld::InventoryStore::InventoryStore()
|
||||||
: mSelectedEnchantItem(end())
|
: mSelectedEnchantItem(end())
|
||||||
, mUpdatesEnabled (true)
|
, mUpdatesEnabled (true)
|
||||||
, mFirstAutoEquip(true)
|
, mFirstAutoEquip(true)
|
||||||
|
, mListener(NULL)
|
||||||
{
|
{
|
||||||
initSlots (mSlots);
|
initSlots (mSlots);
|
||||||
}
|
}
|
||||||
|
@ -53,6 +51,8 @@ MWWorld::InventoryStore::InventoryStore()
|
||||||
MWWorld::InventoryStore::InventoryStore (const InventoryStore& store)
|
MWWorld::InventoryStore::InventoryStore (const InventoryStore& store)
|
||||||
: ContainerStore (store)
|
: ContainerStore (store)
|
||||||
, mSelectedEnchantItem(end())
|
, mSelectedEnchantItem(end())
|
||||||
|
, mListener(NULL)
|
||||||
|
, mUpdatesEnabled(true)
|
||||||
{
|
{
|
||||||
mMagicEffects = store.mMagicEffects;
|
mMagicEffects = store.mMagicEffects;
|
||||||
mFirstAutoEquip = store.mFirstAutoEquip;
|
mFirstAutoEquip = store.mFirstAutoEquip;
|
||||||
|
@ -122,9 +122,8 @@ void MWWorld::InventoryStore::equip (int slot, const ContainerStoreIterator& ite
|
||||||
|
|
||||||
flagAsModified();
|
flagAsModified();
|
||||||
|
|
||||||
updateActorModel(actor);
|
fireEquipmentChangedEvent();
|
||||||
|
updateMagicEffects();
|
||||||
updateMagicEffects(actor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MWWorld::InventoryStore::unequipAll(const MWWorld::Ptr& actor)
|
void MWWorld::InventoryStore::unequipAll(const MWWorld::Ptr& actor)
|
||||||
|
@ -255,11 +254,10 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& npc)
|
||||||
if (changed)
|
if (changed)
|
||||||
{
|
{
|
||||||
mSlots.swap (slots_);
|
mSlots.swap (slots_);
|
||||||
updateActorModel(npc);
|
fireEquipmentChangedEvent();
|
||||||
updateMagicEffects(npc);
|
updateMagicEffects();
|
||||||
flagAsModified();
|
flagAsModified();
|
||||||
}
|
}
|
||||||
mFirstAutoEquip = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const MWMechanics::MagicEffects& MWWorld::InventoryStore::getMagicEffects() const
|
const MWMechanics::MagicEffects& MWWorld::InventoryStore::getMagicEffects() const
|
||||||
|
@ -267,12 +265,16 @@ const MWMechanics::MagicEffects& MWWorld::InventoryStore::getMagicEffects() cons
|
||||||
return mMagicEffects;
|
return mMagicEffects;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor)
|
void MWWorld::InventoryStore::updateMagicEffects()
|
||||||
{
|
{
|
||||||
// To avoid excessive updates during auto-equip
|
// To avoid excessive updates during auto-equip
|
||||||
if (!mUpdatesEnabled)
|
if (!mUpdatesEnabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Delay update until the listener is set up
|
||||||
|
if (!mListener)
|
||||||
|
return;
|
||||||
|
|
||||||
mMagicEffects = MWMechanics::MagicEffects();
|
mMagicEffects = MWMechanics::MagicEffects();
|
||||||
|
|
||||||
for (TSlots::const_iterator iter (mSlots.begin()); iter!=mSlots.end(); ++iter)
|
for (TSlots::const_iterator iter (mSlots.begin()); iter!=mSlots.end(); ++iter)
|
||||||
|
@ -296,6 +298,16 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor)
|
||||||
for (unsigned int i=0; i<random.size();++i)
|
for (unsigned int i=0; i<random.size();++i)
|
||||||
random[i] = static_cast<float> (std::rand()) / RAND_MAX;
|
random[i] = static_cast<float> (std::rand()) / RAND_MAX;
|
||||||
|
|
||||||
|
bool existed = (mPermanentMagicEffectMagnitudes.find((**iter).getCellRef().mRefID) != mPermanentMagicEffectMagnitudes.end());
|
||||||
|
if (!existed)
|
||||||
|
{
|
||||||
|
// Note that using the RefID as a key here is not entirely correct.
|
||||||
|
// Consider equipping the same item twice (e.g. a ring)
|
||||||
|
// However, permanent enchantments with a random magnitude are kind of an exploit anyway,
|
||||||
|
// so it doesn't really matter if both items will get the same magnitude. *Extreme* edge case.
|
||||||
|
mPermanentMagicEffectMagnitudes[(**iter).getCellRef().mRefID] = random;
|
||||||
|
}
|
||||||
|
|
||||||
int i=0;
|
int i=0;
|
||||||
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt (enchantment.mEffects.mList.begin());
|
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt (enchantment.mEffects.mList.begin());
|
||||||
effectIt!=enchantment.mEffects.mList.end(); ++effectIt)
|
effectIt!=enchantment.mEffects.mList.end(); ++effectIt)
|
||||||
|
@ -304,42 +316,13 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor)
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find (
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find (
|
||||||
effectIt->mEffectID);
|
effectIt->mEffectID);
|
||||||
|
|
||||||
if (mPermanentMagicEffectMagnitudes.find((**iter).getCellRef().mRefID) == mPermanentMagicEffectMagnitudes.end())
|
if (!existed)
|
||||||
{
|
{
|
||||||
// Note that using the RefID as a key here is not entirely correct.
|
|
||||||
// Consider equipping the same item twice (e.g. a ring)
|
|
||||||
// However, permanent enchantments with a random magnitude are kind of an exploit anyway,
|
|
||||||
// so it doesn't really matter if both items will get the same magnitude. *Extreme* edge case.
|
|
||||||
mPermanentMagicEffectMagnitudes[(**iter).getCellRef().mRefID] = random;
|
|
||||||
|
|
||||||
// During first auto equip, we don't play any sounds.
|
// During first auto equip, we don't play any sounds.
|
||||||
// Basically we don't want sounds when the actor is first loaded,
|
// Basically we don't want sounds when the actor is first loaded,
|
||||||
// the items should appear as if they'd always been equipped.
|
// the items should appear as if they'd always been equipped.
|
||||||
if (!mFirstAutoEquip)
|
mListener->permanentEffectAdded(magicEffect, !mFirstAutoEquip,
|
||||||
{
|
!mFirstAutoEquip && effectIt == enchantment.mEffects.mList.begin());
|
||||||
// Only the sound of the first effect plays
|
|
||||||
if (effectIt == enchantment.mEffects.mList.begin())
|
|
||||||
{
|
|
||||||
static const std::string schools[] = {
|
|
||||||
"alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration"
|
|
||||||
};
|
|
||||||
|
|
||||||
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
|
||||||
if(!magicEffect->mHitSound.empty())
|
|
||||||
sndMgr->playSound3D(actor, magicEffect->mHitSound, 1.0f, 1.0f);
|
|
||||||
else
|
|
||||||
sndMgr->playSound3D(actor, schools[magicEffect->mData.mSchool]+" hit", 1.0f, 1.0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!magicEffect->mHit.empty())
|
|
||||||
{
|
|
||||||
const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().find (magicEffect->mHit);
|
|
||||||
bool loop = magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx;
|
|
||||||
// Similar as above, we don't want particles during first autoequip either, unless they're continuous.
|
|
||||||
if (!mFirstAutoEquip || loop)
|
|
||||||
MWBase::Environment::get().getWorld()->getAnimation(actor)->addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, "");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mMagicEffects.add (*effectIt, random[i]);
|
mMagicEffects.add (*effectIt, random[i]);
|
||||||
|
@ -367,6 +350,8 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor)
|
||||||
else
|
else
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mFirstAutoEquip = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MWWorld::InventoryStore::flagAsModified()
|
void MWWorld::InventoryStore::flagAsModified()
|
||||||
|
@ -380,7 +365,7 @@ bool MWWorld::InventoryStore::stacks(const Ptr& ptr1, const Ptr& ptr2)
|
||||||
if (!canStack)
|
if (!canStack)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// don't stack if 'stack' (the item being checked against) is currently equipped.
|
// don't stack if either item is currently equipped
|
||||||
for (TSlots::const_iterator iter (mSlots.begin());
|
for (TSlots::const_iterator iter (mSlots.begin());
|
||||||
iter!=mSlots.end(); ++iter)
|
iter!=mSlots.end(); ++iter)
|
||||||
{
|
{
|
||||||
|
@ -481,8 +466,8 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipSlot(int slot, c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateActorModel(actor);
|
fireEquipmentChangedEvent();
|
||||||
updateMagicEffects(actor);
|
updateMagicEffects();
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -502,8 +487,16 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipItem(const MWWor
|
||||||
throw std::runtime_error ("attempt to unequip an item that is not currently equipped");
|
throw std::runtime_error ("attempt to unequip an item that is not currently equipped");
|
||||||
}
|
}
|
||||||
|
|
||||||
void MWWorld::InventoryStore::updateActorModel(const MWWorld::Ptr& actor)
|
void MWWorld::InventoryStore::setListener(InventoryStoreListener *listener)
|
||||||
{
|
{
|
||||||
if (mUpdatesEnabled)
|
mListener = listener;
|
||||||
MWBase::Environment::get().getWorld()->updateAnimParts(actor);
|
updateMagicEffects();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MWWorld::InventoryStore::fireEquipmentChangedEvent()
|
||||||
|
{
|
||||||
|
if (!mUpdatesEnabled)
|
||||||
|
return;
|
||||||
|
if (mListener)
|
||||||
|
mListener->equipmentChanged();
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,25 @@ namespace MWMechanics
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
|
class InventoryStoreListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Fired when items are equipped or unequipped
|
||||||
|
*/
|
||||||
|
virtual void equipmentChanged () {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param effect
|
||||||
|
* @param isNew Is this effect new (e.g. the item for it was just now manually equipped)
|
||||||
|
* or was it loaded from a savegame / initial game state? \n
|
||||||
|
* If it isn't new, non-looping VFX should not be played.
|
||||||
|
* @param playSound Play effect sound?
|
||||||
|
*/
|
||||||
|
virtual void permanentEffectAdded (const ESM::MagicEffect *magicEffect, bool isNew, bool playSound) {}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
///< \brief Variant of the ContainerStore for NPCs
|
///< \brief Variant of the ContainerStore for NPCs
|
||||||
class InventoryStore : public ContainerStore
|
class InventoryStore : public ContainerStore
|
||||||
{
|
{
|
||||||
|
@ -45,6 +64,8 @@ namespace MWWorld
|
||||||
|
|
||||||
MWMechanics::MagicEffects mMagicEffects;
|
MWMechanics::MagicEffects mMagicEffects;
|
||||||
|
|
||||||
|
InventoryStoreListener* mListener;
|
||||||
|
|
||||||
// Enables updates of magic effects and actor model whenever items are equipped or unequipped.
|
// Enables updates of magic effects and actor model whenever items are equipped or unequipped.
|
||||||
// This is disabled during autoequip to avoid excessive updates
|
// This is disabled during autoequip to avoid excessive updates
|
||||||
bool mUpdatesEnabled;
|
bool mUpdatesEnabled;
|
||||||
|
@ -67,9 +88,9 @@ namespace MWWorld
|
||||||
|
|
||||||
void initSlots (TSlots& slots_);
|
void initSlots (TSlots& slots_);
|
||||||
|
|
||||||
void updateActorModel (const Ptr& actor);
|
void updateMagicEffects();
|
||||||
|
|
||||||
void updateMagicEffects(const Ptr& actor);
|
void fireEquipmentChangedEvent();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -138,6 +159,9 @@ namespace MWWorld
|
||||||
/// @return an iterator to the item that was previously in the slot
|
/// @return an iterator to the item that was previously in the slot
|
||||||
/// (it can be re-stacked so its count may be different than when it
|
/// (it can be re-stacked so its count may be different than when it
|
||||||
/// was equipped).
|
/// was equipped).
|
||||||
|
|
||||||
|
void setListener (InventoryStoreListener* listener);
|
||||||
|
///< Set a listener for various events, see \a InventoryStoreListener
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue