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.
pull/1/head
Austin Salgat 9 years ago
parent 92b352989a
commit 34726c24d9

@ -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);

@ -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;

Loading…
Cancel
Save