diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 529e7ca41..f837ad2ee 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -176,7 +176,9 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float dur if (!mObstacleCheck.check(actor, duration)) return; // first check if obstacle is a door - MWWorld::Ptr door = getNearbyDoor(actor); // NOTE: checks interior cells only + static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance(); + + MWWorld::Ptr door = getNearbyDoor(actor, distance); if (door != MWWorld::Ptr()) { // note: AiWander currently does not open doors diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index ad6db4d01..baf4efc03 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -449,11 +449,14 @@ namespace MWMechanics { // Check if an idle actor is too close to a door - if so start walking storage.mDoorCheckDuration += duration; + + static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance(); + if (storage.mDoorCheckDuration >= DOOR_CHECK_INTERVAL) { storage.mDoorCheckDuration = 0; // restart timer if (mDistance && // actor is not intended to be stationary - proximityToDoor(actor, MIN_DIST_TO_DOOR_SQUARED*1.6f*1.6f)) // NOTE: checks interior cells only + proximityToDoor(actor, distance*1.6f)) { storage.setState(Wander_MoveNow); storage.mTrimCurrentNode = false; // just in case @@ -527,10 +530,12 @@ namespace MWMechanics void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration, ESM::Position& pos) { + static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance(); + if (mObstacleCheck.isEvading()) { // first check if we're walking into a door - if (proximityToDoor(actor)) // NOTE: checks interior cells only + if (proximityToDoor(actor, distance)) { // remove allowed points then select another random destination storage.mTrimCurrentNode = true; diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index 5d99fe723..3c6f14bfd 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -1,6 +1,7 @@ #include "obstacle.hpp" #include +#include #include "../mwbase/world.hpp" #include "../mwworld/class.hpp" @@ -23,50 +24,48 @@ namespace MWMechanics { -1.0f, -1.0f } // move to side and backwards }; - // Proximity check function for interior doors. Given that most interior cells - // do not have many doors performance shouldn't be too much of an issue. - // - // Limitation: there can be false detections, and does not test whether the - // actor is facing the door. - bool proximityToDoor(const MWWorld::Ptr& actor, float minSqr) + bool proximityToDoor(const MWWorld::Ptr& actor, float minDist) { - if(getNearbyDoor(actor, minSqr)!=MWWorld::Ptr()) + if(getNearbyDoor(actor, minDist)!=MWWorld::Ptr()) return true; else return false; } - MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minSqr) + MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minDist) { MWWorld::CellStore *cell = actor.getCell(); - if(cell->getCell()->isExterior()) - return MWWorld::Ptr(); // check interior cells only - // Check all the doors in this cell const MWWorld::CellRefList& doors = cell->getReadOnlyDoors(); const MWWorld::CellRefList::List& refList = doors.mList; MWWorld::CellRefList::List::const_iterator it = refList.begin(); osg::Vec3f pos(actor.getRefData().getPosition().asVec3()); + pos.z() = 0; - /// TODO: How to check whether the actor is facing a door? Below code is for - /// the player, perhaps it can be adapted. - //MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getFacedObject(); - //if(!ptr.isEmpty()) - //std::cout << "faced door " << ptr.getClass().getName(ptr) << std::endl; + osg::Vec3f actorDir = (actor.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0,1,0)); - /// TODO: The in-game observation of rot[2] value seems to be the - /// opposite of the code in World::activateDoor() ::confused:: for (; it != refList.end(); ++it) { const MWWorld::LiveCellRef& ref = *it; - if((pos - ref.mData.getPosition().asVec3()).length2() < minSqr - && ref.mData.getPosition().rot[2] == ref.mRef.getPosition().rot[2]) - { - // FIXME cast - return MWWorld::Ptr(&const_cast &>(ref), actor.getCell()); // found, stop searching - } + + osg::Vec3f doorPos(ref.mData.getPosition().asVec3()); + doorPos.z() = 0; + + float angle = std::acos(actorDir * (doorPos - pos) / (actorDir.length() * (doorPos - pos).length())); + + // Allow 60 degrees angle between actor and door + if (angle < -osg::PI / 3 || angle > osg::PI / 3) + continue; + + // Door is not close enough + if ((pos - doorPos).length2() > minDist*minDist) + continue; + + // FIXME cast + return MWWorld::Ptr(&const_cast &>(ref), actor.getCell()); // found, stop searching } + return MWWorld::Ptr(); // none found } diff --git a/apps/openmw/mwmechanics/obstacle.hpp b/apps/openmw/mwmechanics/obstacle.hpp index 1d7cf1e0e..f71207346 100644 --- a/apps/openmw/mwmechanics/obstacle.hpp +++ b/apps/openmw/mwmechanics/obstacle.hpp @@ -10,19 +10,14 @@ namespace MWMechanics { struct Movement; - /// NOTE: determined empirically based on in-game behaviour - static const float MIN_DIST_TO_DOOR_SQUARED = 128*128; - static const int NUM_EVADE_DIRECTIONS = 4; /// tests actor's proximity to a closed door by default - bool proximityToDoor(const MWWorld::Ptr& actor, - float minSqr = MIN_DIST_TO_DOOR_SQUARED); + bool proximityToDoor(const MWWorld::Ptr& actor, float minDist); /// Returns door pointer within range. No guarantee is given as to which one /** \return Pointer to the door, or NULL if none exists **/ - MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, - float minSqr = MIN_DIST_TO_DOOR_SQUARED); + MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minDist); class ObstacleCheck { diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index da1cf1396..f8d44292e 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1460,6 +1460,7 @@ namespace MWWorld { osg::Vec3f a(x1,y1,z1); osg::Vec3f b(x2,y2,z2); + MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(a, b, MWWorld::Ptr(), std::vector(), MWPhysics::CollisionType_World|MWPhysics::CollisionType_Door); return result.mHit; }