@ -1,5 +1,7 @@
# include "aitravel.hpp"
# include <algorithm>
# include <components/esm/aisequence.hpp>
# include "../mwbase/environment.hpp"
@ -23,6 +25,11 @@ 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
@ -70,18 +77,26 @@ namespace MWMechanics
// 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.
int destinationTolerance = 64 ;
if ( distance ( actorPos , targetPos ) < = destinationTolerance )
if ( mDestinationCheck . update ( duration ) = = Misc : : TimerStatus : : Elapsed )
{
std : : vector < MWWorld : : Ptr > targetActors ;
std : : pair < MWWorld : : Ptr , osg : : Vec3f > result = MWBase : : Environment : : get ( ) . getWorld ( ) - > getHitContact ( actor , destinationTolerance , targetActors ) ;
if ( ! result . first . isEmpty ( ) )
std : : vector < MWWorld : : Ptr > occupyingActors ;
if ( isAreaOccupiedByOtherActor ( actor , targetPos , & 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 ) )
{