diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 549931b9a..c78bd2053 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -486,9 +486,8 @@ namespace MWBase virtual void castSpell (const MWWorld::Ptr& actor) = 0; - virtual void launchMagicBolt (const std::string& model, const std::string& sound, const std::string& spellId, - float speed, bool stack, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection) = 0; + virtual void launchMagicBolt (const std::string& spellId, bool stack, const ESM::EffectList& effects, + const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection) = 0; 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; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 93f553f19..bb8929f8b 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1236,19 +1236,27 @@ bool CharacterController::updateWeaponState() cast.playSpellCastingEffects(spellid); const ESM::Spell *spell = store.get().find(spellid); - const ESM::ENAMstruct &effectentry = spell->mEffects.mList.at(0); + + const ESM::ENAMstruct &lastEffect = spell->mEffects.mList.at(spell->mEffects.mList.size() - 1); const ESM::MagicEffect *effect; - effect = store.get().find(effectentry.mEffectID); + + effect = store.get().find(lastEffect.mEffectID); // use last effect of list for color of VFX_Hands const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Hands"); - if (mAnimation->getNode("Bip01 L Hand")) - mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 L Hand", effect->mParticle); - if (mAnimation->getNode("Bip01 R Hand")) - mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 R Hand", effect->mParticle); + for (size_t iter = 0; iter < spell->mEffects.mList.size(); ++iter) // play hands vfx for each effect + { + if (mAnimation->getNode("Bip01 L Hand")) + mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 L Hand", effect->mParticle); + + if (mAnimation->getNode("Bip01 R Hand")) + mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 R Hand", effect->mParticle); + } + + const ESM::ENAMstruct &firstEffect = spell->mEffects.mList.at(0); // first effect used for casting animation - switch(effectentry.mRange) + switch(firstEffect.mRange) { case 0: mAttackType = "self"; break; case 1: mAttackType = "touch"; break; diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index cdf8a2a67..f1c920421 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -2,6 +2,7 @@ #include #include +#include #include @@ -27,41 +28,6 @@ #include "npcstats.hpp" #include "actorutil.hpp" -namespace -{ - - /// Get projectile properties (model, sound and speed) for a spell with the given effects - /// If \a model is empty, the spell has no ranged effects and should not spawn a projectile. - void getProjectileInfo (const ESM::EffectList& effects, std::string& model, std::string& sound, float& speed) - { - for (std::vector::const_iterator iter (effects.mList.begin()); - iter!=effects.mList.end(); ++iter) - { - if (iter->mRange != ESM::RT_Target) - continue; - - const ESM::MagicEffect *magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find ( - iter->mEffectID); - - model = magicEffect->mBolt; - if (model.empty()) - model = "VFX_DefaultBolt"; - - static const std::string schools[] = { - "alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration" - }; - if (!magicEffect->mBoltSound.empty()) - sound = magicEffect->mBoltSound; - else - sound = schools[magicEffect->mData.mSchool] + " bolt"; - - speed = magicEffect->mData.mSpeed; - break; - } - } - -} - namespace MWMechanics { @@ -317,6 +283,23 @@ namespace MWMechanics { } + /// Get projectile properties (model, sound and speed) for a spell with the given effects and launch. + /// If \a model is empty, the spell has no ranged effects and should not spawn a projectile. + void CastSpell::launchMagicBolt (const ESM::EffectList& effects) + { + osg::Vec3f fallbackDirection (0,1,0); + + // Fall back to a "caster to target" direction if we have no other means of determining it + // (e.g. when cast by a non-actor) + if (!mTarget.isEmpty()) + fallbackDirection = + osg::Vec3f(mTarget.getRefData().getPosition().asVec3())- + osg::Vec3f(mCaster.getRefData().getPosition().asVec3()); + + MWBase::Environment::get().getWorld()->launchMagicBolt(mId, false, effects, + mCaster, mSourceName, fallbackDirection); + } + void CastSpell::inflict(const MWWorld::Ptr &target, const MWWorld::Ptr &caster, const ESM::EffectList &effects, ESM::RangeType range, bool reflected, bool exploded) { @@ -356,7 +339,6 @@ namespace MWMechanics ESM::EffectList reflectedEffects; std::vector appliedLastingEffects; - bool firstAppliedEffect = true; bool anyHarmfulEffect = false; // HACK: cache target's magic effects here, and add any applied effects to it. Use the cached effects for determining resistance. @@ -545,20 +527,15 @@ namespace MWMechanics if (target.getClass().isActor() || magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration) { - // Play sound, only for the first effect - if (firstAppliedEffect) - { - static const std::string schools[] = { - "alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration" - }; - - MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - if(!magicEffect->mHitSound.empty()) - sndMgr->playSound3D(target, magicEffect->mHitSound, 1.0f, 1.0f); - else - sndMgr->playSound3D(target, schools[magicEffect->mData.mSchool]+" hit", 1.0f, 1.0f); - firstAppliedEffect = false; - } + static const std::string schools[] = { + "alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration" + }; + + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); + if(!magicEffect->mHitSound.empty()) + sndMgr->playSound3D(target, magicEffect->mHitSound, 1.0f, 1.0f); + else + sndMgr->playSound3D(target, schools[magicEffect->mData.mSchool]+" hit", 1.0f, 1.0f); // Add VFX const ESM::Static* castStatic; @@ -791,17 +768,7 @@ namespace MWMechanics } if (launchProjectile) - { - std::string projectileModel; - std::string sound; - float speed = 0; - getProjectileInfo(enchantment->mEffects, projectileModel, sound, speed); - if (!projectileModel.empty()) - MWBase::Environment::get().getWorld()->launchMagicBolt(projectileModel, sound, mId, speed, - false, enchantment->mEffects, mCaster, mSourceName, - // Not needed, enchantments can only be cast by actors - osg::Vec3f(1,0,0)); - } + launchMagicBolt(enchantment->mEffects); else if (!mTarget.isEmpty()) inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Target); @@ -882,28 +849,9 @@ namespace MWMechanics inflict(mCaster, mCaster, spell->mEffects, ESM::RT_Self); if (!mTarget.isEmpty()) - { inflict(mTarget, mCaster, spell->mEffects, ESM::RT_Touch); - } - - std::string projectileModel; - std::string sound; - float speed = 0; - getProjectileInfo(spell->mEffects, projectileModel, sound, speed); - if (!projectileModel.empty()) - { - osg::Vec3f fallbackDirection (0,1,0); - // Fall back to a "caster to target" direction if we have no other means of determining it - // (e.g. when cast by a non-actor) - if (!mTarget.isEmpty()) - fallbackDirection = - osg::Vec3f(mTarget.getRefData().getPosition().asVec3())- - osg::Vec3f(mCaster.getRefData().getPosition().asVec3()); - - MWBase::Environment::get().getWorld()->launchMagicBolt(projectileModel, sound, mId, speed, - false, spell->mEffects, mCaster, mSourceName, fallbackDirection); - } + launchMagicBolt(spell->mEffects); return true; } @@ -976,36 +924,39 @@ namespace MWMechanics const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); const ESM::Spell *spell = store.get().find(spellid); - const ESM::ENAMstruct &effectentry = spell->mEffects.mList.at(0); - const ESM::MagicEffect *effect; - effect = store.get().find(effectentry.mEffectID); + for (std::vector::const_iterator iter = spell->mEffects.mList.begin(); + iter != spell->mEffects.mList.end(); ++iter) + { + const ESM::MagicEffect *effect; + effect = store.get().find(iter->mEffectID); - MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(mCaster); + MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(mCaster); - if (mCaster.getClass().isActor()) // TODO: Non-actors (except for large statics?) should also create a spell cast vfx - { - const ESM::Static* castStatic; - if (!effect->mCasting.empty()) - castStatic = store.get().find (effect->mCasting); - else - castStatic = store.get().find ("VFX_DefaultCast"); + if (mCaster.getClass().isActor()) // TODO: Non-actors (except for large statics?) should also create a spell cast vfx + { + const ESM::Static* castStatic; + if (!effect->mCasting.empty()) + castStatic = store.get().find (effect->mCasting); + else + castStatic = store.get().find ("VFX_DefaultCast"); - animation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex); - } + animation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex); + } - if (!mCaster.getClass().isActor()) - animation->addSpellCastGlow(effect); + if (!mCaster.getClass().isActor()) + animation->addSpellCastGlow(effect); - static const std::string schools[] = { - "alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration" - }; + static const std::string schools[] = { + "alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration" + }; - MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - if(!effect->mCastSound.empty()) - sndMgr->playSound3D(mCaster, effect->mCastSound, 1.0f, 1.0f); - else - sndMgr->playSound3D(mCaster, schools[effect->mData.mSchool]+" cast", 1.0f, 1.0f); + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); + if(!effect->mCastSound.empty()) + sndMgr->playSound3D(mCaster, effect->mCastSound, 1.0f, 1.0f); + else + sndMgr->playSound3D(mCaster, schools[effect->mData.mSchool]+" cast", 1.0f, 1.0f); + } } int getEffectiveEnchantmentCastCost(float castCost, const MWWorld::Ptr &actor) diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index aba263b01..85277401f 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -94,6 +94,9 @@ namespace MWMechanics void playSpellCastingEffects(const std::string &spellid); + /// Launch a bolt with the given effects. + void launchMagicBolt (const ESM::EffectList& effects); + /// @note \a target can be any type of object, not just actors. /// @note \a caster can be any type of object, or even an empty object. void inflict (const MWWorld::Ptr& target, const MWWorld::Ptr& caster, diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 90fba827f..aa5a1b650 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -1,5 +1,7 @@ #include "projectilemanager.hpp" +#include + #include #include @@ -33,6 +35,55 @@ #include "../mwphysics/physicssystem.hpp" +namespace +{ + ESM::EffectList getMagicBoltData(std::vector& projectileIDs, std::vector& sounds, float& speed, const ESM::EffectList& effects) + { + int count = 0; + ESM::EffectList projectileEffects; + for (std::vector::const_iterator iter (effects.mList.begin()); + iter!=effects.mList.end(); ++iter) + { + const ESM::MagicEffect *magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find ( + iter->mEffectID); + + // All the projectiles should use the same speed. From observations in the + // original engine, this seems to be the average of the constituent effects. + speed += magicEffect->mData.mSpeed; + count++; + + if (iter->mRange != ESM::RT_Target) + continue; + + if (magicEffect->mBolt.empty()) + projectileIDs.push_back("VFX_DefaultBolt"); + else + projectileIDs.push_back(magicEffect->mBolt); + + static const std::string schools[] = { + "alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration" + }; + if (!magicEffect->mBoltSound.empty()) + sounds.push_back(magicEffect->mBoltSound); + else + sounds.push_back(schools[magicEffect->mData.mSchool] + " bolt"); + projectileEffects.mList.push_back(*iter); + } + + if (count != 0) + speed /= count; + + if (projectileEffects.mList.size() > 1) // insert a VFX_Multiple projectile if there are multiple projectile effects + { + std::ostringstream ID; + ID << "VFX_Multiple" << effects.mList.size(); + std::vector::iterator it; + it = projectileIDs.begin(); + it = projectileIDs.insert(it, ID.str()); + } + return projectileEffects; + } +} namespace MWWorld { @@ -92,7 +143,19 @@ namespace MWWorld attachTo = rotateNode; } - mResourceSystem->getSceneManager()->getInstance(model, attachTo); + osg::ref_ptr ptr = mResourceSystem->getSceneManager()->getInstance(model, attachTo); + + if (state.mIdMagic.size() > 1) + for (size_t iter = 1; iter != state.mIdMagic.size(); ++iter) + { + std::ostringstream nodeName; + nodeName << "Dummy" << std::setw(2) << std::setfill('0') << iter; + const ESM::Weapon* weapon = MWBase::Environment::get().getWorld()->getStore().get().find (state.mIdMagic.at(iter)); + SceneUtil::FindByNameVisitor findVisitor(nodeName.str()); + attachTo->accept(findVisitor); + if (findVisitor.mFoundNode) + mResourceSystem->getSceneManager()->getInstance("meshes\\" + weapon->mModel, findVisitor.mFoundNode); + } SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; state.mNode->accept(disableFreezeOnCullVisitor); @@ -112,10 +175,8 @@ namespace MWWorld state.mEffectAnimationTime->addTime(duration); } - void ProjectileManager::launchMagicBolt(const std::string &model, const std::string &sound, - const std::string &spellId, float speed, bool stack, - const ESM::EffectList &effects, const Ptr &caster, const std::string &sourceName, - const osg::Vec3f& fallbackDirection) + void ProjectileManager::launchMagicBolt(const std::string &spellId, bool stack, const ESM::EffectList &effects, const Ptr &caster, + const std::string &sourceName, const osg::Vec3f& fallbackDirection) { osg::Vec3f pos = caster.getRefData().getPosition().asVec3(); if (caster.getClass().isActor()) @@ -137,33 +198,31 @@ namespace MWWorld MagicBoltState state; state.mSourceName = sourceName; - state.mId = model; state.mSpellId = spellId; state.mCasterHandle = caster; if (caster.getClass().isActor()) state.mActorId = caster.getClass().getCreatureStats(caster).getActorId(); else state.mActorId = -1; - state.mSpeed = speed; state.mStack = stack; - state.mSoundId = sound; - // Only interested in "on target" effects - for (std::vector::const_iterator iter (effects.mList.begin()); - iter!=effects.mList.end(); ++iter) - { - if (iter->mRange == ESM::RT_Target) - state.mEffects.mList.push_back(*iter); - } + state.mEffects = getMagicBoltData(state.mIdMagic, state.mSoundIds, state.mSpeed, effects); - MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), model); + // Non-projectile should have been removed by getMagicBoltData + if (state.mEffects.mList.size() == 0) + return; + + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), state.mIdMagic.at(0)); MWWorld::Ptr ptr = ref.getPtr(); createModel(state, ptr.getClass().getModel(ptr), pos, orient, true); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - state.mSound = sndMgr->playSound3D(pos, sound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); - + for (size_t it = 0; it != state.mSoundIds.size(); it++) + { + state.mSounds.push_back(sndMgr->playSound3D(pos, state.mSoundIds.at(it), 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop)); + } + mMagicBolts.push_back(state); } @@ -173,7 +232,7 @@ namespace MWWorld state.mActorId = actor.getClass().getCreatureStats(actor).getActorId(); state.mBowId = bow.getCellRef().getRefId(); state.mVelocity = orient * osg::Vec3f(0,1,0) * speed; - state.mId = projectile.getCellRef().getRefId(); + state.mIdArrow = projectile.getCellRef().getRefId(); state.mCasterHandle = actor; state.mAttackStrength = attackStrength; @@ -205,8 +264,10 @@ namespace MWWorld osg::Vec3f pos(it->mNode->getPosition()); osg::Vec3f newPos = pos + direction * duration * speed; - if (it->mSound.get()) - it->mSound->setPosition(newPos); + for (size_t soundIter = 0; soundIter != it->mSounds.size(); soundIter++) + { + it->mSounds.at(soundIter)->setPosition(newPos); + } it->mNode->setPosition(newPos); @@ -246,7 +307,11 @@ namespace MWWorld MWBase::Environment::get().getWorld()->explodeSpell(pos, it->mEffects, caster, result.mHitObject, ESM::RT_Target, it->mSpellId, it->mSourceName); - MWBase::Environment::get().getSoundManager()->stopSound(it->mSound); + for (size_t soundIter = 0; soundIter != it->mSounds.size(); soundIter++) + { + MWBase::Environment::get().getSoundManager()->stopSound(it->mSounds.at(soundIter)); + } + mParent->removeChild(it->mNode); it = mMagicBolts.erase(it); @@ -286,7 +351,7 @@ namespace MWWorld { if (result.mHit) { - MWWorld::ManualRef projectileRef(MWBase::Environment::get().getWorld()->getStore(), it->mId); + MWWorld::ManualRef projectileRef(MWBase::Environment::get().getWorld()->getStore(), it->mIdArrow); // Try to get a Ptr to the bow that was used. It might no longer exist. MWWorld::Ptr bow = projectileRef.getPtr(); @@ -326,7 +391,10 @@ namespace MWWorld for (std::vector::iterator it = mMagicBolts.begin(); it != mMagicBolts.end(); ++it) { mParent->removeChild(it->mNode); - MWBase::Environment::get().getSoundManager()->stopSound(it->mSound); + for (size_t soundIter = 0; soundIter != it->mSounds.size(); soundIter++) + { + MWBase::Environment::get().getSoundManager()->stopSound(it->mSounds.at(soundIter)); + } } mMagicBolts.clear(); } @@ -338,7 +406,7 @@ namespace MWWorld writer.startRecord(ESM::REC_PROJ); ESM::ProjectileState state; - state.mId = it->mId; + state.mId = it->mIdArrow; state.mPosition = ESM::Vector3(osg::Vec3f(it->mNode->getPosition())); state.mOrientation = ESM::Quaternion(osg::Quat(it->mNode->getAttitude())); state.mActorId = it->mActorId; @@ -357,14 +425,14 @@ namespace MWWorld writer.startRecord(ESM::REC_MPRJ); ESM::MagicBoltState state; - state.mId = it->mId; + state.mId = it->mIdMagic.at(0); state.mPosition = ESM::Vector3(osg::Vec3f(it->mNode->getPosition())); state.mOrientation = ESM::Quaternion(osg::Quat(it->mNode->getAttitude())); state.mActorId = it->mActorId; state.mSpellId = it->mSpellId; state.mEffects = it->mEffects; - state.mSound = it->mSoundId; + state.mSound = it->mSoundIds.at(0); state.mSourceName = it->mSourceName; state.mSpeed = it->mSpeed; state.mStack = it->mStack; @@ -386,7 +454,7 @@ namespace MWWorld state.mActorId = esm.mActorId; state.mBowId = esm.mBowId; state.mVelocity = esm.mVelocity; - state.mId = esm.mId; + state.mIdArrow = esm.mId; state.mAttackStrength = esm.mAttackStrength; std::string model; @@ -413,17 +481,20 @@ namespace MWWorld MagicBoltState state; state.mSourceName = esm.mSourceName; - state.mId = esm.mId; + state.mIdMagic.push_back(esm.mId); state.mSpellId = esm.mSpellId; state.mActorId = esm.mActorId; - state.mSpeed = esm.mSpeed; state.mStack = esm.mStack; - state.mEffects = esm.mEffects; + state.mEffects = getMagicBoltData(state.mIdMagic, state.mSoundIds, state.mSpeed, esm.mEffects); + state.mSpeed = esm.mSpeed; // speed is derived from non-projectile effects as well as + // projectile effects, so we can't calculate it from the save + // file's effect list, which is already trimmed of non-projectile + // effects. We need to use the stored value. std::string model; try { - MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), esm.mId); + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), state.mIdMagic.at(0)); MWWorld::Ptr ptr = ref.getPtr(); model = ptr.getClass().getModel(ptr); } @@ -435,9 +506,12 @@ namespace MWWorld createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - state.mSound = sndMgr->playSound3D(esm.mPosition, esm.mSound, 1.0f, 1.0f, - MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); - state.mSoundId = esm.mSound; + + for (size_t soundIter = 0; soundIter != state.mSoundIds.size(); soundIter++) + { + state.mSounds.push_back(sndMgr->playSound3D(esm.mPosition, state.mSoundIds.at(soundIter), 1.0f, 1.0f, + MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop)); + } mMagicBolts.push_back(state); return true; diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index 74d4c1dc5..55ce0cd12 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -49,9 +49,8 @@ namespace MWWorld MWRender::RenderingManager* rendering, MWPhysics::PhysicsSystem* physics); /// If caster is an actor, the actor's facing orientation is used. Otherwise fallbackDirection is used. - void launchMagicBolt (const std::string& model, const std::string &sound, const std::string &spellId, - float speed, bool stack, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection); + void launchMagicBolt (const std::string &spellId, bool stack, const ESM::EffectList& effects, + const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection); void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, const osg::Vec3f& pos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength); @@ -84,8 +83,11 @@ namespace MWWorld MWWorld::Ptr getCaster(); - // MW-id of this projectile - std::string mId; + // MW-ids of a magic projectile + std::vector mIdMagic; + + // MW-id of an arrow projectile + std::string mIdArrow; }; struct MagicBoltState : public State @@ -101,8 +103,8 @@ namespace MWWorld bool mStack; - MWBase::SoundPtr mSound; - std::string mSoundId; + std::vector mSounds; + std::vector mSoundIds; }; struct ProjectileState : public State diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6c5fae014..4ebd41662 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2705,11 +2705,10 @@ namespace MWWorld mProjectileManager->launchProjectile(actor, projectile, worldPos, orient, bow, speed, attackStrength); } - void World::launchMagicBolt (const std::string& model, const std::string &sound, const std::string &spellId, - float speed, bool stack, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection) + void World::launchMagicBolt (const std::string &spellId, bool stack, const ESM::EffectList& effects, + const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection) { - mProjectileManager->launchMagicBolt(model, sound, spellId, speed, stack, effects, caster, sourceName, fallbackDirection); + mProjectileManager->launchMagicBolt(spellId, stack, effects, caster, sourceName, fallbackDirection); } const std::vector& World::getContentFiles() const @@ -3163,8 +3162,9 @@ namespace MWWorld { const ESM::MagicEffect* effect = getStore().get().find(effectIt->mEffectID); - if (effectIt->mArea <= 0) - continue; // Not an area effect + if (effectIt->mArea <= 0 || effectIt->mRange != rangeType) + continue; // Not an area effect or not right range type + // Spawn the explosion orb effect const ESM::Static* areaStatic; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index da665e27c..8774e549f 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -594,9 +594,8 @@ namespace MWWorld */ virtual void castSpell (const MWWorld::Ptr& actor); - virtual void launchMagicBolt (const std::string& model, const std::string& sound, const std::string& spellId, - float speed, bool stack, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection); + virtual void launchMagicBolt (const std::string& spellId, bool stack, const ESM::EffectList& effects, + const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection); virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength);