From 709baafd124556521fff6cbfa871e540b80fdaa0 Mon Sep 17 00:00:00 2001 From: elsid Date: Tue, 30 Aug 2022 20:19:01 +0200 Subject: [PATCH] Limit AiWander destination by wander distance From initial actor position. findRandomPointAroundCircle may return a position outside given range. Use raycast to choose a different reachable point within a radius but double check and discard if it's still outside. Use wander radius instead of wander distance for findRandomPointAroundCircle to have better chance for a position to be inside wander distance. --- CHANGELOG.md | 1 + apps/openmw/mwmechanics/aiwander.cpp | 29 ++++++++++++++++++++-------- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 16312fd98c..063eb1b877 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ Bug #5057: Weapon swing sound plays at same pitch whether it hits or misses Bug #5129: Stuttering animation on Centurion Archer Bug #5977: Fatigueless NPCs' corpse underwater changes animation on game load + Bug #6937: Divided by Nix Hounds quest is broken Bug #6939: OpenMW-CS: ID columns are too short Bug #6949: Sun Damage effect doesn't work in quasi exteriors Bug #6964: Nerasa Dralor Won't Follow diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index c5e15497ac..05eff857e0 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -360,14 +360,27 @@ namespace MWMechanics if (!isWaterCreature && !isFlyingCreature) { // findRandomPointAroundCircle uses wanderDistance as limit for random and not as exact distance - if (const auto destination = DetourNavigator::findRandomPointAroundCircle(*navigator, agentBounds, - mInitialActorPosition, wanderDistance, navigatorFlags, []() { - auto& prng = MWBase::Environment::get().getWorld()->getPrng(); - return Misc::Rng::rollProbability(prng); - })) - mDestination = *destination; - else - mDestination = getRandomPointAround(mInitialActorPosition, wanderRadius); + const auto getRandom = []() + { + return Misc::Rng::rollProbability(MWBase::Environment::get().getWorld()->getPrng()); + }; + auto destination = DetourNavigator::findRandomPointAroundCircle(*navigator, agentBounds, + mInitialActorPosition, wanderRadius, navigatorFlags, getRandom); + if (destination.has_value()) + { + osg::Vec3f direction = *destination - mInitialActorPosition; + if (direction.length() > wanderDistance) + { + direction.normalize(); + const osg::Vec3f adjustedDestination = mInitialActorPosition + direction * wanderRadius; + destination = DetourNavigator::raycast(*navigator, agentBounds, currentPosition, + adjustedDestination, navigatorFlags); + if (destination.has_value() && (*destination - mInitialActorPosition).length() > wanderDistance) + continue; + } + } + mDestination = destination.has_value() ? *destination + : getRandomPointAround(mInitialActorPosition, wanderRadius); } else mDestination = getRandomPointAround(mInitialActorPosition, wanderRadius);