mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-20 09:23:52 +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,26 +316,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
|
|
||||||
const float enchantCost = enchantment->mData.mCost;
|
|
||||||
int eSkill = getSkill(ptr, ESM::Skill::Enchant);
|
|
||||||
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);
|
MWMechanics::CastSpell cast(ptr, victim);
|
||||||
|
cast.mHitPosition = hitPosition;
|
||||||
cast.cast(weapon);
|
cast.cast(weapon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: do not do this if the attack is blocked
|
// TODO: do not do this if the attack is blocked
|
||||||
MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition);
|
MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition);
|
||||||
|
|
|
@ -576,30 +576,14 @@ namespace MWClass
|
||||||
enchantmentName);
|
enchantmentName);
|
||||||
if (enchantment->mData.mType == ESM::Enchantment::WhenStrikes)
|
if (enchantment->mData.mType == ESM::Enchantment::WhenStrikes)
|
||||||
{
|
{
|
||||||
// Check if we have enough charges
|
|
||||||
const float enchantCost = enchantment->mData.mCost;
|
|
||||||
int eSkill = stats.getSkill(ESM::Skill::Enchant).getModified();
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
if (ptr.getRefData().getHandle() == "player")
|
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicInsufficientCharge}");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
weapon.getCellRef().mEnchantmentCharge -= castCost;
|
|
||||||
|
|
||||||
MWMechanics::CastSpell cast(ptr, victim);
|
MWMechanics::CastSpell cast(ptr, victim);
|
||||||
cast.cast(weapon);
|
cast.mHitPosition = hitPosition;
|
||||||
|
bool success = cast.cast(weapon);
|
||||||
|
|
||||||
if (ptr.getRefData().getHandle() == "player")
|
if (ptr.getRefData().getHandle() == "player" && success)
|
||||||
skillUsageSucceeded (ptr, ESM::Skill::Enchant, 3);
|
skillUsageSucceeded (ptr, ESM::Skill::Enchant, 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: do not do this if the attack is blocked
|
// TODO: do not do this if the attack is blocked
|
||||||
if (healthdmg)
|
if (healthdmg)
|
||||||
|
|
|
@ -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,10 +376,11 @@ 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
|
// Check if there's enough charge left
|
||||||
|
if (enchantment->mData.mType == ESM::Enchantment::WhenUsed || enchantment->mData.mType == ESM::Enchantment::WhenStrikes)
|
||||||
|
{
|
||||||
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,75 +2242,20 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (explode)
|
if (explode)
|
||||||
{
|
|
||||||
std::map<MWWorld::Ptr, std::vector<ESM::ENAMstruct> > toApply;
|
|
||||||
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt = it->second.mEffects.mList.begin();
|
|
||||||
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);
|
MWWorld::Ptr caster = searchPtrViaHandle(it->second.mActorHandle);
|
||||||
|
explodeSpell(Ogre::Vector3(ptr.getRefData().getPosition().pos), ptr, it->second.mEffects, caster, it->second.mId, it->second.mSourceName);
|
||||||
// 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