Store allowed positions as osg::Vec3f

There is no need to store pathgrid points.
This commit is contained in:
elsid 2025-04-21 14:51:41 +02:00
parent 7c46635a5a
commit 50f5bc51c6
No known key found for this signature in database
GPG Key ID: B845CB9FEE18AB40
4 changed files with 108 additions and 116 deletions

View File

@ -109,24 +109,25 @@ namespace MWMechanics
return std::vector<unsigned char>(std::begin(idle), std::end(idle)); return std::vector<unsigned char>(std::begin(idle), std::end(idle));
} }
void trimAllowedNodes(const std::deque<osg::Vec3f>& path, std::vector<ESM::Pathgrid::Point>& nodes) void trimAllowedPositions(const std::deque<osg::Vec3f>& path, std::vector<osg::Vec3f>& allowedPositions)
{ {
// TODO: how to add these back in once the door opens? // TODO: how to add these back in once the door opens?
// Idea: keep a list of detected closed doors (see aicombat.cpp) // Idea: keep a list of detected closed doors (see aicombat.cpp)
// Every now and then check whether one of the doors is opened. (maybe // Every now and then check whether one of the doors is opened. (maybe
// at the end of playing idle?) If the door is opened then re-calculate // at the end of playing idle?) If the door is opened then re-calculate
// allowed nodes starting from the spawn point. // allowed positions starting from the spawn point.
std::vector<osg::Vec3f> points(path.begin(), path.end()); std::vector<osg::Vec3f> points(path.begin(), path.end());
while (points.size() >= 2) while (points.size() >= 2)
{ {
const osg::Vec3f point = points.back(); const osg::Vec3f point = points.back();
for (std::size_t j = 0; j < nodes.size(); j++) for (std::size_t j = 0; j < allowedPositions.size(); j++)
{ {
// FIXME: doesn't handle a door with the same X/Y // FIXME: doesn't handle a door with the same X/Y
// coordinates but with a different Z // coordinates but with a different Z
if (std::abs(nodes[j].mX - point.x()) <= 0.5 && std::abs(nodes[j].mY - point.y()) <= 0.5) if (std::abs(allowedPositions[j].x() - point.x()) <= 0.5
&& std::abs(allowedPositions[j].y() - point.y()) <= 0.5)
{ {
nodes.erase(nodes.begin() + j); allowedPositions.erase(allowedPositions.begin() + j);
break; break;
} }
} }
@ -143,9 +144,9 @@ namespace MWMechanics
, mCanWanderAlongPathGrid(true) , mCanWanderAlongPathGrid(true)
, mIdleAnimation(0) , mIdleAnimation(0)
, mBadIdles() , mBadIdles()
, mPopulateAvailableNodes(true) , mPopulateAvailablePositions(true)
, mAllowedNodes() , mAllowedPositions()
, mTrimCurrentNode(false) , mTrimCurrentPosition(false)
, mCheckIdlePositionTimer(0) , mCheckIdlePositionTimer(0)
, mStuckCount(0) , mStuckCount(0)
{ {
@ -298,10 +299,10 @@ namespace MWMechanics
mStoredInitialActorPosition = true; mStoredInitialActorPosition = true;
} }
// Initialization to discover & store allowed node points for this actor. // Initialization to discover & store allowed positions points for this actor.
if (storage.mPopulateAvailableNodes) if (storage.mPopulateAvailablePositions)
{ {
getAllowedNodes(actor, storage); fillAllowedPositions(actor, storage);
} }
MWBase::World& world = *MWBase::Environment::get().getWorld(); MWBase::World& world = *MWBase::Environment::get().getWorld();
@ -319,7 +320,7 @@ namespace MWMechanics
} }
// If the package has a wander distance but no pathgrid is available, // If the package has a wander distance but no pathgrid is available,
// randomly idle or wander near spawn point // randomly idle or wander near spawn point
else if (storage.mAllowedNodes.empty() && mDistance > 0 && !storage.mIsWanderingManually) else if (storage.mAllowedPositions.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, prng) >= 96) if (Misc::Rng::rollDice(100, prng) >= 96)
@ -331,7 +332,7 @@ namespace MWMechanics
storage.setState(AiWanderStorage::Wander_IdleNow); storage.setState(AiWanderStorage::Wander_IdleNow);
} }
} }
else if (storage.mAllowedNodes.empty() && !storage.mIsWanderingManually) else if (storage.mAllowedPositions.empty() && !storage.mIsWanderingManually)
{ {
storage.mCanWanderAlongPathGrid = false; storage.mCanWanderAlongPathGrid = false;
} }
@ -347,9 +348,9 @@ namespace MWMechanics
// Construct a new path if there isn't one // Construct a new path if there isn't one
if (!mPathFinder.isPathConstructed()) if (!mPathFinder.isPathConstructed())
{ {
if (!storage.mAllowedNodes.empty()) if (!storage.mAllowedPositions.empty())
{ {
setPathToAnAllowedNode(actor, storage, pos); setPathToAnAllowedPosition(actor, storage, pos);
} }
} }
} }
@ -515,17 +516,17 @@ 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 far from all allowed nodes or too close to a door - if so start walking. // Check if an idle actor is too far from all allowed positions or too close to a door - if so start walking.
storage.mCheckIdlePositionTimer += duration; storage.mCheckIdlePositionTimer += duration;
if (storage.mCheckIdlePositionTimer >= idlePositionCheckInterval && !isStationary()) if (storage.mCheckIdlePositionTimer >= idlePositionCheckInterval && !isStationary())
{ {
storage.mCheckIdlePositionTimer = 0; // restart timer storage.mCheckIdlePositionTimer = 0; // restart timer
static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance() * 1.6f; static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance() * 1.6f;
if (proximityToDoor(actor, distance) || !isNearAllowedNode(actor, storage, distance)) if (proximityToDoor(actor, distance) || !isNearAllowedPosition(actor, storage, distance))
{ {
storage.setState(AiWanderStorage::Wander_MoveNow); storage.setState(AiWanderStorage::Wander_MoveNow);
storage.mTrimCurrentNode = false; // just in case storage.mTrimCurrentPosition = false; // just in case
return; return;
} }
} }
@ -541,16 +542,14 @@ namespace MWMechanics
} }
} }
bool AiWander::isNearAllowedNode(const MWWorld::Ptr& actor, const AiWanderStorage& storage, float distance) const bool AiWander::isNearAllowedPosition(
const MWWorld::Ptr& actor, const AiWanderStorage& storage, float distance) const
{ {
const osg::Vec3f actorPos = actor.getRefData().getPosition().asVec3(); const osg::Vec3f actorPos = actor.getRefData().getPosition().asVec3();
for (const ESM::Pathgrid::Point& node : storage.mAllowedNodes) const float squaredDistance = distance * distance;
{ return std::ranges::find_if(storage.mAllowedPositions, [&](const osg::Vec3& v) {
osg::Vec3f point(node.mX, node.mY, node.mZ); return (actorPos - v).length2() < squaredDistance;
if ((actorPos - point).length2() < distance * distance) }) != storage.mAllowedPositions.end();
return true;
}
return false;
} }
void AiWander::onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, float duration, void AiWander::onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, float duration,
@ -610,8 +609,8 @@ namespace MWMechanics
if (proximityToDoor(actor, distance)) if (proximityToDoor(actor, distance))
{ {
// remove allowed points then select another random destination // remove allowed points then select another random destination
storage.mTrimCurrentNode = true; storage.mTrimCurrentPosition = true;
trimAllowedNodes(mPathFinder.getPath(), storage.mAllowedNodes); trimAllowedPositions(mPathFinder.getPath(), storage.mAllowedPositions);
mObstacleCheck.clear(); mObstacleCheck.clear();
stopWalking(actor); stopWalking(actor);
storage.setState(AiWanderStorage::Wander_MoveNow); storage.setState(AiWanderStorage::Wander_MoveNow);
@ -630,42 +629,41 @@ namespace MWMechanics
} }
} }
void AiWander::setPathToAnAllowedNode( void AiWander::setPathToAnAllowedPosition(
const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos) const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos)
{ {
auto world = MWBase::Environment::get().getWorld(); auto world = MWBase::Environment::get().getWorld();
auto& prng = world->getPrng(); auto& prng = world->getPrng();
unsigned int randNode = Misc::Rng::rollDice(storage.mAllowedNodes.size(), prng); const std::size_t randomAllowedPositionIndex
const ESM::Pathgrid::Point& dest = storage.mAllowedNodes[randNode]; = static_cast<std::size_t>(Misc::Rng::rollDice(storage.mAllowedPositions.size(), prng));
const osg::Vec3f randomAllowedPosition = storage.mAllowedPositions[randomAllowedPositionIndex];
const osg::Vec3f start = actorPos.asVec3(); const osg::Vec3f start = actorPos.asVec3();
// don't take shortcuts for wandering // don't take shortcuts for wandering
const ESM::Pathgrid* pathgrid = world->getStore().get<ESM::Pathgrid>().search(*actor.getCell()->getCell()); const ESM::Pathgrid* pathgrid = world->getStore().get<ESM::Pathgrid>().search(*actor.getCell()->getCell());
const osg::Vec3f destVec3f = PathFinder::makeOsgVec3(dest); mPathFinder.buildPathByPathgrid(start, randomAllowedPosition, actor.getCell(), getPathGridGraph(pathgrid));
mPathFinder.buildPathByPathgrid(start, destVec3f, actor.getCell(), getPathGridGraph(pathgrid));
if (mPathFinder.isPathConstructed()) if (mPathFinder.isPathConstructed())
{ {
mDestination = destVec3f; mDestination = randomAllowedPosition;
mHasDestination = true; mHasDestination = true;
mUsePathgrid = true; mUsePathgrid = true;
// Remove this node as an option and add back the previously used node (stops NPC from picking the same // Remove this position as an option and add back the previously used position (stops NPC from picking the
// node): // same position):
ESM::Pathgrid::Point temp = storage.mAllowedNodes[randNode]; storage.mAllowedPositions.erase(storage.mAllowedPositions.begin() + randomAllowedPositionIndex);
storage.mAllowedNodes.erase(storage.mAllowedNodes.begin() + randNode); // check if mCurrentPosition was taken out of mAllowedPositions
// check if mCurrentNode was taken out of mAllowedNodes if (storage.mTrimCurrentPosition && storage.mAllowedPositions.size() > 1)
if (storage.mTrimCurrentNode && storage.mAllowedNodes.size() > 1) storage.mTrimCurrentPosition = false;
storage.mTrimCurrentNode = false;
else else
storage.mAllowedNodes.push_back(storage.mCurrentNode); storage.mAllowedPositions.push_back(storage.mCurrentPosition);
storage.mCurrentNode = temp; storage.mCurrentPosition = randomAllowedPosition;
storage.setState(AiWanderStorage::Wander_Walking); storage.setState(AiWanderStorage::Wander_Walking);
} }
// Choose a different node and delete this one from possible nodes because it is uncreachable: // Choose a different position and delete this one from possible positions because it is uncreachable:
else else
storage.mAllowedNodes.erase(storage.mAllowedNodes.begin() + randNode); storage.mAllowedPositions.erase(storage.mAllowedPositions.begin() + randomAllowedPositionIndex);
} }
void AiWander::stopWalking(const MWWorld::Ptr& actor) void AiWander::stopWalking(const MWWorld::Ptr& actor)
@ -741,20 +739,20 @@ namespace MWMechanics
return; return;
AiWanderStorage& storage = state.get<AiWanderStorage>(); AiWanderStorage& storage = state.get<AiWanderStorage>();
if (storage.mPopulateAvailableNodes) if (storage.mPopulateAvailablePositions)
getAllowedNodes(actor, storage); fillAllowedPositions(actor, storage);
if (storage.mAllowedNodes.empty()) if (storage.mAllowedPositions.empty())
return; return;
auto& prng = MWBase::Environment::get().getWorld()->getPrng(); auto& prng = MWBase::Environment::get().getWorld()->getPrng();
int index = Misc::Rng::rollDice(storage.mAllowedNodes.size(), prng); int index = Misc::Rng::rollDice(storage.mAllowedPositions.size(), prng);
ESM::Pathgrid::Point worldDest = storage.mAllowedNodes[index]; const osg::Vec3f worldDest = storage.mAllowedPositions[index];
const Misc::CoordinateConverter converter = Misc::makeCoordinateConverter(*actor.getCell()->getCell()); const Misc::CoordinateConverter converter = Misc::makeCoordinateConverter(*actor.getCell()->getCell());
ESM::Pathgrid::Point dest = converter.toLocalPoint(worldDest); osg::Vec3f dest = converter.toLocalVec3(worldDest);
bool isPathGridOccupied = MWBase::Environment::get().getMechanicsManager()->isAnyActorInRange( const bool isPathGridOccupied
PathFinder::makeOsgVec3(worldDest), 60); = MWBase::Environment::get().getMechanicsManager()->isAnyActorInRange(worldDest, 60);
// add offset only if the selected pathgrid is occupied by another actor // add offset only if the selected pathgrid is occupied by another actor
if (isPathGridOccupied) if (isPathGridOccupied)
@ -774,19 +772,17 @@ namespace MWMechanics
const ESM::Pathgrid::Point& connDest = points[randomIndex]; const ESM::Pathgrid::Point& connDest = points[randomIndex];
// add an offset towards random neighboring node // add an offset towards random neighboring node
osg::Vec3f dir = PathFinder::makeOsgVec3(connDest) - PathFinder::makeOsgVec3(dest); osg::Vec3f dir = PathFinder::makeOsgVec3(connDest) - dest;
float length = dir.length(); const float length = dir.length();
dir.normalize(); dir.normalize();
for (int j = 1; j <= 3; j++) for (int j = 1; j <= 3; j++)
{ {
// move for 5-15% towards random neighboring node // move for 5-15% towards random neighboring node
dest dest = dest + dir * (j * 5 * length / 100.f);
= PathFinder::makePathgridPoint(PathFinder::makeOsgVec3(dest) + dir * (j * 5 * length / 100.f));
worldDest = converter.toWorldPoint(dest);
isOccupied = MWBase::Environment::get().getMechanicsManager()->isAnyActorInRange( isOccupied = MWBase::Environment::get().getMechanicsManager()->isAnyActorInRange(
PathFinder::makeOsgVec3(worldDest), 60); converter.toWorldVec3(dest), 60);
if (!isOccupied) if (!isOccupied)
break; break;
@ -806,19 +802,18 @@ namespace MWMechanics
// place above to prevent moving inside objects, e.g. stairs, because a vector between pathgrids can be // 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. // underground. Adding 20 in adjustPosition() is not enough.
dest.mZ += 60; dest.z() += 60;
converter.toWorld(dest); converter.toWorld(dest);
state.reset(); state.reset();
osg::Vec3f pos(static_cast<float>(dest.mX), static_cast<float>(dest.mY), static_cast<float>(dest.mZ)); MWBase::Environment::get().getWorld()->moveObject(actor, dest);
MWBase::Environment::get().getWorld()->moveObject(actor, pos);
actor.getClass().adjustPosition(actor, false); actor.getClass().adjustPosition(actor, false);
} }
void AiWander::getNeighbouringNodes( void AiWander::getNeighbouringNodes(
ESM::Pathgrid::Point dest, const MWWorld::CellStore* currentCell, ESM::Pathgrid::PointList& points) const osg::Vec3f& dest, const MWWorld::CellStore* currentCell, ESM::Pathgrid::PointList& points)
{ {
const ESM::Pathgrid* pathgrid const ESM::Pathgrid* pathgrid
= MWBase::Environment::get().getESMStore()->get<ESM::Pathgrid>().search(*currentCell->getCell()); = MWBase::Environment::get().getESMStore()->get<ESM::Pathgrid>().search(*currentCell->getCell());
@ -826,19 +821,19 @@ namespace MWMechanics
if (pathgrid == nullptr || pathgrid->mPoints.empty()) if (pathgrid == nullptr || pathgrid->mPoints.empty())
return; return;
size_t index = PathFinder::getClosestPoint(pathgrid, PathFinder::makeOsgVec3(dest)); const size_t index = PathFinder::getClosestPoint(pathgrid, dest);
getPathGridGraph(pathgrid).getNeighbouringPoints(index, points); getPathGridGraph(pathgrid).getNeighbouringPoints(index, points);
} }
void AiWander::getAllowedNodes(const MWWorld::Ptr& actor, AiWanderStorage& storage) void AiWander::fillAllowedPositions(const MWWorld::Ptr& actor, AiWanderStorage& storage)
{ {
// infrequently used, therefore no benefit in caching it as a member // infrequently used, therefore no benefit in caching it as a member
const MWWorld::CellStore* cellStore = actor.getCell(); const MWWorld::CellStore* cellStore = actor.getCell();
const ESM::Pathgrid* pathgrid const ESM::Pathgrid* pathgrid
= MWBase::Environment::get().getESMStore()->get<ESM::Pathgrid>().search(*cellStore->getCell()); = MWBase::Environment::get().getESMStore()->get<ESM::Pathgrid>().search(*cellStore->getCell());
storage.mAllowedNodes.clear(); storage.mAllowedPositions.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
@ -861,32 +856,33 @@ namespace MWMechanics
// Find closest pathgrid point // Find closest pathgrid point
size_t closestPointIndex = PathFinder::getClosestPoint(pathgrid, npcPos); size_t closestPointIndex = PathFinder::getClosestPoint(pathgrid, npcPos);
// mAllowedNodes for this actor with pathgrid point indexes based on mDistance // mAllowedPositions for this actor with pathgrid point indexes based on mDistance
// and if the point is connected to the closest current point // and if the point is connected to the closest current point
// NOTE: mPoints is in local coordinates // NOTE: mPoints is in local coordinates
size_t pointIndex = 0; size_t pointIndex = 0;
for (size_t counter = 0; counter < pathgrid->mPoints.size(); counter++) for (size_t counter = 0; counter < pathgrid->mPoints.size(); counter++)
{ {
osg::Vec3f nodePos(PathFinder::makeOsgVec3(pathgrid->mPoints[counter])); const osg::Vec3f nodePos = PathFinder::makeOsgVec3(pathgrid->mPoints[counter]);
if ((npcPos - nodePos).length2() <= mDistance * mDistance if ((npcPos - nodePos).length2() <= mDistance * mDistance
&& getPathGridGraph(pathgrid).isPointConnected(closestPointIndex, counter)) && getPathGridGraph(pathgrid).isPointConnected(closestPointIndex, counter))
{ {
storage.mAllowedNodes.push_back(converter.toWorldPoint(pathgrid->mPoints[counter])); storage.mAllowedPositions.push_back(
Misc::Convert::makeOsgVec3f(converter.toWorldPoint(pathgrid->mPoints[counter])));
pointIndex = counter; pointIndex = counter;
} }
} }
if (storage.mAllowedNodes.size() == 1) if (storage.mAllowedPositions.size() == 1)
{ {
storage.mAllowedNodes.push_back(PathFinder::makePathgridPoint(mInitialActorPosition)); storage.mAllowedPositions.push_back(mInitialActorPosition);
addNonPathGridAllowedPoints(pathgrid, pointIndex, storage, converter); addNonPathGridAllowedPoints(pathgrid, pointIndex, storage, converter);
} }
if (!storage.mAllowedNodes.empty()) if (!storage.mAllowedPositions.empty())
{ {
setCurrentNodeToClosestAllowedNode(storage); setCurrentPositionToClosestAllowedPosition(storage);
} }
} }
storage.mPopulateAvailableNodes = false; storage.mPopulateAvailablePositions = false;
} }
// When only one path grid point in wander distance, // When only one path grid point in wander distance,
@ -900,13 +896,13 @@ namespace MWMechanics
{ {
if (edge.mV0 == pointIndex) if (edge.mV0 == pointIndex)
{ {
AddPointBetweenPathGridPoints(converter.toWorldPoint(pathGrid->mPoints[edge.mV0]), addPositionBetweenPathgridPoints(converter.toWorldPoint(pathGrid->mPoints[edge.mV0]),
converter.toWorldPoint(pathGrid->mPoints[edge.mV1]), storage); converter.toWorldPoint(pathGrid->mPoints[edge.mV1]), storage);
} }
} }
} }
void AiWander::AddPointBetweenPathGridPoints( void AiWander::addPositionBetweenPathgridPoints(
const ESM::Pathgrid::Point& start, const ESM::Pathgrid::Point& end, AiWanderStorage& storage) const ESM::Pathgrid::Point& start, const ESM::Pathgrid::Point& end, AiWanderStorage& storage)
{ {
osg::Vec3f vectorStart = PathFinder::makeOsgVec3(start); osg::Vec3f vectorStart = PathFinder::makeOsgVec3(start);
@ -919,25 +915,25 @@ 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<unsigned>(length)); distance = std::min(distance, static_cast<unsigned>(length));
delta *= distance; delta *= distance;
storage.mAllowedNodes.push_back(PathFinder::makePathgridPoint(vectorStart + delta)); storage.mAllowedPositions.push_back(vectorStart + delta);
} }
void AiWander::setCurrentNodeToClosestAllowedNode(AiWanderStorage& storage) void AiWander::setCurrentPositionToClosestAllowedPosition(AiWanderStorage& storage)
{ {
float distanceToClosestNode = std::numeric_limits<float>::max(); float distanceToClosestPosition = std::numeric_limits<float>::max();
size_t index = 0; size_t index = 0;
for (size_t i = 0; i < storage.mAllowedNodes.size(); ++i) for (size_t i = 0; i < storage.mAllowedPositions.size(); ++i)
{ {
osg::Vec3f nodePos(PathFinder::makeOsgVec3(storage.mAllowedNodes[i])); const osg::Vec3f position = storage.mAllowedPositions[i];
float tempDist = (mInitialActorPosition - nodePos).length2(); const float tempDist = (mInitialActorPosition - position).length2();
if (tempDist < distanceToClosestNode) if (tempDist < distanceToClosestPosition)
{ {
index = i; index = i;
distanceToClosestNode = tempDist; distanceToClosestPosition = tempDist;
} }
} }
storage.mCurrentNode = storage.mAllowedNodes[index]; storage.mCurrentPosition = storage.mAllowedPositions[index];
storage.mAllowedNodes.erase(storage.mAllowedNodes.begin() + index); storage.mAllowedPositions.erase(storage.mAllowedPositions.begin() + index);
} }
void AiWander::writeState(ESM::AiSequence::AiSequence& sequence) const void AiWander::writeState(ESM::AiSequence::AiSequence& sequence) const

