mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-05-08 19:47:49 +03:00
Move explodeSpell out of World
This commit is contained in:
parent
84ec78f0d6
commit
4eafe3696c
5 changed files with 101 additions and 111 deletions
|
@ -597,10 +597,6 @@ namespace MWBase
|
||||||
|
|
||||||
virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos, float scale = 1.f, bool isMagicVFX = true) = 0;
|
virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos, float scale = 1.f, bool isMagicVFX = true) = 0;
|
||||||
|
|
||||||
virtual void explodeSpell(const osg::Vec3f& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster,
|
|
||||||
const MWWorld::Ptr& ignore, ESM::RangeType rangeType, const std::string& id,
|
|
||||||
const std::string& sourceName, const bool fromProjectile=false, int slot = 0) = 0;
|
|
||||||
|
|
||||||
virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) = 0;
|
virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) = 0;
|
||||||
|
|
||||||
/// @see MWWorld::WeatherManager::isInStorm
|
/// @see MWWorld::WeatherManager::isInStorm
|
||||||
|
|
|
@ -39,6 +39,104 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CastSpell::explodeSpell(const ESM::EffectList& effects, const MWWorld::Ptr& caster, const MWWorld::Ptr& ignore, ESM::RangeType rangeType) const
|
||||||
|
{
|
||||||
|
const auto world = MWBase::Environment::get().getWorld();
|
||||||
|
const VFS::Manager* const vfs = MWBase::Environment::get().getResourceSystem()->getVFS();
|
||||||
|
std::map<MWWorld::Ptr, std::vector<ESM::ENAMstruct> > toApply;
|
||||||
|
int index = -1;
|
||||||
|
for (const ESM::ENAMstruct& effectInfo : effects.mList)
|
||||||
|
{
|
||||||
|
++index;
|
||||||
|
const ESM::MagicEffect* effect = world->getStore().get<ESM::MagicEffect>().find(effectInfo.mEffectID);
|
||||||
|
|
||||||
|
if (effectInfo.mRange != rangeType || (effectInfo.mArea <= 0 && !ignore.isEmpty() && ignore.getClass().isActor()))
|
||||||
|
continue; // Not right range type, or not area effect and hit an actor
|
||||||
|
|
||||||
|
if (mFromProjectile && effectInfo.mArea <= 0)
|
||||||
|
continue; // Don't play explosion for projectiles with 0-area effects
|
||||||
|
|
||||||
|
if (!mFromProjectile && effectInfo.mRange == ESM::RT_Touch && !ignore.isEmpty() && !ignore.getClass().isActor() && !ignore.getClass().hasToolTip(ignore)
|
||||||
|
&& (caster.isEmpty() || caster.getClass().isActor()))
|
||||||
|
continue; // Don't play explosion for touch spells on non-activatable objects except when spell is from a projectile enchantment or ExplodeSpell
|
||||||
|
|
||||||
|
// Spawn the explosion orb effect
|
||||||
|
const ESM::Static* areaStatic;
|
||||||
|
if (!effect->mArea.empty())
|
||||||
|
areaStatic = world->getStore().get<ESM::Static>().find(effect->mArea);
|
||||||
|
else
|
||||||
|
areaStatic = world->getStore().get<ESM::Static>().find("VFX_DefaultArea");
|
||||||
|
|
||||||
|
const std::string& texture = effect->mParticle;
|
||||||
|
|
||||||
|
if (effectInfo.mArea <= 0)
|
||||||
|
{
|
||||||
|
if (effectInfo.mRange == ESM::RT_Target)
|
||||||
|
world->spawnEffect(Misc::ResourceHelpers::correctMeshPath(areaStatic->mModel, vfs), texture, mHitPosition, 1.0f);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
world->spawnEffect(Misc::ResourceHelpers::correctMeshPath(areaStatic->mModel, vfs), texture, mHitPosition, static_cast<float>(effectInfo.mArea * 2));
|
||||||
|
|
||||||
|
// 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(mHitPosition, effect->mAreaSound, 1.0f, 1.0f);
|
||||||
|
else
|
||||||
|
sndMgr->playSound3D(mHitPosition, schools[effect->mData.mSchool]+" area", 1.0f, 1.0f);
|
||||||
|
}
|
||||||
|
// Get the actors in range of the effect
|
||||||
|
std::vector<MWWorld::Ptr> objects;
|
||||||
|
static const int unitsPerFoot = ceil(Constants::UnitsPerFoot);
|
||||||
|
MWBase::Environment::get().getMechanicsManager()->getObjectsInRange(mHitPosition, static_cast<float>(effectInfo.mArea * unitsPerFoot), objects);
|
||||||
|
for (const MWWorld::Ptr& affected : objects)
|
||||||
|
{
|
||||||
|
// Ignore actors without collisions here, otherwise it will be possible to hit actors outside processing range.
|
||||||
|
if (affected.getClass().isActor() && !world->isActorCollisionEnabled(affected))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto& list = toApply[affected];
|
||||||
|
while (list.size() < static_cast<std::size_t>(index))
|
||||||
|
{
|
||||||
|
// Insert dummy effects to preserve indices
|
||||||
|
auto& dummy = list.emplace_back(effectInfo);
|
||||||
|
dummy.mRange = ESM::RT_Self;
|
||||||
|
assert(dummy.mRange != rangeType);
|
||||||
|
}
|
||||||
|
list.push_back(effectInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now apply the appropriate effects to each actor in range
|
||||||
|
for (auto& applyPair : toApply)
|
||||||
|
{
|
||||||
|
MWWorld::Ptr source = caster;
|
||||||
|
// Vanilla-compatible behaviour of never applying the spell to the caster
|
||||||
|
// (could be changed by mods later)
|
||||||
|
if (applyPair.first == caster)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (applyPair.first == ignore)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (source.isEmpty())
|
||||||
|
source = applyPair.first;
|
||||||
|
|
||||||
|
MWMechanics::CastSpell cast(source, applyPair.first);
|
||||||
|
cast.mHitPosition = mHitPosition;
|
||||||
|
cast.mId = mId;
|
||||||
|
cast.mSourceName = mSourceName;
|
||||||
|
cast.mSlot = mSlot;
|
||||||
|
ESM::EffectList effectsToApply;
|
||||||
|
effectsToApply.mList = applyPair.second;
|
||||||
|
cast.inflict(applyPair.first, caster, effectsToApply, rangeType, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CastSpell::launchMagicBolt ()
|
void CastSpell::launchMagicBolt ()
|
||||||
{
|
{
|
||||||
osg::Vec3f fallbackDirection(0, 1, 0);
|
osg::Vec3f fallbackDirection(0, 1, 0);
|
||||||
|
@ -174,7 +272,7 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!exploded)
|
if (!exploded)
|
||||||
MWBase::Environment::get().getWorld()->explodeSpell(mHitPosition, effects, caster, target, range, mId, mSourceName, mFromProjectile, mSlot);
|
explodeSpell(effects, caster, target, range);
|
||||||
|
|
||||||
if (!target.isEmpty())
|
if (!target.isEmpty())
|
||||||
{
|
{
|
||||||
|
|
|
@ -27,6 +27,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
void playSpellCastingEffects(const std::vector<ESM::ENAMstruct>& effects);
|
void playSpellCastingEffects(const std::vector<ESM::ENAMstruct>& effects);
|
||||||
|
|
||||||
|
void explodeSpell(const ESM::EffectList& effects, const MWWorld::Ptr& caster, const MWWorld::Ptr& ignore, ESM::RangeType rangeType) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
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
|
||||||
|
@ -37,7 +39,6 @@ namespace MWMechanics
|
||||||
int mSlot{0};
|
int mSlot{0};
|
||||||
ESM::ActiveSpells::EffectType mType{ESM::ActiveSpells::Type_Temporary};
|
ESM::ActiveSpells::EffectType mType{ESM::ActiveSpells::Type_Temporary};
|
||||||
|
|
||||||
public:
|
|
||||||
CastSpell(const MWWorld::Ptr& caster, const MWWorld::Ptr& target, const bool fromProjectile=false, const bool manualSpell=false);
|
CastSpell(const MWWorld::Ptr& caster, const MWWorld::Ptr& target, const bool fromProjectile=false, const bool manualSpell=false);
|
||||||
|
|
||||||
bool cast (const ESM::Spell* spell);
|
bool cast (const ESM::Spell* spell);
|
||||||
|
|
|
@ -3730,107 +3730,6 @@ namespace MWWorld
|
||||||
mRendering->spawnEffect(model, textureOverride, worldPos, scale, isMagicVFX);
|
mRendering->spawnEffect(model, textureOverride, worldPos, scale, isMagicVFX);
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::explodeSpell(const osg::Vec3f& origin, const ESM::EffectList& effects, const Ptr& caster, const Ptr& ignore, ESM::RangeType rangeType,
|
|
||||||
const std::string& id, const std::string& sourceName, const bool fromProjectile, int slot)
|
|
||||||
{
|
|
||||||
std::map<MWWorld::Ptr, std::vector<ESM::ENAMstruct> > toApply;
|
|
||||||
int index = -1;
|
|
||||||
for (const ESM::ENAMstruct& effectInfo : effects.mList)
|
|
||||||
{
|
|
||||||
++index;
|
|
||||||
const ESM::MagicEffect* effect = mStore.get<ESM::MagicEffect>().find(effectInfo.mEffectID);
|
|
||||||
|
|
||||||
if (effectInfo.mRange != rangeType || (effectInfo.mArea <= 0 && !ignore.isEmpty() && ignore.getClass().isActor()))
|
|
||||||
continue; // Not right range type, or not area effect and hit an actor
|
|
||||||
|
|
||||||
if (fromProjectile && effectInfo.mArea <= 0)
|
|
||||||
continue; // Don't play explosion for projectiles with 0-area effects
|
|
||||||
|
|
||||||
if (!fromProjectile && effectInfo.mRange == ESM::RT_Touch && !ignore.isEmpty() && !ignore.getClass().isActor() && !ignore.getClass().hasToolTip(ignore)
|
|
||||||
&& (caster.isEmpty() || caster.getClass().isActor()))
|
|
||||||
continue; // Don't play explosion for touch spells on non-activatable objects except when spell is from a projectile enchantment or ExplodeSpell
|
|
||||||
|
|
||||||
// Spawn the explosion orb effect
|
|
||||||
const ESM::Static* areaStatic;
|
|
||||||
if (!effect->mArea.empty())
|
|
||||||
areaStatic = mStore.get<ESM::Static>().find (effect->mArea);
|
|
||||||
else
|
|
||||||
areaStatic = mStore.get<ESM::Static>().find ("VFX_DefaultArea");
|
|
||||||
|
|
||||||
const std::string& texture = effect->mParticle;
|
|
||||||
|
|
||||||
if (effectInfo.mArea <= 0)
|
|
||||||
{
|
|
||||||
if (effectInfo.mRange == ESM::RT_Target)
|
|
||||||
mRendering->spawnEffect(
|
|
||||||
Misc::ResourceHelpers::correctMeshPath(areaStatic->mModel, mResourceSystem->getVFS()),
|
|
||||||
texture, origin, 1.0f);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
mRendering->spawnEffect(
|
|
||||||
Misc::ResourceHelpers::correctMeshPath(areaStatic->mModel, mResourceSystem->getVFS()),
|
|
||||||
texture, origin, static_cast<float>(effectInfo.mArea * 2));
|
|
||||||
|
|
||||||
// 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(origin, effect->mAreaSound, 1.0f, 1.0f);
|
|
||||||
else
|
|
||||||
sndMgr->playSound3D(origin, schools[effect->mData.mSchool]+" area", 1.0f, 1.0f);
|
|
||||||
}
|
|
||||||
// Get the actors in range of the effect
|
|
||||||
std::vector<MWWorld::Ptr> objects;
|
|
||||||
MWBase::Environment::get().getMechanicsManager()->getObjectsInRange(
|
|
||||||
origin, feetToGameUnits(static_cast<float>(effectInfo.mArea)), objects);
|
|
||||||
for (const Ptr& affected : objects)
|
|
||||||
{
|
|
||||||
// Ignore actors without collisions here, otherwise it will be possible to hit actors outside processing range.
|
|
||||||
if (affected.getClass().isActor() && !isActorCollisionEnabled(affected))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
auto& list = toApply[affected];
|
|
||||||
while (list.size() < static_cast<std::size_t>(index))
|
|
||||||
{
|
|
||||||
// Insert dummy effects to preserve indices
|
|
||||||
auto& dummy = list.emplace_back(effectInfo);
|
|
||||||
dummy.mRange = ESM::RT_Self;
|
|
||||||
assert(dummy.mRange != rangeType);
|
|
||||||
}
|
|
||||||
list.push_back(effectInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now apply the appropriate effects to each actor in range
|
|
||||||
for (auto& applyPair : toApply)
|
|
||||||
{
|
|
||||||
MWWorld::Ptr source = caster;
|
|
||||||
// Vanilla-compatible behaviour of never applying the spell to the caster
|
|
||||||
// (could be changed by mods later)
|
|
||||||
if (applyPair.first == caster)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (applyPair.first == ignore)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (source.isEmpty())
|
|
||||||
source = applyPair.first;
|
|
||||||
|
|
||||||
MWMechanics::CastSpell cast(source, applyPair.first);
|
|
||||||
cast.mHitPosition = origin;
|
|
||||||
cast.mId = id;
|
|
||||||
cast.mSourceName = sourceName;
|
|
||||||
cast.mSlot = slot;
|
|
||||||
ESM::EffectList effectsToApply;
|
|
||||||
effectsToApply.mList = applyPair.second;
|
|
||||||
cast.inflict(applyPair.first, caster, effectsToApply, rangeType, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void World::activate(const Ptr &object, const Ptr &actor)
|
void World::activate(const Ptr &object, const Ptr &actor)
|
||||||
{
|
{
|
||||||
breakInvisibility(actor);
|
breakInvisibility(actor);
|
||||||
|
|
|
@ -692,10 +692,6 @@ namespace MWWorld
|
||||||
|
|
||||||
void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos, float scale = 1.f, bool isMagicVFX = true) override;
|
void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos, float scale = 1.f, bool isMagicVFX = true) override;
|
||||||
|
|
||||||
void explodeSpell(const osg::Vec3f& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const MWWorld::Ptr& ignore,
|
|
||||||
ESM::RangeType rangeType, const std::string& id, const std::string& sourceName,
|
|
||||||
const bool fromProjectile=false, int slot = 0) override;
|
|
||||||
|
|
||||||
void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) override;
|
void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) override;
|
||||||
|
|
||||||
/// @see MWWorld::WeatherManager::isInStorm
|
/// @see MWWorld::WeatherManager::isInStorm
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue