Skip to content

Commit d356fea

Browse files
committed
Merge branch 'whycantitalkthedoorintoopening' into 'master'
Let AI open moved doors (#7548) Closes #7548 See merge request OpenMW/openmw!4435
2 parents 20f77ec + 4fdfd6a commit d356fea

File tree

1 file changed

+40
-26
lines changed

1 file changed

+40
-26
lines changed

apps/openmw/mwmechanics/obstacle.cpp

+40-26
Original file line numberDiff line numberDiff line change
@@ -49,47 +49,61 @@ namespace MWMechanics
4949
return true;
5050
}
5151

52-
const MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minDist)
52+
struct GetNearbyDoorVisitor
5353
{
54-
MWWorld::CellStore* cell = actor.getCell();
55-
56-
// Check all the doors in this cell
57-
const MWWorld::CellRefList<ESM::Door>& doors = cell->getReadOnlyDoors();
58-
osg::Vec3f pos(actor.getRefData().getPosition().asVec3());
59-
pos.z() = 0;
54+
MWWorld::Ptr mResult;
6055

61-
osg::Vec3f actorDir = (actor.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0, 1, 0));
62-
63-
for (const auto& ref : doors.mList)
56+
GetNearbyDoorVisitor(const MWWorld::Ptr& actor, const float minDist)
57+
: mPos(actor.getRefData().getPosition().asVec3())
58+
, mDir(actor.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0, 1, 0))
59+
, mMinDist(minDist)
6460
{
65-
osg::Vec3f doorPos(ref.mData.getPosition().asVec3());
61+
mPos.z() = 0;
62+
mDir.normalize();
63+
}
6664

67-
// FIXME: cast
68-
const MWWorld::Ptr doorPtr
69-
= MWWorld::Ptr(&const_cast<MWWorld::LiveCellRef<ESM::Door>&>(ref), actor.getCell());
65+
bool operator()(const MWWorld::Ptr& ptr)
66+
{
67+
MWWorld::LiveCellRef<ESM::Door>& ref = *static_cast<MWWorld::LiveCellRef<ESM::Door>*>(ptr.getBase());
68+
if (!ptr.getRefData().isEnabled() || ref.isDeleted())
69+
return true;
7070

71-
const auto doorState = doorPtr.getClass().getDoorState(doorPtr);
72-
float doorRot = ref.mData.getPosition().rot[2] - doorPtr.getCellRef().getPosition().rot[2];
71+
if (ptr.getClass().getDoorState(ptr) != MWWorld::DoorState::Idle)
72+
return true;
7373

74-
if (doorState != MWWorld::DoorState::Idle || doorRot != 0)
75-
continue; // the door is already opened/opening
74+
const float doorRot = ref.mData.getPosition().rot[2] - ptr.getCellRef().getPosition().rot[2];
75+
if (doorRot != 0)
76+
return true;
7677

78+
osg::Vec3f doorPos(ref.mData.getPosition().asVec3());
7779
doorPos.z() = 0;
7880

79-
float angle = std::acos(actorDir * (doorPos - pos) / (actorDir.length() * (doorPos - pos).length()));
81+
osg::Vec3f actorToDoor = doorPos - mPos;
82+
// Door is not close enough
83+
if (actorToDoor.length2() > mMinDist * mMinDist)
84+
return true;
85+
86+
actorToDoor.normalize();
87+
const float angle = std::acos(mDir * actorToDoor);
8088

8189
// Allow 60 degrees angle between actor and door
8290
if (angle < -osg::PI / 3 || angle > osg::PI / 3)
83-
continue;
84-
85-
// Door is not close enough
86-
if ((pos - doorPos).length2() > minDist * minDist)
87-
continue;
91+
return true;
8892

89-
return doorPtr; // found, stop searching
93+
mResult = ptr;
94+
return false; // found, stop searching
9095
}
9196

92-
return MWWorld::Ptr(); // none found
97+
private:
98+
osg::Vec3f mPos, mDir;
99+
float mMinDist;
100+
};
101+
102+
const MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minDist)
103+
{
104+
GetNearbyDoorVisitor visitor(actor, minDist);
105+
actor.getCell()->forEachType<ESM::Door>(visitor);
106+
return visitor.mResult;
93107
}
94108

95109
bool isAreaOccupiedByOtherActor(const MWWorld::ConstPtr& actor, const osg::Vec3f& destination, bool ignorePlayer,

0 commit comments

Comments
 (0)