mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-31 20:26:43 +00:00 
			
		
		
		
	Merge pull request #1044 from Allofich/magic
Changes to multi-effect spells
This commit is contained in:
		
						commit
						8677a6f803
					
				
					 8 changed files with 203 additions and 167 deletions
				
			
		|  | @ -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; | ||||
| 
 | ||||
|  |  | |||
|  | @ -1236,19 +1236,27 @@ bool CharacterController::updateWeaponState() | |||
|                     cast.playSpellCastingEffects(spellid); | ||||
| 
 | ||||
|                     const ESM::Spell *spell = store.get<ESM::Spell>().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<ESM::MagicEffect>().find(effectentry.mEffectID); | ||||
| 
 | ||||
|                     effect = store.get<ESM::MagicEffect>().find(lastEffect.mEffectID); // use last effect of list for color of VFX_Hands
 | ||||
| 
 | ||||
|                     const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().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); | ||||
| 
 | ||||
|                     switch(effectentry.mRange) | ||||
|                         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(firstEffect.mRange) | ||||
|                     { | ||||
|                         case 0: mAttackType = "self"; break; | ||||
|                         case 1: mAttackType = "touch"; break; | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ | |||
| 
 | ||||
| #include <cfloat> | ||||
| #include <limits> | ||||
| #include <iomanip> | ||||
| 
 | ||||
| #include <boost/format.hpp> | ||||
| 
 | ||||
|  | @ -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<ESM::ENAMstruct>::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<ESM::MagicEffect>().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<ActiveSpells::ActiveEffect> 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" | ||||
|                         }; | ||||
|                     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; | ||||
|                     } | ||||
|                     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<ESM::Spell>().find(spellid); | ||||
|         const ESM::ENAMstruct &effectentry = spell->mEffects.mList.at(0); | ||||
| 
 | ||||
|         const ESM::MagicEffect *effect; | ||||
|         effect = store.get<ESM::MagicEffect>().find(effectentry.mEffectID); | ||||
| 
 | ||||
|         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
 | ||||
|         for (std::vector<ESM::ENAMstruct>::const_iterator iter = spell->mEffects.mList.begin(); | ||||
|             iter != spell->mEffects.mList.end(); ++iter) | ||||
|         { | ||||
|             const ESM::Static* castStatic; | ||||
|             if (!effect->mCasting.empty()) | ||||
|                 castStatic = store.get<ESM::Static>().find (effect->mCasting); | ||||
|             const ESM::MagicEffect *effect; | ||||
|             effect = store.get<ESM::MagicEffect>().find(iter->mEffectID); | ||||
| 
 | ||||
|             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<ESM::Static>().find (effect->mCasting); | ||||
|                 else | ||||
|                     castStatic = store.get<ESM::Static>().find ("VFX_DefaultCast"); | ||||
| 
 | ||||
|                 animation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex); | ||||
|             } | ||||
| 
 | ||||
|             if (!mCaster.getClass().isActor()) | ||||
|                 animation->addSpellCastGlow(effect); | ||||
| 
 | ||||
|             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 | ||||
|                 castStatic = store.get<ESM::Static>().find ("VFX_DefaultCast"); | ||||
| 
 | ||||
|             animation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex); | ||||
|                 sndMgr->playSound3D(mCaster, schools[effect->mData.mSchool]+" cast", 1.0f, 1.0f); | ||||
|         } | ||||
| 
 | ||||
|         if (!mCaster.getClass().isActor()) | ||||
|             animation->addSpellCastGlow(effect); | ||||
| 
 | ||||
|         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); | ||||
|     } | ||||
| 
 | ||||
|     int getEffectiveEnchantmentCastCost(float castCost, const MWWorld::Ptr &actor) | ||||
|  |  | |||
|  | @ -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, | ||||
|  |  | |||
|  | @ -1,5 +1,7 @@ | |||
| #include "projectilemanager.hpp" | ||||
| 
 | ||||
| #include <iomanip> | ||||
| 
 | ||||
| #include <osg/PositionAttitudeTransform> | ||||
| 
 | ||||
| #include <components/esm/esmwriter.hpp> | ||||
|  | @ -33,6 +35,55 @@ | |||
| 
 | ||||
| #include "../mwphysics/physicssystem.hpp" | ||||
| 
 | ||||
| namespace | ||||
| { | ||||
|     ESM::EffectList getMagicBoltData(std::vector<std::string>& projectileIDs, std::vector<std::string>& sounds, float& speed, const ESM::EffectList& effects) | ||||
|     { | ||||
|         int count = 0; | ||||
|         ESM::EffectList projectileEffects; | ||||
|         for (std::vector<ESM::ENAMstruct>::const_iterator iter (effects.mList.begin()); | ||||
|             iter!=effects.mList.end(); ++iter) | ||||
|         { | ||||
|             const ESM::MagicEffect *magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().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<std::string>::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<osg::Node> 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<ESM::Weapon>().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<ESM::ENAMstruct>::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<MagicBoltState>::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; | ||||
|  |  | |||
|  | @ -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<std::string> 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<MWBase::SoundPtr> mSounds; | ||||
|             std::vector<std::string> mSoundIds; | ||||
|         }; | ||||
| 
 | ||||
|         struct ProjectileState : public State | ||||
|  |  | |||
|  | @ -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<std::string>& World::getContentFiles() const | ||||
|  | @ -3163,8 +3162,9 @@ namespace MWWorld | |||
|         { | ||||
|             const ESM::MagicEffect* effect = getStore().get<ESM::MagicEffect>().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; | ||||
|  |  | |||
|  | @ -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); | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue