From b29e9e9c77a73755f420b0eb89361998a4ed6657 Mon Sep 17 00:00:00 2001 From: Allofich Date: Fri, 1 Jul 2016 02:27:20 +0900 Subject: [PATCH 01/17] Don't allow telekinesis on actors or teleport doors --- apps/openmw/mwworld/worldimp.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 313fe73b1..5bc38005d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1025,6 +1025,10 @@ namespace MWWorld float activationDistance = getMaxActivationDistance() + telekinesisRangeBonus; facedObject = getFacedObject(activationDistance); + if (!facedObject.isEmpty() && !facedObject.getClass().isActor() && !facedObject.getCellRef().getTeleport()) + return facedObject; + else + facedObject = getFacedObject(getMaxActivationDistance()); } return facedObject; From 574e40db5e34ebd0827b21be52c4f35f24ca0aaa Mon Sep 17 00:00:00 2001 From: Allofich Date: Mon, 4 Jul 2016 01:50:47 +0900 Subject: [PATCH 02/17] Don't allow telekinesis on activators --- apps/openmw/mwworld/worldimp.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5bc38005d..6915a389c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1025,7 +1025,10 @@ namespace MWWorld float activationDistance = getMaxActivationDistance() + telekinesisRangeBonus; facedObject = getFacedObject(activationDistance); - if (!facedObject.isEmpty() && !facedObject.getClass().isActor() && !facedObject.getCellRef().getTeleport()) + + // Not allowing telekinesis on actors, on doors that teleport to other cells, or on activators + // Original engine doesn't allow telekinesis on books or lights, either + if (!facedObject.isEmpty() && !facedObject.getClass().isActor() && !facedObject.getCellRef().getTeleport() && facedObject.getClass().getTypeName() != "struct ESM::Activator") return facedObject; else facedObject = getFacedObject(getMaxActivationDistance()); From 64d53a2314976f87165102aa79c811e444269354 Mon Sep 17 00:00:00 2001 From: Allofich Date: Mon, 4 Jul 2016 02:11:30 +0900 Subject: [PATCH 03/17] Avoid double raycasts when using getFacedObject --- apps/openmw/mwrender/renderingmanager.cpp | 4 ++- apps/openmw/mwrender/renderingmanager.hpp | 1 + apps/openmw/mwworld/worldimp.cpp | 37 ++++++++++++++++++++--- apps/openmw/mwworld/worldimp.hpp | 6 ++++ 4 files changed, 42 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index ea3e7b7ee..c9be3bdcb 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -738,7 +738,9 @@ namespace MWRender mViewer->getCamera()->accept(*createIntersectionVisitor(intersector, ignorePlayer, ignoreActors)); - return getIntersectionResult(intersector); + RayResult result = getIntersectionResult(intersector); + result.mDistanceToFirstIntersection = maxDistance * intersector->getFirstIntersection().ratio; + return result; } void RenderingManager::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index ebe75d39b..3345d121f 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -120,6 +120,7 @@ namespace MWRender osg::Vec3f mHitNormalWorld; osg::Vec3f mHitPointWorld; MWWorld::Ptr mHitObject; + float mDistanceToFirstIntersection; }; RayResult castRay(const osg::Vec3f& origin, const osg::Vec3f& dest, bool ignorePlayer, bool ignoreActors=false); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6915a389c..5b156cba0 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1,4 +1,5 @@ #include "worldimp.hpp" +#include #include #include @@ -1023,15 +1024,16 @@ namespace MWWorld telekinesisRangeBonus = feetToGameUnits(telekinesisRangeBonus); float activationDistance = getMaxActivationDistance() + telekinesisRangeBonus; + float distanceToObject; - facedObject = getFacedObject(activationDistance); + facedObject = getFacedObject(activationDistance, distanceToObject, true); // Not allowing telekinesis on actors, on doors that teleport to other cells, or on activators // Original engine doesn't allow telekinesis on books or lights, either - if (!facedObject.isEmpty() && !facedObject.getClass().isActor() && !facedObject.getCellRef().getTeleport() && facedObject.getClass().getTypeName() != "struct ESM::Activator") - return facedObject; - else - facedObject = getFacedObject(getMaxActivationDistance()); + if (!facedObject.isEmpty() && (facedObject.getClass().isActor() + || facedObject.getCellRef().getTeleport() || facedObject.getClass().getTypeName() == "struct ESM::Activator") + && (distanceToObject > getMaxActivationDistance())) + return 0; } return facedObject; @@ -1731,6 +1733,31 @@ namespace MWWorld return mRendering->castCameraToViewportRay(0.5f, 0.5f, maxDistance, ignorePlayer).mHitObject; } } + + MWWorld::Ptr World::getFacedObject(float maxDistance, float& distance, bool ignorePlayer) + { + maxDistance += mRendering->getCameraDistance(); + MWWorld::Ptr facedObject; + + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) + { + float x, y; + MWBase::Environment::get().getWindowManager()->getMousePosition(x, y); + MWRender::RenderingManager::RayResult rayToObject = mRendering->castCameraToViewportRay(x, y, maxDistance, ignorePlayer); + facedObject = rayToObject.mHitObject; + if (!facedObject.isEmpty()) + distance = rayToObject.mDistanceToFirstIntersection; + return facedObject; + } + else + { + MWRender::RenderingManager::RayResult rayToObject = mRendering->castCameraToViewportRay(0.5f, 0.5f, maxDistance, ignorePlayer); + facedObject = rayToObject.mHitObject; + if (!facedObject.isEmpty()) + distance = rayToObject.mDistanceToFirstIntersection; + return facedObject; + } + } bool World::isCellExterior() const { diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 7af632d23..d5c3c7815 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -127,7 +127,13 @@ namespace MWWorld void updateSoundListener(); void updateWindowManager (); void updatePlayer(bool paused); + + /// Return faced object MWWorld::Ptr getFacedObject(float maxDistance, bool ignorePlayer=true); + + /// Return faced object and distance from player to it + MWWorld::Ptr getFacedObject(float maxDistance, float& distanceToObject, bool ignorePlayer=true); + public: // FIXME void removeContainerScripts(const Ptr& reference); private: From 64d298d2b54fe6e13ab9dc4e4c171ebe21a287b2 Mon Sep 17 00:00:00 2001 From: Allofich Date: Mon, 4 Jul 2016 02:23:04 +0900 Subject: [PATCH 04/17] Use raycast distance when player activates trapped object --- apps/openmw/mwworld/action.cpp | 30 +++++++++++++++++++++++++++++- apps/openmw/mwworld/action.hpp | 5 ++++- apps/openmw/mwworld/actiontrap.cpp | 6 +++--- apps/openmw/mwworld/actiontrap.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 15 ++++++++++++++- 5 files changed, 51 insertions(+), 7 deletions(-) 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); } } From 199607423b3f06391598fae265ca4c7773fa84e5 Mon Sep 17 00:00:00 2001 From: Allofich Date: Mon, 4 Jul 2016 02:24:45 +0900 Subject: [PATCH 05/17] Use iMaxActivateDist for AI actors that use Activate packages --- apps/openmw/mwmechanics/aiactivate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aiactivate.cpp b/apps/openmw/mwmechanics/aiactivate.cpp index 3c5504228..a79adbc8b 100644 --- a/apps/openmw/mwmechanics/aiactivate.cpp +++ b/apps/openmw/mwmechanics/aiactivate.cpp @@ -39,7 +39,7 @@ namespace MWMechanics //Set the target desition from the actor ESM::Pathgrid::Point dest = target.getRefData().getPosition().pos; - if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]) < 200) { //Stop when you get close + if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]) < MWBase::Environment::get().getWorld()->getMaxActivationDistance()) { //Stop when you get in activation range actor.getClass().getMovementSettings(actor).mPosition[1] = 0; MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr(mObjectId,false); From c02695e56d3d5298407f6cdb9e5854b0aa695492 Mon Sep 17 00:00:00 2001 From: Allofich Date: Mon, 4 Jul 2016 14:39:44 +0900 Subject: [PATCH 06/17] Cleanups and fixes --- apps/openmw/mwworld/action.cpp | 36 ++++--------------------- apps/openmw/mwworld/action.hpp | 3 +-- apps/openmw/mwworld/actiontrap.cpp | 16 +++++------ apps/openmw/mwworld/worldimp.cpp | 43 ++++++++++-------------------- apps/openmw/mwworld/worldimp.hpp | 8 +++--- 5 files changed, 30 insertions(+), 76 deletions(-) diff --git a/apps/openmw/mwworld/action.cpp b/apps/openmw/mwworld/action.cpp index 35cd99de7..028080d7a 100644 --- a/apps/openmw/mwworld/action.cpp +++ b/apps/openmw/mwworld/action.cpp @@ -17,7 +17,7 @@ MWWorld::Action::Action (bool keepSound, const Ptr& target) : mKeepSound (keepSo MWWorld::Action::~Action() {} -void MWWorld::Action::execute (const Ptr& actor) +void MWWorld::Action::execute (const Ptr& actor, float distanceToObject, bool useDistance) { if(!mSoundId.empty()) { @@ -41,36 +41,10 @@ void MWWorld::Action::execute (const Ptr& 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); + if (useDistance) + executeImp(actor, distanceToObject); + else + executeImp(actor); } void MWWorld::Action::setSound (const std::string& id) diff --git a/apps/openmw/mwworld/action.hpp b/apps/openmw/mwworld/action.hpp index 867c1e27c..39df539cd 100644 --- a/apps/openmw/mwworld/action.hpp +++ b/apps/openmw/mwworld/action.hpp @@ -37,8 +37,7 @@ namespace MWWorld virtual bool isNullAction() { return false; } ///< Is running this action a no-op? (default false) - void execute (const Ptr& actor); - void execute (const Ptr& actor, float distanceToObject); + void execute (const Ptr& actor, float distanceToObject = 0, bool useDistance = false); 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 0279eea3e..a8b937c0a 100644 --- a/apps/openmw/mwworld/actiontrap.cpp +++ b/apps/openmw/mwworld/actiontrap.cpp @@ -1,40 +1,36 @@ #include "actiontrap.hpp" #include "../mwmechanics/spellcasting.hpp" + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" namespace MWWorld { - 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; - - // 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 + // 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. + // Using the activation distance as the trap range. + if (distance < activationDistance) { - // assume actor touched trap + // actor activated object within range of trap MWMechanics::CastSpell cast(mTrapSource, actor); cast.mHitPosition = actorPosition; cast.cast(mSpellId); } else { - // assume telekinesis used + // actor activated object outside range of trap 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 f3ed54eaf..e54c75afe 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1,5 +1,4 @@ #include "worldimp.hpp" -#include #include #include @@ -151,7 +150,7 @@ namespace MWWorld mSky (true), mCells (mStore, mEsm), mGodMode(false), mScriptsEnabled(true), mContentFiles (contentFiles), mActivationDistanceOverride (activationDistanceOverride), mStartupScript(startupScript), - mStartCell (startCell), mTeleportEnabled(true), + mStartCell (startCell), mDistanceToFacedObject(0), mTeleportEnabled(true), mLevitationEnabled(true), mGoToJail(false), mDaysInPrison(0) { mPhysics = new MWPhysics::PhysicsSystem(resourceSystem, rootNode); @@ -1012,10 +1011,11 @@ namespace MWWorld MWWorld::Ptr World::getFacedObject() { MWWorld::Ptr facedObject; + float distanceToObject; if (MWBase::Environment::get().getWindowManager()->isGuiMode() && MWBase::Environment::get().getWindowManager()->isConsoleMode()) - facedObject = getFacedObject(getMaxActivationDistance() * 50, false); + facedObject = getFacedObject(getMaxActivationDistance() * 50, distanceToObject, false); else { float telekinesisRangeBonus = @@ -1024,7 +1024,6 @@ namespace MWWorld telekinesisRangeBonus = feetToGameUnits(telekinesisRangeBonus); float activationDistance = getMaxActivationDistance() + telekinesisRangeBonus; - float distanceToObject; facedObject = getFacedObject(activationDistance, distanceToObject, true); @@ -1036,6 +1035,8 @@ namespace MWWorld return 0; } + mDistanceToFacedObject = distanceToObject; + mFacedObject = facedObject; return facedObject; } @@ -1718,22 +1719,6 @@ namespace MWWorld } } - MWWorld::Ptr World::getFacedObject(float maxDistance, bool ignorePlayer) - { - maxDistance += mRendering->getCameraDistance(); - - if (MWBase::Environment::get().getWindowManager()->isGuiMode()) - { - float x, y; - MWBase::Environment::get().getWindowManager()->getMousePosition(x, y); - return mRendering->castCameraToViewportRay(x, y, maxDistance, ignorePlayer).mHitObject; - } - else - { - return mRendering->castCameraToViewportRay(0.5f, 0.5f, maxDistance, ignorePlayer).mHitObject; - } - } - MWWorld::Ptr World::getFacedObject(float maxDistance, float& distance, bool ignorePlayer) { maxDistance += mRendering->getCameraDistance(); @@ -3228,20 +3213,20 @@ namespace MWWorld if (object.getRefData().activate()) { boost::shared_ptr action = (object.getClass().activate(object, actor)); - if (object.getCellRef().getTrap() != "") // If the object is trapped, do a distance check to account for opening with telekinesis + if (object.getCellRef().getTrap() != "") { - 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 + // For the distance check to a trapped object, use the raycast-derived distance if we have it + if (actor == getPlayerPtr() && (object == mFacedObject)) + action->execute (actor, mDistanceToFacedObject, true); + else // Otherwise use a position comparison { 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, (objectPosition - actorPosition).length(), true); + } } - action->execute (actor); + else + action->execute (actor); } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index d5c3c7815..b1cc08120 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -128,10 +128,6 @@ namespace MWWorld void updateWindowManager (); void updatePlayer(bool paused); - /// Return faced object - MWWorld::Ptr getFacedObject(float maxDistance, bool ignorePlayer=true); - - /// Return faced object and distance from player to it MWWorld::Ptr getFacedObject(float maxDistance, float& distanceToObject, bool ignorePlayer=true); public: // FIXME @@ -160,6 +156,10 @@ namespace MWWorld const std::vector& content, ContentLoader& contentLoader); float mSwimHeightScale; + + float mDistanceToFacedObject; + MWWorld::Ptr mFacedObject; + bool isUnderwater(const MWWorld::ConstPtr &object, const float heightRatio) const; ///< helper function for implementing isSwimming(), isSubmerged(), isWading() From c1236f4113ae3a395ce1f9738533bbbc42219d29 Mon Sep 17 00:00:00 2001 From: Allofich Date: Mon, 4 Jul 2016 19:09:12 +0900 Subject: [PATCH 07/17] Simplified code --- apps/openmw/mwworld/action.cpp | 4 ++-- apps/openmw/mwworld/action.hpp | 2 +- apps/openmw/mwworld/actiontrap.cpp | 32 ++++++++++++++++++------------ apps/openmw/mwworld/actiontrap.hpp | 6 +++++- apps/openmw/mwworld/worldimp.cpp | 19 +++++------------- apps/openmw/mwworld/worldimp.hpp | 1 - 6 files changed, 32 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwworld/action.cpp b/apps/openmw/mwworld/action.cpp index 028080d7a..748e30ceb 100644 --- a/apps/openmw/mwworld/action.cpp +++ b/apps/openmw/mwworld/action.cpp @@ -17,7 +17,7 @@ MWWorld::Action::Action (bool keepSound, const Ptr& target) : mKeepSound (keepSo MWWorld::Action::~Action() {} -void MWWorld::Action::execute (const Ptr& actor, float distanceToObject, bool useDistance) +void MWWorld::Action::execute (const Ptr& actor, float distanceToObject) { if(!mSoundId.empty()) { @@ -41,7 +41,7 @@ void MWWorld::Action::execute (const Ptr& actor, float distanceToObject, bool us ); } } - if (useDistance) + if (distanceToObject != 0) executeImp(actor, distanceToObject); else executeImp(actor); diff --git a/apps/openmw/mwworld/action.hpp b/apps/openmw/mwworld/action.hpp index 39df539cd..e363927ff 100644 --- a/apps/openmw/mwworld/action.hpp +++ b/apps/openmw/mwworld/action.hpp @@ -37,7 +37,7 @@ namespace MWWorld virtual bool isNullAction() { return false; } ///< Is running this action a no-op? (default false) - void execute (const Ptr& actor, float distanceToObject = 0, bool useDistance = false); + void execute (const Ptr& actor, float distanceToObject = 0); 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 a8b937c0a..86e232302 100644 --- a/apps/openmw/mwworld/actiontrap.cpp +++ b/apps/openmw/mwworld/actiontrap.cpp @@ -7,30 +7,36 @@ namespace MWWorld { - void ActionTrap::executeImp(const Ptr &actor, float distance) + // actor activated object without telekinesis, so trap will hit + void ActionTrap::executeImp(const Ptr &actor) { osg::Vec3f actorPosition(actor.getRefData().getPosition().asVec3()); + + MWMechanics::CastSpell cast(mTrapSource, actor); + cast.mHitPosition = actorPosition; + cast.cast(mSpellId); + + mTrapSource.getCellRef().setTrap(""); + } + + // actor activated object with telekinesis, so trap may or may not hit + void ActionTrap::executeImp(const Ptr &actor, float distance) + { osg::Vec3f trapPosition(mTrapSource.getRefData().getPosition().asVec3()); float activationDistance = MWBase::Environment::get().getWorld()->getMaxActivationDistance(); // 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. - // Using the activation distance as the trap range. + // Using activation distance as the trap range. - if (distance < activationDistance) + if (distance < activationDistance) // actor activated object within range of trap + executeImp(actor); + else // actor activated object outside range of trap { - // actor activated object within range of trap - MWMechanics::CastSpell cast(mTrapSource, actor); - cast.mHitPosition = actorPosition; - cast.cast(mSpellId); - } - else - { - // actor activated object outside range of trap MWMechanics::CastSpell cast(mTrapSource, mTrapSource); cast.mHitPosition = trapPosition; cast.cast(mSpellId); - } - mTrapSource.getCellRef().setTrap(""); + mTrapSource.getCellRef().setTrap(""); + } } } diff --git a/apps/openmw/mwworld/actiontrap.hpp b/apps/openmw/mwworld/actiontrap.hpp index 7fd6f2bcc..73a43b354 100644 --- a/apps/openmw/mwworld/actiontrap.hpp +++ b/apps/openmw/mwworld/actiontrap.hpp @@ -13,7 +13,11 @@ namespace MWWorld std::string mSpellId; MWWorld::Ptr mTrapSource; - virtual void executeImp (const Ptr& actor, float distance); + /// Activating trapped object without telekinesis active or within trap range + virtual void executeImp (const Ptr& actor); + + /// Activating trapped object with telekinesis active + virtual void executeImp (const Ptr& actor, float distanceToObject); public: diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index e54c75afe..a6ea308e8 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1036,7 +1036,6 @@ namespace MWWorld } mDistanceToFacedObject = distanceToObject; - mFacedObject = facedObject; return facedObject; } @@ -3213,19 +3212,11 @@ namespace MWWorld if (object.getRefData().activate()) { boost::shared_ptr action = (object.getClass().activate(object, actor)); - if (object.getCellRef().getTrap() != "") - { - // For the distance check to a trapped object, use the raycast-derived distance if we have it - if (actor == getPlayerPtr() && (object == mFacedObject)) - action->execute (actor, mDistanceToFacedObject, true); - else // Otherwise use a position comparison - { - osg::Vec3f actorPosition(actor.getRefData().getPosition().asVec3()); - osg::Vec3f objectPosition(object.getRefData().getPosition().asVec3()); - action->execute (actor, (objectPosition - actorPosition).length(), true); - } - } - else + // If the player is opening a trap with telekinesis on, use the raycast-derived distance to check if the trap should hit + if (object.getCellRef().getTrap() != "" && actor == getPlayerPtr() && mPlayer->getPlayer().getClass().getCreatureStats(mPlayer->getPlayer()).getMagicEffects() + .get(ESM::MagicEffect::Telekinesis).getMagnitude() > 0) + action->execute (actor, mDistanceToFacedObject); + else // Otherwise just activate, and if it's trapped it will always hit action->execute (actor); } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index b1cc08120..64160018f 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -158,7 +158,6 @@ namespace MWWorld float mSwimHeightScale; float mDistanceToFacedObject; - MWWorld::Ptr mFacedObject; bool isUnderwater(const MWWorld::ConstPtr &object, const float heightRatio) const; ///< helper function for implementing isSwimming(), isSubmerged(), isWading() From e25e6989781cfe03ce989acb0e907787fde86f10 Mon Sep 17 00:00:00 2001 From: Allofich Date: Mon, 4 Jul 2016 23:27:02 +0900 Subject: [PATCH 08/17] Fix telekinesis check for activators --- apps/openmw/mwworld/worldimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a6ea308e8..f1cee80f1 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1030,7 +1030,7 @@ namespace MWWorld // Not allowing telekinesis on actors, on doors that teleport to other cells, or on activators // Original engine doesn't allow telekinesis on books or lights, either if (!facedObject.isEmpty() && (facedObject.getClass().isActor() - || facedObject.getCellRef().getTeleport() || facedObject.getClass().getTypeName() == "struct ESM::Activator") + || facedObject.getCellRef().getTeleport() || facedObject.getClass().getTypeName() == typeid(ESM::Activator).name()) && (distanceToObject > getMaxActivationDistance())) return 0; } From 538209b0a240cc8b113c1280c599d814c9ee6e89 Mon Sep 17 00:00:00 2001 From: Allofich Date: Wed, 6 Jul 2016 22:03:37 +0900 Subject: [PATCH 09/17] Change variable to mRatio and initialize it --- apps/openmw/mwrender/renderingmanager.cpp | 6 +++--- apps/openmw/mwrender/renderingmanager.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c9be3bdcb..c18fa9dd2 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -668,6 +668,7 @@ namespace MWRender { RenderingManager::RayResult result; result.mHit = false; + result.mRatio = 0; if (intersector->containsIntersections()) { result.mHit = true; @@ -675,6 +676,7 @@ namespace MWRender result.mHitPointWorld = intersection.getWorldIntersectPoint(); result.mHitNormalWorld = intersection.getWorldIntersectNormal(); + result.mRatio = intersection.ratio; PtrHolder* ptrHolder = NULL; for (osg::NodePath::const_iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end(); ++it) @@ -738,9 +740,7 @@ namespace MWRender mViewer->getCamera()->accept(*createIntersectionVisitor(intersector, ignorePlayer, ignoreActors)); - RayResult result = getIntersectionResult(intersector); - result.mDistanceToFirstIntersection = maxDistance * intersector->getFirstIntersection().ratio; - return result; + return getIntersectionResult(intersector); } void RenderingManager::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 3345d121f..d2adbd31f 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -120,7 +120,7 @@ namespace MWRender osg::Vec3f mHitNormalWorld; osg::Vec3f mHitPointWorld; MWWorld::Ptr mHitObject; - float mDistanceToFirstIntersection; + float mRatio; }; RayResult castRay(const osg::Vec3f& origin, const osg::Vec3f& dest, bool ignorePlayer, bool ignoreActors=false); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f1cee80f1..35749049d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1730,7 +1730,7 @@ namespace MWWorld MWRender::RenderingManager::RayResult rayToObject = mRendering->castCameraToViewportRay(x, y, maxDistance, ignorePlayer); facedObject = rayToObject.mHitObject; if (!facedObject.isEmpty()) - distance = rayToObject.mDistanceToFirstIntersection; + distance = rayToObject.mRatio * maxDistance; return facedObject; } else @@ -1738,7 +1738,7 @@ namespace MWWorld MWRender::RenderingManager::RayResult rayToObject = mRendering->castCameraToViewportRay(0.5f, 0.5f, maxDistance, ignorePlayer); facedObject = rayToObject.mHitObject; if (!facedObject.isEmpty()) - distance = rayToObject.mDistanceToFirstIntersection; + distance = rayToObject.mRatio * maxDistance; return facedObject; } } From 8014f37879e1de82a443cd684fd9c1085a0adc55 Mon Sep 17 00:00:00 2001 From: Allofich Date: Wed, 6 Jul 2016 22:09:39 +0900 Subject: [PATCH 10/17] Avoid duplicate code --- apps/openmw/mwworld/worldimp.cpp | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 35749049d..c2d27e60e 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1722,25 +1722,21 @@ namespace MWWorld { maxDistance += mRendering->getCameraDistance(); MWWorld::Ptr facedObject; + MWRender::RenderingManager::RayResult rayToObject; if (MWBase::Environment::get().getWindowManager()->isGuiMode()) { float x, y; MWBase::Environment::get().getWindowManager()->getMousePosition(x, y); - MWRender::RenderingManager::RayResult rayToObject = mRendering->castCameraToViewportRay(x, y, maxDistance, ignorePlayer); - facedObject = rayToObject.mHitObject; - if (!facedObject.isEmpty()) - distance = rayToObject.mRatio * maxDistance; - return facedObject; + rayToObject = mRendering->castCameraToViewportRay(x, y, maxDistance, ignorePlayer); } else - { - MWRender::RenderingManager::RayResult rayToObject = mRendering->castCameraToViewportRay(0.5f, 0.5f, maxDistance, ignorePlayer); - facedObject = rayToObject.mHitObject; - if (!facedObject.isEmpty()) - distance = rayToObject.mRatio * maxDistance; - return facedObject; - } + rayToObject = mRendering->castCameraToViewportRay(0.5f, 0.5f, maxDistance, ignorePlayer); + + facedObject = rayToObject.mHitObject; + if (!facedObject.isEmpty()) + distance = rayToObject.mRatio * maxDistance; + return facedObject; } bool World::isCellExterior() const From 35a23c3b49b7986a8d288e0af625d4041a8be626 Mon Sep 17 00:00:00 2001 From: Allofich Date: Thu, 7 Jul 2016 00:03:14 +0900 Subject: [PATCH 11/17] Implement and use new method allowTelekinesis() --- apps/openmw/mwclass/activator.cpp | 4 ++++ apps/openmw/mwclass/activator.hpp | 3 +++ apps/openmw/mwclass/actor.cpp | 4 ++++ apps/openmw/mwclass/actor.hpp | 3 +++ apps/openmw/mwclass/door.cpp | 8 ++++++++ apps/openmw/mwclass/door.hpp | 3 +++ apps/openmw/mwworld/class.hpp | 3 +++ apps/openmw/mwworld/worldimp.cpp | 7 ++----- 8 files changed, 30 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 9785eef1e..b3747f916 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -81,6 +81,10 @@ namespace MWClass return (ref->mBase->mName != ""); } + bool Activator::allowTelekinesis(const MWWorld::ConstPtr &ptr) const { + return false; + } + MWGui::ToolTipInfo Activator::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/activator.hpp b/apps/openmw/mwclass/activator.hpp index 15dbf5767..e90620cea 100644 --- a/apps/openmw/mwclass/activator.hpp +++ b/apps/openmw/mwclass/activator.hpp @@ -24,6 +24,9 @@ namespace MWClass virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) + virtual bool allowTelekinesis(const MWWorld::ConstPtr& ptr) const; + ///< Return whether this class of object can be activated with telekinesis + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. diff --git a/apps/openmw/mwclass/actor.cpp b/apps/openmw/mwclass/actor.cpp index 4e89c7282..56de5e3f8 100644 --- a/apps/openmw/mwclass/actor.cpp +++ b/apps/openmw/mwclass/actor.cpp @@ -79,4 +79,8 @@ namespace MWClass weight += effects.get(MWMechanics::EffectKey(ESM::MagicEffect::Burden)).getMagnitude(); return (weight < 0) ? 0.0f : weight; } + + bool Actor::allowTelekinesis(const MWWorld::ConstPtr &ptr) const { + return false; + } } diff --git a/apps/openmw/mwclass/actor.hpp b/apps/openmw/mwclass/actor.hpp index 88a3f1a32..1aca5e660 100644 --- a/apps/openmw/mwclass/actor.hpp +++ b/apps/openmw/mwclass/actor.hpp @@ -35,6 +35,9 @@ namespace MWClass ///< Returns total weight of objects inside this object (including modifications from magic /// effects). Throws an exception, if the object can't hold other objects. + virtual bool allowTelekinesis(const MWWorld::ConstPtr& ptr) const; + ///< Return whether this class of object can be activated with telekinesis + // not implemented Actor(const Actor&); Actor& operator= (const Actor&); diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 8d54dff5d..81188fe10 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -213,6 +213,14 @@ namespace MWClass return true; } + bool Door::allowTelekinesis(const MWWorld::ConstPtr &ptr) const + { + if (ptr.getCellRef().getTeleport()) + return false; + else + return true; + } + std::string Door::getScript (const MWWorld::ConstPtr& ptr) const { const MWWorld::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index 42aa6d64d..906b18511 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -45,6 +45,9 @@ namespace MWClass virtual bool canLock(const MWWorld::ConstPtr &ptr) const; + virtual bool allowTelekinesis(const MWWorld::ConstPtr &ptr) const; + ///< Return whether this class of object can be activated with telekinesis + virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 0bb3edbee..23128ea9d 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -279,6 +279,9 @@ namespace MWWorld virtual bool isKey (const MWWorld::ConstPtr& ptr) const { return false; } virtual bool isGold(const MWWorld::ConstPtr& ptr) const { return false; } + + virtual bool allowTelekinesis(const MWWorld::ConstPtr& ptr) const { return true; } + ///< Return whether this class of object can be activated with telekinesis /// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini) virtual int getBloodTexture (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index c2d27e60e..869ccdfe5 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1027,11 +1027,8 @@ namespace MWWorld facedObject = getFacedObject(activationDistance, distanceToObject, true); - // Not allowing telekinesis on actors, on doors that teleport to other cells, or on activators - // Original engine doesn't allow telekinesis on books or lights, either - if (!facedObject.isEmpty() && (facedObject.getClass().isActor() - || facedObject.getCellRef().getTeleport() || facedObject.getClass().getTypeName() == typeid(ESM::Activator).name()) - && (distanceToObject > getMaxActivationDistance())) + if (!facedObject.isEmpty() && !facedObject.getClass().allowTelekinesis(facedObject) + && distanceToObject > getMaxActivationDistance()) return 0; } From cb621939fdbb9c54390deb7ec6b8713fb274ae33 Mon Sep 17 00:00:00 2001 From: Allofich Date: Thu, 7 Jul 2016 04:03:56 +0900 Subject: [PATCH 12/17] Streamline trap code --- apps/openmw/mwworld/action.cpp | 6 +++--- apps/openmw/mwworld/action.hpp | 2 +- apps/openmw/mwworld/actiontrap.cpp | 28 ++++++++++------------------ apps/openmw/mwworld/actiontrap.hpp | 8 ++------ apps/openmw/mwworld/worldimp.cpp | 7 +------ 5 files changed, 17 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwworld/action.cpp b/apps/openmw/mwworld/action.cpp index 748e30ceb..e76ff8105 100644 --- a/apps/openmw/mwworld/action.cpp +++ b/apps/openmw/mwworld/action.cpp @@ -17,7 +17,7 @@ MWWorld::Action::Action (bool keepSound, const Ptr& target) : mKeepSound (keepSo MWWorld::Action::~Action() {} -void MWWorld::Action::execute (const Ptr& actor, float distanceToObject) +void MWWorld::Action::execute (const Ptr& actor, float distanceToFacedObject) { if(!mSoundId.empty()) { @@ -41,8 +41,8 @@ void MWWorld::Action::execute (const Ptr& actor, float distanceToObject) ); } } - if (distanceToObject != 0) - executeImp(actor, distanceToObject); + if (mTarget.getCellRef().getTrap() != "") + executeImp(actor, distanceToFacedObject); else executeImp(actor); } diff --git a/apps/openmw/mwworld/action.hpp b/apps/openmw/mwworld/action.hpp index e363927ff..d61e72551 100644 --- a/apps/openmw/mwworld/action.hpp +++ b/apps/openmw/mwworld/action.hpp @@ -37,7 +37,7 @@ namespace MWWorld virtual bool isNullAction() { return false; } ///< Is running this action a no-op? (default false) - void execute (const Ptr& actor, float distanceToObject = 0); + void execute (const Ptr& actor, float distanceToObject = -1); 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 86e232302..991e05313 100644 --- a/apps/openmw/mwworld/actiontrap.cpp +++ b/apps/openmw/mwworld/actiontrap.cpp @@ -7,36 +7,28 @@ namespace MWWorld { - // actor activated object without telekinesis, so trap will hit - void ActionTrap::executeImp(const Ptr &actor) - { - osg::Vec3f actorPosition(actor.getRefData().getPosition().asVec3()); - - MWMechanics::CastSpell cast(mTrapSource, actor); - cast.mHitPosition = actorPosition; - cast.cast(mSpellId); - - mTrapSource.getCellRef().setTrap(""); - } - - // actor activated object with telekinesis, so trap may or may not hit 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(); + float trapRange = MWBase::Environment::get().getWorld()->getMaxActivationDistance(); // 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. // Using activation distance as the trap range. - if (distance < activationDistance) // actor activated object within range of trap - executeImp(actor); - else // actor activated object outside range of trap + if (distance > trapRange) // actor activated object outside range of trap { MWMechanics::CastSpell cast(mTrapSource, mTrapSource); cast.mHitPosition = trapPosition; + cast.cast(mSpellId); + } + else // actor activated object within range of trap + { + MWMechanics::CastSpell cast(mTrapSource, actor); + cast.mHitPosition = actorPosition; cast.cast(mSpellId); - mTrapSource.getCellRef().setTrap(""); } + mTrapSource.getCellRef().setTrap(""); } } diff --git a/apps/openmw/mwworld/actiontrap.hpp b/apps/openmw/mwworld/actiontrap.hpp index 73a43b354..5fb76eb5d 100644 --- a/apps/openmw/mwworld/actiontrap.hpp +++ b/apps/openmw/mwworld/actiontrap.hpp @@ -13,11 +13,7 @@ namespace MWWorld std::string mSpellId; MWWorld::Ptr mTrapSource; - /// Activating trapped object without telekinesis active or within trap range - virtual void executeImp (const Ptr& actor); - - /// Activating trapped object with telekinesis active - virtual void executeImp (const Ptr& actor, float distanceToObject); + virtual void executeImp (const Ptr& actor, float distanceToObject = -1); public: @@ -25,7 +21,7 @@ namespace MWWorld /// @param actor Actor that activated the trap /// @param trapSource ActionTrap (const Ptr& actor, const std::string& spellId, const Ptr& trapSource) - : Action(false, actor), mSpellId(spellId), mTrapSource(trapSource) {} + : Action(false, trapSource), mSpellId(spellId), mTrapSource(trapSource) {} }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 869ccdfe5..3b53e8cac 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3205,12 +3205,7 @@ namespace MWWorld if (object.getRefData().activate()) { boost::shared_ptr action = (object.getClass().activate(object, actor)); - // If the player is opening a trap with telekinesis on, use the raycast-derived distance to check if the trap should hit - if (object.getCellRef().getTrap() != "" && actor == getPlayerPtr() && mPlayer->getPlayer().getClass().getCreatureStats(mPlayer->getPlayer()).getMagicEffects() - .get(ESM::MagicEffect::Telekinesis).getMagnitude() > 0) - action->execute (actor, mDistanceToFacedObject); - else // Otherwise just activate, and if it's trapped it will always hit - action->execute (actor); + action->execute (actor, mDistanceToFacedObject); } } From 7de3afaa7d29502a653ab8a8f230e9fcf98f8cb6 Mon Sep 17 00:00:00 2001 From: Allofich Date: Thu, 7 Jul 2016 21:46:58 +0900 Subject: [PATCH 13/17] Cleanups --- apps/openmw/mwworld/actiontrap.cpp | 2 +- apps/openmw/mwworld/actiontrap.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 13 ++++++------- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwworld/actiontrap.cpp b/apps/openmw/mwworld/actiontrap.cpp index 991e05313..e9ec5fa5e 100644 --- a/apps/openmw/mwworld/actiontrap.cpp +++ b/apps/openmw/mwworld/actiontrap.cpp @@ -21,7 +21,7 @@ namespace MWWorld { MWMechanics::CastSpell cast(mTrapSource, mTrapSource); cast.mHitPosition = trapPosition; - cast.cast(mSpellId); + cast.cast(mSpellId); } else // actor activated object within range of trap { diff --git a/apps/openmw/mwworld/actiontrap.hpp b/apps/openmw/mwworld/actiontrap.hpp index 5fb76eb5d..6a0820381 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, float distanceToObject = -1); + virtual void executeImp (const Ptr& actor, float distanceToObject); public: diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 3b53e8cac..05b060bce 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -150,7 +150,7 @@ namespace MWWorld mSky (true), mCells (mStore, mEsm), mGodMode(false), mScriptsEnabled(true), mContentFiles (contentFiles), mActivationDistanceOverride (activationDistanceOverride), mStartupScript(startupScript), - mStartCell (startCell), mDistanceToFacedObject(0), mTeleportEnabled(true), + mStartCell (startCell), mDistanceToFacedObject(-1), mTeleportEnabled(true), mLevitationEnabled(true), mGoToJail(false), mDaysInPrison(0) { mPhysics = new MWPhysics::PhysicsSystem(resourceSystem, rootNode); @@ -1011,11 +1011,10 @@ namespace MWWorld MWWorld::Ptr World::getFacedObject() { MWWorld::Ptr facedObject; - float distanceToObject; if (MWBase::Environment::get().getWindowManager()->isGuiMode() && MWBase::Environment::get().getWindowManager()->isConsoleMode()) - facedObject = getFacedObject(getMaxActivationDistance() * 50, distanceToObject, false); + facedObject = getFacedObject(getMaxActivationDistance() * 50, mDistanceToFacedObject, false); else { float telekinesisRangeBonus = @@ -1025,14 +1024,12 @@ namespace MWWorld float activationDistance = getMaxActivationDistance() + telekinesisRangeBonus; - facedObject = getFacedObject(activationDistance, distanceToObject, true); + facedObject = getFacedObject(activationDistance, mDistanceToFacedObject, true); if (!facedObject.isEmpty() && !facedObject.getClass().allowTelekinesis(facedObject) - && distanceToObject > getMaxActivationDistance()) + && mDistanceToFacedObject > getMaxActivationDistance()) return 0; } - - mDistanceToFacedObject = distanceToObject; return facedObject; } @@ -1733,6 +1730,8 @@ namespace MWWorld facedObject = rayToObject.mHitObject; if (!facedObject.isEmpty()) distance = rayToObject.mRatio * maxDistance; + else + distance = -1; return facedObject; } From 0e5c3f781fe1419163f52936f49b466f0d1f4bbc Mon Sep 17 00:00:00 2001 From: Allofich Date: Thu, 7 Jul 2016 22:10:38 +0900 Subject: [PATCH 14/17] Only allow trap distance check to apply to player --- apps/openmw/mwworld/actiontrap.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/actiontrap.cpp b/apps/openmw/mwworld/actiontrap.cpp index e9ec5fa5e..1ddf86bf6 100644 --- a/apps/openmw/mwworld/actiontrap.cpp +++ b/apps/openmw/mwworld/actiontrap.cpp @@ -1,6 +1,7 @@ #include "actiontrap.hpp" #include "../mwmechanics/spellcasting.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -17,13 +18,13 @@ namespace MWWorld // radius, because for most trap spells this is 1 foot, much less than the activation distance. // Using activation distance as the trap range. - if (distance > trapRange) // actor activated object outside range of trap + if (distance > trapRange && actor == MWMechanics::getPlayer()) // player activated object outside range of trap { MWMechanics::CastSpell cast(mTrapSource, mTrapSource); cast.mHitPosition = trapPosition; cast.cast(mSpellId); } - else // actor activated object within range of trap + else // player activated object within range of trap, or NPC activated trap { MWMechanics::CastSpell cast(mTrapSource, actor); cast.mHitPosition = actorPosition; From 4e54338ce083d91ded1145341c3cc44a9456cd0d Mon Sep 17 00:00:00 2001 From: Allofich Date: Fri, 8 Jul 2016 23:07:07 +0900 Subject: [PATCH 15/17] Implement and use getDistanceToFacedObject() --- apps/openmw/mwbase/world.hpp | 2 ++ apps/openmw/mwworld/action.cpp | 8 +++----- apps/openmw/mwworld/action.hpp | 6 ++---- apps/openmw/mwworld/actiontrap.cpp | 5 ++--- apps/openmw/mwworld/actiontrap.hpp | 4 ++-- apps/openmw/mwworld/worldimp.cpp | 7 ++++++- apps/openmw/mwworld/worldimp.hpp | 2 ++ 7 files changed, 19 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 7376e6b51..82d5ddd5e 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -250,6 +250,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 getDistanceToFacedObject() = 0; + virtual float getMaxActivationDistance() = 0; /// Returns a pointer to the object the provided object would hit (if within the diff --git a/apps/openmw/mwworld/action.cpp b/apps/openmw/mwworld/action.cpp index e76ff8105..c29377ecb 100644 --- a/apps/openmw/mwworld/action.cpp +++ b/apps/openmw/mwworld/action.cpp @@ -17,7 +17,7 @@ MWWorld::Action::Action (bool keepSound, const Ptr& target) : mKeepSound (keepSo MWWorld::Action::~Action() {} -void MWWorld::Action::execute (const Ptr& actor, float distanceToFacedObject) +void MWWorld::Action::execute (const Ptr& actor) { if(!mSoundId.empty()) { @@ -41,10 +41,8 @@ void MWWorld::Action::execute (const Ptr& actor, float distanceToFacedObject) ); } } - if (mTarget.getCellRef().getTrap() != "") - executeImp(actor, distanceToFacedObject); - else - executeImp(actor); + + executeImp (actor); } void MWWorld::Action::setSound (const std::string& id) diff --git a/apps/openmw/mwworld/action.hpp b/apps/openmw/mwworld/action.hpp index d61e72551..38907cf44 100644 --- a/apps/openmw/mwworld/action.hpp +++ b/apps/openmw/mwworld/action.hpp @@ -19,9 +19,7 @@ namespace MWWorld Action (const Action& action); Action& operator= (const Action& action); - virtual void executeImp (const Ptr& actor) { return; } - virtual void executeImp (const Ptr& actor, float distanceToObject) { return; } - + virtual void executeImp (const Ptr& actor) = 0; protected: @@ -37,7 +35,7 @@ namespace MWWorld virtual bool isNullAction() { return false; } ///< Is running this action a no-op? (default false) - void execute (const Ptr& actor, float distanceToObject = -1); + void execute (const Ptr& actor); 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 1ddf86bf6..cdabaf8c8 100644 --- a/apps/openmw/mwworld/actiontrap.cpp +++ b/apps/openmw/mwworld/actiontrap.cpp @@ -1,14 +1,13 @@ #include "actiontrap.hpp" #include "../mwmechanics/spellcasting.hpp" -#include "../mwmechanics/actorutil.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" namespace MWWorld { - void ActionTrap::executeImp(const Ptr &actor, float distance) + void ActionTrap::executeImp(const Ptr &actor) { osg::Vec3f actorPosition(actor.getRefData().getPosition().asVec3()); osg::Vec3f trapPosition(mTrapSource.getRefData().getPosition().asVec3()); @@ -18,7 +17,7 @@ namespace MWWorld // radius, because for most trap spells this is 1 foot, much less than the activation distance. // Using activation distance as the trap range. - if (distance > trapRange && actor == MWMechanics::getPlayer()) // player activated object outside range of trap + if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr() && MWBase::Environment::get().getWorld()->getDistanceToFacedObject() > trapRange) // player activated object outside range of trap { MWMechanics::CastSpell cast(mTrapSource, mTrapSource); cast.mHitPosition = trapPosition; diff --git a/apps/openmw/mwworld/actiontrap.hpp b/apps/openmw/mwworld/actiontrap.hpp index 6a0820381..4c2f4139f 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, float distanceToObject); + virtual void executeImp (const Ptr& actor); public: @@ -21,7 +21,7 @@ namespace MWWorld /// @param actor Actor that activated the trap /// @param trapSource ActionTrap (const Ptr& actor, const std::string& spellId, const Ptr& trapSource) - : Action(false, trapSource), mSpellId(spellId), mTrapSource(trapSource) {} + : Action(false, actor), mSpellId(spellId), mTrapSource(trapSource) {} }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 05b060bce..4aa249a6d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1033,6 +1033,11 @@ namespace MWWorld return facedObject; } + float World::getDistanceToFacedObject() + { + return mDistanceToFacedObject; + } + osg::Matrixf World::getActorHeadTransform(const MWWorld::ConstPtr& actor) const { const MWRender::Animation *anim = mRendering->getAnimation(actor); @@ -3204,7 +3209,7 @@ namespace MWWorld if (object.getRefData().activate()) { boost::shared_ptr action = (object.getClass().activate(object, actor)); - action->execute (actor, mDistanceToFacedObject); + action->execute (actor); } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 64160018f..411dbc103 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -348,6 +348,8 @@ namespace MWWorld virtual MWWorld::Ptr getFacedObject(); ///< Return pointer to the object the player is looking at, if it is within activation range + virtual float getDistanceToFacedObject(); + /// 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 as a basis. From 53ceefa46adc01bda639949615a41cd8e316e75c Mon Sep 17 00:00:00 2001 From: Allofich Date: Sat, 9 Jul 2016 00:31:39 +0900 Subject: [PATCH 16/17] Allow some telekinesis on teleport doors --- apps/openmw/mwclass/door.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 81188fe10..d8a9efba5 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -146,11 +146,18 @@ namespace MWClass if (ptr.getCellRef().getTeleport()) { - boost::shared_ptr action(new MWWorld::ActionTeleport (ptr.getCellRef().getDestCell(), ptr.getCellRef().getDoorDest(), true)); - - action->setSound(openSound); - - return action; + if (actor == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getDistanceToFacedObject() > MWBase::Environment::get().getWorld()->getMaxActivationDistance()) + { + // player activated teleport door with telekinesis + boost::shared_ptr action(new MWWorld::FailedAction); + return action; + } + else + { + boost::shared_ptr action(new MWWorld::ActionTeleport (ptr.getCellRef().getDestCell(), ptr.getCellRef().getDoorDest(), true)); + action->setSound(openSound); + return action; + } } else { @@ -215,7 +222,7 @@ namespace MWClass bool Door::allowTelekinesis(const MWWorld::ConstPtr &ptr) const { - if (ptr.getCellRef().getTeleport()) + if (ptr.getCellRef().getTeleport() && ptr.getCellRef().getLockLevel() <= 0 && ptr.getCellRef().getTrap().empty()) return false; else return true; From 7a0f9a79898fc17a48e700baf14a308c0fa03113 Mon Sep 17 00:00:00 2001 From: Allofich Date: Sat, 9 Jul 2016 02:12:58 +0900 Subject: [PATCH 17/17] Clean up, remove unnecessary code changes --- apps/openmw/mwworld/worldimp.cpp | 12 ++++++------ apps/openmw/mwworld/worldimp.hpp | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 4aa249a6d..abae3a3ae 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1014,7 +1014,7 @@ namespace MWWorld if (MWBase::Environment::get().getWindowManager()->isGuiMode() && MWBase::Environment::get().getWindowManager()->isConsoleMode()) - facedObject = getFacedObject(getMaxActivationDistance() * 50, mDistanceToFacedObject, false); + facedObject = getFacedObject(getMaxActivationDistance() * 50, false); else { float telekinesisRangeBonus = @@ -1024,7 +1024,7 @@ namespace MWWorld float activationDistance = getMaxActivationDistance() + telekinesisRangeBonus; - facedObject = getFacedObject(activationDistance, mDistanceToFacedObject, true); + facedObject = getFacedObject(activationDistance, true); if (!facedObject.isEmpty() && !facedObject.getClass().allowTelekinesis(facedObject) && mDistanceToFacedObject > getMaxActivationDistance()) @@ -1717,7 +1717,7 @@ namespace MWWorld } } - MWWorld::Ptr World::getFacedObject(float maxDistance, float& distance, bool ignorePlayer) + MWWorld::Ptr World::getFacedObject(float maxDistance, bool ignorePlayer) { maxDistance += mRendering->getCameraDistance(); MWWorld::Ptr facedObject; @@ -1733,10 +1733,10 @@ namespace MWWorld rayToObject = mRendering->castCameraToViewportRay(0.5f, 0.5f, maxDistance, ignorePlayer); facedObject = rayToObject.mHitObject; - if (!facedObject.isEmpty()) - distance = rayToObject.mRatio * maxDistance; + if (rayToObject.mHit) + mDistanceToFacedObject = rayToObject.mRatio * maxDistance; else - distance = -1; + mDistanceToFacedObject = -1; return facedObject; } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 411dbc103..aa67c9ea8 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -128,7 +128,7 @@ namespace MWWorld void updateWindowManager (); void updatePlayer(bool paused); - MWWorld::Ptr getFacedObject(float maxDistance, float& distanceToObject, bool ignorePlayer=true); + MWWorld::Ptr getFacedObject(float maxDistance, bool ignorePlayer=true); public: // FIXME void removeContainerScripts(const Ptr& reference);