mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-03-03 17:49:41 +00:00
refactor pathfinding code in AiWander: use AiPackage::pathTo, reuse AiPackage::ObstacleCheck
This commit is contained in:
parent
b304e98568
commit
0793e4a80e
5 changed files with 31 additions and 33 deletions
|
@ -68,7 +68,8 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const ESM::Pathgr
|
||||||
{
|
{
|
||||||
bool wasShortcutting = mIsShortcutting;
|
bool wasShortcutting = mIsShortcutting;
|
||||||
bool destInLOS = false;
|
bool destInLOS = false;
|
||||||
mIsShortcutting = shortcutPath(start, dest, actor, &destInLOS); // try to shortcut first
|
if (getTypeId() != TypeIdWander) // prohibit shortcuts for AiWander
|
||||||
|
mIsShortcutting = shortcutPath(start, dest, actor, &destInLOS); // try to shortcut first
|
||||||
|
|
||||||
if (!mIsShortcutting)
|
if (!mIsShortcutting)
|
||||||
{
|
{
|
||||||
|
@ -139,8 +140,10 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float dur
|
||||||
MWWorld::Ptr door = getNearbyDoor(actor); // NOTE: checks interior cells only
|
MWWorld::Ptr door = getNearbyDoor(actor); // NOTE: checks interior cells only
|
||||||
if (door != MWWorld::Ptr())
|
if (door != MWWorld::Ptr())
|
||||||
{
|
{
|
||||||
if (!door.getCellRef().getTeleport() && door.getCellRef().getTrap().empty()
|
// note: AiWander currently does not open doors
|
||||||
&& door.getCellRef().getLockLevel() <= 0 && door.getClass().getDoorState(door) == 0) {
|
if (getTypeId() != TypeIdWander && !door.getCellRef().getTeleport() && door.getCellRef().getTrap().empty()
|
||||||
|
&& door.getCellRef().getLockLevel() <= 0 && door.getClass().getDoorState(door) == 0)
|
||||||
|
{
|
||||||
MWBase::Environment::get().getWorld()->activateDoor(door, 1);
|
MWBase::Environment::get().getWorld()->activateDoor(door, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,8 +70,6 @@ namespace MWMechanics
|
||||||
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
|
||||||
|
|
||||||
PathFinder mPathFinder;
|
|
||||||
|
|
||||||
AiWanderStorage():
|
AiWanderStorage():
|
||||||
mTargetAngleRadians(0),
|
mTargetAngleRadians(0),
|
||||||
mTurnActorGivingGreetingToFacePlayer(false),
|
mTurnActorGivingGreetingToFacePlayer(false),
|
||||||
|
@ -87,7 +85,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<unsigned char>& idle, bool repeat):
|
AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<unsigned char>& idle, bool repeat):
|
||||||
mDistance(distance), mDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), mRepeat(repeat)
|
mDistance(distance), mDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), mRepeat(repeat)
|
||||||
, mStoredInitialActorPosition(false)
|
, mStoredInitialActorPosition(false), mIsWanderDestReady(false)
|
||||||
{
|
{
|
||||||
mIdle.resize(8, 0);
|
mIdle.resize(8, 0);
|
||||||
init();
|
init();
|
||||||
|
@ -252,7 +250,7 @@ namespace MWMechanics
|
||||||
if ((wanderState == Wander_MoveNow) && mDistance)
|
if ((wanderState == Wander_MoveNow) && mDistance)
|
||||||
{
|
{
|
||||||
// Construct a new path if there isn't one
|
// Construct a new path if there isn't one
|
||||||
if(!storage.mPathFinder.isPathConstructed())
|
if(!mPathFinder.isPathConstructed())
|
||||||
{
|
{
|
||||||
if (mAllowedNodes.size())
|
if (mAllowedNodes.size())
|
||||||
{
|
{
|
||||||
|
@ -290,7 +288,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
void AiWander::returnToStartLocation(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos)
|
void AiWander::returnToStartLocation(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos)
|
||||||
{
|
{
|
||||||
if (!storage.mPathFinder.isPathConstructed())
|
if (!mPathFinder.isPathConstructed())
|
||||||
{
|
{
|
||||||
ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(mReturnPosition));
|
ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(mReturnPosition));
|
||||||
|
|
||||||
|
@ -298,10 +296,11 @@ namespace MWMechanics
|
||||||
ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos));
|
ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos));
|
||||||
|
|
||||||
// don't take shortcuts for wandering
|
// don't take shortcuts for wandering
|
||||||
storage.mPathFinder.buildSyncedPath(start, dest, actor.getCell());
|
mPathFinder.buildSyncedPath(start, dest, actor.getCell());
|
||||||
|
|
||||||
if (storage.mPathFinder.isPathConstructed())
|
if (mPathFinder.isPathConstructed())
|
||||||
{
|
{
|
||||||
|
mIsWanderDestReady = true;
|
||||||
storage.mState = Wander_Walking;
|
storage.mState = Wander_Walking;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -371,7 +370,7 @@ namespace MWMechanics
|
||||||
float duration, AiWanderStorage& storage, ESM::Position& pos)
|
float duration, AiWanderStorage& storage, ESM::Position& pos)
|
||||||
{
|
{
|
||||||
// Are we there yet?
|
// Are we there yet?
|
||||||
if (storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], DESTINATION_TOLERANCE))
|
if (mIsWanderDestReady && pathTo(actor, mPathFinder.getPath().back(), duration, DESTINATION_TOLERANCE))
|
||||||
{
|
{
|
||||||
stopWalking(actor, storage);
|
stopWalking(actor, storage);
|
||||||
storage.mState = Wander_ChooseAction;
|
storage.mState = Wander_ChooseAction;
|
||||||
|
@ -414,34 +413,21 @@ namespace MWMechanics
|
||||||
|
|
||||||
void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration, ESM::Position& pos)
|
void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration, ESM::Position& pos)
|
||||||
{
|
{
|
||||||
// turn towards the next point in mPath
|
if (mObstacleCheck.isEvading())
|
||||||
zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]));
|
|
||||||
|
|
||||||
MWMechanics::Movement& movement = actor.getClass().getMovementSettings(actor);
|
|
||||||
if (mObstacleCheck.check(actor, duration))
|
|
||||||
{
|
{
|
||||||
// first check if we're walking into a door
|
// first check if we're walking into a door
|
||||||
if (proximityToDoor(actor)) // NOTE: checks interior cells only
|
if (proximityToDoor(actor)) // NOTE: checks interior cells only
|
||||||
{
|
{
|
||||||
// remove allowed points then select another random destination
|
// remove allowed points then select another random destination
|
||||||
mTrimCurrentNode = true;
|
mTrimCurrentNode = true;
|
||||||
trimAllowedNodes(mAllowedNodes, storage.mPathFinder);
|
trimAllowedNodes(mAllowedNodes, mPathFinder);
|
||||||
mObstacleCheck.clear();
|
mObstacleCheck.clear();
|
||||||
storage.mPathFinder.clearPath();
|
mPathFinder.clearPath();
|
||||||
storage.mState = Wander_MoveNow;
|
storage.mState = Wander_MoveNow;
|
||||||
}
|
}
|
||||||
else // probably walking into another NPC
|
|
||||||
{
|
|
||||||
// TODO: diagonal should have same animation as walk forward
|
|
||||||
// but doesn't seem to do that?
|
|
||||||
mObstacleCheck.takeEvasiveAction(movement);
|
|
||||||
}
|
|
||||||
mStuckCount++; // TODO: maybe no longer needed
|
mStuckCount++; // TODO: maybe no longer needed
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
movement.mPosition[1] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if stuck for sufficiently long, act like current location was the destination
|
// if stuck for sufficiently long, act like current location was the destination
|
||||||
if (mStuckCount >= COUNT_BEFORE_RESET) // something has gone wrong, reset
|
if (mStuckCount >= COUNT_BEFORE_RESET) // something has gone wrong, reset
|
||||||
|
@ -564,11 +550,12 @@ namespace MWMechanics
|
||||||
ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(actorPos));
|
ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(actorPos));
|
||||||
|
|
||||||
// don't take shortcuts for wandering
|
// don't take shortcuts for wandering
|
||||||
storage.mPathFinder.buildSyncedPath(start, dest, actor.getCell());
|
mPathFinder.buildSyncedPath(start, dest, actor.getCell());
|
||||||
storage.mPathFinder.buildPath(start, dest, actor.getCell());
|
|
||||||
|
|
||||||
if (storage.mPathFinder.isPathConstructed())
|
if (mPathFinder.isPathConstructed())
|
||||||
{
|
{
|
||||||
|
mIsWanderDestReady = true;
|
||||||
|
|
||||||
// Remove this node as an option and add back the previously used node (stops NPC from picking the same node):
|
// Remove this node as an option and add back the previously used node (stops NPC from picking the same node):
|
||||||
ESM::Pathgrid::Point temp = mAllowedNodes[randNode];
|
ESM::Pathgrid::Point temp = mAllowedNodes[randNode];
|
||||||
mAllowedNodes.erase(mAllowedNodes.begin() + randNode);
|
mAllowedNodes.erase(mAllowedNodes.begin() + randNode);
|
||||||
|
@ -624,7 +611,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
void AiWander::stopWalking(const MWWorld::Ptr& actor, AiWanderStorage& storage)
|
void AiWander::stopWalking(const MWWorld::Ptr& actor, AiWanderStorage& storage)
|
||||||
{
|
{
|
||||||
storage.mPathFinder.clearPath();
|
mPathFinder.clearPath();
|
||||||
|
mIsWanderDestReady = false;
|
||||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -850,6 +838,7 @@ namespace MWMechanics
|
||||||
, mRepeat(wander->mData.mShouldRepeat != 0)
|
, mRepeat(wander->mData.mShouldRepeat != 0)
|
||||||
, mStoredInitialActorPosition(wander->mStoredInitialActorPosition)
|
, mStoredInitialActorPosition(wander->mStoredInitialActorPosition)
|
||||||
, mStartTime(MWWorld::TimeStamp(wander->mStartTime))
|
, mStartTime(MWWorld::TimeStamp(wander->mStartTime))
|
||||||
|
, mIsWanderDestReady(false)
|
||||||
{
|
{
|
||||||
if (mStoredInitialActorPosition)
|
if (mStoredInitialActorPosition)
|
||||||
mInitialActorPosition = wander->mInitialActorPosition;
|
mInitialActorPosition = wander->mInitialActorPosition;
|
||||||
|
|
|
@ -130,9 +130,9 @@ namespace MWMechanics
|
||||||
const PathFinder& pathfinder);
|
const PathFinder& pathfinder);
|
||||||
|
|
||||||
|
|
||||||
// ObstacleCheck mObstacleCheck;
|
|
||||||
float mDoorCheckDuration;
|
float mDoorCheckDuration;
|
||||||
int mStuckCount;
|
int mStuckCount;
|
||||||
|
bool mIsWanderDestReady;
|
||||||
|
|
||||||
// constants for converting idleSelect values into groupNames
|
// constants for converting idleSelect values into groupNames
|
||||||
enum GroupIndex
|
enum GroupIndex
|
||||||
|
|
|
@ -93,6 +93,11 @@ namespace MWMechanics
|
||||||
return mWalkState == State_Norm;
|
return mWalkState == State_Norm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ObstacleCheck::isEvading() const
|
||||||
|
{
|
||||||
|
return mWalkState == State_Evade;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* input - actor, duration (time since last check)
|
* input - actor, duration (time since last check)
|
||||||
* output - true if evasive action needs to be taken
|
* output - true if evasive action needs to be taken
|
||||||
|
|
|
@ -33,6 +33,7 @@ namespace MWMechanics
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
bool isNormalState() const;
|
bool isNormalState() const;
|
||||||
|
bool isEvading() const;
|
||||||
|
|
||||||
// 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
|
||||||
|
|
Loading…
Reference in a new issue