mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-31 19:56:38 +00:00 
			
		
		
		
	Feature #957: Implement area magic
This commit is contained in:
		
							parent
							
								
									ba5300b071
								
							
						
					
					
						commit
						205e8aa4e9
					
				
					 12 changed files with 108 additions and 29 deletions
				
			
		|  | @ -157,6 +157,8 @@ namespace MWBase | |||
| 
 | ||||
|         virtual void toggleAI() = 0; | ||||
|         virtual bool isAIActive() = 0; | ||||
| 
 | ||||
|             virtual void getObjectsInRange (const Ogre::Vector3& position, float radius, std::vector<MWWorld::Ptr>& objects) = 0; | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -919,4 +919,13 @@ namespace MWMechanics | |||
|             return iter->second->isAnimPlaying(groupName); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     void Actors::getObjectsInRange(const Ogre::Vector3& position, float radius, std::vector<MWWorld::Ptr>& out) | ||||
|     { | ||||
|         for (PtrControllerMap::iterator iter = mActors.begin(); iter != mActors.end(); ++iter) | ||||
|         { | ||||
|             if (Ogre::Vector3(iter->first.getRefData().getPosition().pos).squaredDistance(position) <= radius*radius) | ||||
|                 out.push_back(iter->first); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -94,6 +94,8 @@ namespace MWMechanics | |||
|         void skipAnimation(const MWWorld::Ptr& ptr); | ||||
|         bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName); | ||||
| 
 | ||||
|         void getObjectsInRange(const Ogre::Vector3& position, float radius, std::vector<MWWorld::Ptr>& out); | ||||
| 
 | ||||
|     private: | ||||
|         PtrControllerMap mActors; | ||||
| 
 | ||||
|  |  | |||
|  | @ -950,4 +950,10 @@ namespace MWMechanics | |||
| 
 | ||||
|         return (roll >= target); | ||||
|     } | ||||
| 
 | ||||
|     void MechanicsManager::getObjectsInRange(const Ogre::Vector3 &position, float radius, std::vector<MWWorld::Ptr> &objects) | ||||
|     { | ||||
|         mActors.getObjectsInRange(position, radius, objects); | ||||
|         mObjects.getObjectsInRange(position, radius, objects); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -135,6 +135,8 @@ namespace MWMechanics | |||
| 
 | ||||
|         virtual void toggleAI(); | ||||
|         virtual bool isAIActive(); | ||||
| 
 | ||||
|             virtual void getObjectsInRange (const Ogre::Vector3& position, float radius, std::vector<MWWorld::Ptr>& objects); | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -92,4 +92,13 @@ void Objects::skipAnimation(const MWWorld::Ptr& ptr) | |||
|         iter->second->skipAnim(); | ||||
| } | ||||
| 
 | ||||
