mirror of
				https://github.com/TES3MP/openmw-tes3mp.git
				synced 2025-11-03 23:56:47 +00:00 
			
		
		
		
	Feature #957: Handle area effects for "on touch" range
This commit is contained in:
		
							parent
							
								
									c8a9e9f7fa
								
							
						
					
					
						commit
						851a7d5014
					
				
					 9 changed files with 104 additions and 109 deletions
				
			
		| 
						 | 
					@ -466,6 +466,9 @@ namespace MWBase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            /// Spawn a blood effect for \a ptr at \a worldPosition
 | 
					            /// Spawn a blood effect for \a ptr at \a worldPosition
 | 
				
			||||||
            virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const Ogre::Vector3& worldPosition) = 0;
 | 
					            virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const Ogre::Vector3& worldPosition) = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            virtual void explodeSpell (const Ogre::Vector3& origin, const MWWorld::Ptr& object, const ESM::EffectList& effects,
 | 
				
			||||||
 | 
					                                       const MWWorld::Ptr& caster, const std::string& id, const std::string& sourceName) = 0;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -316,23 +316,9 @@ namespace MWClass
 | 
				
			||||||
                            enchantmentName);
 | 
					                            enchantmentName);
 | 
				
			||||||
                if (enchantment->mData.mType == ESM::Enchantment::WhenStrikes)
 | 
					                if (enchantment->mData.mType == ESM::Enchantment::WhenStrikes)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    // Check if we have enough charges
 | 
					                    MWMechanics::CastSpell cast(ptr, victim);
 | 
				
			||||||
                    const float enchantCost = enchantment->mData.mCost;
 | 
					                    cast.mHitPosition = hitPosition;
 | 
				
			||||||
                    int eSkill = getSkill(ptr, ESM::Skill::Enchant);
 | 
					                    cast.cast(weapon);
 | 
				
			||||||
                    const int castCost = std::max(1.f, enchantCost - (enchantCost / 100) * (eSkill - 10));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    if (weapon.getCellRef().mEnchantmentCharge == -1)
 | 
					 | 
				
			||||||
                        weapon.getCellRef().mEnchantmentCharge = enchantment->mData.mCharge;
 | 
					 | 
				
			||||||
                    if (weapon.getCellRef().mEnchantmentCharge < castCost)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicInsufficientCharge}");
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    else
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        weapon.getCellRef().mEnchantmentCharge -= castCost;
 | 
					 | 
				
			||||||
                        MWMechanics::CastSpell cast(ptr, victim);
 | 
					 | 
				
			||||||
                        cast.cast(weapon);
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -576,28 +576,12 @@ namespace MWClass
 | 
				
			||||||
                        enchantmentName);
 | 
					                        enchantmentName);
 | 
				
			||||||
            if (enchantment->mData.mType == ESM::Enchantment::WhenStrikes)
 | 
					            if (enchantment->mData.mType == ESM::Enchantment::WhenStrikes)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                // Check if we have enough charges
 | 
					                MWMechanics::CastSpell cast(ptr, victim);
 | 
				
			||||||
                const float enchantCost = enchantment->mData.mCost;
 | 
					                cast.mHitPosition = hitPosition;
 | 
				
			||||||
                int eSkill = stats.getSkill(ESM::Skill::Enchant).getModified();
 | 
					                bool success = cast.cast(weapon);
 | 
				
			||||||
                const int castCost = std::max(1.f, enchantCost - (enchantCost / 100) * (eSkill - 10));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (weapon.getCellRef().mEnchantmentCharge == -1)
 | 
					                if (ptr.getRefData().getHandle() == "player" && success)
 | 
				
			||||||
                    weapon.getCellRef().mEnchantmentCharge = enchantment->mData.mCharge;
 | 
					                    skillUsageSucceeded (ptr, ESM::Skill::Enchant, 3);
 | 
				
			||||||
                if (weapon.getCellRef().mEnchantmentCharge < castCost)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    if (ptr.getRefData().getHandle() == "player")
 | 
					 | 
				
			||||||
                        MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicInsufficientCharge}");
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                else
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    weapon.getCellRef().mEnchantmentCharge -= castCost;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    MWMechanics::CastSpell cast(ptr, victim);
 | 
					 | 
				
			||||||
                    cast.cast(weapon);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    if (ptr.getRefData().getHandle() == "player")
 | 
					 | 
				
			||||||
                        skillUsageSucceeded (ptr, ESM::Skill::Enchant, 3);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -181,11 +181,12 @@ namespace MWMechanics
 | 
				
			||||||
        : mCaster(caster)
 | 
					        : mCaster(caster)
 | 
				
			||||||
        , mTarget(target)
 | 
					        , mTarget(target)
 | 
				
			||||||
        , mStack(false)
 | 
					        , mStack(false)
 | 
				
			||||||
 | 
					        , mHitPosition(0,0,0)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void CastSpell::inflict(const MWWorld::Ptr &target, const MWWorld::Ptr &caster,
 | 
					    void CastSpell::inflict(const MWWorld::Ptr &target, const MWWorld::Ptr &caster,
 | 
				
			||||||
                            const ESM::EffectList &effects, ESM::RangeType range, bool reflected)
 | 
					                            const ESM::EffectList &effects, ESM::RangeType range, bool reflected, bool exploded)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        // If none of the effects need to apply, we can early-out
 | 
					        // If none of the effects need to apply, we can early-out
 | 
				
			||||||
        bool found = false;
 | 
					        bool found = false;
 | 
				
			||||||
