From 92b352989ace68319e700959269b9777333841a2 Mon Sep 17 00:00:00 2001 From: Austin Salgat Date: Wed, 13 Apr 2016 20:48:08 -0500 Subject: [PATCH] Add logic for NPC wandering without pathgrids --- apps/openmw/mwmechanics/aiwander.cpp | 35 ++++++++++++++++------------ apps/openmw/mwmechanics/aiwander.hpp | 2 +- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index b1df110fb..0e3d20d4a 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -232,6 +232,12 @@ namespace MWMechanics return true; } + if (!mStoredInitialActorPosition) + { + mInitialActorPosition = actor.getRefData().getPosition().asVec3(); + mStoredInitialActorPosition = true; + } + // Initialization to discover & store allowed node points for this actor. if (mPopulateAvailableNodes) { @@ -239,11 +245,12 @@ namespace MWMechanics } // Actor becomes stationary - see above URL's for previous research - // If not an NPC and no pathgrid is available, randomly idle or wander around near spawn point - if(mAllowedNodes.empty() && !actor.getBase()->mClass->isNpc() && !storage.mIsWanderingManually) { + // If a creature or an NPC with a wander distance and no pathgrid is available, + // randomly idle or wander around near spawn point + if(mAllowedNodes.empty() && (mDistance > 0 || !actor.getClass().isNpc()) && !storage.mIsWanderingManually) { // Typically want to idle for a short time before the next wander if (Misc::Rng::rollDice(100) >= 96) { - wanderNearSpawn(actor, storage); + wanderNearStart(actor, storage, mDistance, actor.getClass().isNpc()); } } else if (mAllowedNodes.empty() && !storage.mIsWanderingManually) { mDistance = 0; @@ -334,18 +341,22 @@ namespace MWMechanics /* * Commands actor to walk to a random location near original spawn location. + * + * Creatures simply wander a certain distance from their starting location, while NPCs wander a scripted + * distance (mDistance) from the position where they started the wander package. + * http://www.uesp.net/wiki/Tes3Mod:AIWander */ - void AiWander::wanderNearSpawn(const MWWorld::Ptr& actor, AiWanderStorage& storage) { + void AiWander::wanderNearStart(const MWWorld::Ptr &actor, AiWanderStorage &storage, int wanderDistance, bool isNpc) { const ESM::Pathgrid::Point currentPosition = actor.getRefData().getPosition().pos; - const ESM::Pathgrid::Point originalPosition = actor.getCellRef().getPosition().pos; // Determine a random location within radius of original position const float pi = 3.14159265359f; - const float randomRadius = Misc::Rng::rollClosedProbability() * MINIMUM_WANDER_DISTANCE * 14.0f; + const float maxWanderDistance = isNpc ? wanderDistance : MINIMUM_WANDER_DISTANCE * 14.0f; + const float wanderRadius = Misc::Rng::rollClosedProbability() * maxWanderDistance; const float randomDirection = Misc::Rng::rollClosedProbability() * 2.0f * pi; - const float destinationX = originalPosition.mX + randomRadius * std::cos(randomDirection); - const float destinationY = originalPosition.mY + randomRadius * std::sin(randomDirection); - ESM::Pathgrid::Point destinationPosition = ESM::Pathgrid::Point(destinationX, destinationY, originalPosition.mZ); + const float destinationX = mInitialActorPosition.x() + wanderRadius * std::cos(randomDirection); + const float destinationY = mInitialActorPosition.y() + wanderRadius * std::sin(randomDirection); + ESM::Pathgrid::Point destinationPosition = ESM::Pathgrid::Point(destinationX, destinationY, mInitialActorPosition.z()); storage.mPathFinder.buildSyncedPath(currentPosition, destinationPosition, actor.getCell(), true); storage.mPathFinder.addPointToPath(destinationPosition); @@ -787,12 +798,6 @@ namespace MWMechanics void AiWander::getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell) { - if (!mStoredInitialActorPosition) - { - mInitialActorPosition = actor.getRefData().getPosition().asVec3(); - mStoredInitialActorPosition = true; - } - // infrequently used, therefore no benefit in caching it as a member const ESM::Pathgrid * pathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*cell); diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index b8001c701..dde87079a 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -94,7 +94,7 @@ namespace MWMechanics const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos); bool isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage); void returnToStartLocation(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos); - void wanderNearSpawn(const MWWorld::Ptr& actor, AiWanderStorage& storage); + void wanderNearStart(const MWWorld::Ptr &actor, AiWanderStorage &storage, int wanderDistance, bool isNpc); void detectManualWanderingObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage); int mDistance; // how far the actor can wander from the spawn point