From 4fdfd6ae918975ce13a744aec079095ea9e9d6c3 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Wed, 30 Oct 2024 11:56:55 +0300 Subject: [PATCH] Let AI open moved doors (#7548) --- apps/openmw/mwmechanics/obstacle.cpp | 66 +++++++++++++++++----------- 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index 4afaf7c2d5b..a6eb4f9c24d 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -49,47 +49,61 @@ namespace MWMechanics return true; } - const MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minDist) + struct GetNearbyDoorVisitor { - MWWorld::CellStore* cell = actor.getCell(); - - // Check all the doors in this cell - const MWWorld::CellRefList& doors = cell->getReadOnlyDoors(); - osg::Vec3f pos(actor.getRefData().getPosition().asVec3()); - pos.z() = 0; + MWWorld::Ptr mResult; - osg::Vec3f actorDir = (actor.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0, 1, 0)); - - for (const auto& ref : doors.mList) + GetNearbyDoorVisitor(const MWWorld::Ptr& actor, const float minDist) + : mPos(actor.getRefData().getPosition().asVec3()) + , mDir(actor.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0, 1, 0)) + , mMinDist(minDist) { - osg::Vec3f doorPos(ref.mData.getPosition().asVec3()); + mPos.z() = 0; + mDir.normalize(); + } - // FIXME: cast - const MWWorld::Ptr doorPtr - = MWWorld::Ptr(&const_cast&>(ref), actor.getCell()); + bool operator()(const MWWorld::Ptr& ptr) + { + MWWorld::LiveCellRef& ref = *static_cast*>(ptr.getBase()); + if (!ptr.getRefData().isEnabled() || ref.isDeleted()) + return true; - const auto doorState = doorPtr.getClass().getDoorState(doorPtr); - float doorRot = ref.mData.getPosition().rot[2] - doorPtr.getCellRef().getPosition().rot[2]; + if (ptr.getClass().getDoorState(ptr) != MWWorld::DoorState::Idle) + return true; - if (doorState != MWWorld::DoorState::Idle || doorRot != 0) - continue; // the door is already opened/opening + const float doorRot = ref.mData.getPosition().rot[2] - ptr.getCellRef().getPosition().rot[2]; + if (doorRot != 0) + return true; + osg::Vec3f doorPos(ref.mData.getPosition().asVec3()); doorPos.z() = 0; - float angle = std::acos(actorDir * (doorPos - pos) / (actorDir.length() * (doorPos - pos).length())); + osg::Vec3f actorToDoor = doorPos - mPos; + // Door is not close enough + if (actorToDoor.length2() > mMinDist * mMinDist) + return true; + + actorToDoor.normalize(); + const float angle = std::acos(mDir * actorToDoor); // 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; + return true; - return doorPtr; // found, stop searching + mResult = ptr; + return false; // found, stop searching } - return MWWorld::Ptr(); // none found + private: + osg::Vec3f mPos, mDir; + float mMinDist; + }; + + const MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minDist) + { + GetNearbyDoorVisitor visitor(actor, minDist); + actor.getCell()->forEachType(visitor); + return visitor.mResult; } bool isAreaOccupiedByOtherActor(const MWWorld::ConstPtr& actor, const osg::Vec3f& destination, bool ignorePlayer,