Fix mDistance being reset prematurely

This was causing wandering without pathgrids to become disabled for most wandering units. Additionally, wandering now behaves the same for both NPCs and creatures.
This commit is contained in:
Austin Salgat 2016-04-15 21:56:41 -05:00
parent 92b352989a
commit 34726c24d9
2 changed files with 23 additions and 17 deletions

View file

@ -16,6 +16,7 @@
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
#include "../mwworld/cellstore.hpp" #include "../mwworld/cellstore.hpp"
#include "../mwworld/customdata.hpp"
#include "creaturestats.hpp" #include "creaturestats.hpp"
#include "steering.hpp" #include "steering.hpp"
@ -72,6 +73,8 @@ namespace MWMechanics
bool mIsWanderingManually; bool mIsWanderingManually;
ESM::Pathgrid::Point mPreviousWanderingNearSpawnLocation; ESM::Pathgrid::Point mPreviousWanderingNearSpawnLocation;
int mStuckTimer; int mStuckTimer;
bool mCanWanderAlongPathGrid;
unsigned short mIdleAnimation; unsigned short mIdleAnimation;
std::vector<unsigned short> mBadIdles; // Idle animations that when called cause errors std::vector<unsigned short> mBadIdles; // Idle animations that when called cause errors
@ -88,6 +91,7 @@ namespace MWMechanics
mState(AiWander::Wander_ChooseAction), mState(AiWander::Wander_ChooseAction),
mIsWanderingManually(false), mIsWanderingManually(false),
mStuckTimer(0), mStuckTimer(0),
mCanWanderAlongPathGrid(true),
mIdleAnimation(0), mIdleAnimation(0),
mBadIdles() mBadIdles()
{}; {};
@ -227,6 +231,9 @@ namespace MWMechanics
bool AiWander::reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, bool AiWander::reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage,
const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos) const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos)
{ {
if (mDistance <= 0)
storage.mCanWanderAlongPathGrid = false;
if (isPackageCompleted(actor, storage)) if (isPackageCompleted(actor, storage))
{ {
return true; return true;
@ -241,19 +248,19 @@ namespace MWMechanics
// Initialization to discover & store allowed node points for this actor. // Initialization to discover & store allowed node points for this actor.
if (mPopulateAvailableNodes) if (mPopulateAvailableNodes)
{ {
getAllowedNodes(actor, currentCell->getCell()); getAllowedNodes(actor, currentCell->getCell(), storage);
} }
// Actor becomes stationary - see above URL's for previous research // Actor becomes stationary - see above URL's for previous research
// If a creature or an NPC with a wander distance and no pathgrid is available, // If a creature or an NPC with a wander distance and no pathgrid is available,
// randomly idle or wander around near spawn point // randomly idle or wander around near spawn point
if(mAllowedNodes.empty() && (mDistance > 0 || !actor.getClass().isNpc()) && !storage.mIsWanderingManually) { if(mAllowedNodes.empty() && mDistance > 0 && !storage.mIsWanderingManually) {
// Typically want to idle for a short time before the next wander // Typically want to idle for a short time before the next wander
if (Misc::Rng::rollDice(100) >= 96) { if (Misc::Rng::rollDice(100) >= 96) {
wanderNearStart(actor, storage, mDistance, actor.getClass().isNpc()); wanderNearStart(actor, storage, mDistance);
} }
} else if (mAllowedNodes.empty() && !storage.mIsWanderingManually) { } else if (mAllowedNodes.empty() && !storage.mIsWanderingManually) {
mDistance = 0; storage.mCanWanderAlongPathGrid = false;
} }
// Detect obstacles if wandering manually // Detect obstacles if wandering manually
@ -281,7 +288,7 @@ namespace MWMechanics
playGreetingIfPlayerGetsTooClose(actor, storage); playGreetingIfPlayerGetsTooClose(actor, storage);
} }
if ((wanderState == Wander_MoveNow) && mDistance) if ((wanderState == Wander_MoveNow) && storage.mCanWanderAlongPathGrid)
{ {
// Construct a new path if there isn't one // Construct a new path if there isn't one
if(!storage.mPathFinder.isPathConstructed()) if(!storage.mPathFinder.isPathConstructed())
@ -346,13 +353,12 @@ namespace MWMechanics
* distance (mDistance) from the position where they started the wander package. * distance (mDistance) from the position where they started the wander package.
* http://www.uesp.net/wiki/Tes3Mod:AIWander * http://www.uesp.net/wiki/Tes3Mod:AIWander
*/ */
void AiWander::wanderNearStart(const MWWorld::Ptr &actor, AiWanderStorage &storage, int wanderDistance, bool isNpc) { void AiWander::wanderNearStart(const MWWorld::Ptr &actor, AiWanderStorage &storage, int wanderDistance) {
const ESM::Pathgrid::Point currentPosition = actor.getRefData().getPosition().pos; const ESM::Pathgrid::Point currentPosition = actor.getRefData().getPosition().pos;
// Determine a random location within radius of original position // Determine a random location within radius of original position
const float pi = 3.14159265359f; const float pi = 3.14159265359f;
const float maxWanderDistance = isNpc ? wanderDistance : MINIMUM_WANDER_DISTANCE * 14.0f; const float wanderRadius = Misc::Rng::rollClosedProbability() * wanderDistance;
const float wanderRadius = Misc::Rng::rollClosedProbability() * maxWanderDistance;
const float randomDirection = Misc::Rng::rollClosedProbability() * 2.0f * pi; const float randomDirection = Misc::Rng::rollClosedProbability() * 2.0f * pi;
const float destinationX = mInitialActorPosition.x() + wanderRadius * std::cos(randomDirection); const float destinationX = mInitialActorPosition.x() + wanderRadius * std::cos(randomDirection);
const float destinationY = mInitialActorPosition.y() + wanderRadius * std::sin(randomDirection); const float destinationY = mInitialActorPosition.y() + wanderRadius * std::sin(randomDirection);
@ -376,10 +382,10 @@ namespace MWMechanics
const float minimumDistanceTraveled = actorSpeed / 5.0f; const float minimumDistanceTraveled = actorSpeed / 5.0f;
if (distanceApart2d(storage.mPreviousWanderingNearSpawnLocation, currentPosition) < minimumDistanceTraveled) { if (distanceApart2d(storage.mPreviousWanderingNearSpawnLocation, currentPosition) < minimumDistanceTraveled) {
// Hit an obstacle and haven't moved much // Hit an obstacle and haven't moved much
if (++(storage.mStuckTimer) > 10) { if (++(storage.mStuckTimer) > 8) {
// Stuck too long, stop wandering // Stuck too long, wander elsewhere
storage.setState(Wander_ChooseAction); storage.setState(Wander_ChooseAction);
mDistance = 0; wanderNearStart(actor, storage, mDistance);
} }
} else { } else {
storage.mPreviousWanderingNearSpawnLocation = currentPosition; storage.mPreviousWanderingNearSpawnLocation = currentPosition;
@ -769,7 +775,7 @@ namespace MWMechanics
return; return;
if (mPopulateAvailableNodes) if (mPopulateAvailableNodes)
getAllowedNodes(actor, actor.getCell()->getCell()); getAllowedNodes(actor, actor.getCell()->getCell(), state.get<AiWanderStorage>());
if (mAllowedNodes.empty()) if (mAllowedNodes.empty())
return; return;
@ -796,7 +802,7 @@ namespace MWMechanics
return static_cast<int>(DESTINATION_TOLERANCE * (Misc::Rng::rollProbability() * 2.0f - 1.0f)); return static_cast<int>(DESTINATION_TOLERANCE * (Misc::Rng::rollProbability() * 2.0f - 1.0f));
} }
void AiWander::getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell) void AiWander::getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell, AiWanderStorage& storage)
{ {
// infrequently used, therefore no benefit in caching it as a member // infrequently used, therefore no benefit in caching it as a member
const ESM::Pathgrid * const ESM::Pathgrid *
@ -810,14 +816,14 @@ namespace MWMechanics
// http://www.fliggerty.com/phpBB3/viewtopic.php?f=30&t=5833 // http://www.fliggerty.com/phpBB3/viewtopic.php?f=30&t=5833
// Note: In order to wander, need at least two points. // Note: In order to wander, need at least two points.
if(!pathgrid || (pathgrid->mPoints.size() < 2)) if(!pathgrid || (pathgrid->mPoints.size() < 2))
mDistance = 0; storage.mCanWanderAlongPathGrid = false;
// A distance value passed into the constructor indicates how far the // A distance value passed into the constructor indicates how far the
// actor can wander from the spawn position. AiWander assumes that // actor can wander from the spawn position. AiWander assumes that
// pathgrid points are available, and uses them to randomly select wander // pathgrid points are available, and uses them to randomly select wander
// destinations within the allowed set of pathgrid points (nodes). // destinations within the allowed set of pathgrid points (nodes).
// ... pathgrids don't usually include water, so swimmers ignore them // ... pathgrids don't usually include water, so swimmers ignore them
if (mDistance && !actor.getClass().isPureWaterCreature(actor)) if (mDistance && storage.mCanWanderAlongPathGrid && !actor.getClass().isPureWaterCreature(actor))
{ {
// get NPC's position in local (i.e. cell) co-ordinates // get NPC's position in local (i.e. cell) co-ordinates
osg::Vec3f npcPos(mInitialActorPosition); osg::Vec3f npcPos(mInitialActorPosition);

View file

@ -94,7 +94,7 @@ namespace MWMechanics
const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos); const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos);
bool isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage); bool isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage);
void returnToStartLocation(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos); void returnToStartLocation(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos);
void wanderNearStart(const MWWorld::Ptr &actor, AiWanderStorage &storage, int wanderDistance, bool isNpc); void wanderNearStart(const MWWorld::Ptr &actor, AiWanderStorage &storage, int wanderDistance);
void detectManualWanderingObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage); void detectManualWanderingObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage);
int mDistance; // how far the actor can wander from the spawn point int mDistance; // how far the actor can wander from the spawn point
@ -126,7 +126,7 @@ namespace MWMechanics
// FIXME: move to AiWanderStorage // FIXME: move to AiWanderStorage
std::vector<ESM::Pathgrid::Point> mAllowedNodes; std::vector<ESM::Pathgrid::Point> mAllowedNodes;
void getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell); void getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell, AiWanderStorage& storage);
// FIXME: move to AiWanderStorage // FIXME: move to AiWanderStorage
ESM::Pathgrid::Point mCurrentNode; ESM::Pathgrid::Point mCurrentNode;