|
|
|
@ -2106,6 +2106,8 @@ namespace MWWorld
|
|
|
|
|
std::string selectedSpell = stats.getSpells().getSelectedSpell();
|
|
|
|
|
|
|
|
|
|
MWMechanics::CastSpell cast(actor, target);
|
|
|
|
|
if (!target.isEmpty())
|
|
|
|
|
cast.mHitPosition = Ogre::Vector3(target.getRefData().getPosition().pos);
|
|
|
|
|
|
|
|
|
|
if (!selectedSpell.empty())
|
|
|
|
|
{
|
|
|
|
@ -2240,10 +2242,11 @@ namespace MWWorld
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
MWMechanics::CastSpell cast(caster, obstacle);
|
|
|
|
|
cast.mHitPosition = pos;
|
|
|
|
|
cast.mId = it->second.mId;
|
|
|
|
|
cast.mSourceName = it->second.mSourceName;
|
|
|
|
|
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;
|
|
|
|
@ -2251,64 +2254,8 @@ namespace MWWorld
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
deleteObject(ptr);
|
|
|
|
|
mProjectiles.erase(it++);
|
|
|
|
@ -2707,4 +2654,67 @@ namespace MWWorld
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|