mirror of
https://github.com/OpenMW/openmw.git
synced 2025-03-03 16:09:39 +00:00
Stop continuous VFX when the effect is no longer active.
This commit is contained in:
parent
9b0e82a37f
commit
a6e2f43b75
9 changed files with 85 additions and 40 deletions
|
@ -23,6 +23,8 @@ namespace MWGui
|
||||||
|
|
||||||
void SpellIcons::updateWidgets(MyGUI::Widget *parent, bool adjustSize)
|
void SpellIcons::updateWidgets(MyGUI::Widget *parent, bool adjustSize)
|
||||||
{
|
{
|
||||||
|
// TODO: Tracking add/remove/expire would be better than force updating every frame
|
||||||
|
|
||||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||||
const MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);
|
const MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);
|
||||||
|
|
||||||
|
|
|
@ -252,7 +252,7 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().find (magicEffect->mHit);
|
const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().find (magicEffect->mHit);
|
||||||
bool loop = magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx;
|
bool loop = magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx;
|
||||||
MWBase::Environment::get().getWorld()->getAnimation(actor)->addEffect("meshes\\" + castStatic->mModel, loop, "");
|
MWBase::Environment::get().getWorld()->getAnimation(actor)->addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
first = false;
|
first = false;
|
||||||
|
|
|
@ -378,7 +378,6 @@ namespace MWMechanics
|
||||||
iter->second->update(duration);
|
iter->second->update(duration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Actors::restoreDynamicStats()
|
void Actors::restoreDynamicStats()
|
||||||
{
|
{
|
||||||
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
||||||
|
|
|
@ -513,7 +513,7 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun
|
||||||
effect = store.get<ESM::MagicEffect>().find(effectentry.mEffectID);
|
effect = store.get<ESM::MagicEffect>().find(effectentry.mEffectID);
|
||||||
|
|
||||||
const ESM::Static* castStatic = store.get<ESM::Static>().find (effect->mCasting);
|
const ESM::Static* castStatic = store.get<ESM::Static>().find (effect->mCasting);
|
||||||
mAnimation->addEffect("meshes\\" + castStatic->mModel);
|
mAnimation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex);
|
||||||
|
|
||||||
switch(effectentry.mRange)
|
switch(effectentry.mRange)
|
||||||
{
|
{
|
||||||
|
@ -716,6 +716,8 @@ void CharacterController::update(float duration)
|
||||||
const MWWorld::Class &cls = MWWorld::Class::get(mPtr);
|
const MWWorld::Class &cls = MWWorld::Class::get(mPtr);
|
||||||
Ogre::Vector3 movement(0.0f);
|
Ogre::Vector3 movement(0.0f);
|
||||||
|
|
||||||
|
updateContinuousVfx();
|
||||||
|
|
||||||
if(!cls.isActor())
|
if(!cls.isActor())
|
||||||
{
|
{
|
||||||
if(mAnimQueue.size() > 1)
|
if(mAnimQueue.size() > 1)
|
||||||
|
@ -1103,4 +1105,20 @@ void CharacterController::resurrect()
|
||||||
mDeathState = CharState_None;
|
mDeathState = CharState_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CharacterController::updateContinuousVfx()
|
||||||
|
{
|
||||||
|
// Keeping track of when to stop a continuous VFX seems to be very difficult to do inside the spells code,
|
||||||
|
// as it's extremely spread out (ActiveSpells, Spells, InventoryStore effects, etc...) so we do it here.
|
||||||
|
|
||||||
|
// Stop any effects that are no longer active
|
||||||
|
std::vector<int> effects;
|
||||||
|
mAnimation->getLoopingEffects(effects);
|
||||||
|
|
||||||
|
for (std::vector<int>::iterator it = effects.begin(); it != effects.end(); ++it)
|
||||||
|
{
|
||||||
|
if (mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(MWMechanics::EffectKey(*it)).mMagnitude <= 0)
|
||||||
|
mAnimation->removeEffect(*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,6 +173,8 @@ class CharacterController
|
||||||
|
|
||||||
bool updateNpcState(bool onground, bool inwater, bool isrunning, bool sneak);
|
bool updateNpcState(bool onground, bool inwater, bool isrunning, bool sneak);
|
||||||
|
|
||||||
|
void updateContinuousVfx();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim);
|
CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim);
|
||||||
virtual ~CharacterController();
|
virtual ~CharacterController();
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "../mwworld/ptr.hpp"
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
struct Spell;
|
struct Spell;
|
||||||
|
|
|
@ -928,37 +928,7 @@ Ogre::Vector3 Animation::runAnimation(float duration)
|
||||||
mSkelBase->getAllAnimationStates()->_notifyDirty();
|
mSkelBase->getAllAnimationStates()->_notifyDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateEffects(duration);
|
||||||
for (std::vector<EffectParams>::iterator it = mEffects.begin(); it != mEffects.end(); )
|
|
||||||
{
|
|
||||||
NifOgre::ObjectList& objects = it->mObjects;
|
|
||||||
for(size_t i = 0; i < objects.mControllers.size() ;i++)
|
|
||||||
{
|
|
||||||
static_cast<EffectAnimationValue*> (objects.mControllers[i].getSource().get())->addTime(duration);
|
|
||||||
|
|
||||||
objects.mControllers[i].update();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (objects.mControllers[0].getSource()->getValue() >= objects.mMaxControllerLength)
|
|
||||||
{
|
|
||||||
if (it->mLoop)
|
|
||||||
{
|
|
||||||
// Start from the beginning again; carry over the remainder
|
|
||||||
float remainder = objects.mControllers[0].getSource()->getValue() - objects.mMaxControllerLength;
|
|
||||||
for(size_t i = 0; i < objects.mControllers.size() ;i++)
|
|
||||||
{
|
|
||||||
static_cast<EffectAnimationValue*> (objects.mControllers[i].getSource().get())->resetTime(remainder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
destroyObjectList(mInsert->getCreator(), it->mObjects);
|
|
||||||
it = mEffects.erase(it);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
|
|
||||||
return movement;
|
return movement;
|
||||||
}
|
}
|
||||||
|
@ -1024,7 +994,7 @@ void Animation::detachObjectFromBone(Ogre::MovableObject *obj)
|
||||||
mSkelBase->detachObjectFromBone(obj);
|
mSkelBase->detachObjectFromBone(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animation::addEffect(const std::string &model, bool loop, const std::string &bonename)
|
void Animation::addEffect(const std::string &model, int effectId, bool loop, const std::string &bonename)
|
||||||
{
|
{
|
||||||
// Early out if we already have this effect
|
// Early out if we already have this effect
|
||||||
for (std::vector<EffectParams>::iterator it = mEffects.begin(); it != mEffects.end(); ++it)
|
for (std::vector<EffectParams>::iterator it = mEffects.begin(); it != mEffects.end(); ++it)
|
||||||
|
@ -1035,6 +1005,7 @@ void Animation::addEffect(const std::string &model, bool loop, const std::string
|
||||||
params.mModelName = model;
|
params.mModelName = model;
|
||||||
params.mObjects = NifOgre::Loader::createObjects(mInsert, model);
|
params.mObjects = NifOgre::Loader::createObjects(mInsert, model);
|
||||||
params.mLoop = loop;
|
params.mLoop = loop;
|
||||||
|
params.mEffectId = effectId;
|
||||||
|
|
||||||
for(size_t i = 0;i < params.mObjects.mControllers.size();i++)
|
for(size_t i = 0;i < params.mObjects.mControllers.size();i++)
|
||||||
{
|
{
|
||||||
|
@ -1044,11 +1015,11 @@ void Animation::addEffect(const std::string &model, bool loop, const std::string
|
||||||
mEffects.push_back(params);
|
mEffects.push_back(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animation::removeEffect(const std::string &model)
|
void Animation::removeEffect(int effectId)
|
||||||
{
|
{
|
||||||
for (std::vector<EffectParams>::iterator it = mEffects.begin(); it != mEffects.end(); ++it)
|
for (std::vector<EffectParams>::iterator it = mEffects.begin(); it != mEffects.end(); ++it)
|
||||||
{
|
{
|
||||||
if (it->mModelName == model)
|
if (it->mEffectId == effectId)
|
||||||
{
|
{
|
||||||
destroyObjectList(mInsert->getCreator(), it->mObjects);
|
destroyObjectList(mInsert->getCreator(), it->mObjects);
|
||||||
mEffects.erase(it);
|
mEffects.erase(it);
|
||||||
|
@ -1057,6 +1028,49 @@ void Animation::removeEffect(const std::string &model)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Animation::getLoopingEffects(std::vector<int> &out)
|
||||||
|
{
|
||||||
|
for (std::vector<EffectParams>::iterator it = mEffects.begin(); it != mEffects.end(); ++it)
|
||||||
|
{
|
||||||
|
if (it->mLoop)
|
||||||
|
out.push_back(it->mEffectId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Animation::updateEffects(float duration)
|
||||||
|
{
|
||||||
|
for (std::vector<EffectParams>::iterator it = mEffects.begin(); it != mEffects.end(); )
|
||||||
|
{
|
||||||
|
NifOgre::ObjectList& objects = it->mObjects;
|
||||||
|
for(size_t i = 0; i < objects.mControllers.size() ;i++)
|
||||||
|
{
|
||||||
|
static_cast<EffectAnimationValue*> (objects.mControllers[i].getSource().get())->addTime(duration);
|
||||||
|
|
||||||
|
objects.mControllers[i].update();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (objects.mControllers[0].getSource()->getValue() >= objects.mMaxControllerLength)
|
||||||
|
{
|
||||||
|
if (it->mLoop)
|
||||||
|
{
|
||||||
|
// Start from the beginning again; carry over the remainder
|
||||||
|
float remainder = objects.mControllers[0].getSource()->getValue() - objects.mMaxControllerLength;
|
||||||
|
for(size_t i = 0; i < objects.mControllers.size() ;i++)
|
||||||
|
{
|
||||||
|
static_cast<EffectAnimationValue*> (objects.mControllers[i].getSource().get())->resetTime(remainder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
destroyObjectList(mInsert->getCreator(), it->mObjects);
|
||||||
|
it = mEffects.erase(it);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ObjectAnimation::ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &model)
|
ObjectAnimation::ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &model)
|
||||||
: Animation(ptr, ptr.getRefData().getBaseNode())
|
: Animation(ptr, ptr.getRefData().getBaseNode())
|
||||||
|
|
|
@ -113,6 +113,7 @@ protected:
|
||||||
{
|
{
|
||||||
std::string mModelName; // Just here so we don't add the same effect twice
|
std::string mModelName; // Just here so we don't add the same effect twice
|
||||||
NifOgre::ObjectList mObjects;
|
NifOgre::ObjectList mObjects;
|
||||||
|
int mEffectId;
|
||||||
bool mLoop;
|
bool mLoop;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -200,15 +201,20 @@ public:
|
||||||
/**
|
/**
|
||||||
* @brief Add an effect mesh attached to a bone or the insert scene node
|
* @brief Add an effect mesh attached to a bone or the insert scene node
|
||||||
* @param model
|
* @param model
|
||||||
|
* @param effectId An ID for this effect. Note that adding the same ID again won't add another effect.
|
||||||
* @param loop Loop the effect. If false, it is removed automatically after it finishes playing. If true,
|
* @param loop Loop the effect. If false, it is removed automatically after it finishes playing. If true,
|
||||||
* you need to remove it manually using removeEffect when the effect should end.
|
* you need to remove it manually using removeEffect when the effect should end.
|
||||||
* @param bonename Bone to attach to, or empty string to use the scene node instead
|
* @param bonename Bone to attach to, or empty string to use the scene node instead
|
||||||
* @note Will not add an effect twice.
|
* @note Will not add an effect twice.
|
||||||
*/
|
*/
|
||||||
void addEffect (const std::string& model, bool loop = false, const std::string& bonename = "");
|
void addEffect (const std::string& model, int effectId, bool loop = false, const std::string& bonename = "");
|
||||||
|
void removeEffect (int effectId);
|
||||||
|
void getLoopingEffects (std::vector<int>& out);
|
||||||
|
private:
|
||||||
|
void updateEffects(float duration);
|
||||||
|
|
||||||
void removeEffect (const std::string& model);
|
|
||||||
|
|
||||||
|
public:
|
||||||
void updatePtr(const MWWorld::Ptr &ptr);
|
void updatePtr(const MWWorld::Ptr &ptr);
|
||||||
|
|
||||||
bool hasAnimation(const std::string &anim);
|
bool hasAnimation(const std::string &anim);
|
||||||
|
|
|
@ -232,7 +232,9 @@ struct MagicEffect
|
||||||
SummonBear = 139,
|
SummonBear = 139,
|
||||||
SummonBonewolf = 140,
|
SummonBonewolf = 140,
|
||||||
SummonCreature04 = 141,
|
SummonCreature04 = 141,
|
||||||
SummonCreature05 = 142
|
SummonCreature05 = 142,
|
||||||
|
|
||||||
|
Length
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue