mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-04-01 00:36:46 +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 void toggleAI() = 0;
|
||||||
virtual bool isAIActive() = 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 iter->second->isAnimPlaying(groupName);
|
||||||
return false;
|
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);
|
void skipAnimation(const MWWorld::Ptr& ptr);
|
||||||
bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName);
|
bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName);
|
||||||
|
|
||||||
|
void getObjectsInRange(const Ogre::Vector3& position, float radius, std::vector<MWWorld::Ptr>& out);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PtrControllerMap mActors;
|
PtrControllerMap mActors;
|
||||||
|
|
||||||
|
|
|
@ -950,4 +950,10 @@ namespace MWMechanics
|
||||||
|
|
||||||
return (roll >= target);
|
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 void toggleAI();
|
||||||
virtual bool isAIActive();
|
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();
|
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 playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number);
|
||||||
void skipAnimation(const MWWorld::Ptr& ptr);
|
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);
|
Ogre::SceneNode* sceneNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(worldPosition);
|
||||||
|
sceneNode->setScale(scale,scale,scale);
|
||||||
|
|
||||||
// fix texture extension to .dds
|
// fix texture extension to .dds
|
||||||
if (textureOverride.size() > 4)
|
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));
|
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(); )
|
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->mControllers[i].update();
|
||||||
}
|
}
|
||||||
|
objects->rotateBillboardNodes(camera);
|
||||||
|
|
||||||
// Finished playing?
|
// Finished playing?
|
||||||
if (objects->mControllers[0].getSource()->getValue() >= objects->mMaxControllerLength)
|
if (objects->mControllers[0].getSource()->getValue() >= objects->mMaxControllerLength)
|
||||||
|
|
|
@ -14,9 +14,9 @@ namespace MWRender
|
||||||
~EffectManager() { clear(); }
|
~EffectManager() { clear(); }
|
||||||
|
|
||||||
/// Add an effect. When it's finished playing, it will be removed automatically.
|
/// 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
|
/// Remove all effects
|
||||||
void clear();
|
void clear();
|
||||||
|
|
|
@ -378,7 +378,7 @@ void RenderingManager::update (float duration, bool paused)
|
||||||
if(paused)
|
if(paused)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mEffectManager->update(duration);
|
mEffectManager->update(duration, mRendering.getCamera());
|
||||||
|
|
||||||
mActors->update (mRendering.getCamera());
|
mActors->update (mRendering.getCamera());
|
||||||
mPlayerAnimation->preRender(mRendering.getCamera());
|
mPlayerAnimation->preRender(mRendering.getCamera());
|
||||||
|
@ -1024,9 +1024,9 @@ float RenderingManager::getCameraDistance() const
|
||||||
return mCamera->getCameraDistance();
|
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
|
} // namespace
|
||||||
|
|
|
@ -207,7 +207,7 @@ public:
|
||||||
void stopVideo();
|
void stopVideo();
|
||||||
void frameStarted(float dt, bool paused);
|
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:
|
protected:
|
||||||
virtual void windowResized(int x, int y);
|
virtual void windowResized(int x, int y);
|
||||||
|
|
|
@ -2174,9 +2174,16 @@ namespace MWWorld
|
||||||
state.mId = id;
|
state.mId = id;
|
||||||
state.mActorHandle = actor.getRefData().getHandle();
|
state.mActorHandle = actor.getRefData().getHandle();
|
||||||
state.mSpeed = speed;
|
state.mSpeed = speed;
|
||||||
state.mEffects = effects;
|
|
||||||
state.mStack = stack;
|
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();
|
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||||
sndMgr->playSound3D(ptr, sound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop);
|
sndMgr->playSound3D(ptr, sound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop);
|
||||||
|
|
||||||
|
@ -2223,30 +2230,68 @@ namespace MWWorld
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
explode = true;
|
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)
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue