AiWander fast forwarding improvements (bug #3638)

pull/349/head
Andrei Kortunov 7 years ago
parent a5ba1caed1
commit 9943bd4d74

@ -191,6 +191,9 @@ namespace MWBase
virtual void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector<MWWorld::Ptr>& objects) = 0;
virtual void getActorsInRange(const osg::Vec3f &position, float radius, std::vector<MWWorld::Ptr> &objects) = 0;
/// Check if there are actors in selected range
virtual bool isAnyActorInRange(const osg::Vec3f &position, float radius) = 0;
///Returns the list of actors which are siding with the given actor in fights
/**ie AiFollow or AiEscort is active and the target is the actor **/
virtual std::list<MWWorld::Ptr> getActorsSidingWith(const MWWorld::Ptr& actor) = 0;

@ -1621,6 +1621,17 @@ namespace MWMechanics
}
}
bool Actors::isAnyObjectInRange(const osg::Vec3f& position, float radius)
{
for (PtrActorMap::iterator iter = mActors.begin(); iter != mActors.end(); ++iter)
{
if ((iter->first.getRefData().getPosition().asVec3() - position).length2() <= radius*radius)
return true;
}
return false;
}
std::list<MWWorld::Ptr> Actors::getActorsSidingWith(const MWWorld::Ptr& actor)
{
std::list<MWWorld::Ptr> list;

@ -115,15 +115,17 @@ namespace MWMechanics
bool isRunning(const MWWorld::Ptr& ptr);
bool isSneaking(const MWWorld::Ptr& ptr);
void forceStateUpdate(const MWWorld::Ptr &ptr);
void forceStateUpdate(const MWWorld::Ptr &ptr);
bool playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number, bool persist=false);
void skipAnimation(const MWWorld::Ptr& ptr);
bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName);
void persistAnimationStates();
bool playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number, bool persist=false);
void skipAnimation(const MWWorld::Ptr& ptr);
bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName);
void persistAnimationStates();
void getObjectsInRange(const osg::Vec3f& position, float radius, std::vector<MWWorld::Ptr>& out);
bool isAnyObjectInRange(const osg::Vec3f& position, float radius);
void cleanupSummonedCreature (CreatureStats& casterStats, int creatureActorId);
///Returns the list of actors which are siding with the given actor in fights

@ -799,20 +799,80 @@ namespace MWMechanics
int index = Misc::Rng::rollDice(storage.mAllowedNodes.size());
ESM::Pathgrid::Point dest = storage.mAllowedNodes[index];
state.moveIn(new AiWanderStorage());
ESM::Pathgrid::Point worldDest = dest;
ToWorldCoordinates(worldDest, actor.getCell()->getCell());
bool isPathGridOccupied = MWBase::Environment::get().getMechanicsManager()->isAnyActorInRange(PathFinder::MakeOsgVec3(worldDest), 60);
// add offset only if the selected pathgrid is occupied by another actor
if (isPathGridOccupied)
{
ESM::Pathgrid::PointList points;
getNeighbouringNodes(dest, actor.getCell(), points);
// there are no neighbouring nodes, nowhere to move
if (points.empty())
return;
int initialSize = points.size();
bool isOccupied = false;
// AI will try to move the NPC towards every neighboring node until suitable place will be found
for (int i = 0; i < initialSize; i++)
{
int randomIndex = Misc::Rng::rollDice(points.size());
ESM::Pathgrid::Point connDest = points[randomIndex];
// add an offset towards random neighboring node
osg::Vec3f dir = PathFinder::MakeOsgVec3(connDest) - PathFinder::MakeOsgVec3(dest);
float length = dir.length();
dir.normalize();
for (int j = 1; j <= 3; j++)
{
// move for 5-15% towards random neighboring node
dest = PathFinder::MakePathgridPoint(PathFinder::MakeOsgVec3(dest) + dir * (j * 5 * length / 100.f));
worldDest = dest;
ToWorldCoordinates(worldDest, actor.getCell()->getCell());
isOccupied = MWBase::Environment::get().getMechanicsManager()->isAnyActorInRange(PathFinder::MakeOsgVec3(worldDest), 60);
if (!isOccupied)
break;
}
if (!isOccupied)
break;
// Will try an another neighboring node
points.erase(points.begin()+randomIndex);
}
// there is no free space, nowhere to move
if (isOccupied)
return;
}
// place above to prevent moving inside objects, e.g. stairs, because a vector between pathgrids can be underground.
// Adding 20 in adjustPosition() is not enough.
dest.mZ += 60;
dest.mX += OffsetToPreventOvercrowding();
dest.mY += OffsetToPreventOvercrowding();
ToWorldCoordinates(dest, actor.getCell()->getCell());
state.moveIn(new AiWanderStorage());
MWBase::Environment::get().getWorld()->moveObject(actor, static_cast<float>(dest.mX),
static_cast<float>(dest.mY), static_cast<float>(dest.mZ));
actor.getClass().adjustPosition(actor, false);
}
int AiWander::OffsetToPreventOvercrowding()
void AiWander::getNeighbouringNodes(ESM::Pathgrid::Point dest, const MWWorld::CellStore* currentCell, ESM::Pathgrid::PointList& points)
{
return static_cast<int>(20 * (Misc::Rng::rollProbability() * 2.0f - 1.0f));
const ESM::Pathgrid *pathgrid =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*currentCell->getCell());
int index = PathFinder::GetClosestPoint(pathgrid, PathFinder::MakeOsgVec3(dest));
currentCell->getNeighbouringPoints(index, points);
}
void AiWander::getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell, AiWanderStorage& storage)

