|
|
|
@ -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,
|
|
|
|
|