View File

@ -51,14 +51,13 @@ namespace MWMechanics
unsigned short mIdleAnimation; unsigned short mIdleAnimation;
std::vector<unsigned short> mBadIdles; // Idle animations that when called cause errors std::vector<unsigned short> mBadIdles; // Idle animations that when called cause errors
// do we need to calculate allowed nodes based on mDistance bool mPopulateAvailablePositions;
bool mPopulateAvailableNodes;
// allowed pathgrid nodes based on mDistance from the spawn point // allowed destination positions based on mDistance from the spawn point
std::vector<ESM::Pathgrid::Point> mAllowedNodes; std::vector<osg::Vec3f> mAllowedPositions;
ESM::Pathgrid::Point mCurrentNode; osg::Vec3f mCurrentPosition;
bool mTrimCurrentNode; bool mTrimCurrentPosition;
float mCheckIdlePositionTimer; float mCheckIdlePositionTimer;
int mStuckCount; int mStuckCount;
@ -132,7 +131,8 @@ namespace MWMechanics
bool playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); bool playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect);
bool checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); bool checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect);
int getRandomIdle() const; int getRandomIdle() const;
void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos); void setPathToAnAllowedPosition(
const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos);
void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage); void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage);
void doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, void doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration,
MWWorld::MovementDirectionFlags supportedMovementDirections, AiWanderStorage& storage); MWWorld::MovementDirectionFlags supportedMovementDirections, AiWanderStorage& storage);
@ -145,26 +145,27 @@ namespace MWMechanics
void wanderNearStart(const MWWorld::Ptr& actor, AiWanderStorage& storage, int wanderDistance); void wanderNearStart(const MWWorld::Ptr& actor, AiWanderStorage& storage, int wanderDistance);
bool destinationIsAtWater(const MWWorld::Ptr& actor, const osg::Vec3f& destination); bool destinationIsAtWater(const MWWorld::Ptr& actor, const osg::Vec3f& destination);
void completeManualWalking(const MWWorld::Ptr& actor, AiWanderStorage& storage); void completeManualWalking(const MWWorld::Ptr& actor, AiWanderStorage& storage);
bool isNearAllowedNode(const MWWorld::Ptr& actor, const AiWanderStorage& storage, float distance) const; bool isNearAllowedPosition(const MWWorld::Ptr& actor, const AiWanderStorage& storage, float distance) const;
const unsigned mDistance; // how far the actor can wander from the spawn point // how far the actor can wander from the spawn point
const unsigned mDistance;
const unsigned mDuration; const unsigned mDuration;
float mRemainingDuration; float mRemainingDuration;
const int mTimeOfDay; const int mTimeOfDay;
const std::vector<unsigned char> mIdle; const std::vector<unsigned char> mIdle;
bool mStoredInitialActorPosition; bool mStoredInitialActorPosition;
osg::Vec3f // Note: an original engine does not reset coordinates even when actor changes a cell
mInitialActorPosition; // Note: an original engine does not reset coordinates even when actor changes a cell osg::Vec3f mInitialActorPosition;
bool mHasDestination; bool mHasDestination;
osg::Vec3f mDestination; osg::Vec3f mDestination;
bool mUsePathgrid; bool mUsePathgrid;
void getNeighbouringNodes( void getNeighbouringNodes(
ESM::Pathgrid::Point dest, const MWWorld::CellStore* currentCell, ESM::Pathgrid::PointList& points); const osg::Vec3f& dest, const MWWorld::CellStore* currentCell, ESM::Pathgrid::PointList& points);
void getAllowedNodes(const MWWorld::Ptr& actor, AiWanderStorage& storage); void fillAllowedPositions(const MWWorld::Ptr& actor, AiWanderStorage& storage);
// constants for converting idleSelect values into groupNames // constants for converting idleSelect values into groupNames
enum GroupIndex enum GroupIndex
@ -173,12 +174,12 @@ namespace MWMechanics
GroupIndex_MaxIdle = 9 GroupIndex_MaxIdle = 9
}; };
void setCurrentNodeToClosestAllowedNode(AiWanderStorage& storage); void setCurrentPositionToClosestAllowedPosition(AiWanderStorage& storage);
void addNonPathGridAllowedPoints(const ESM::Pathgrid* pathGrid, size_t pointIndex, AiWanderStorage& storage, void addNonPathGridAllowedPoints(const ESM::Pathgrid* pathGrid, size_t pointIndex, AiWanderStorage& storage,
const Misc::CoordinateConverter& converter); const Misc::CoordinateConverter& converter);
void AddPointBetweenPathGridPoints( void addPositionBetweenPathgridPoints(
const ESM::Pathgrid::Point& start, const ESM::Pathgrid::Point& end, AiWanderStorage& storage); 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

View File

@ -145,19 +145,6 @@ namespace MWMechanics
mPath.push_back(point); mPath.push_back(point);
} }
/// utility function to convert a osg::Vec3f to a Pathgrid::Point
static ESM::Pathgrid::Point makePathgridPoint(const osg::Vec3f& v)
{
return ESM::Pathgrid::Point(static_cast<int>(v[0]), static_cast<int>(v[1]), static_cast<int>(v[2]));
}
/// utility function to convert an ESM::Position to a Pathgrid::Point
static ESM::Pathgrid::Point makePathgridPoint(const ESM::Position& p)
{
return ESM::Pathgrid::Point(
static_cast<int>(p.pos[0]), static_cast<int>(p.pos[1]), static_cast<int>(p.pos[2]));
}
static osg::Vec3f makeOsgVec3(const ESM::Pathgrid::Point& p) static osg::Vec3f makeOsgVec3(const ESM::Pathgrid::Point& p)
{ {
return osg::Vec3f(static_cast<float>(p.mX), static_cast<float>(p.mY), static_cast<float>(p.mZ)); return osg::Vec3f(static_cast<float>(p.mX), static_cast<float>(p.mY), static_cast<float>(p.mZ));

View File

@ -59,10 +59,18 @@ namespace Misc
point.y() -= static_cast<float>(mCellY); point.y() -= static_cast<float>(mCellY);
} }
osg::Vec3f toWorldVec3(const osg::Vec3f& point) const
{
osg::Vec3f result = point;
toWorld(result);
return result;
}
osg::Vec3f toLocalVec3(const osg::Vec3f& point) const osg::Vec3f toLocalVec3(const osg::Vec3f& point) const
{ {
return osg::Vec3f( osg::Vec3f result = point;
point.x() - static_cast<float>(mCellX), point.y() - static_cast<float>(mCellY), point.z()); toLocal(result);
return result;
} }
private: private: