Refactor to reuse existing obstacle detection

pull/1/head
Austin Salgat 9 years ago
parent 34726c24d9
commit fc03216d48

@ -69,11 +69,7 @@ namespace MWMechanics
// AiWander states // AiWander states
AiWander::WanderState mState; AiWander::WanderState mState;
// Wandering near spawn logic
bool mIsWanderingManually; bool mIsWanderingManually;
ESM::Pathgrid::Point mPreviousWanderingNearSpawnLocation;
int mStuckTimer;
bool mCanWanderAlongPathGrid; bool mCanWanderAlongPathGrid;
unsigned short mIdleAnimation; unsigned short mIdleAnimation;
@ -90,7 +86,6 @@ namespace MWMechanics
mCell(NULL), mCell(NULL),
mState(AiWander::Wander_ChooseAction), mState(AiWander::Wander_ChooseAction),
mIsWanderingManually(false), mIsWanderingManually(false),
mStuckTimer(0),
mCanWanderAlongPathGrid(true), mCanWanderAlongPathGrid(true),
mIdleAnimation(0), mIdleAnimation(0),
mBadIdles() mBadIdles()
@ -222,14 +217,14 @@ namespace MWMechanics
if (REACTION_INTERVAL <= lastReaction) if (REACTION_INTERVAL <= lastReaction)
{ {
lastReaction = 0; lastReaction = 0;
return reactionTimeActions(actor, storage, currentCell, cellChange, pos); return reactionTimeActions(actor, storage, currentCell, cellChange, pos, duration);
} }
else else
return false; return false;
} }
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, float duration)
{ {
if (mDistance <= 0) if (mDistance <= 0)
storage.mCanWanderAlongPathGrid = false; storage.mCanWanderAlongPathGrid = false;
@ -263,9 +258,9 @@ namespace MWMechanics
storage.mCanWanderAlongPathGrid = false; storage.mCanWanderAlongPathGrid = false;
} }
// Detect obstacles if wandering manually // If Wandering manually and hit an obstacle, stop
if (storage.mIsWanderingManually) { if (storage.mIsWanderingManually && mObstacleCheck.check(actor, duration*10.0f, 2.5f)) {
detectManualWanderingObstacles(actor, storage); stopWalking(actor, storage);
} }
// Don't try to move if you are in a new cell (ie: positioncell command called) but still play idles. // Don't try to move if you are in a new cell (ie: positioncell command called) but still play idles.
@ -348,10 +343,6 @@ namespace MWMechanics
/* /*
* Commands actor to walk to a random location near original spawn location. * 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::wanderNearStart(const MWWorld::Ptr &actor, AiWanderStorage &storage, int wanderDistance) { 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;
@ -366,32 +357,9 @@ namespace MWMechanics
storage.mPathFinder.buildSyncedPath(currentPosition, destinationPosition, actor.getCell(), true); storage.mPathFinder.buildSyncedPath(currentPosition, destinationPosition, actor.getCell(), true);
storage.mPathFinder.addPointToPath(destinationPosition); storage.mPathFinder.addPointToPath(destinationPosition);
storage.mPreviousWanderingNearSpawnLocation = currentPosition;
storage.mStuckTimer = 0;
storage.setState(Wander_Walking, true); storage.setState(Wander_Walking, true);
} }
/*
* Detects if a manually wandering actor has spent too much time at one spot (stuck by an obstacle)
* and stops wandering when that occurs. Uses the unit's speed to help determine how long they should
* not be in one spot.
*/
void AiWander::detectManualWanderingObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage) {
const ESM::Pathgrid::Point currentPosition = actor.getRefData().getPosition().pos;
const float actorSpeed = actor.getClass().getSpeed(actor);
const float minimumDistanceTraveled = actorSpeed / 5.0f;
if (distanceApart2d(storage.mPreviousWanderingNearSpawnLocation, currentPosition) < minimumDistanceTraveled) {
// Hit an obstacle and haven't moved much
if (++(storage.mStuckTimer) > 8) {
// Stuck too long, wander elsewhere
storage.setState(Wander_ChooseAction);
wanderNearStart(actor, storage, mDistance);
}
} else {
storage.mPreviousWanderingNearSpawnLocation = currentPosition;
}
}
void AiWander::doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos) void AiWander::doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos)
{ {
switch (storage.mState) switch (storage.mState)

@ -91,11 +91,10 @@ namespace MWMechanics
void onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos); void onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos);
void onChooseActionStatePerFrameActions(const MWWorld::Ptr& actor, AiWanderStorage& storage); void onChooseActionStatePerFrameActions(const MWWorld::Ptr& actor, AiWanderStorage& storage);
bool reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, bool 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, float duration);
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); 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 int mDistance; // how far the actor can wander from the spawn point
int mDuration; int mDuration;
@ -160,12 +159,6 @@ namespace MWMechanics
static const std::string sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1]; static const std::string sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1];
static int OffsetToPreventOvercrowding(); static int OffsetToPreventOvercrowding();
float distanceApart2d(const ESM::Pathgrid::Point& first, const ESM::Pathgrid::Point& second) {
const float deltaX = second.mX - first.mX;
const float deltaY = second.mY - first.mY;
return std::sqrt(deltaX*deltaX + deltaY*deltaY);
}
}; };

@ -115,13 +115,13 @@ namespace MWMechanics
* u = how long to move sideways * u = how long to move sideways
* *
*/ */
bool ObstacleCheck::check(const MWWorld::Ptr& actor, float duration) bool ObstacleCheck::check(const MWWorld::Ptr& actor, float duration, float scaleMinimumDistance)
{ {
const MWWorld::Class& cls = actor.getClass(); const MWWorld::Class& cls = actor.getClass();
ESM::Position pos = actor.getRefData().getPosition(); ESM::Position pos = actor.getRefData().getPosition();
if(mDistSameSpot == -1) if(mDistSameSpot == -1)
mDistSameSpot = DIST_SAME_SPOT * cls.getSpeed(actor); mDistSameSpot = DIST_SAME_SPOT * cls.getSpeed(actor) * scaleMinimumDistance;
float distSameSpot = mDistSameSpot * duration; float distSameSpot = mDistSameSpot * duration;

@ -36,7 +36,7 @@ namespace MWMechanics
// Returns true if there is an obstacle and an evasive action // Returns true if there is an obstacle and an evasive action
// should be taken // should be taken
bool check(const MWWorld::Ptr& actor, float duration); bool check(const MWWorld::Ptr& actor, float duration, float scaleMinimumDistance = 1.0f);
// change direction to try to fix "stuck" actor // change direction to try to fix "stuck" actor
void takeEvasiveAction(MWMechanics::Movement& actorMovement); void takeEvasiveAction(MWMechanics::Movement& actorMovement);

Loading…
Cancel
Save