| void Objects::getObjectsInRange(const Ogre::Vector3& position, float radius, std::vector<MWWorld::Ptr>& out) | ||||
| { | ||||
|     for (PtrControllerMap::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter) | ||||
|     { | ||||
|         if (Ogre::Vector3(iter->first.getRefData().getPosition().pos).squaredDistance(position) <= radius*radius) | ||||
|             out.push_back(iter->first); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -40,6 +40,8 @@ namespace MWMechanics | |||
| 
 | ||||
|         void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); | ||||
|         void skipAnimation(const MWWorld::Ptr& ptr); | ||||
| 
 | ||||
|         void getObjectsInRange (const Ogre::Vector3& position, float radius, std::vector<MWWorld::Ptr>& out); | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -26,9 +26,10 @@ EffectManager::EffectManager(Ogre::SceneManager *sceneMgr) | |||
| { | ||||
| } | ||||
| 
 | ||||
| void EffectManager::addEffect(const std::string &model, std::string textureOverride, const Ogre::Vector3 &worldPosition) | ||||
| void EffectManager::addEffect(const std::string &model, std::string textureOverride, const Ogre::Vector3 &worldPosition, float scale) | ||||
| { | ||||
|     Ogre::SceneNode* sceneNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(worldPosition); | ||||
|     sceneNode->setScale(scale,scale,scale); | ||||
| 
 | ||||
|     // fix texture extension to .dds
 | ||||
|     if (textureOverride.size() > 4) | ||||
|  | @ -78,7 +79,7 @@ void EffectManager::addEffect(const std::string &model, std::string textureOverr | |||
|     mEffects.push_back(std::make_pair(sceneNode, scene)); | ||||
| } | ||||
| 
 | ||||
| void EffectManager::update(float dt) | ||||
| void EffectManager::update(float dt, Ogre::Camera* camera) | ||||
| { | ||||
|     for (std::vector<std::pair<Ogre::SceneNode*, NifOgre::ObjectScenePtr> >::iterator it = mEffects.begin(); it != mEffects.end(); ) | ||||
|     { | ||||
|  | @ -91,6 +92,7 @@ void EffectManager::update(float dt) | |||
| 
 | ||||
|             objects->mControllers[i].update(); | ||||
|         } | ||||
|         objects->rotateBillboardNodes(camera); | ||||
| 
 | ||||
|         // Finished playing?
 | ||||
|         if (objects->mControllers[0].getSource()->getValue() >= objects->mMaxControllerLength) | ||||
|  |  | |||
|  | @ -14,9 +14,9 @@ namespace MWRender | |||
|         ~EffectManager() { clear(); } | ||||
| 
 | ||||
|         /// Add an effect. When it's finished playing, it will be removed automatically.
 | ||||
|         void addEffect (const std::string& model, std::string textureOverride, const Ogre::Vector3& worldPosition); | ||||
|         void addEffect (const std::string& model, std::string textureOverride, const Ogre::Vector3& worldPosition, float scale); | ||||
| 
 | ||||
|         void update(float dt); | ||||
|         void update(float dt, Ogre::Camera* camera); | ||||
| 
 | ||||
|         /// Remove all effects
 | ||||
|         void clear(); | ||||
|  |  | |||
|  | @ -378,7 +378,7 @@ void RenderingManager::update (float duration, bool paused) | |||
|     if(paused) | ||||
|         return; | ||||
| 
 | ||||
|     mEffectManager->update(duration); | ||||
|     mEffectManager->update(duration, mRendering.getCamera()); | ||||
| 
 | ||||
|     mActors->update (mRendering.getCamera()); | ||||
|     mPlayerAnimation->preRender(mRendering.getCamera()); | ||||
|  | @ -1024,9 +1024,9 @@ float RenderingManager::getCameraDistance() const | |||
|     return mCamera->getCameraDistance(); | ||||
| } | ||||
| 
 | ||||
| void RenderingManager::spawnEffect(const std::string &model, const std::string &texture, const Vector3 &worldPosition) | ||||
| void RenderingManager::spawnEffect(const std::string &model, const std::string &texture, const Vector3 &worldPosition, float scale) | ||||
| { | ||||
|     mEffectManager->addEffect(model, texture, worldPosition); | ||||
|     mEffectManager->addEffect(model, "", worldPosition, scale); | ||||
| } | ||||
| 
 | ||||
| } // namespace
 | ||||
|  |  | |||
|  | @ -207,7 +207,7 @@ public: | |||
|     void stopVideo(); | ||||
|     void frameStarted(float dt, bool paused); | ||||
| 
 | ||||
|     void spawnEffect (const std::string& model, const std::string& texture, const Ogre::Vector3& worldPosition); | ||||
|     void spawnEffect (const std::string& model, const std::string& texture, const Ogre::Vector3& worldPosition, float scale=1.f); | ||||
| 
 | ||||
| protected: | ||||
|     virtual void windowResized(int x, int y); | ||||
|  |  | |||
|  | @ -2174,9 +2174,16 @@ namespace MWWorld | |||
|         state.mId = id; | ||||
|         state.mActorHandle = actor.getRefData().getHandle(); | ||||
|         state.mSpeed = speed; | ||||
|         state.mEffects = effects; | ||||
|         state.mStack = stack; | ||||
| 
 | ||||
|         // 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); | ||||
|         } | ||||
| 
 | ||||
|         MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); | ||||
|         sndMgr->playSound3D(ptr, sound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); | ||||
| 
 | ||||
|  | @ -2223,30 +2230,68 @@ namespace MWWorld | |||
|                     continue; | ||||
| 
 | ||||
|                 explode = true; | ||||
| 
 | ||||
|                 MWWorld::Ptr caster = searchPtrViaHandle(it->second.mActorHandle); | ||||
|                 if (caster.isEmpty()) | ||||
|                     caster = obstacle; | ||||
|                 if (obstacle.isEmpty()) | ||||
|                 { | ||||
|                     // Terrain
 | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     MWMechanics::CastSpell cast(caster, obstacle); | ||||
|                     cast.mStack = it->second.mStack; | ||||
|                     cast.mId = it->second.mId; | ||||
|                     cast.mSourceName = it->second.mSourceName; | ||||
|                     cast.inflict(obstacle, caster, it->second.mEffects, ESM::RT_Target, false); | ||||
|                 } | ||||
| 
 | ||||
|                 deleteObject(ptr); | ||||
|                 mProjectiles.erase(it++); | ||||
|             } | ||||
| 
 | ||||
|             if (explode) | ||||
|             { | ||||
|                 // TODO: 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); | ||||
| 
 | ||||
|                     // 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); | ||||
|                 } | ||||
| 
 | ||||
|                 deleteObject(ptr); | ||||
|                 mProjectiles.erase(it++); | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue