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;
}
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<ESM::Door>& 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<MWWorld::LiveCellRef<ESM::Door>&>(ref), actor.getCell());
bool operator()(const MWWorld::Ptr& ptr)
{
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);
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<ESM::Door>(visitor);
return visitor.mResult;
}
bool isAreaOccupiedByOtherActor(const MWWorld::ConstPtr& actor, const osg::Vec3f& destination, bool ignorePlayer,

Loading…
Cancel
Save