From 53ef3456808476a69ee26518f08225e80fd0cd9f Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 17 Mar 2018 13:41:13 +0400 Subject: [PATCH] Update magic effect particles after building new animation (bug #2254) --- apps/openmw/mwbase/world.hpp | 2 ++ apps/openmw/mwmechanics/spellcasting.cpp | 22 ++++++++++++++++++++-- apps/openmw/mwmechanics/spellcasting.hpp | 17 +++++++++++++++++ apps/openmw/mwworld/scene.cpp | 3 +++ apps/openmw/mwworld/worldimp.cpp | 15 +++++++++++++++ apps/openmw/mwworld/worldimp.hpp | 1 + 6 files changed, 58 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 038535939..dc11189d1 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -491,6 +491,8 @@ namespace MWBase virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) = 0; + virtual void applyLoopingParticles(const MWWorld::Ptr& ptr) = 0; + virtual const std::vector& getContentFiles() const = 0; virtual void breakInvisibility (const MWWorld::Ptr& actor) = 0; diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index d864dc619..99b46db10 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -24,7 +24,6 @@ #include "../mwrender/animation.hpp" -#include "magiceffects.hpp" #include "npcstats.hpp" #include "actorutil.hpp" #include "aifollow.hpp" @@ -609,7 +608,6 @@ namespace MWMechanics std::string texture = magicEffect->mParticle; - // TODO: VFX are no longer active after saving/reloading the game bool loop = (magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx) != 0; // Note: in case of non actor, a free effect should be fine as well MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(target); @@ -1314,4 +1312,24 @@ namespace MWMechanics return MWBase::Environment::get().getWorld()->getStore().get().find(it->second)->getString(); } + void ApplyLoopingParticlesVisitor::visit (MWMechanics::EffectKey key, + const std::string& /*sourceName*/, const std::string& /*sourceId*/, int /*casterActorId*/, + float /*magnitude*/, float /*remainingTime*/, float /*totalTime*/) + { + const ESM::MagicEffect *magicEffect = + MWBase::Environment::get().getWorld()->getStore().get().find(key.mId); + + const ESM::Static* castStatic; + if (!magicEffect->mHit.empty()) + castStatic = MWBase::Environment::get().getWorld()->getStore().get().find (magicEffect->mHit); + else + castStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_DefaultHit"); + + std::string texture = magicEffect->mParticle; + + bool loop = (magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx) != 0; + MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(mActor); + if (anim && loop) + anim->addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, "", texture); + } } diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 1f5ef45bd..07c5b8477 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -6,6 +6,8 @@ #include "../mwworld/ptr.hpp" +#include "magiceffects.hpp" + namespace ESM { struct Spell; @@ -119,6 +121,21 @@ namespace MWMechanics bool applyInstantEffect (const MWWorld::Ptr& target, const MWWorld::Ptr& caster, const MWMechanics::EffectKey& effect, float magnitude); }; + class ApplyLoopingParticlesVisitor : public EffectSourceVisitor + { + private: + MWWorld::Ptr mActor; + + public: + ApplyLoopingParticlesVisitor(const MWWorld::Ptr& actor) + : mActor(actor) + { + } + + virtual void visit (MWMechanics::EffectKey key, + const std::string& /*sourceName*/, const std::string& /*sourceId*/, int /*casterActorId*/, + float /*magnitude*/, float /*remainingTime*/ = -1, float /*totalTime*/ = -1); + }; } #endif diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 0a27cf257..4b844f464 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -79,6 +79,9 @@ namespace if (ptr.getClass().isActor()) rendering.addWaterRippleEmitter(ptr); + + // Restore effect particles + MWBase::Environment::get().getWorld()->applyLoopingParticles(ptr); } void updateObjectRotation (const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics, diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 7786b6823..1ddeac903 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2244,6 +2244,8 @@ namespace MWWorld model = Misc::ResourceHelpers::correctActorModelPath(model, mResourceSystem->getVFS()); mPhysics->remove(getPlayerPtr()); mPhysics->addActor(getPlayerPtr(), model); + + applyLoopingParticles(player); } int World::canRest () @@ -2831,6 +2833,19 @@ namespace MWWorld mProjectileManager->launchMagicBolt(spellId, caster, fallbackDirection); } + void World::applyLoopingParticles(const MWWorld::Ptr& ptr) + { + const MWWorld::Class &cls = ptr.getClass(); + if (cls.isActor()) + { + MWMechanics::ApplyLoopingParticlesVisitor visitor(ptr); + cls.getCreatureStats(ptr).getActiveSpells().visitEffectSources(visitor); + cls.getCreatureStats(ptr).getSpells().visitEffectSources(visitor); + if (cls.hasInventoryStore(ptr)) + cls.getInventoryStore(ptr).visitEffectSources(visitor); + } + } + const std::vector& World::getContentFiles() const { return mContentFiles; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 02b3756d5..6c44a62e7 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -604,6 +604,7 @@ namespace MWWorld void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) override; + void applyLoopingParticles(const MWWorld::Ptr& ptr); const std::vector& getContentFiles() const override;