| 
						 | 
					@ -375,11 +376,12 @@ namespace MWMechanics
 | 
				
			||||||
                    if (anim)
 | 
					                    if (anim)
 | 
				
			||||||
                        anim->addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, "");
 | 
					                        anim->addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, "");
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					 | 
				
			||||||
                // TODO: For Area effects, launch a growing particle effect that applies the effect to more actors as it hits them. Best managed in World.
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!exploded)
 | 
				
			||||||
 | 
					            MWBase::Environment::get().getWorld()->explodeSpell(mHitPosition, mTarget, effects, caster, mId, mSourceName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (reflectedEffects.mList.size())
 | 
					        if (reflectedEffects.mList.size())
 | 
				
			||||||
            inflict(caster, target, reflectedEffects, range, true);
 | 
					            inflict(caster, target, reflectedEffects, range, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -521,12 +523,11 @@ namespace MWMechanics
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        mStack = (enchantment->mData.mType == ESM::Enchantment::CastOnce);
 | 
					        mStack = (enchantment->mData.mType == ESM::Enchantment::CastOnce);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (enchantment->mData.mType == ESM::Enchantment::WhenUsed)
 | 
					        // Check if there's enough charge left
 | 
				
			||||||
 | 
					        if (enchantment->mData.mType == ESM::Enchantment::WhenUsed || enchantment->mData.mType == ESM::Enchantment::WhenStrikes)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            // Check if there's enough charge left
 | 
					 | 
				
			||||||
            const float enchantCost = enchantment->mData.mCost;
 | 
					            const float enchantCost = enchantment->mData.mCost;
 | 
				
			||||||
            MWMechanics::NpcStats &stats = MWWorld::Class::get(mCaster).getNpcStats(mCaster);
 | 
					            int eSkill = mCaster.getClass().getSkill(mCaster, ESM::Skill::Enchant);
 | 
				
			||||||
            int eSkill = stats.getSkill(ESM::Skill::Enchant).getModified();
 | 
					 | 
				
			||||||
            const int castCost = std::max(1.f, enchantCost - (enchantCost / 100) * (eSkill - 10));
 | 
					            const int castCost = std::max(1.f, enchantCost - (enchantCost / 100) * (eSkill - 10));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (item.getCellRef().mEnchantmentCharge == -1)
 | 
					            if (item.getCellRef().mEnchantmentCharge == -1)
 | 
				
			||||||
| 
						 | 
					@ -539,10 +540,15 @@ namespace MWMechanics
 | 
				
			||||||
                    MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicInsufficientCharge}");
 | 
					                    MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicInsufficientCharge}");
 | 
				
			||||||
                return false;
 | 
					                return false;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					 | 
				
			||||||
            // Reduce charge
 | 
					            // Reduce charge
 | 
				
			||||||
            item.getCellRef().mEnchantmentCharge -= castCost;
 | 
					            item.getCellRef().mEnchantmentCharge -= castCost;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (enchantment->mData.mType == ESM::Enchantment::WhenUsed)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (mCaster.getRefData().getHandle() == "player")
 | 
				
			||||||
 | 
					                mCaster.getClass().skillUsageSucceeded (mCaster, ESM::Skill::Enchant, 1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        if (enchantment->mData.mType == ESM::Enchantment::CastOnce)
 | 
					        if (enchantment->mData.mType == ESM::Enchantment::CastOnce)
 | 
				
			||||||
            item.getContainerStore()->remove(item, 1, mCaster);
 | 
					            item.getContainerStore()->remove(item, 1, mCaster);
 | 
				
			||||||
        else if (enchantment->mData.mType != ESM::Enchantment::WhenStrikes)
 | 
					        else if (enchantment->mData.mType != ESM::Enchantment::WhenStrikes)
 | 
				
			||||||
| 
						 | 
					@ -551,9 +557,6 @@ namespace MWMechanics
 | 
				
			||||||
                MWBase::Environment::get().getWindowManager()->setSelectedEnchantItem(item); // Set again to show the modified charge
 | 
					                MWBase::Environment::get().getWindowManager()->setSelectedEnchantItem(item); // Set again to show the modified charge
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (mCaster.getRefData().getHandle() == "player")
 | 
					 | 
				
			||||||
            mCaster.getClass().skillUsageSucceeded (mCaster, ESM::Skill::Enchant, 1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        inflict(mCaster, mCaster, enchantment->mEffects, ESM::RT_Self);
 | 
					        inflict(mCaster, mCaster, enchantment->mEffects, ESM::RT_Self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!mTarget.isEmpty())
 | 
					        if (!mTarget.isEmpty())
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,8 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "../mwworld/ptr.hpp"
 | 
					#include "../mwworld/ptr.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <OgreVector3.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace MWMechanics
 | 
					namespace MWMechanics
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    class EffectKey;
 | 
					    class EffectKey;
 | 
				
			||||||
| 
						 | 
					@ -36,6 +38,7 @@ namespace MWMechanics
 | 
				
			||||||
        bool mStack;
 | 
					        bool mStack;
 | 
				
			||||||
        std::string mId; // ID of spell, potion, item etc
 | 
					        std::string mId; // ID of spell, potion, item etc
 | 
				
			||||||
        std::string mSourceName; // Display name for spell, potion, etc
 | 
					        std::string mSourceName; // Display name for spell, potion, etc
 | 
				
			||||||
 | 
					        Ogre::Vector3 mHitPosition; // Used for spawning area orb
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public:
 | 
					    public:
 | 
				
			||||||
        CastSpell(const MWWorld::Ptr& caster, const MWWorld::Ptr& target);
 | 
					        CastSpell(const MWWorld::Ptr& caster, const MWWorld::Ptr& target);
 | 
				
			||||||
| 
						 | 
					@ -49,7 +52,7 @@ namespace MWMechanics
 | 
				
			||||||
        bool cast (const std::string& id);
 | 
					        bool cast (const std::string& id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void inflict (const MWWorld::Ptr& target, const MWWorld::Ptr& caster,
 | 
					        void inflict (const MWWorld::Ptr& target, const MWWorld::Ptr& caster,
 | 
				
			||||||
                      const ESM::EffectList& effects, ESM::RangeType range, bool reflected=false);
 | 
					                      const ESM::EffectList& effects, ESM::RangeType range, bool reflected=false, bool exploded=false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void applyInstantEffect (const MWWorld::Ptr& target, const MWWorld::Ptr& caster, const MWMechanics::EffectKey& effect, float magnitude);
 | 
					        void applyInstantEffect (const MWWorld::Ptr& target, const MWWorld::Ptr& caster, const MWMechanics::EffectKey& effect, float magnitude);
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -745,6 +745,7 @@ namespace MWScript
 | 
				
			||||||
                MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr (targetId, false);
 | 
					                MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr (targetId, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                MWMechanics::CastSpell cast(ptr, target);
 | 
					                MWMechanics::CastSpell cast(ptr, target);
 | 
				
			||||||
 | 
					                cast.mHitPosition = Ogre::Vector3(target.getRefData().getPosition().pos);
 | 
				
			||||||
                cast.cast(spell);
 | 
					                cast.cast(spell);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
| 
						 | 
					@ -761,6 +762,7 @@ namespace MWScript
 | 
				
			||||||
                runtime.pop();
 | 
					                runtime.pop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                MWMechanics::CastSpell cast(ptr, ptr);
 | 
					                MWMechanics::CastSpell cast(ptr, ptr);
 | 
				
			||||||
 | 
					                cast.mHitPosition = Ogre::Vector3(ptr.getRefData().getPosition().pos);
 | 
				
			||||||
                cast.cast(spell);
 | 
					                cast.cast(spell);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,7 @@ namespace MWWorld
 | 
				
			||||||
    void ActionTrap::executeImp(const Ptr &actor)
 | 
					    void ActionTrap::executeImp(const Ptr &actor)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        MWMechanics::CastSpell cast(mTrapSource, actor);
 | 
					        MWMechanics::CastSpell cast(mTrapSource, actor);
 | 
				
			||||||
 | 
					        cast.mHitPosition = Ogre::Vector3(actor.getRefData().getPosition().pos);
 | 
				
			||||||
        cast.cast(mSpellId);
 | 
					        cast.cast(mSpellId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        mTrapSource.getCellRef().mTrap = "";
 | 
					        mTrapSource.getCellRef().mTrap = "";
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2106,6 +2106,8 @@ namespace MWWorld
 | 
				
			||||||
        std::string selectedSpell = stats.getSpells().getSelectedSpell();
 | 
					        std::string selectedSpell = stats.getSpells().getSelectedSpell();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        MWMechanics::CastSpell cast(actor, target);
 | 
					        MWMechanics::CastSpell cast(actor, target);
 | 
				
			||||||
 | 
					        if (!target.isEmpty())
 | 
				
			||||||
 | 
					            cast.mHitPosition = Ogre::Vector3(target.getRefData().getPosition().pos);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!selectedSpell.empty())
 | 
					        if (!selectedSpell.empty())
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
| 
						 | 
					@ -2240,10 +2242,11 @@ namespace MWWorld
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    MWMechanics::CastSpell cast(caster, obstacle);
 | 
					                    MWMechanics::CastSpell cast(caster, obstacle);
 | 
				
			||||||
 | 
					                    cast.mHitPosition = pos;
 | 
				
			||||||
                    cast.mId = it->second.mId;
 | 
					                    cast.mId = it->second.mId;
 | 
				
			||||||
                    cast.mSourceName = it->second.mSourceName;
 | 
					                    cast.mSourceName = it->second.mSourceName;
 | 
				
			||||||
                    cast.mStack = it->second.mStack;
 | 
					                    cast.mStack = it->second.mStack;
 | 
				
			||||||
                    cast.inflict(obstacle, caster, it->second.mEffects, ESM::RT_Target);
 | 
					                    cast.inflict(obstacle, caster, it->second.mEffects, ESM::RT_Target, false, true);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                explode = true;
 | 
					                explode = true;
 | 
				
			||||||
| 
						 | 
					@ -2251,64 +2254,8 @@ namespace MWWorld
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (explode)
 | 
					            if (explode)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                std::map<MWWorld::Ptr, std::vector<ESM::ENAMstruct> > toApply;
 | 
					                MWWorld::Ptr caster = searchPtrViaHandle(it->second.mActorHandle);
 | 
				
			||||||
                for (std::vector<ESM::ENAMstruct>::const_iterator effectIt = it->second.mEffects.mList.begin();
 | 
					                explodeSpell(Ogre::Vector3(ptr.getRefData().getPosition().pos), ptr, it->second.mEffects, caster, it->second.mId, it->second.mSourceName);
 | 
				
			||||||
                     effectIt != it->second.mEffects.mList.end(); ++effectIt)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    const ESM::MagicEffect* effect = getStore().get<ESM::MagicEffect>().find(effectIt->mEffectID);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    if (effectIt->mArea <= 0)
 | 
					 | 
				
			||||||
                        continue; // Not an area effect
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    // Spawn the explosion orb effect
 | 
					 | 
				
			||||||
                    const ESM::Static* areaStatic;
 | 
					 | 
				
			||||||
                    if (!effect->mCasting.empty())
 | 
					 | 
				
			||||||
                        areaStatic = getStore().get<ESM::Static>().find (effect->mArea);
 | 
					 | 
				
			||||||
                    else
 | 
					 | 
				
			||||||
                        areaStatic = getStore().get<ESM::Static>().find ("VFX_DefaultArea");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    mRendering->spawnEffect("meshes\\" + areaStatic->mModel, "", Ogre::Vector3(ptr.getRefData().getPosition().pos), effectIt->mArea);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    // Play explosion sound (make sure to use NoTrack, since we will delete the projectile now)
 | 
					 | 
				
			||||||
                    static const std::string schools[] = {
 | 
					 | 
				
			||||||
                        "alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration"
 | 
					 | 
				
			||||||
                    };
 | 
					 | 
				
			||||||
                    MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
 | 
					 | 
				
			||||||
                    if(!effect->mAreaSound.empty())
 | 
					 | 
				
			||||||
                        sndMgr->playSound3D(ptr, effect->mAreaSound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoTrack);
 | 
					 | 
				
			||||||
                    else
 | 
					 | 
				
			||||||
                        sndMgr->playSound3D(ptr, schools[effect->mData.mSchool]+" area", 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoTrack);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    // Get the actors in range of the effect
 | 
					 | 
				
			||||||
                    std::vector<MWWorld::Ptr> objects;
 | 
					 | 
				
			||||||
                    MWBase::Environment::get().getMechanicsManager()->getObjectsInRange(
 | 
					 | 
				
			||||||
                                Ogre::Vector3(ptr.getRefData().getPosition().pos), feetToGameUnits(effectIt->mArea), objects);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    for (std::vector<MWWorld::Ptr>::iterator affected = objects.begin(); affected != objects.end(); ++affected)
 | 
					 | 
				
			||||||
                        toApply[*affected].push_back(*effectIt);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // Now apply the appropriate effects to each actor in range
 | 
					 | 
				
			||||||
                for (std::map<MWWorld::Ptr, std::vector<ESM::ENAMstruct> >::iterator apply = toApply.begin(); apply != toApply.end(); ++apply)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    MWWorld::Ptr caster = searchPtrViaHandle(it->second.mActorHandle);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    // Vanilla-compatible behaviour of never applying the spell to the caster
 | 
					 | 
				
			||||||
                    // (could be changed by mods later)
 | 
					 | 
				
			||||||
                    if (apply->first == caster)
 | 
					 | 
				
			||||||
                        continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    if (caster.isEmpty())
 | 
					 | 
				
			||||||
                        caster = apply->first;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    MWMechanics::CastSpell cast(caster, apply->first);
 | 
					 | 
				
			||||||
                    cast.mId = it->second.mId;
 | 
					 | 
				
			||||||
                    cast.mSourceName = it->second.mSourceName;
 | 
					 | 
				
			||||||
                    cast.mStack = it->second.mStack;
 | 
					 | 
				
			||||||
                    ESM::EffectList effects;
 | 
					 | 
				
			||||||
                    effects.mList = apply->second;
 | 
					 | 
				
			||||||
                    cast.inflict(apply->first, caster, effects, ESM::RT_Target);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                deleteObject(ptr);
 | 
					                deleteObject(ptr);
 | 
				
			||||||
                mProjectiles.erase(it++);
 | 
					                mProjectiles.erase(it++);
 | 
				
			||||||
| 
						 | 
					@ -2707,4 +2654,67 @@ namespace MWWorld
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        mRendering->spawnEffect(model, texture, worldPosition);
 | 
					        mRendering->spawnEffect(model, texture, worldPosition);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void World::explodeSpell(const Vector3 &origin, const MWWorld::Ptr& object, const ESM::EffectList &effects, const Ptr &caster,
 | 
				
			||||||
 | 
					                             const std::string& id, const std::string& sourceName)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        std::map<MWWorld::Ptr, std::vector<ESM::ENAMstruct> > toApply;
 | 
				
			||||||
 | 
					        for (std::vector<ESM::ENAMstruct>::const_iterator effectIt = effects.mList.begin();
 | 
				
			||||||
 | 
					             effectIt != effects.mList.end(); ++effectIt)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            const ESM::MagicEffect* effect = getStore().get<ESM::MagicEffect>().find(effectIt->mEffectID);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (effectIt->mArea <= 0)
 | 
				
			||||||
 | 
					                continue; // Not an area effect
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Spawn the explosion orb effect
 | 
				
			||||||
 | 
					            const ESM::Static* areaStatic;
 | 
				
			||||||
 | 
					            if (!effect->mCasting.empty())
 | 
				
			||||||
 | 
					                areaStatic = getStore().get<ESM::Static>().find (effect->mArea);
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					                areaStatic = getStore().get<ESM::Static>().find ("VFX_DefaultArea");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            mRendering->spawnEffect("meshes\\" + areaStatic->mModel, "", origin, effectIt->mArea);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Play explosion sound (make sure to use NoTrack, since we will delete the projectile now)
 | 
				
			||||||
 | 
					            static const std::string schools[] = {
 | 
				
			||||||
 | 
					                "alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration"
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
 | 
				
			||||||
 | 
					            if(!effect->mAreaSound.empty())
 | 
				
			||||||
 | 
					                sndMgr->playSound3D(object, effect->mAreaSound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoTrack);
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					                sndMgr->playSound3D(object, schools[effect->mData.mSchool]+" area", 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoTrack);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Get the actors in range of the effect
 | 
				
			||||||
 | 
					            std::vector<MWWorld::Ptr> objects;
 | 
				
			||||||
 | 
					            MWBase::Environment::get().getMechanicsManager()->getObjectsInRange(
 | 
				
			||||||
 | 
					                        origin, feetToGameUnits(effectIt->mArea), objects);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for (std::vector<MWWorld::Ptr>::iterator affected = objects.begin(); affected != objects.end(); ++affected)
 | 
				
			||||||
 | 
					                toApply[*affected].push_back(*effectIt);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Now apply the appropriate effects to each actor in range
 | 
				
			||||||
 | 
					        for (std::map<MWWorld::Ptr, std::vector<ESM::ENAMstruct> >::iterator apply = toApply.begin(); apply != toApply.end(); ++apply)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            MWWorld::Ptr source = caster;
 | 
				
			||||||
 | 
					            // Vanilla-compatible behaviour of never applying the spell to the caster
 | 
				
			||||||
 | 
					            // (could be changed by mods later)
 | 
				
			||||||
 | 
					            if (apply->first == caster)
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (source.isEmpty())
 | 
				
			||||||
 | 
					                source = apply->first;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            MWMechanics::CastSpell cast(source, apply->first);
 | 
				
			||||||
 | 
					            cast.mHitPosition = origin;
 | 
				
			||||||
 | 
					            cast.mId = id;
 | 
				
			||||||
 | 
					            cast.mSourceName = sourceName;
 | 
				
			||||||
 | 
					            cast.mStack = false;
 | 
				
			||||||
 | 
					            ESM::EffectList effects;
 | 
				
			||||||
 | 
					            effects.mList = apply->second;
 | 
				
			||||||
 | 
					            cast.inflict(apply->first, caster, effects, ESM::RT_Target, false, true);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -552,6 +552,9 @@ namespace MWWorld
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            /// Spawn a blood effect for \a ptr at \a worldPosition
 | 
					            /// Spawn a blood effect for \a ptr at \a worldPosition
 | 
				
			||||||
            virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const Ogre::Vector3& worldPosition);
 | 
					            virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const Ogre::Vector3& worldPosition);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            virtual void explodeSpell (const Ogre::Vector3& origin, const MWWorld::Ptr& object, const ESM::EffectList& effects,
 | 
				
			||||||
 | 
					                                       const MWWorld::Ptr& caster, const std::string& id, const std::string& sourceName);
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue