Let AI open moved doors (#7548)

pull/3236/head
Alexei Kotov 2 months ago
parent 4c11dcdd7d
commit 4fdfd6ae91

@ -49,47 +49,61 @@ namespace MWMechanics
return true; return true;
} }
const MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minDist) struct GetNearbyDoorVisitor
{ {
MWWorld::CellStore* cell = actor.getCell(); MWWorld::Ptr mResult;
// Check all the doors in this cell
const MWWorld::CellRefList<ESM::Door>& doors = cell->getReadOnlyDoors();
osg::Vec3f pos(actor.getRefData().getPosition().asVec3());
pos.z() = 0;
osg::Vec3f actorDir = (actor.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0, 1, 0)); GetNearbyDoorVisitor(const MWWorld::Ptr& actor, const float minDist)
: mPos(actor.getRefData().getPosition().asVec3())
for (const auto& ref : doors.mList) , 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 bool operator()(const MWWorld::Ptr& ptr)
const MWWorld::Ptr doorPtr {
= MWWorld::Ptr(&const_cast<MWWorld::LiveCellRef<ESM::Door>&>(ref), actor.getCell()); MWWorld::LiveCellRef<ESM::Door>& ref = *static_cast<MWWorld::LiveCellRef<ESM::Door>*>(ptr.getBase());
if (!ptr.getRefData().isEnabled() || ref.isDeleted())
return true;
const auto doorState = doorPtr.getClass().getDoorState(doorPtr); if (ptr.getClass().getDoorState(ptr) != MWWorld::DoorState::Idle)
float doorRot = ref.mData.getPosition().rot[2] - doorPtr.getCellRef().getPosition().rot[2]; return true;
if (doorState != MWWorld::DoorState::Idle || doorRot != 0) const float doorRot = ref.mData.getPosition().rot[2] - ptr.getCellRef().getPosition().rot[2];
continue; // the door is already opened/opening if (doorRot != 0)
return true;
osg::Vec3f doorPos(ref.mData.getPosition().asVec3());
doorPos.z() = 0; 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 // Allow 60 degrees angle between actor and door
if (angle < -osg::PI / 3 || angle > osg::PI / 3) if (angle < -osg::PI / 3 || angle > osg::PI / 3)
continue; return true;
// Door is not close enough
if ((pos - doorPos).length2() > minDist * minDist)
continue;
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<ESM::Door>(visitor);
return visitor.mResult;
} }
bool isAreaOccupiedByOtherActor(const MWWorld::ConstPtr& actor, const osg::Vec3f& destination, bool ignorePlayer, bool isAreaOccupiedByOtherActor(const MWWorld::ConstPtr& actor, const osg::Vec3f& destination, bool ignorePlayer,

Loading…
Cancel
Save