Fixed issue where allowed nodes were being erased. PathFinder was returning an empty path if the closest pathgrid point to the start was also the closest pathgrid point to the goal. Still need to clean up and remove logging statements.

actorid
cc9cii 11 years ago
parent d3be725ee7
commit aad13d315c

@ -112,11 +112,13 @@ namespace MWMechanics
* allowed set. The issue is when the door opens the allowed set is not * allowed set. The issue is when the door opens the allowed set is not
* re-calculated. Normally this would not be an issue since hostile actors will * re-calculated. Normally this would not be an issue since hostile actors will
* enter combat (i.e. no longer wandering) * enter combat (i.e. no longer wandering)
*
* FIXME: Sometimes allowed nodes that shouldn't be deleted are deleted.
*/ */
bool AiWander::execute (const MWWorld::Ptr& actor,float duration) bool AiWander::execute (const MWWorld::Ptr& actor,float duration)
{ {
MWMechanics::CreatureStats& cStats = actor.getClass().getCreatureStats(actor);
if(cStats.isDead() || cStats.getHealth().getCurrent() <= 0)
return true; // Don't bother with dead actors
bool cellChange = mCell && (actor.getCell() != mCell); bool cellChange = mCell && (actor.getCell() != mCell);
if(!mCell || cellChange) if(!mCell || cellChange)
{ {
@ -125,7 +127,6 @@ namespace MWMechanics
} }
const ESM::Cell *cell = mCell->getCell(); const ESM::Cell *cell = mCell->getCell();
MWMechanics::CreatureStats& cStats = actor.getClass().getCreatureStats(actor);
cStats.setDrawState(DrawState_Nothing); cStats.setDrawState(DrawState_Nothing);
cStats.setMovementFlag(CreatureStats::Flag_Run, false); cStats.setMovementFlag(CreatureStats::Flag_Run, false);
MWBase::World *world = MWBase::Environment::get().getWorld(); MWBase::World *world = MWBase::Environment::get().getWorld();
@ -188,45 +189,56 @@ namespace MWMechanics
mYCell = mCellY * ESM::Land::REAL_SIZE; mYCell = mCellY * ESM::Land::REAL_SIZE;
} }
// convert actorPos to local (i.e. cell) co-ordinates // FIXME: There might be a bug here. The allowed node points are
Ogre::Vector3 actorPos(pos.pos); // based on the actor's current position rather than the actor's
actorPos[0] = actorPos[0] - mXCell; // spawn point. As a result the allowed nodes for wander can change
actorPos[1] = actorPos[1] - mYCell; // between saves, for example.
//
// mAllowedNodes for this actor with pathgrid point indexes // convert npcPos to local (i.e. cell) co-ordinates
// based on mDistance Ogre::Vector3 npcPos(pos.pos);
npcPos[0] = npcPos[0] - mXCell;
npcPos[1] = npcPos[1] - mYCell;
// mAllowedNodes for this actor with pathgrid point indexes based on mDistance
// NOTE: mPoints and mAllowedNodes are in local co-ordinates // NOTE: mPoints and mAllowedNodes are in local co-ordinates
float closestNodeDist = -1;
unsigned int closestIndex = 0;
unsigned int indexAllowedNodes = 0;
for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++) for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++)
{ {
float sqrDist = actorPos.squaredDistance(Ogre::Vector3( Ogre::Vector3 nodePos(pathgrid->mPoints[counter].mX, pathgrid->mPoints[counter].mY,
pathgrid->mPoints[counter].mX, pathgrid->mPoints[counter].mZ);
pathgrid->mPoints[counter].mY, if(npcPos.squaredDistance(nodePos) <= mDistance * mDistance)
pathgrid->mPoints[counter].mZ));
if(sqrDist <= (mDistance * mDistance))
{
mAllowedNodes.push_back(pathgrid->mPoints[counter]); mAllowedNodes.push_back(pathgrid->mPoints[counter]);
// keep track of the closest node
if(closestNodeDist == -1 || sqrDist < closestNodeDist)
{
closestNodeDist = sqrDist;
closestIndex = indexAllowedNodes;
}
indexAllowedNodes++;
}
} }
if(!mAllowedNodes.empty()) if(!mAllowedNodes.empty())
{ {
// Start with the closest node and remove it from the allowed set Ogre::Vector3 firstNodePos(mAllowedNodes[0].mX, mAllowedNodes[0].mY, mAllowedNodes[0].mZ);
// so that it does not get selected again. The removed node will float closestNode = npcPos.squaredDistance(firstNodePos);
// later be put in the back of the queue, unless it gets removed unsigned int index = 0;
// due to inaccessibility (e.g. a closed door) for(unsigned int counterThree = 1; counterThree < mAllowedNodes.size(); counterThree++)
mCurrentNode = mAllowedNodes[closestIndex]; {
mAllowedNodes.erase(mAllowedNodes.begin() + closestIndex); Ogre::Vector3 nodePos(mAllowedNodes[counterThree].mX, mAllowedNodes[counterThree].mY,
// set only if successful in finding allowed nodes mAllowedNodes[counterThree].mZ);
mStoredAvailableNodes = true; float tempDist = npcPos.squaredDistance(nodePos);
if(tempDist < closestNode)
index = counterThree;
}
#if 0
if(actor.getClass().getName(actor) == "Rat")
{
std::cout << "rat allowed "<< std::to_string(mAllowedNodes.size())
+" mDist "+std::to_string(mDistance)
+" pos "+std::to_string(static_cast<int>(npcPos[0]))
+", "+std::to_string(static_cast<int>(npcPos[1]))
<<std::endl;
for(int i=0; i<mAllowedNodes.size(); i++)
std::cout <<"rat "+std::to_string(mAllowedNodes[i].mX)
+", "+std::to_string(mAllowedNodes[i].mY)<<std::endl;
}
#endif
mCurrentNode = mAllowedNodes[index];
mAllowedNodes.erase(mAllowedNodes.begin() + index);
mStoredAvailableNodes = true; // set only if successful in finding allowed nodes
} }
} }
} }
@ -398,10 +410,14 @@ namespace MWMechanics
if(mTrimCurrentNode && mAllowedNodes.size() > 1) if(mTrimCurrentNode && mAllowedNodes.size() > 1)
{ {
mTrimCurrentNode = false; mTrimCurrentNode = false;
#if 0 //#if 0
std::cout << "deleted "<< std::to_string(mCurrentNode.mX) std::cout << "deleted "<< std::to_string(mCurrentNode.mX)
+", "+std::to_string(mCurrentNode.mY) << std::endl; +", "+std::to_string(mCurrentNode.mY) << std::endl;
#endif //#endif
//#if 0
std::cout << "allowed size "<<
std::to_string(mAllowedNodes.size()) << std::endl;
//#endif
} }
else else
mAllowedNodes.push_back(mCurrentNode); mAllowedNodes.push_back(mCurrentNode);
@ -412,7 +428,15 @@ namespace MWMechanics
} }
// 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); mAllowedNodes.erase(mAllowedNodes.begin() + randNode);
//#if 0
//std::cout << "actor \""<< actor.getClass().getName(actor) << "\"" << std::endl;
if(actor.getClass().getName(actor) == "Rat")
std::cout << "erase no path "<< std::to_string(mAllowedNodes[randNode].mX)
+", "+std::to_string(mAllowedNodes[randNode].mY) << std::endl;
//#endif
}
} }
} }
@ -477,9 +501,6 @@ namespace MWMechanics
void AiWander::trimAllowedNodes(std::vector<ESM::Pathgrid::Point>& nodes, void AiWander::trimAllowedNodes(std::vector<ESM::Pathgrid::Point>& nodes,
const PathFinder& pathfinder) const PathFinder& pathfinder)
{ {
//#if 0
std::cout << "allowed size "<< std::to_string(nodes.size()) << std::endl;
//#endif
// TODO: how to add these back in once the door opens? // TODO: how to add these back in once the door opens?
std::list<ESM::Pathgrid::Point> paths = pathfinder.getPath(); std::list<ESM::Pathgrid::Point> paths = pathfinder.getPath();
while(paths.size() >= 2) while(paths.size() >= 2)

@ -100,8 +100,11 @@ namespace
} }
} }
} }
if(start == closestReachableIndex) // AiWander has logic that depends on whether a path was created, deleting
closestReachableIndex = -1; // couldn't find anyting other than start // allowed nodes if not. Hence a path needs to be created even if the start
// and the end points are the same.
//if(start == closestReachableIndex)
//closestReachableIndex = -1; // couldn't find anyting other than start
return std::pair<int, bool> return std::pair<int, bool>
(closestReachableIndex, closestReachableIndex == closestIndex); (closestReachableIndex, closestReachableIndex == closestIndex);
@ -224,6 +227,18 @@ namespace MWMechanics
// this shouldn't really happen, but just in case // this shouldn't really happen, but just in case
if(endNode.first != -1) if(endNode.first != -1)
{ {
// AiWander has logic that depends on whether a path was created,
// deleting allowed nodes if not. Hence a path needs to be created
// even if the start and the end points are the same.
// NOTE: aStarSearch will return an empty path if the start and end
// nodes are the same
if(startNode == endNode.first)
{
mPath.push_back(endPoint);
mIsPathConstructed = true;
return;
}
mPath = mCell->aStarSearch(startNode, endNode.first); mPath = mCell->aStarSearch(startNode, endNode.first);
if(!mPath.empty()) if(!mPath.empty())
@ -243,9 +258,32 @@ namespace MWMechanics
} }
else else
mIsPathConstructed = false; mIsPathConstructed = false;
#if 0
{
mIsPathConstructed = false;
std::cout << "no path "<<
std::to_string(startPoint.mX-xCell)
+", "+std::to_string(startPoint.mY-yCell)
+", "+std::to_string(startNode)
+", "+std::to_string(endPoint.mX-xCell)
+", "+std::to_string(endPoint.mY-yCell)
+", "+std::to_string(endNode.first)<<std::endl;
}
#endif
} }
else else
mIsPathConstructed = false; mIsPathConstructed = false;
#if 0
{
mIsPathConstructed = false;
std::cout << "no end "<<
std::to_string(startPoint.mX-xCell)
+", "+std::to_string(startPoint.mY-yCell)
+", "+std::to_string(startNode)
+", "+std::to_string(endPoint.mX-xCell)
+", "+std::to_string(endPoint.mY-yCell)<<std::endl;
}
#endif
} }
else else
mIsPathConstructed = false; mIsPathConstructed = false;

@ -206,6 +206,20 @@ namespace MWMechanics
if(mSCCPoint[v].first == -1) // undefined (haven't visited) if(mSCCPoint[v].first == -1) // undefined (haven't visited)
recursiveStrongConnect(v); recursiveStrongConnect(v);
} }
//#if 0
// for debugging only
if(mCell->mName == "Gnisis, Arvs-Drelen")
for(unsigned int v = 0; v < mPathgrid->mPoints.size(); v++)
{
std::cout << "SCC \"X:" <<
std::to_string(mPathgrid->mPoints[v].mX)
+", Y:"+std::to_string(mPathgrid->mPoints[v].mY)
+", Num:"+std::to_string(mSCCId)
+", Point:"+std::to_string(v)
+", Group:"+std::to_string(mGraph[v].componentId)
<<"\""<<std::endl;
}
//#endif
} }
bool PathgridGraph::isPointConnected(const int start, const int end) const bool PathgridGraph::isPointConnected(const int start, const int end) const

Loading…
Cancel
Save