|
|
|
@ -1,5 +1,7 @@
|
|
|
|
|
#include "actors.hpp"
|
|
|
|
|
|
|
|
|
|
#include <optional>
|
|
|
|
|
|
|
|
|
|
#include <components/esm/esmreader.hpp>
|
|
|
|
|
#include <components/esm/esmwriter.hpp>
|
|
|
|
|
|
|
|
|
@ -173,6 +175,15 @@ namespace MWMechanics
|
|
|
|
|
static const int GREETING_COOLDOWN = 40; // how many updates should pass before NPC can continue movement
|
|
|
|
|
static const float DECELERATE_DISTANCE = 512.f;
|
|
|
|
|
|
|
|
|
|
namespace
|
|
|
|
|
{
|
|
|
|
|
float getTimeToDestination(const AiPackage& package, const osg::Vec3f& position, float speed, float duration, const osg::Vec3f& halfExtents)
|
|
|
|
|
{
|
|
|
|
|
const auto distanceToNextPathPoint = (package.getNextPathPoint(package.getDestination()) - position).length();
|
|
|
|
|
return (distanceToNextPathPoint - package.getNextPathPointTolerance(speed, duration, halfExtents)) / speed;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class GetStuntedMagickaDuration : public MWMechanics::EffectSourceVisitor
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
@ -1764,7 +1775,7 @@ namespace MWMechanics
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Actors::predictAndAvoidCollisions()
|
|
|
|
|
void Actors::predictAndAvoidCollisions(float duration)
|
|
|
|
|
{
|
|
|
|
|
if (!MWBase::Environment::get().getMechanicsManager()->isAIActive())
|
|
|
|
|
return;
|
|
|
|
@ -1799,7 +1810,8 @@ namespace MWMechanics
|
|
|
|
|
bool shouldAvoidCollision = isMoving;
|
|
|
|
|
bool shouldTurnToApproachingActor = !isMoving;
|
|
|
|
|
MWWorld::Ptr currentTarget; // Combat or pursue target (NPCs should not avoid collision with their targets).
|
|
|
|
|
for (const auto& package : ptr.getClass().getCreatureStats(ptr).getAiSequence())
|
|
|
|
|
const auto& aiSequence = ptr.getClass().getCreatureStats(ptr).getAiSequence();
|
|
|
|
|
for (const auto& package : aiSequence)
|
|
|
|
|
{
|
|
|
|
|
if (package->getTypeId() == AiPackageTypeId::Follow)
|
|
|
|
|
shouldAvoidCollision = true;
|
|
|
|
@ -1829,6 +1841,10 @@ namespace MWMechanics
|
|
|
|
|
osg::Vec2f movementCorrection(0, 0);
|
|
|
|
|
float angleToApproachingActor = 0;
|
|
|
|
|
|
|
|
|
|
const float timeToDestination = aiSequence.isEmpty()
|
|
|
|
|
? std::numeric_limits<float>::max()
|
|
|
|
|
: getTimeToDestination(**aiSequence.begin(), basePos, maxSpeed, duration, halfExtents);
|
|
|
|
|
|
|
|
|
|
// Iterate through all other actors and predict collisions.
|
|
|
|
|
for(PtrActorMap::iterator otherIter(mActors.begin()); otherIter != mActors.end(); ++otherIter)
|
|
|
|
|
{
|
|
|
|
@ -1865,7 +1881,7 @@ namespace MWMechanics
|
|
|
|
|
continue; // No solution; distance is always >= collisionDist.
|
|
|
|
|
float t = (-vr - std::sqrt(Dh)) / v2;
|
|
|
|
|
|
|
|
|
|
if (t < 0 || t > timeToCollision)
|
|
|
|
|
if (t < 0 || t > timeToCollision || t > timeToDestination)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// Check visibility and awareness last as it's expensive.
|
|
|
|
@ -2075,7 +2091,7 @@ namespace MWMechanics
|
|
|
|
|
|
|
|
|
|
static const bool avoidCollisions = Settings::Manager::getBool("NPCs avoid collisions", "Game");
|
|
|
|
|
if (avoidCollisions)
|
|
|
|
|
predictAndAvoidCollisions();
|
|
|
|
|
predictAndAvoidCollisions(duration);
|
|
|
|
|
|
|
|
|
|
timerUpdateHeadTrack += duration;
|
|
|
|
|
timerUpdateEquippedLight += duration;
|
|
|
|
|