@ -104,6 +104,8 @@ namespace MWMechanics
bool mHasDestination;
osg::Vec3f mDestination;
void getNeighbouringNodes(ESM::Pathgrid::Point dest, const MWWorld::CellStore* currentCell, ESM::Pathgrid::PointList& points);
void getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell, AiWanderStorage& storage);
void trimAllowedNodes(std::vector<ESM::Pathgrid::Point>& nodes, const PathFinder& pathfinder);

@ -1529,6 +1529,11 @@ namespace MWMechanics
mActors.getObjectsInRange(position, radius, objects);
}
bool MechanicsManager::isAnyActorInRange(const osg::Vec3f &position, float radius)
{
return mActors.isAnyObjectInRange(position, radius);
}
std::list<MWWorld::Ptr> MechanicsManager::getActorsSidingWith(const MWWorld::Ptr& actor)
{
return mActors.getActorsSidingWith(actor);

@ -158,6 +158,9 @@ namespace MWMechanics
virtual void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector<MWWorld::Ptr>& objects);
virtual void getActorsInRange(const osg::Vec3f &position, float radius, std::vector<MWWorld::Ptr> &objects);
/// Check if there are actors in selected range
virtual bool isAnyActorInRange(const osg::Vec3f &position, float radius);
virtual std::list<MWWorld::Ptr> getActorsSidingWith(const MWWorld::Ptr& actor);
virtual std::list<MWWorld::Ptr> getActorsFollowing(const MWWorld::Ptr& actor);
virtual std::list<int> getActorsFollowingIndices(const MWWorld::Ptr& actor);

@ -214,6 +214,16 @@ namespace MWMechanics
return (mGraph[start].componentId == mGraph[end].componentId);
}
void PathgridGraph::getNeighbouringPoints(const int index, ESM::Pathgrid::PointList &nodes) const
{
for(int i = 0; i < static_cast<int> (mGraph[index].edges.size()); i++)
{
int neighbourIndex = mGraph[index].edges[i].index;
if (neighbourIndex != index)
nodes.push_back(mPathgrid->mPoints[neighbourIndex]);
}
}
/*
* NOTE: Based on buildPath2(), please check git history if interested
* Should consider using a 3rd party library version (e.g. boost)

@ -28,6 +28,9 @@ namespace MWMechanics
// from start point) both start and end are pathgrid point indexes
bool isPointConnected(const int start, const int end) const;
// get neighbouring nodes for index node and put them to "nodes" vector
void getNeighbouringPoints(const int index, ESM::Pathgrid::PointList &nodes) const;
// the input parameters are pathgrid point indexes
// the output list is in local (internal cells) or world (external
// cells) coordinates

@ -942,6 +942,11 @@ namespace MWWorld
return mPathgridGraph.isPointConnected(start, end);
}
void CellStore::getNeighbouringPoints(const int index, ESM::Pathgrid::PointList &nodes) const
{
return mPathgridGraph.getNeighbouringPoints(index, nodes);
}
std::list<ESM::Pathgrid::Point> CellStore::aStarSearch(const int start, const int end) const
{
return mPathgridGraph.aStarSearch(start, end);

@ -377,6 +377,7 @@ namespace MWWorld
///< Check mLastRespawn and respawn references if necessary. This is a no-op if the cell is not loaded.
bool isPointConnected(const int start, const int end) const;
void getNeighbouringPoints(const int index, ESM::Pathgrid::PointList &nodes) const;
std::list<ESM::Pathgrid::Point> aStarSearch(const int start, const int end) const;

Loading…
Cancel
Save