forked from mirror/openmw-tes3mp
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:
parent
92b352989a
commit
34726c24d9
2 changed files with 23 additions and 17 deletions
|
@ -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…
Reference in a new issue