Skip to content

Commit

Permalink
Merge branch 'whycantitalkthedoorintoopening' into 'master'
Browse files Browse the repository at this point in the history
Let AI open moved doors (#7548)

Closes #7548

See merge request OpenMW/openmw!4435
  • Loading branch information
psi29a committed Nov 7, 2024
2 parents 20f77ec + 4fdfd6a commit d356fea
Showing 1 changed file with 40 additions and 26 deletions.
66 changes: 40 additions & 26 deletions apps/openmw/mwmechanics/obstacle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit d356fea

Please sign in to comment.