diff --git a/apps/openmw/mwworld/action.cpp b/apps/openmw/mwworld/action.cpp index c29377ecb..35cd99de7 100644 --- a/apps/openmw/mwworld/action.cpp +++ b/apps/openmw/mwworld/action.cpp @@ -42,7 +42,35 @@ void MWWorld::Action::execute (const Ptr& actor) } } - executeImp (actor); + executeImp(actor); +} + +void MWWorld::Action::execute (const Ptr& actor, float distanceToObject) +{ + if(!mSoundId.empty()) + { + if(mKeepSound && actor == MWMechanics::getPlayer()) + MWBase::Environment::get().getSoundManager()->playSound(mSoundId, 1.0, 1.0, + MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Normal, mSoundOffset + ); + else + { + bool local = mTarget.isEmpty() || !mTarget.isInCell(); // no usable target + if(mKeepSound) + MWBase::Environment::get().getSoundManager()->playSound3D( + (local ? actor : mTarget).getRefData().getPosition().asVec3(), + mSoundId, 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, + MWBase::SoundManager::Play_Normal, mSoundOffset + ); + else + MWBase::Environment::get().getSoundManager()->playSound3D(local ? actor : mTarget, + mSoundId, 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, + MWBase::SoundManager::Play_Normal, mSoundOffset + ); + } + } + + executeImp(actor, distanceToObject); } void MWWorld::Action::setSound (const std::string& id) diff --git a/apps/openmw/mwworld/action.hpp b/apps/openmw/mwworld/action.hpp index 38907cf44..867c1e27c 100644 --- a/apps/openmw/mwworld/action.hpp +++ b/apps/openmw/mwworld/action.hpp @@ -19,7 +19,9 @@ namespace MWWorld Action (const Action& action); Action& operator= (const Action& action); - virtual void executeImp (const Ptr& actor) = 0; + virtual void executeImp (const Ptr& actor) { return; } + virtual void executeImp (const Ptr& actor, float distanceToObject) { return; } + protected: @@ -36,6 +38,7 @@ namespace MWWorld ///< Is running this action a no-op? (default false) void execute (const Ptr& actor); + void execute (const Ptr& actor, float distanceToObject); void setSound (const std::string& id); void setSoundOffset(float offset); diff --git a/apps/openmw/mwworld/actiontrap.cpp b/apps/openmw/mwworld/actiontrap.cpp index 68d7c69e9..0279eea3e 100644 --- a/apps/openmw/mwworld/actiontrap.cpp +++ b/apps/openmw/mwworld/actiontrap.cpp @@ -7,20 +7,20 @@ namespace MWWorld { - void ActionTrap::executeImp(const Ptr &actor) + void ActionTrap::executeImp(const Ptr &actor, float distance) { osg::Vec3f actorPosition(actor.getRefData().getPosition().asVec3()); osg::Vec3f trapPosition(mTrapSource.getRefData().getPosition().asVec3()); float activationDistance = MWBase::Environment::get().getWorld()->getMaxActivationDistance(); // GUI calcs if object in activation distance include object and player geometry - const float fudgeFactor = 1.25f; + //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 - actorPosition).length() < (activationDistance * fudgeFactor)) + if (distance < activationDistance) { // assume actor touched trap MWMechanics::CastSpell cast(mTrapSource, actor); diff --git a/apps/openmw/mwworld/actiontrap.hpp b/apps/openmw/mwworld/actiontrap.hpp index 4c2f4139f..7fd6f2bcc 100644 --- a/apps/openmw/mwworld/actiontrap.hpp +++ b/apps/openmw/mwworld/actiontrap.hpp @@ -13,7 +13,7 @@ namespace MWWorld std::string mSpellId; MWWorld::Ptr mTrapSource; - virtual void executeImp (const Ptr& actor); + virtual void executeImp (const Ptr& actor, float distance); public: diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5b156cba0..f3ed54eaf 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3228,7 +3228,20 @@ namespace MWWorld if (object.getRefData().activate()) { boost::shared_ptr action = (object.getClass().activate(object, actor)); - action->execute (actor); + if (object.getCellRef().getTrap() != "") // If the object is trapped, do a distance check to account for opening with telekinesis + { + float distanceToObject; + if (actor == getPlayerPtr()) // If the actor doing the activation is the player, get distance using the raycast in getFacedObject() + MWWorld::Ptr result = getFacedObject(1.0f, distanceToObject, true); + else // Otherwise do a position-based distance check + { + osg::Vec3f actorPosition(actor.getRefData().getPosition().asVec3()); + osg::Vec3f objectPosition(object.getRefData().getPosition().asVec3()); + distanceToObject = (objectPosition - actorPosition).length(); + } + action->execute (actor, distanceToObject); + } + action->execute (actor); } }