1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-26 18:35:20 +00:00

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/esmstore.hpp"
#include "../mwworld/cellstore.hpp"
#include "../mwworld/customdata.hpp"
#include "creaturestats.hpp"
#include "steering.hpp"
@ -72,6 +73,8 @@ namespace MWMechanics
bool mIsWanderingManually;
ESM::Pathgrid::Point mPreviousWanderingNearSpawnLocation;
int mStuckTimer;
bool mCanWanderAlongPathGrid;
unsigned short mIdleAnimation;
std::vector<unsigned short> mBadIdles; // Idle animations that when called cause errors
@ -88,6 +91,7 @@ namespace MWMechanics
mState(AiWander::Wander_ChooseAction),
mIsWanderingManually(false),
mStuckTimer(0),
mCanWanderAlongPathGrid(true),
mIdleAnimation(0),
mBadIdles()
{};
@ -227,6 +231,9 @@ namespace MWMechanics
bool AiWander::reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage,
const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos)
{
if (mDistance <= 0)
storage.mCanWanderAlongPathGrid = false;
if (isPackageCompleted(actor, storage))
{
return true;
@ -241,19 +248,19 @@ namespace MWMechanics
// Initialization to discover & store allowed node points for this actor.
if (mPopulateAvailableNodes)
{
getAllowedNodes(actor, currentCell->getCell());
getAllowedNodes(actor, currentCell->getCell(), storage);
}
// 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,
// 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
if (Misc::Rng::rollDice(100) >= 96) {
wanderNearStart(actor, storage, mDistance, actor.getClass().isNpc());
wanderNearStart(actor, storage, mDistance);
}
} else if (mAllowedNodes.empty() && !storage.mIsWanderingManually) {
mDistance = 0;
storage.mCanWanderAlongPathGrid = false;
}
// Detect obstacles if wandering manually
@ -281,7 +288,7 @@ namespace MWMechanics
playGreetingIfPlayerGetsTooClose(actor, storage);
}
if ((wanderState == Wander_MoveNow) && mDistance)
if ((wanderState == Wander_MoveNow) && storage.mCanWanderAlongPathGrid)
{
// Construct a new path if there isn't one
if(!storage.mPathFinder.isPathConstructed())
@ -346,13 +353,12 @@ namespace MWMechanics
* distance (mDistance) from the position where they started the wander package.
* 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;
// Determine a random location within radius of original position
const float pi = 3.14159265359f;
const float maxWanderDistance = isNpc ? wanderDistance : MINIMUM_WANDER_DISTANCE * 14.0f;
const float wanderRadius = Misc::Rng::rollClosedProbability() * maxWanderDistance;
const float wanderRadius = Misc::Rng::rollClosedProbability() * wanderDistance;
const float randomDirection = Misc::Rng::rollClosedProbability() * 2.0f * pi;
const float destinationX = mInitialActorPosition.x() + wanderRadius * std::cos(randomDirection);
const float destinationY = mInitialActorPosition.y() + wanderRadius * std::sin(randomDirection);
@ -376,10 +382,10 @@ namespace MWMechanics
const float minimumDistanceTraveled = actorSpeed / 5.0f;
if (distanceApart2d(storage.mPreviousWanderingNearSpawnLocation, currentPosition) < minimumDistanceTraveled) {
// Hit an obstacle and haven't moved much
if (++(storage.mStuckTimer) > 10) {
// Stuck too long, stop wandering
if (++(storage.mStuckTimer) > 8) {
// Stuck too long, wander elsewhere
storage.setState(Wander_ChooseAction);
mDistance = 0;
wanderNearStart(actor, storage, mDistance);
}
} else {
storage.mPreviousWanderingNearSpawnLocation = currentPosition;
@ -769,7 +775,7 @@ namespace MWMechanics
return;
if (mPopulateAvailableNodes)
getAllowedNodes(actor, actor.getCell()->getCell());
getAllowedNodes(actor, actor.getCell()->getCell(), state.get<AiWanderStorage>());
if (mAllowedNodes.empty())
return;
@ -796,7 +802,7 @@ namespace MWMechanics
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
const ESM::Pathgrid *
@ -810,14 +816,14 @@ namespace MWMechanics
// http://www.fliggerty.com/phpBB3/viewtopic.php?f=30&t=5833
// Note: In order to wander, need at least two points.
if(!pathgrid || (pathgrid->mPoints.size() < 2))
mDistance = 0;
storage.mCanWanderAlongPathGrid = false;
// A distance value passed into the constructor indicates how far the
// actor can wander from the spawn position. AiWander assumes that
// pathgrid points are available, and uses them to randomly select wander
// destinations within the allowed set of pathgrid points (nodes).
// ... 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
osg::Vec3f npcPos(mInitialActorPosition);

View File

@ -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 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);
int mDistance; // how far the actor can wander from the spawn point
@ -126,7 +126,7 @@ namespace MWMechanics
// FIXME: move to AiWanderStorage
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
ESM::Pathgrid::Point mCurrentNode;