mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 21:23:52 +00:00
AI package cleanups
This commit is contained in:
parent
372f2e2f18
commit
c2b51112f2
3 changed files with 85 additions and 113 deletions
|
@ -16,7 +16,6 @@
|
||||||
#include "movement.hpp"
|
#include "movement.hpp"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TODO: Test vanilla behavior on passing x0, y0, and z0 with duration of anything including 0.
|
|
||||||
TODO: Different behavior for AIEscort a d x y z and AIEscortCell a c d x y z.
|
TODO: Different behavior for AIEscort a d x y z and AIEscortCell a c d x y z.
|
||||||
TODO: Take account for actors being in different cells.
|
TODO: Take account for actors being in different cells.
|
||||||
*/
|
*/
|
||||||
|
@ -109,7 +108,7 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Stop moving if the player is to far away
|
// Stop moving if the player is too far away
|
||||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle3", 0, 1);
|
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle3", 0, 1);
|
||||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
||||||
mMaxDist = 250;
|
mMaxDist = 250;
|
||||||
|
|
|
@ -76,6 +76,21 @@ namespace MWMechanics
|
||||||
|
|
||||||
PathFinder mPathFinder;
|
PathFinder mPathFinder;
|
||||||
|
|
||||||
|
// do we need to calculate allowed nodes based on mDistance
|
||||||
|
bool mPopulateAvailableNodes;
|
||||||
|
|
||||||
|
// allowed pathgrid nodes based on mDistance from the spawn point
|
||||||
|
// in local coordinates of mCell
|
||||||
|
std::vector<ESM::Pathgrid::Point> mAllowedNodes;
|
||||||
|
|
||||||
|
ESM::Pathgrid::Point mCurrentNode;
|
||||||
|
bool mTrimCurrentNode;
|
||||||
|
|
||||||
|
ObstacleCheck mObstacleCheck;
|
||||||
|
|
||||||
|
float mDoorCheckDuration;
|
||||||
|
int mStuckCount;
|
||||||
|
|
||||||
AiWanderStorage():
|
AiWanderStorage():
|
||||||
mTargetAngleRadians(0),
|
mTargetAngleRadians(0),
|
||||||
mTurnActorGivingGreetingToFacePlayer(false),
|
mTurnActorGivingGreetingToFacePlayer(false),
|
||||||
|
@ -87,7 +102,12 @@ namespace MWMechanics
|
||||||
mIsWanderingManually(false),
|
mIsWanderingManually(false),
|
||||||
mCanWanderAlongPathGrid(true),
|
mCanWanderAlongPathGrid(true),
|
||||||
mIdleAnimation(0),
|
mIdleAnimation(0),
|
||||||
mBadIdles()
|
mBadIdles(),
|
||||||
|
mPopulateAvailableNodes(true),
|
||||||
|
mAllowedNodes(),
|
||||||
|
mTrimCurrentNode(false),
|
||||||
|
mDoorCheckDuration(0), // TODO: maybe no longer needed
|
||||||
|
mStuckCount(0)
|
||||||
{};
|
{};
|
||||||
|
|
||||||
void setState(const AiWander::WanderState wanderState, const bool isManualWander = false) {
|
void setState(const AiWander::WanderState wanderState, const bool isManualWander = false) {
|
||||||
|
@ -108,11 +128,6 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
// NOTE: mDistance and mDuration must be set already
|
// NOTE: mDistance and mDuration must be set already
|
||||||
|
|
||||||
|
|
||||||
mStuckCount = 0;// TODO: maybe no longer needed
|
|
||||||
mDoorCheckDuration = 0;
|
|
||||||
mTrimCurrentNode = false;
|
|
||||||
|
|
||||||
mHasReturnPosition = false;
|
mHasReturnPosition = false;
|
||||||
mReturnPosition = osg::Vec3f(0,0,0);
|
mReturnPosition = osg::Vec3f(0,0,0);
|
||||||
|
|
||||||
|
@ -120,16 +135,6 @@ namespace MWMechanics
|
||||||
mDistance = 0;
|
mDistance = 0;
|
||||||
if(mDuration < 0)
|
if(mDuration < 0)
|
||||||
mDuration = 0;
|
mDuration = 0;
|
||||||
if(mDuration == 0)
|
|
||||||
mTimeOfDay = 0;
|
|
||||||
if(mDuration > 24)
|
|
||||||
{
|
|
||||||
mDuration = 24;
|
|
||||||
mRemainingDuration = (mDuration);
|
|
||||||
}
|
|
||||||
|
|
||||||
mPopulateAvailableNodes = true;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AiPackage * MWMechanics::AiWander::clone() const
|
AiPackage * MWMechanics::AiWander::clone() const
|
||||||
|
@ -202,7 +207,7 @@ namespace MWMechanics
|
||||||
if(!currentCell || cellChange)
|
if(!currentCell || cellChange)
|
||||||
{
|
{
|
||||||
currentCell = actor.getCell();
|
currentCell = actor.getCell();
|
||||||
mPopulateAvailableNodes = true;
|
storage.mPopulateAvailableNodes = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
mRemainingDuration -= ((duration*MWBase::Environment::get().getWorld()->getTimeScaleFactor()) / 3600);
|
mRemainingDuration -= ((duration*MWBase::Environment::get().getWorld()->getTimeScaleFactor()) / 3600);
|
||||||
|
@ -248,7 +253,7 @@ 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 (storage.mPopulateAvailableNodes)
|
||||||
{
|
{
|
||||||
getAllowedNodes(actor, currentCell->getCell(), storage);
|
getAllowedNodes(actor, currentCell->getCell(), storage);
|
||||||
}
|
}
|
||||||
|
@ -256,19 +261,19 @@ namespace MWMechanics
|
||||||
// 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 && !storage.mIsWanderingManually) {
|
if(storage.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);
|
wanderNearStart(actor, storage, mDistance);
|
||||||
} else {
|
} else {
|
||||||
storage.setState(Wander_IdleNow);
|
storage.setState(Wander_IdleNow);
|
||||||
}
|
}
|
||||||
} else if (mAllowedNodes.empty() && !storage.mIsWanderingManually) {
|
} else if (storage.mAllowedNodes.empty() && !storage.mIsWanderingManually) {
|
||||||
storage.mCanWanderAlongPathGrid = false;
|
storage.mCanWanderAlongPathGrid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If Wandering manually and hit an obstacle, stop
|
// If Wandering manually and hit an obstacle, stop
|
||||||
if (storage.mIsWanderingManually && mObstacleCheck.check(actor, duration, 2.0f)) {
|
if (storage.mIsWanderingManually && storage.mObstacleCheck.check(actor, duration, 2.0f)) {
|
||||||
completeManualWalking(actor, storage);
|
completeManualWalking(actor, storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,7 +302,7 @@ namespace MWMechanics
|
||||||
// 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())
|
||||||
{
|
{
|
||||||
if (!mAllowedNodes.empty())
|
if (!storage.mAllowedNodes.empty())
|
||||||
{
|
{
|
||||||
setPathToAnAllowedNode(actor, storage, pos);
|
setPathToAnAllowedNode(actor, storage, pos);
|
||||||
}
|
}
|
||||||
|
@ -314,6 +319,7 @@ namespace MWMechanics
|
||||||
return mRepeat;
|
return mRepeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool AiWander::isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage)
|
bool AiWander::isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage)
|
||||||
{
|
{
|
||||||
if (mDuration)
|
if (mDuration)
|
||||||
|
@ -401,7 +407,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
void AiWander::completeManualWalking(const MWWorld::Ptr &actor, AiWanderStorage &storage) {
|
void AiWander::completeManualWalking(const MWWorld::Ptr &actor, AiWanderStorage &storage) {
|
||||||
stopWalking(actor, storage);
|
stopWalking(actor, storage);
|
||||||
mObstacleCheck.clear();
|
storage.mObstacleCheck.clear();
|
||||||
storage.setState(Wander_IdleNow);
|
storage.setState(Wander_IdleNow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,15 +440,15 @@ namespace MWMechanics
|
||||||
void AiWander::onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage)
|
void AiWander::onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage)
|
||||||
{
|
{
|
||||||
// Check if an idle actor is too close to a door - if so start walking
|
// Check if an idle actor is too close to a door - if so start walking
|
||||||
mDoorCheckDuration += duration;
|
storage.mDoorCheckDuration += duration;
|
||||||
if (mDoorCheckDuration >= DOOR_CHECK_INTERVAL)
|
if (storage.mDoorCheckDuration >= DOOR_CHECK_INTERVAL)
|
||||||
{
|
{
|
||||||
mDoorCheckDuration = 0; // restart timer
|
storage.mDoorCheckDuration = 0; // restart timer
|
||||||
if (mDistance && // actor is not intended to be stationary
|
if (mDistance && // actor is not intended to be stationary
|
||||||
proximityToDoor(actor, MIN_DIST_TO_DOOR_SQUARED*1.6f*1.6f)) // NOTE: checks interior cells only
|
proximityToDoor(actor, MIN_DIST_TO_DOOR_SQUARED*1.6f*1.6f)) // NOTE: checks interior cells only
|
||||||
{
|
{
|
||||||
storage.setState(Wander_MoveNow);
|
storage.setState(Wander_MoveNow);
|
||||||
mTrimCurrentNode = false; // just in case
|
storage.mTrimCurrentNode = false; // just in case
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -515,15 +521,15 @@ namespace MWMechanics
|
||||||
zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]));
|
zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]));
|
||||||
|
|
||||||
MWMechanics::Movement& movement = actor.getClass().getMovementSettings(actor);
|
MWMechanics::Movement& movement = actor.getClass().getMovementSettings(actor);
|
||||||
if (mObstacleCheck.check(actor, duration))
|
if (storage.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;
|
storage.mTrimCurrentNode = true;
|
||||||
trimAllowedNodes(mAllowedNodes, storage.mPathFinder);
|
trimAllowedNodes(storage.mAllowedNodes, storage.mPathFinder);
|
||||||
mObstacleCheck.clear();
|
storage.mObstacleCheck.clear();
|
||||||
storage.mPathFinder.clearPath();
|
storage.mPathFinder.clearPath();
|
||||||
storage.setState(Wander_MoveNow);
|
storage.setState(Wander_MoveNow);
|
||||||
}
|
}
|
||||||
|
@ -531,9 +537,9 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
// TODO: diagonal should have same animation as walk forward
|
// TODO: diagonal should have same animation as walk forward
|
||||||
// but doesn't seem to do that?
|
// but doesn't seem to do that?
|
||||||
mObstacleCheck.takeEvasiveAction(movement);
|
storage.mObstacleCheck.takeEvasiveAction(movement);
|
||||||
}
|
}
|
||||||
mStuckCount++; // TODO: maybe no longer needed
|
storage.mStuckCount++; // TODO: maybe no longer needed
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -541,14 +547,14 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 (storage.mStuckCount >= COUNT_BEFORE_RESET) // something has gone wrong, reset
|
||||||
{
|
{
|
||||||
//std::cout << "Reset \""<< cls.getName(actor) << "\"" << std::endl;
|
//std::cout << "Reset \""<< cls.getName(actor) << "\"" << std::endl;
|
||||||
mObstacleCheck.clear();
|
storage.mObstacleCheck.clear();
|
||||||
|
|
||||||
stopWalking(actor, storage);
|
stopWalking(actor, storage);
|
||||||
storage.setState(Wander_ChooseAction);
|
storage.setState(Wander_ChooseAction);
|
||||||
mStuckCount = 0;
|
storage.mStuckCount = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -621,7 +627,7 @@ namespace MWMechanics
|
||||||
if (storage.mState == Wander_Walking)
|
if (storage.mState == Wander_Walking)
|
||||||
{
|
{
|
||||||
stopWalking(actor, storage);
|
stopWalking(actor, storage);
|
||||||
mObstacleCheck.clear();
|
storage.mObstacleCheck.clear();
|
||||||
storage.setState(Wander_IdleNow);
|
storage.setState(Wander_IdleNow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -653,8 +659,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
void AiWander::setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos)
|
void AiWander::setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos)
|
||||||
{
|
{
|
||||||
unsigned int randNode = Misc::Rng::rollDice(mAllowedNodes.size());
|
unsigned int randNode = Misc::Rng::rollDice(storage.mAllowedNodes.size());
|
||||||
ESM::Pathgrid::Point dest(mAllowedNodes[randNode]);
|
ESM::Pathgrid::Point dest(storage.mAllowedNodes[randNode]);
|
||||||
ToWorldCoordinates(dest, storage.mCell->getCell());
|
ToWorldCoordinates(dest, storage.mCell->getCell());
|
||||||
|
|
||||||
// actor position is already in world co-ordinates
|
// actor position is already in world co-ordinates
|
||||||
|
@ -666,20 +672,20 @@ namespace MWMechanics
|
||||||
if (storage.mPathFinder.isPathConstructed())
|
if (storage.mPathFinder.isPathConstructed())
|
||||||
{
|
{
|
||||||
// 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 = storage.mAllowedNodes[randNode];
|
||||||
mAllowedNodes.erase(mAllowedNodes.begin() + randNode);
|
storage.mAllowedNodes.erase(storage.mAllowedNodes.begin() + randNode);
|
||||||
// check if mCurrentNode was taken out of mAllowedNodes
|
// check if mCurrentNode was taken out of mAllowedNodes
|
||||||
if (mTrimCurrentNode && mAllowedNodes.size() > 1)
|
if (storage.mTrimCurrentNode && storage.mAllowedNodes.size() > 1)
|
||||||
mTrimCurrentNode = false;
|
storage.mTrimCurrentNode = false;
|
||||||
else
|
else
|
||||||
mAllowedNodes.push_back(mCurrentNode);
|
storage.mAllowedNodes.push_back(storage.mCurrentNode);
|
||||||
mCurrentNode = temp;
|
storage.mCurrentNode = temp;
|
||||||
|
|
||||||
storage.setState(Wander_Walking);
|
storage.setState(Wander_Walking);
|
||||||
}
|
}
|
||||||
// Choose a different node and delete this one from possible nodes because it is uncreachable:
|
// Choose a different node and delete this one from possible nodes because it is uncreachable:
|
||||||
else
|
else
|
||||||
mAllowedNodes.erase(mAllowedNodes.begin() + randNode);
|
storage.mAllowedNodes.erase(storage.mAllowedNodes.begin() + randNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiWander::ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell)
|
void AiWander::ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell)
|
||||||
|
@ -788,17 +794,17 @@ namespace MWMechanics
|
||||||
if (mDistance == 0)
|
if (mDistance == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (mPopulateAvailableNodes)
|
AiWanderStorage& storage = state.get<AiWanderStorage>();
|
||||||
getAllowedNodes(actor, actor.getCell()->getCell(), state.get<AiWanderStorage>());
|
if (storage.mPopulateAvailableNodes)
|
||||||
|
getAllowedNodes(actor, actor.getCell()->getCell(), storage);
|
||||||
|
|
||||||
if (mAllowedNodes.empty())
|
if (storage.mAllowedNodes.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
int index = Misc::Rng::rollDice(storage.mAllowedNodes.size());
|
||||||
|
ESM::Pathgrid::Point dest = storage.mAllowedNodes[index];
|
||||||
state.moveIn(new AiWanderStorage());
|
state.moveIn(new AiWanderStorage());
|
||||||
|
|
||||||
int index = Misc::Rng::rollDice(mAllowedNodes.size());
|
|
||||||
ESM::Pathgrid::Point dest = mAllowedNodes[index];
|
|
||||||
|
|
||||||
dest.mX += OffsetToPreventOvercrowding();
|
dest.mX += OffsetToPreventOvercrowding();
|
||||||
dest.mY += OffsetToPreventOvercrowding();
|
dest.mY += OffsetToPreventOvercrowding();
|
||||||
ToWorldCoordinates(dest, actor.getCell()->getCell());
|
ToWorldCoordinates(dest, actor.getCell()->getCell());
|
||||||
|
@ -808,7 +814,7 @@ namespace MWMechanics
|
||||||
actor.getClass().adjustPosition(actor, false);
|
actor.getClass().adjustPosition(actor, false);
|
||||||
|
|
||||||
// may have changed cell
|
// may have changed cell
|
||||||
mPopulateAvailableNodes = true;
|
storage.mPopulateAvailableNodes = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int AiWander::OffsetToPreventOvercrowding()
|
int AiWander::OffsetToPreventOvercrowding()
|
||||||
|
@ -823,7 +829,7 @@ namespace MWMechanics
|
||||||
pathgrid = MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*cell);
|
pathgrid = MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*cell);
|
||||||
const MWWorld::CellStore* cellStore = actor.getCell();
|
const MWWorld::CellStore* cellStore = actor.getCell();
|
||||||
|
|
||||||
mAllowedNodes.clear();
|
storage.mAllowedNodes.clear();
|
||||||
|
|
||||||
// If there is no path this actor doesn't go anywhere. See:
|
// If there is no path this actor doesn't go anywhere. See:
|
||||||
// https://forum.openmw.org/viewtopic.php?t=1556
|
// https://forum.openmw.org/viewtopic.php?t=1556
|
||||||
|
@ -856,40 +862,40 @@ namespace MWMechanics
|
||||||
if((npcPos - nodePos).length2() <= mDistance * mDistance &&
|
if((npcPos - nodePos).length2() <= mDistance * mDistance &&
|
||||||
cellStore->isPointConnected(closestPointIndex, counter))
|
cellStore->isPointConnected(closestPointIndex, counter))
|
||||||
{
|
{
|
||||||
mAllowedNodes.push_back(pathgrid->mPoints[counter]);
|
storage.mAllowedNodes.push_back(pathgrid->mPoints[counter]);
|
||||||
pointIndex = counter;
|
pointIndex = counter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mAllowedNodes.size() == 1)
|
if (storage.mAllowedNodes.size() == 1)
|
||||||
{
|
{
|
||||||
AddNonPathGridAllowedPoints(npcPos, pathgrid, pointIndex);
|
AddNonPathGridAllowedPoints(npcPos, pathgrid, pointIndex, storage);
|
||||||
}
|
}
|
||||||
if(!mAllowedNodes.empty())
|
if(!storage.mAllowedNodes.empty())
|
||||||
{
|
{
|
||||||
SetCurrentNodeToClosestAllowedNode(npcPos);
|
SetCurrentNodeToClosestAllowedNode(npcPos, storage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mPopulateAvailableNodes = false;
|
storage.mPopulateAvailableNodes = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// When only one path grid point in wander distance,
|
// When only one path grid point in wander distance,
|
||||||
// additional points for NPC to wander to are:
|
// additional points for NPC to wander to are:
|
||||||
// 1. NPC's initial location
|
// 1. NPC's initial location
|
||||||
// 2. Partway along the path between the point and its connected points.
|
// 2. Partway along the path between the point and its connected points.
|
||||||
void AiWander::AddNonPathGridAllowedPoints(osg::Vec3f npcPos, const ESM::Pathgrid * pathGrid, int pointIndex)
|
void AiWander::AddNonPathGridAllowedPoints(osg::Vec3f npcPos, const ESM::Pathgrid * pathGrid, int pointIndex, AiWanderStorage& storage)
|
||||||
{
|
{
|
||||||
mAllowedNodes.push_back(PathFinder::MakePathgridPoint(npcPos));
|
storage.mAllowedNodes.push_back(PathFinder::MakePathgridPoint(npcPos));
|
||||||
for (std::vector<ESM::Pathgrid::Edge>::const_iterator it = pathGrid->mEdges.begin(); it != pathGrid->mEdges.end(); ++it)
|
for (std::vector<ESM::Pathgrid::Edge>::const_iterator it = pathGrid->mEdges.begin(); it != pathGrid->mEdges.end(); ++it)
|
||||||
{
|
{
|
||||||
if (it->mV0 == pointIndex)
|
if (it->mV0 == pointIndex)
|
||||||
{
|
{
|
||||||
AddPointBetweenPathGridPoints(pathGrid->mPoints[it->mV0], pathGrid->mPoints[it->mV1]);
|
AddPointBetweenPathGridPoints(pathGrid->mPoints[it->mV0], pathGrid->mPoints[it->mV1], storage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiWander::AddPointBetweenPathGridPoints(const ESM::Pathgrid::Point& start, const ESM::Pathgrid::Point& end)
|
void AiWander::AddPointBetweenPathGridPoints(const ESM::Pathgrid::Point& start, const ESM::Pathgrid::Point& end, AiWanderStorage& storage)
|
||||||
{
|
{
|
||||||
osg::Vec3f vectorStart = PathFinder::MakeOsgVec3(start);
|
osg::Vec3f vectorStart = PathFinder::MakeOsgVec3(start);
|
||||||
osg::Vec3f delta = PathFinder::MakeOsgVec3(end) - vectorStart;
|
osg::Vec3f delta = PathFinder::MakeOsgVec3(end) - vectorStart;
|
||||||
|
@ -901,16 +907,16 @@ namespace MWMechanics
|
||||||
// must not travel longer than distance between waypoints or NPC goes past waypoint
|
// must not travel longer than distance between waypoints or NPC goes past waypoint
|
||||||
distance = std::min(distance, static_cast<int>(length));
|
distance = std::min(distance, static_cast<int>(length));
|
||||||
delta *= distance;
|
delta *= distance;
|
||||||
mAllowedNodes.push_back(PathFinder::MakePathgridPoint(vectorStart + delta));
|
storage.mAllowedNodes.push_back(PathFinder::MakePathgridPoint(vectorStart + delta));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiWander::SetCurrentNodeToClosestAllowedNode(osg::Vec3f npcPos)
|
void AiWander::SetCurrentNodeToClosestAllowedNode(osg::Vec3f npcPos, AiWanderStorage& storage)
|
||||||
{
|
{
|
||||||
float distanceToClosestNode = std::numeric_limits<float>::max();
|
float distanceToClosestNode = std::numeric_limits<float>::max();
|
||||||
unsigned int index = 0;
|
unsigned int index = 0;
|
||||||
for (unsigned int counterThree = 0; counterThree < mAllowedNodes.size(); counterThree++)
|
for (unsigned int counterThree = 0; counterThree < storage.mAllowedNodes.size(); counterThree++)
|
||||||
{
|
{
|
||||||
osg::Vec3f nodePos(PathFinder::MakeOsgVec3(mAllowedNodes[counterThree]));
|
osg::Vec3f nodePos(PathFinder::MakeOsgVec3(storage.mAllowedNodes[counterThree]));
|
||||||
float tempDist = (npcPos - nodePos).length2();
|
float tempDist = (npcPos - nodePos).length2();
|
||||||
if (tempDist < distanceToClosestNode)
|
if (tempDist < distanceToClosestNode)
|
||||||
{
|
{
|
||||||
|
@ -918,8 +924,8 @@ namespace MWMechanics
|
||||||
distanceToClosestNode = tempDist;
|
distanceToClosestNode = tempDist;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mCurrentNode = mAllowedNodes[index];
|
storage.mCurrentNode = storage.mAllowedNodes[index];
|
||||||
mAllowedNodes.erase(mAllowedNodes.begin() + index);
|
storage.mAllowedNodes.erase(storage.mAllowedNodes.begin() + index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiWander::writeState(ESM::AiSequence::AiSequence &sequence) const
|
void AiWander::writeState(ESM::AiSequence::AiSequence &sequence) const
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
|
|
||||||
#include "../mwworld/timestamp.hpp"
|
#include "../mwworld/timestamp.hpp"
|
||||||
|
|
||||||
|
|
||||||
#include "aistate.hpp"
|
#include "aistate.hpp"
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
|
@ -24,8 +23,6 @@ namespace ESM
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
struct AiWanderStorage;
|
struct AiWanderStorage;
|
||||||
|
|
||||||
/// \brief Causes the Actor to wander within a specified range
|
/// \brief Causes the Actor to wander within a specified range
|
||||||
|
@ -42,8 +39,6 @@ namespace MWMechanics
|
||||||
|
|
||||||
AiWander (const ESM::AiSequence::AiWander* wander);
|
AiWander (const ESM::AiSequence::AiWander* wander);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual AiPackage *clone() const;
|
virtual AiPackage *clone() const;
|
||||||
|
|
||||||
virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration);
|
virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration);
|
||||||
|
@ -72,10 +67,10 @@ namespace MWMechanics
|
||||||
Wander_MoveNow,
|
Wander_MoveNow,
|
||||||
Wander_Walking
|
Wander_Walking
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// NOTE: mDistance and mDuration must be set already
|
// NOTE: mDistance and mDuration must be set already
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
void stopWalking(const MWWorld::Ptr& actor, AiWanderStorage& storage);
|
void stopWalking(const MWWorld::Ptr& actor, AiWanderStorage& storage);
|
||||||
|
|
||||||
/// Have the given actor play an idle animation
|
/// Have the given actor play an idle animation
|
||||||
|
@ -108,41 +103,15 @@ namespace MWMechanics
|
||||||
std::vector<unsigned char> mIdle;
|
std::vector<unsigned char> mIdle;
|
||||||
bool mRepeat;
|
bool mRepeat;
|
||||||
|
|
||||||
|
|
||||||
bool mHasReturnPosition; // NOTE: Could be removed if mReturnPosition was initialized to actor position,
|
bool mHasReturnPosition; // NOTE: Could be removed if mReturnPosition was initialized to actor position,
|
||||||
// if we had the actor in the AiWander constructor...
|
// if we had the actor in the AiWander constructor...
|
||||||
osg::Vec3f mReturnPosition;
|
osg::Vec3f mReturnPosition;
|
||||||
|
|
||||||
osg::Vec3f mInitialActorPosition;
|
osg::Vec3f mInitialActorPosition;
|
||||||
bool mStoredInitialActorPosition;
|
bool mStoredInitialActorPosition;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// do we need to calculate allowed nodes based on mDistance
|
|
||||||
bool mPopulateAvailableNodes;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// allowed pathgrid nodes based on mDistance from the spawn point
|
|
||||||
// in local coordinates of mCell
|
|
||||||
// FIXME: move to AiWanderStorage
|
|
||||||
std::vector<ESM::Pathgrid::Point> mAllowedNodes;
|
|
||||||
|
|
||||||
void getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell, AiWanderStorage& storage);
|
void getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell, AiWanderStorage& storage);
|
||||||
|
|
||||||
// FIXME: move to AiWanderStorage
|
void trimAllowedNodes(std::vector<ESM::Pathgrid::Point>& nodes, const PathFinder& pathfinder);
|
||||||
ESM::Pathgrid::Point mCurrentNode;
|
|
||||||
bool mTrimCurrentNode;
|
|
||||||
void trimAllowedNodes(std::vector<ESM::Pathgrid::Point>& nodes,
|
|
||||||
const PathFinder& pathfinder);
|
|
||||||
|
|
||||||
|
|
||||||
// FIXME: move to AiWanderStorage
|
|
||||||
// ObstacleCheck mObstacleCheck;
|
|
||||||
float mDoorCheckDuration;
|
|
||||||
int mStuckCount;
|
|
||||||
|
|
||||||
// constants for converting idleSelect values into groupNames
|
// constants for converting idleSelect values into groupNames
|
||||||
enum GroupIndex
|
enum GroupIndex
|
||||||
|
@ -154,19 +123,17 @@ namespace MWMechanics
|
||||||
/// convert point from local (i.e. cell) to world co-ordinates
|
/// convert point from local (i.e. cell) to world co-ordinates
|
||||||
void ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell);
|
void ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell);
|
||||||
|
|
||||||
void SetCurrentNodeToClosestAllowedNode(osg::Vec3f npcPos);
|
void SetCurrentNodeToClosestAllowedNode(osg::Vec3f npcPos, AiWanderStorage& storage);
|
||||||
|
|
||||||
void AddNonPathGridAllowedPoints(osg::Vec3f npcPos, const ESM::Pathgrid * pathGrid, int pointIndex);
|
void AddNonPathGridAllowedPoints(osg::Vec3f npcPos, const ESM::Pathgrid * pathGrid, int pointIndex, AiWanderStorage& storage);
|
||||||
|
|
||||||
void AddPointBetweenPathGridPoints(const ESM::Pathgrid::Point& start, const ESM::Pathgrid::Point& end);
|
void AddPointBetweenPathGridPoints(const ESM::Pathgrid::Point& start, const ESM::Pathgrid::Point& end, AiWanderStorage& storage);
|
||||||
|
|
||||||
/// lookup table for converting idleSelect value to groupName
|
/// lookup table for converting idleSelect value to groupName
|
||||||
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();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue