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
* re-calculated. Normally this would not be an issue since hostile actors will
* 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)
{
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);
if(!mCell || cellChange)
{
@ -125,7 +127,6 @@ namespace MWMechanics
}
const ESM::Cell *cell = mCell->getCell();
MWMechanics::CreatureStats& cStats = actor.getClass().getCreatureStats(actor);
cStats.setDrawState(DrawState_Nothing);
cStats.setMovementFlag(CreatureStats::Flag_Run, false);
MWBase::World *world = MWBase::Environment::get().getWorld();
@ -188,45 +189,56 @@ namespace MWMechanics
mYCell = mCellY * ESM::Land::REAL_SIZE;
}
// convert actorPos to local (i.e. cell) co-ordinates
Ogre::Vector3 actorPos(pos.pos);
actorPos[0] = actorPos[0] - mXCell;
actorPos[1] = actorPos[1] - mYCell;
// mAllowedNodes for this actor with pathgrid point indexes
// based on mDistance
// FIXME: There might be a bug here. The allowed node points are
// based on the actor's current position rather than the actor's
// spawn point. As a result the allowed nodes for wander can change
// between saves, for example.
//
// convert npcPos to local (i.e. cell) co-ordinates
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
float closestNodeDist = -1;
unsigned int closestIndex = 0;
unsigned int indexAllowedNodes = 0;
for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++)
{
float sqrDist = actorPos.squaredDistance(Ogre::Vector3(
pathgrid->mPoints[counter].mX,
pathgrid->mPoints[counter].mY,
pathgrid->mPoints[counter].mZ));
if(sqrDist <= (mDistance * mDistance))
{
Ogre::Vector3 nodePos(pathgrid->mPoints[counter].mX, pathgrid->mPoints[counter].mY,
pathgrid->mPoints[counter].mZ);
if(npcPos.squaredDistance(nodePos) <= mDistance * mDistance)
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())
{
// Start with the closest node and remove it from the allowed set
// so that it does not get selected again. The removed node will
// later be put in the back of the queue, unless it gets removed
// due to inaccessibility (e.g. a closed door)
mCurrentNode = mAllowedNodes[closestIndex];
mAllowedNodes.erase(mAllowedNodes.begin() + closestIndex);
// set only if successful in finding allowed nodes
mStoredAvailableNodes = true;
Ogre::Vector3 firstNodePos(mAllowedNodes[0].mX, mAllowedNodes[0].mY, mAllowedNodes[0].mZ);
float closestNode = npcPos.squaredDistance(firstNodePos);
unsigned int index = 0;
for(unsigned int counterThree = 1; counterThree < mAllowedNodes.size(); counterThree++)
{
Ogre::Vector3 nodePos(mAllowedNodes[counterThree].mX, mAllowedNodes[counterThree].mY,
mAllowedNodes[counterThree].mZ);
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)
{
mTrimCurrentNode = false;
#if 0
//#if 0
std::cout << "deleted "<< std::to_string(mCurrentNode.mX)
+", "+std::to_string(mCurrentNode.mY) << std::endl;
#endif
//#endif
//#if 0
std::cout << "allowed size "<<
std::to_string(mAllowedNodes.size()) << std::endl;
//#endif
}
else
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:
else
{
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,
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?
std::list<ESM::Pathgrid::Point> paths = pathfinder.getPath();
while(paths.size() >= 2)

@ -100,8 +100,11 @@ namespace
}
}
}
if(start == closestReachableIndex)
closestReachableIndex = -1; // couldn't find anyting other than start
// 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.
//if(start == closestReachableIndex)
//closestReachableIndex = -1; // couldn't find anyting other than start
return std::pair<int, bool>
(closestReachableIndex, closestReachableIndex == closestIndex);
@ -224,6 +227,18 @@ namespace MWMechanics
// this shouldn't really happen, but just in case
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);
if(!mPath.empty())
@ -243,9 +258,32 @@ namespace MWMechanics
}
else
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
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
mIsPathConstructed = false;

@ -206,6 +206,20 @@ namespace MWMechanics
if(mSCCPoint[v].first == -1) // undefined (haven't visited)
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

Loading…
Cancel
Save