mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-16 19:19:56 +00:00
AiWander fast forwarding improvements (bug #3638)
This commit is contained in:
parent
a5ba1caed1
commit
9943bd4d74
11 changed files with 115 additions and 10 deletions
|
@ -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;
|
||||
|
|
|
@ -124,6 +124,8 @@ namespace MWMechanics
|
|||
|
||||
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…
Reference in a new issue