From 8d7de7d1ece744356fee88f7e8613089725fcd67 Mon Sep 17 00:00:00 2001 From: dteviot Date: Tue, 17 Feb 2015 22:14:25 +1300 Subject: [PATCH] Telekinesis allows safe opening of traps (Fixes #1916) When trap activated at beyond normal activation distance, assume telekinesis used and detonate trap at trapped object's location. Also some minor code refactoring of spellcasting. 1. Corrected parameter passed to explodeSpell(). 2. For loop now correctly does an early exit. 3. Removed duplicated tests. --- apps/openmw/mwbase/world.hpp | 4 +++- apps/openmw/mwmechanics/spellcasting.cpp | 16 ++++++------- apps/openmw/mwworld/actiontrap.cpp | 29 +++++++++++++++++++++--- apps/openmw/mwworld/worldimp.cpp | 4 ++-- apps/openmw/mwworld/worldimp.hpp | 2 +- 5 files changed, 39 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index f58ef0809..f71975433 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -269,6 +269,8 @@ namespace MWBase virtual MWWorld::Ptr getFacedObject() = 0; ///< Return pointer to the object the player is looking at, if it is within activation range + virtual float getMaxActivationDistance() = 0; + /// Returns a pointer to the object the provided object would hit (if within the /// specified distance), and the point where the hit occurs. This will attempt to /// use the "Head" node, or alternatively the "Bip01 Head" node as a basis. @@ -548,7 +550,7 @@ namespace MWBase virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const Ogre::Vector3& worldPos) = 0; virtual void explodeSpell (const Ogre::Vector3& origin, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, int rangeType, const std::string& id, const std::string& sourceName) = 0; + const MWWorld::Ptr& caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName) = 0; virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) = 0; diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 49887e560..4ce3fcaf5 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -309,9 +309,11 @@ namespace MWMechanics for (std::vector::const_iterator iter (effects.mList.begin()); iter!=effects.mList.end(); ++iter) { - if (iter->mRange != range) - continue; - found = true; + if (iter->mRange == range) + { + found = true; + break; + } } if (!found) return; @@ -766,8 +768,7 @@ namespace MWMechanics if (!mTarget.isEmpty()) { - if (!mTarget.getClass().isActor() || !mTarget.getClass().getCreatureStats(mTarget).isDead()) - inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Touch); + inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Touch); } std::string projectileModel; @@ -851,10 +852,7 @@ namespace MWMechanics if (!mTarget.isEmpty()) { - if (!mTarget.getClass().isActor() || !mTarget.getClass().getCreatureStats(mTarget).isDead()) - { - inflict(mTarget, mCaster, spell->mEffects, ESM::RT_Touch); - } + inflict(mTarget, mCaster, spell->mEffects, ESM::RT_Touch); } diff --git a/apps/openmw/mwworld/actiontrap.cpp b/apps/openmw/mwworld/actiontrap.cpp index 1472afc08..d153b7e61 100644 --- a/apps/openmw/mwworld/actiontrap.cpp +++ b/apps/openmw/mwworld/actiontrap.cpp @@ -1,16 +1,39 @@ #include "actiontrap.hpp" #include "../mwmechanics/spellcasting.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" namespace MWWorld { void ActionTrap::executeImp(const Ptr &actor) { - MWMechanics::CastSpell cast(mTrapSource, actor); - cast.mHitPosition = Ogre::Vector3(actor.getRefData().getPosition().pos); - cast.cast(mSpellId); + Ogre::Vector3 actorPosition(actor.getRefData().getPosition().pos); + Ogre::Vector3 trapPosition(mTrapSource.getRefData().getPosition().pos); + float activationDistance = MWBase::Environment::get().getWorld()->getMaxActivationDistance(); + // GUI calcs if object in activation distance include object and player geometry + const float fudgeFactor = 1.25f; + + // Hack: if actor is beyond activation range, then assume actor is using telekinesis + // to open door/container. + // Note, can't just detonate the trap at the trapped object's location and use the blast + // radius, because for most trap spells this is 1 foot, much less than the activation distance. + if (trapPosition.distance(actorPosition) < (activationDistance * fudgeFactor)) + { + // assume actor touched trap + MWMechanics::CastSpell cast(mTrapSource, actor); + cast.mHitPosition = actorPosition; + cast.cast(mSpellId); + } + else + { + // assume telekinesis used + MWMechanics::CastSpell cast(mTrapSource, mTrapSource); + cast.mHitPosition = trapPosition; + cast.cast(mSpellId); + } mTrapSource.getCellRef().setTrap(""); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 8bcfcb421..333f172b9 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3128,7 +3128,7 @@ namespace MWWorld mRendering->spawnEffect(model, textureOverride, worldPos); } - void World::explodeSpell(const Vector3 &origin, const ESM::EffectList &effects, const Ptr &caster, int rangeType, + void World::explodeSpell(const Vector3 &origin, const ESM::EffectList &effects, const Ptr &caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName) { std::map > toApply; @@ -3187,7 +3187,7 @@ namespace MWWorld cast.mStack = false; ESM::EffectList effects; effects.mList = apply->second; - cast.inflict(apply->first, caster, effects, (ESM::RangeType)rangeType, false, true); + cast.inflict(apply->first, caster, effects, rangeType, false, true); } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 9834015ac..84da984f8 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -627,7 +627,7 @@ namespace MWWorld virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const Ogre::Vector3& worldPos); virtual void explodeSpell (const Ogre::Vector3& origin, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, int rangeType, const std::string& id, const std::string& sourceName); + const MWWorld::Ptr& caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName); virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor);