1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-26 09:35:28 +00:00

Give AITravel time to end if the actor is close to the destination

This commit is contained in:
Alexei Kotov 2022-06-19 22:21:41 +03:00
parent a768068db9
commit bd6716d89d
2 changed files with 29 additions and 35 deletions

View File

@ -17,6 +17,8 @@
namespace
{
constexpr float TRAVEL_FINISH_TIME = 2.f;
bool isWithinMaxRange(const osg::Vec3f& pos1, const osg::Vec3f& pos2)
{
// Maximum travel distance for vanilla compatibility.
@ -25,24 +27,17 @@ bool isWithinMaxRange(const osg::Vec3f& pos1, const osg::Vec3f& pos2)
return (pos1 - pos2).length2() <= 7168*7168;
}
float getActorRadius(const MWWorld::ConstPtr& actor)
{
const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(actor);
return std::max(halfExtents.x(), std::max(halfExtents.y(), halfExtents.z()));
}
}
namespace MWMechanics
{
AiTravel::AiTravel(float x, float y, float z, bool repeat, AiTravel*)
: TypedAiPackage<AiTravel>(repeat), mX(x), mY(y), mZ(z), mHidden(false)
, mDestinationCheck(MWBase::Environment::get().getWorld()->getPrng())
: TypedAiPackage<AiTravel>(repeat), mX(x), mY(y), mZ(z), mHidden(false), mDestinationTimer(TRAVEL_FINISH_TIME)
{
}
AiTravel::AiTravel(float x, float y, float z, AiInternalTravel* derived)
: TypedAiPackage<AiTravel>(derived), mX(x), mY(y), mZ(z), mHidden(true)
, mDestinationCheck(MWBase::Environment::get().getWorld()->getPrng())
: TypedAiPackage<AiTravel>(derived), mX(x), mY(y), mZ(z), mHidden(true), mDestinationTimer(TRAVEL_FINISH_TIME)
{
}
@ -53,7 +48,7 @@ namespace MWMechanics
AiTravel::AiTravel(const ESM::AiSequence::AiTravel *travel)
: TypedAiPackage<AiTravel>(travel->mRepeat), mX(travel->mData.mX), mY(travel->mData.mY), mZ(travel->mData.mZ), mHidden(false)
, mDestinationCheck(MWBase::Environment::get().getWorld()->getPrng())
, mDestinationTimer(TRAVEL_FINISH_TIME)
{
// Hidden ESM::AiSequence::AiTravel package should be converted into MWMechanics::AiInternalTravel type
assert(!travel->mHidden);
@ -78,35 +73,34 @@ namespace MWMechanics
if (!isWithinMaxRange(targetPos, actorPos))
return mHidden;
// Unfortunately, with vanilla assets destination is sometimes blocked by other actor.
// If we got close to target, check for actors nearby. If they are, finish AI package.
if (mDestinationCheck.update(duration) == Misc::TimerStatus::Elapsed)
{
std::vector<MWWorld::Ptr> occupyingActors;
if (isAreaOccupiedByOtherActor(actor, targetPos, true, &occupyingActors))
{
const float actorRadius = getActorRadius(actor);
const float distanceToTarget = distance(actorPos, targetPos);
for (const MWWorld::Ptr& other : occupyingActors)
{
const float otherRadius = getActorRadius(other);
const auto [minRadius, maxRadius] = std::minmax(actorRadius, otherRadius);
constexpr float toleranceFactor = 1.25;
if (minRadius * toleranceFactor + maxRadius > distanceToTarget)
{
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
return true;
}
}
}
}
if (pathTo(actor, targetPos, duration))
{
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
return true;
}
return false;
// If we've been close enough to the destination for some time give up like Morrowind.
// The end condition should be pretty much accurate.
// FIXME: But the timing isn't. Right now we're being very generous,
// but Morrowind might stop the actor prematurely under unclear conditions.
// Note Morrowind uses the halved eye level, but this is close enough.
float dist = distanceIgnoreZ(actorPos, targetPos) - MWBase::Environment::get().getWorld()->getHalfExtents(actor).z();
const float endTolerance = std::max(64.f, actor.getClass().getCurrentSpeed(actor) * duration);
// Even if we have entered the threshold, we might have been pushed away. Reset the timer if we're currently too far.
if (dist > endTolerance)
{
mDestinationTimer = TRAVEL_FINISH_TIME;
return false;
}
mDestinationTimer -= duration;
if (mDestinationTimer > 0)
return false;
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
return true;
}
void AiTravel::fastForward(const MWWorld::Ptr& actor, AiState& state)

View File

@ -53,7 +53,7 @@ namespace MWMechanics
const bool mHidden;
AiReactionTimer mDestinationCheck;
float mDestinationTimer;
};
struct AiInternalTravel final : public AiTravel