mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-04 12:39:55 +00:00
refactor pathfinding code in AiWander: use AiPackage::pathTo, reuse AiPackage::ObstacleCheck
This commit is contained in:
parent
b304e98568
commit
0793e4a80e
@ -68,7 +68,8 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const ESM::Pathgr
|
||||
{
|
||||
bool wasShortcutting = mIsShortcutting;
|
||||
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)
|
||||
{
|
||||
@ -139,8 +140,10 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float dur
|
||||
MWWorld::Ptr door = getNearbyDoor(actor); // NOTE: checks interior cells only
|
||||
if (door != MWWorld::Ptr())
|
||||
{
|
||||
if (!door.getCellRef().getTeleport() && door.getCellRef().getTrap().empty()
|
||||
&& door.getCellRef().getLockLevel() <= 0 && door.getClass().getDoorState(door) == 0) {
|
||||
// note: AiWander currently does not open doors
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -70,8 +70,6 @@ namespace MWMechanics
|
||||
unsigned short mIdleAnimation;
|
||||
std::vector<unsigned short> mBadIdles; // Idle animations that when called cause errors
|
||||
|
||||
PathFinder mPathFinder;
|
||||
|
||||
AiWanderStorage():
|
||||
mTargetAngleRadians(0),
|
||||
mTurnActorGivingGreetingToFacePlayer(false),
|
||||
@ -87,7 +85,7 @@ namespace MWMechanics
|
||||
|
||||
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)
|
||||
, mStoredInitialActorPosition(false)
|
||||
, mStoredInitialActorPosition(false), mIsWanderDestReady(false)
|
||||
{
|
||||
mIdle.resize(8, 0);
|
||||
init();
|
||||
@ -252,7 +250,7 @@ namespace MWMechanics
|
||||
if ((wanderState == Wander_MoveNow) && mDistance)
|
||||
{
|
||||
// Construct a new path if there isn't one
|
||||
if(!storage.mPathFinder.isPathConstructed())
|
||||
if(!mPathFinder.isPathConstructed())
|
||||
{
|
||||
if (mAllowedNodes.size())
|
||||
{
|
||||
@ -290,7 +288,7 @@ namespace MWMechanics
|
||||
|
||||
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));
|
||||
|
||||
@ -298,10 +296,11 @@ namespace MWMechanics
|
||||
ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos));
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
@ -371,7 +370,7 @@ namespace MWMechanics
|
||||
float duration, AiWanderStorage& storage, ESM::Position& pos)
|
||||
{
|
||||
// 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);
|
||||
storage.mState = Wander_ChooseAction;
|
||||
@ -414,34 +413,21 @@ namespace MWMechanics
|
||||
|
||||
void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration, ESM::Position& pos)
|
||||
{
|
||||
// turn towards the next point in mPath
|
||||
zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]));
|
||||
|
||||
MWMechanics::Movement& movement = actor.getClass().getMovementSettings(actor);
|
||||
if (mObstacleCheck.check(actor, duration))
|
||||
if (mObstacleCheck.isEvading())
|
||||
{
|
||||
// first check if we're walking into a door
|
||||
if (proximityToDoor(actor)) // NOTE: checks interior cells only
|
||||
{
|
||||
// remove allowed points then select another random destination
|
||||
mTrimCurrentNode = true;
|
||||
trimAllowedNodes(mAllowedNodes, storage.mPathFinder);
|
||||
trimAllowedNodes(mAllowedNodes, mPathFinder);
|
||||
mObstacleCheck.clear();
|
||||
storage.mPathFinder.clearPath();
|
||||
mPathFinder.clearPath();
|
||||
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
|
||||
}
|
||||
else
|
||||
{
|
||||
movement.mPosition[1] = 1;
|
||||
}
|
||||
|
||||
// if stuck for sufficiently long, act like current location was the destination
|
||||
if (mStuckCount >= COUNT_BEFORE_RESET) // something has gone wrong, reset
|
||||
@ -564,11 +550,12 @@ namespace MWMechanics
|
||||
ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(actorPos));
|
||||
|
||||
// don't take shortcuts for wandering
|
||||
storage.mPathFinder.buildSyncedPath(start, dest, actor.getCell());
|
||||
storage.mPathFinder.buildPath(start, dest, actor.getCell());
|
||||
mPathFinder.buildSyncedPath(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):
|
||||
ESM::Pathgrid::Point temp = mAllowedNodes[randNode];
|
||||
mAllowedNodes.erase(mAllowedNodes.begin() + randNode);
|
||||
@ -624,7 +611,8 @@ namespace MWMechanics
|
||||
|
||||
void AiWander::stopWalking(const MWWorld::Ptr& actor, AiWanderStorage& storage)
|
||||
{
|
||||
storage.mPathFinder.clearPath();
|
||||
mPathFinder.clearPath();
|
||||
mIsWanderDestReady = false;
|
||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
||||
}
|
||||
|
||||
@ -850,6 +838,7 @@ namespace MWMechanics
|
||||
, mRepeat(wander->mData.mShouldRepeat != 0)
|
||||
, mStoredInitialActorPosition(wander->mStoredInitialActorPosition)
|
||||
, mStartTime(MWWorld::TimeStamp(wander->mStartTime))
|
||||
, mIsWanderDestReady(false)
|
||||
{
|
||||
if (mStoredInitialActorPosition)
|
||||
mInitialActorPosition = wander->mInitialActorPosition;
|
||||
|
@ -130,9 +130,9 @@ namespace MWMechanics
|
||||
const PathFinder& pathfinder);
|
||||
|
||||
|
||||
// ObstacleCheck mObstacleCheck;
|
||||
float mDoorCheckDuration;
|
||||
int mStuckCount;
|
||||
bool mIsWanderDestReady;
|
||||
|
||||
// constants for converting idleSelect values into groupNames
|
||||
enum GroupIndex
|
||||
|
@ -93,6 +93,11 @@ namespace MWMechanics
|
||||
return mWalkState == State_Norm;
|
||||
}
|
||||
|
||||
bool ObstacleCheck::isEvading() const
|
||||
{
|
||||
return mWalkState == State_Evade;
|
||||
}
|
||||
|
||||
/*
|
||||
* input - actor, duration (time since last check)
|
||||
* output - true if evasive action needs to be taken
|
||||
|
@ -33,6 +33,7 @@ namespace MWMechanics
|
||||
void clear();
|
||||
|
||||
bool isNormalState() const;
|
||||
bool isEvading() const;
|
||||
|
||||
// Returns true if there is an obstacle and an evasive action
|
||||
// should be taken
|
||||
|
Loading…
x
Reference in New Issue
Block a user