mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-16 18:19:55 +00:00
AI package cleanup
This commit is contained in:
parent
782aa3e584
commit
1de9674c81
8 changed files with 77 additions and 111 deletions
|
@ -29,14 +29,13 @@ namespace MWMechanics
|
|||
|
||||
actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing);
|
||||
|
||||
if (target == MWWorld::Ptr() ||
|
||||
!target.getRefData().getCount() || !target.getRefData().isEnabled() // Really we should check whether the target is currently registered
|
||||
// with the MechanicsManager
|
||||
)
|
||||
return true; //Target doesn't exist
|
||||
// Stop if the target doesn't exist
|
||||
// Really we should be checking whether the target is currently registered with the MechanicsManager
|
||||
if (target == MWWorld::Ptr() || !target.getRefData().getCount() || !target.getRefData().isEnabled())
|
||||
return true;
|
||||
|
||||
//Set the target destination for the actor
|
||||
const auto dest = target.getRefData().getPosition().asVec3();
|
||||
const osg::Vec3f dest = target.getRefData().getPosition().asVec3();
|
||||
|
||||
if (pathTo(actor, dest, duration, MWBase::Environment::get().getWorld()->getMaxActivationDistance())) //Stop when you get in activation range
|
||||
{
|
||||
|
|
|
@ -26,9 +26,9 @@ bool MWMechanics::AiBreathe::execute (const MWWorld::Ptr& actor, CharacterContro
|
|||
{
|
||||
if (actorClass.getNpcStats(actor).getTimeToStartDrowning() < fHoldBreathTime / 2)
|
||||
{
|
||||
actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
|
||||
actorClass.getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
|
||||
|
||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
|
||||
actorClass.getMovementSettings(actor).mPosition[1] = 1;
|
||||
smoothTurn(actor, -180, 0);
|
||||
|
||||
return false;
|
||||
|
|
|
@ -83,24 +83,13 @@ namespace MWMechanics
|
|||
actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, false);
|
||||
|
||||
const MWWorld::Ptr follower = MWBase::Environment::get().getWorld()->getPtr(mTargetActorRefId, false);
|
||||
const float* const leaderPos = actor.getRefData().getPosition().pos;
|
||||
const float* const followerPos = follower.getRefData().getPosition().pos;
|
||||
double differenceBetween[3];
|
||||
const osg::Vec3f leaderPos = actor.getRefData().getPosition().asVec3();
|
||||
const osg::Vec3f followerPos = follower.getRefData().getPosition().asVec3();
|
||||
|
||||
for (short counter = 0; counter < 3; counter++)
|
||||
differenceBetween[counter] = (leaderPos[counter] - followerPos[counter]);
|
||||
|
||||
double distanceBetweenResult =
|
||||
(differenceBetween[0] * differenceBetween[0]) + (differenceBetween[1] * differenceBetween[1]) + (differenceBetween[2] *
|
||||
differenceBetween[2]);
|
||||
|
||||
if (distanceBetweenResult <= mMaxDist * mMaxDist)
|
||||
if ((leaderPos - followerPos).length2() <= mMaxDist * mMaxDist)
|
||||
{
|
||||
ESM::Pathgrid::Point point(static_cast<int>(mX), static_cast<int>(mY), static_cast<int>(mZ));
|
||||
point.mAutogenerated = 0;
|
||||
point.mConnectionNum = 0;
|
||||
point.mUnknown = 0;
|
||||
if (pathTo(actor, osg::Vec3f(mX, mY, mZ), duration)) //Returns true on path complete
|
||||
const osg::Vec3f dest(mX, mY, mZ);
|
||||
if (pathTo(actor, dest, duration)) //Returns true on path complete
|
||||
{
|
||||
mRemainingDuration = mDuration;
|
||||
return true;
|
||||
|
|
|
@ -74,12 +74,12 @@ AiFollow::AiFollow(const ESM::AiSequence::AiFollow *follow)
|
|||
|
||||
bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
|
||||
{
|
||||
MWWorld::Ptr target = getTarget();
|
||||
const MWWorld::Ptr target = getTarget();
|
||||
|
||||
if (target.isEmpty() || !target.getRefData().getCount() || !target.getRefData().isEnabled() // Really we should be checking whether the target is currently registered
|
||||
// with the MechanicsManager
|
||||
)
|
||||
return false; // Target is not here right now, wait for it to return
|
||||
// Target is not here right now, wait for it to return
|
||||
// Really we should be checking whether the target is currently registered with the MechanicsManager
|
||||
if (target == MWWorld::Ptr() || !target.getRefData().getCount() || !target.getRefData().isEnabled())
|
||||
return false;
|
||||
|
||||
actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing);
|
||||
|
||||
|
@ -94,6 +94,10 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte
|
|||
return false;
|
||||
}
|
||||
|
||||
const osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3());
|
||||
const osg::Vec3f targetPos(target.getRefData().getPosition().asVec3());
|
||||
const osg::Vec3f targetDir = targetPos - actorPos;
|
||||
|
||||
// AiFollow requires the target to be in range and within sight for the initial activation
|
||||
if (!mActive)
|
||||
{
|
||||
|
@ -101,9 +105,7 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte
|
|||
|
||||
if (storage.mTimer < 0)
|
||||
{
|
||||
if ((actor.getRefData().getPosition().asVec3() - target.getRefData().getPosition().asVec3()).length2()
|
||||
< 500*500
|
||||
&& MWBase::Environment::get().getWorld()->getLOS(actor, target))
|
||||
if (targetDir.length2() < 500*500 && MWBase::Environment::get().getWorld()->getLOS(actor, target))
|
||||
mActive = true;
|
||||
storage.mTimer = 0.5f;
|
||||
}
|
||||
|
@ -111,8 +113,6 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte
|
|||
if (!mActive)
|
||||
return false;
|
||||
|
||||
ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
|
||||
|
||||
// The distances below are approximations based on observations of the original engine.
|
||||
// If only one actor is following the target, it uses 186.
|
||||
// If there are multiple actors following the same target, they form a group with each group member at 313 + (130 * i) distance to the target.
|
||||
|
@ -145,9 +145,8 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte
|
|||
}
|
||||
}
|
||||
|
||||
if ((pos.pos[0]-mX)*(pos.pos[0]-mX) +
|
||||
(pos.pos[1]-mY)*(pos.pos[1]-mY) +
|
||||
(pos.pos[2]-mZ)*(pos.pos[2]-mZ) < followDistance*followDistance) //Close-ish to final position
|
||||
osg::Vec3f finalPos(mX, mY, mZ);
|
||||
if ((actorPos-finalPos).length2() < followDistance*followDistance) //Close-ish to final position
|
||||
{
|
||||
if (actor.getCell()->isExterior()) //Outside?
|
||||
{
|
||||
|
@ -162,8 +161,6 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte
|
|||
}
|
||||
}
|
||||
|
||||
//Set the target destination from the actor
|
||||
const auto dest = target.getRefData().getPosition().asVec3();
|
||||
|
||||
short baseFollowDistance = followDistance;
|
||||
short threshold = 30; // to avoid constant switching between moving/stopping
|
||||
|
@ -172,15 +169,9 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte
|
|||
else
|
||||
followDistance += threshold;
|
||||
|
||||
osg::Vec3f targetPos(target.getRefData().getPosition().asVec3());
|
||||
osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3());
|
||||
|
||||
osg::Vec3f dir = targetPos - actorPos;
|
||||
float targetDistSqr = dir.length2();
|
||||
|
||||
if (targetDistSqr <= followDistance * followDistance)
|
||||
if (targetDir.length2() <= followDistance * followDistance)
|
||||
{
|
||||
float faceAngleRadians = std::atan2(dir.x(), dir.y());
|
||||
float faceAngleRadians = std::atan2(targetDir.x(), targetDir.y());
|
||||
|
||||
if (!zTurn(actor, faceAngleRadians, osg::DegreesToRadians(45.f)))
|
||||
{
|
||||
|
@ -191,16 +182,14 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte
|
|||
return false;
|
||||
}
|
||||
|
||||
storage.mMoving = !pathTo(actor, dest, duration, baseFollowDistance); // Go to the destination
|
||||
storage.mMoving = !pathTo(actor, targetPos, duration, baseFollowDistance); // Go to the destination
|
||||
|
||||
if (storage.mMoving)
|
||||
{
|
||||
//Check if you're far away
|
||||
float dist = distance(dest, pos.asVec3());
|
||||
|
||||
if (dist > 450)
|
||||
if (targetDir.length2() > 450 * 450)
|
||||
actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, true); //Make NPC run
|
||||
else if (dist < 325) //Have a bit of a dead zone, otherwise npc will constantly flip between running and not when right on the edge of the running threshold
|
||||
else if (targetDir.length2() < 325 * 325) //Have a bit of a dead zone, otherwise npc will constantly flip between running and not when right on the edge of the running threshold
|
||||
actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, false); //make NPC walk
|
||||
}
|
||||
|
||||
|
|
|
@ -101,11 +101,11 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f&
|
|||
{
|
||||
mTimer += duration; //Update timer
|
||||
|
||||
const auto position = actor.getRefData().getPosition().asVec3(); //position of the actor
|
||||
const auto world = MWBase::Environment::get().getWorld();
|
||||
const osg::Vec3f position = actor.getRefData().getPosition().asVec3(); //position of the actor
|
||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||
|
||||
{
|
||||
const auto halfExtents = world->getHalfExtents(actor);
|
||||
const osg::Vec3f halfExtents = world->getHalfExtents(actor);
|
||||
world->updateActorPath(actor, mPathFinder.getPath(), halfExtents, position, dest);
|
||||
}
|
||||
|
||||
|
@ -139,7 +139,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f&
|
|||
{
|
||||
if (wasShortcutting || doesPathNeedRecalc(dest, actor.getCell())) // if need to rebuild path
|
||||
{
|
||||
const auto playerHalfExtents = world->getHalfExtents(world->getPlayerPtr());
|
||||
const osg::Vec3f playerHalfExtents = world->getHalfExtents(getPlayer()); // Using player half extents for better performance
|
||||
mPathFinder.buildPath(actor, position, dest, actor.getCell(), getPathGridGraph(actor.getCell()),
|
||||
playerHalfExtents, getNavigatorFlags(actor));
|
||||
mRotateOnTheRunChecks = 3;
|
||||
|
@ -161,7 +161,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f&
|
|||
|
||||
if (!mPathFinder.getPath().empty()) //Path has points in it
|
||||
{
|
||||
const auto& lastPos = mPathFinder.getPath().back(); //Get the end of the proposed path
|
||||
const osg::Vec3f& lastPos = mPathFinder.getPath().back(); //Get the end of the proposed path
|
||||
|
||||
if(distance(dest, lastPos) > 100) //End of the path is far from the destination
|
||||
mPathFinder.addPointToPath(dest); //Adds the final destination to the path, to try to get to where you want to go
|
||||
|
@ -171,7 +171,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f&
|
|||
mTimer = 0;
|
||||
}
|
||||
|
||||
const auto pointTolerance = std::min(actor.getClass().getSpeed(actor), DEFAULT_TOLERANCE);
|
||||
const float pointTolerance = std::min(actor.getClass().getSpeed(actor), DEFAULT_TOLERANCE);
|
||||
|
||||
mPathFinder.update(position, pointTolerance, DEFAULT_TOLERANCE);
|
||||
|
||||
|
@ -223,7 +223,7 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor)
|
|||
|
||||
void MWMechanics::AiPackage::openDoors(const MWWorld::Ptr& actor)
|
||||
{
|
||||
const auto world = MWBase::Environment::get().getWorld();
|
||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||
static float distance = world->getMaxActivationDistance();
|
||||
|
||||
const MWWorld::Ptr door = getNearbyDoor(actor, distance);
|
||||
|
@ -296,11 +296,7 @@ bool MWMechanics::AiPackage::shortcutPath(const osg::Vec3f& startPoint, const os
|
|||
|
||||
bool MWMechanics::AiPackage::checkWayIsClearForActor(const osg::Vec3f& startPoint, const osg::Vec3f& endPoint, const MWWorld::Ptr& actor)
|
||||
{
|
||||
const auto world = MWBase::Environment::get().getWorld();
|
||||
const bool actorCanMoveByZ = (actor.getClass().canSwim(actor) && world->isSwimming(actor))
|
||||
|| world->isFlying(actor);
|
||||
|
||||
if (actorCanMoveByZ)
|
||||
if (canActorMoveByZAxis(actor))
|
||||
return true;
|
||||
|
||||
const float actorSpeed = actor.getClass().getSpeed(actor);
|
||||
|
@ -309,18 +305,17 @@ bool MWMechanics::AiPackage::checkWayIsClearForActor(const osg::Vec3f& startPoin
|
|||
|
||||
const float offsetXY = distToTarget > maxAvoidDist*1.5? maxAvoidDist : maxAvoidDist/2;
|
||||
|
||||
const bool isClear = checkWayIsClear(startPoint, endPoint, offsetXY);
|
||||
|
||||
// update shortcut prohibit state
|
||||
if (isClear)
|
||||
if (checkWayIsClear(startPoint, endPoint, offsetXY))
|
||||
{
|
||||
if (mShortcutProhibited)
|
||||
{
|
||||
mShortcutProhibited = false;
|
||||
mShortcutFailPos = osg::Vec3f();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (!isClear)
|
||||
else
|
||||
{
|
||||
if (mShortcutFailPos == osg::Vec3f())
|
||||
{
|
||||
|
@ -329,7 +324,7 @@ bool MWMechanics::AiPackage::checkWayIsClearForActor(const osg::Vec3f& startPoin
|
|||
}
|
||||
}
|
||||
|
||||
return isClear;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MWMechanics::AiPackage::doesPathNeedRecalc(const osg::Vec3f& newDest, const MWWorld::CellStore* currentCell)
|
||||
|
@ -399,7 +394,7 @@ bool MWMechanics::AiPackage::isReachableRotatingOnTheRun(const MWWorld::Ptr& act
|
|||
|
||||
DetourNavigator::Flags MWMechanics::AiPackage::getNavigatorFlags(const MWWorld::Ptr& actor) const
|
||||
{
|
||||
const auto& actorClass = actor.getClass();
|
||||
const MWWorld::Class& actorClass = actor.getClass();
|
||||
DetourNavigator::Flags result = DetourNavigator::Flag_none;
|
||||
|
||||
if (actorClass.isPureWaterCreature(actor) || (getTypeId() != TypeIdWander && actorClass.canSwim(actor)))
|
||||
|
@ -416,7 +411,6 @@ DetourNavigator::Flags MWMechanics::AiPackage::getNavigatorFlags(const MWWorld::
|
|||
|
||||
bool MWMechanics::AiPackage::canActorMoveByZAxis(const MWWorld::Ptr& actor) const
|
||||
{
|
||||
const auto world = MWBase::Environment::get().getWorld();
|
||||
const auto& actorClass = actor.getClass();
|
||||
return (actorClass.canSwim(actor) && world->isSwimming(actor)) || world->isFlying(actor);
|
||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||
return (actor.getClass().canSwim(actor) && world->isSwimming(actor)) || world->isFlying(actor);
|
||||
}
|
||||
|
|
|
@ -35,27 +35,27 @@ bool AiPursue::execute (const MWWorld::Ptr& actor, CharacterController& characte
|
|||
|
||||
const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId); //The target to follow
|
||||
|
||||
if(target == MWWorld::Ptr() || !target.getRefData().getCount() || !target.getRefData().isEnabled() // Really we should be checking whether the target is currently registered
|
||||
// with the MechanicsManager
|
||||
)
|
||||
return true; //Target doesn't exist
|
||||
// Stop if the target doesn't exist
|
||||
// Really we should be checking whether the target is currently registered with the MechanicsManager
|
||||
if (target == MWWorld::Ptr() || !target.getRefData().getCount() || !target.getRefData().isEnabled())
|
||||
return true;
|
||||
|
||||
if (isTargetMagicallyHidden(target))
|
||||
return true;
|
||||
|
||||
if(target.getClass().getCreatureStats(target).isDead())
|
||||
if (target.getClass().getCreatureStats(target).isDead())
|
||||
return true;
|
||||
|
||||
actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing);
|
||||
|
||||
//Set the target desition from the actor
|
||||
const auto dest = target.getRefData().getPosition().asVec3();
|
||||
ESM::Position aPos = actor.getRefData().getPosition();
|
||||
//Set the target destination
|
||||
const osg::Vec3f dest = target.getRefData().getPosition().asVec3();
|
||||
const osg::Vec3f actorPos = actor.getRefData().getPosition().asVec3();
|
||||
|
||||
float pathTolerance = 100.0;
|
||||
const float pathTolerance = 100.f;
|
||||
|
||||
if (pathTo(actor, dest, duration, pathTolerance) &&
|
||||
std::abs(dest.z() - aPos.pos[2]) < pathTolerance) // check the true distance in case the target is far away in Z-direction
|
||||
std::abs(dest.z() - actorPos.z()) < pathTolerance) // check the true distance in case the target is far away in Z-direction
|
||||
{
|
||||
target.getClass().activate(target,actor).get()->execute(actor); //Arrest player when reached
|
||||
return true;
|
||||
|
|
|
@ -21,7 +21,7 @@ bool isWithinMaxRange(const osg::Vec3f& pos1, const osg::Vec3f& pos2)
|
|||
{
|
||||
// Maximum travel distance for vanilla compatibility.
|
||||
// Was likely meant to prevent NPCs walking into non-loaded exterior cells, but for some reason is used in interior cells as well.
|
||||
// We can make this configurable at some point, but the default *must* be the below value. Anything else will break shoddily-written content (*cough* MW *cough*) in bizarre ways.
|
||||
// The specific range below is configurable, but its limit is currently 7168 units. Anything greater will break shoddily-written content (*cough* MW *cough*) in bizarre ways.
|
||||
float aiDistance = MWBase::Environment::get().getMechanicsManager()->getActorsProcessingRange();
|
||||
return (pos1 - pos2).length2() <= aiDistance*aiDistance;
|
||||
}
|
||||
|
@ -47,18 +47,19 @@ namespace MWMechanics
|
|||
|
||||
bool AiTravel::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
|
||||
{
|
||||
ESM::Position pos = actor.getRefData().getPosition();
|
||||
const osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3());
|
||||
const osg::Vec3f targetPos(mX, mY, mZ);
|
||||
|
||||
actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, false);
|
||||
actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing);
|
||||
|
||||
if (!isWithinMaxRange(osg::Vec3f(mX, mY, mZ), pos.asVec3()))
|
||||
if (!isWithinMaxRange(targetPos, actorPos))
|
||||
return false;
|
||||
|
||||
// Unfortunately, with vanilla assets destination is sometimes blocked by other actor.
|
||||
// If we got close to target, check for actors nearby. If they are, finish AI package.
|
||||
int destinationTolerance = 64;
|
||||
if (distance(pos.asVec3(), osg::Vec3f(mX, mY, mZ)) <= destinationTolerance)
|
||||
if (distance(actorPos, targetPos) <= destinationTolerance)
|
||||
{
|
||||
std::vector<MWWorld::Ptr> targetActors;
|
||||
std::pair<MWWorld::Ptr, osg::Vec3f> result = MWBase::Environment::get().getWorld()->getHitContact(actor, destinationTolerance, targetActors);
|
||||
|
@ -70,7 +71,7 @@ namespace MWMechanics
|
|||
}
|
||||
}
|
||||
|
||||
if (pathTo(actor, osg::Vec3f(mX, mY, mZ), duration))
|
||||
if (pathTo(actor, targetPos, duration))
|
||||
{
|
||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
||||
return true;
|
||||
|
|
|
@ -124,14 +124,13 @@ namespace MWMechanics
|
|||
*/
|
||||
bool AiWander::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
|
||||
{
|
||||
// get or create temporary storage
|
||||
AiWanderStorage& storage = state.get<AiWanderStorage>();
|
||||
|
||||
const MWWorld::CellStore*& currentCell = storage.mCell;
|
||||
MWMechanics::CreatureStats& cStats = actor.getClass().getCreatureStats(actor);
|
||||
if(cStats.isDead() || cStats.getHealth().getCurrent() <= 0)
|
||||
if (cStats.isDead() || cStats.getHealth().getCurrent() <= 0)
|
||||
return true; // Don't bother with dead actors
|
||||
|
||||
// get or create temporary storage
|
||||
AiWanderStorage& storage = state.get<AiWanderStorage>();
|
||||
const MWWorld::CellStore*& currentCell = storage.mCell;
|
||||
bool cellChange = currentCell && (actor.getCell() != currentCell);
|
||||
if(!currentCell || cellChange)
|
||||
{
|
||||
|
@ -159,8 +158,7 @@ namespace MWMechanics
|
|||
}
|
||||
else
|
||||
{
|
||||
const auto world = MWBase::Environment::get().getWorld();
|
||||
const auto playerHalfExtents = world->getHalfExtents(world->getPlayerPtr());
|
||||
const osg::Vec3f playerHalfExtents = MWBase::Environment::get().getWorld()->getHalfExtents(getPlayer()); // Using player half extents for better performance
|
||||
mPathFinder.buildPath(actor, pos.asVec3(), mDestination, actor.getCell(),
|
||||
getPathGridGraph(actor.getCell()), playerHalfExtents, getNavigatorFlags(actor));
|
||||
}
|
||||
|
@ -279,9 +277,7 @@ namespace MWMechanics
|
|||
if (mHasDestination)
|
||||
return mDestination;
|
||||
|
||||
const ESM::Pathgrid::Point currentPosition = actor.getRefData().getPosition().pos;
|
||||
const osg::Vec3f currentPositionVec3f = osg::Vec3f(currentPosition.mX, currentPosition.mY, currentPosition.mZ);
|
||||
return currentPositionVec3f;
|
||||
return actor.getRefData().getPosition().asVec3();
|
||||
}
|
||||
|
||||
bool AiWander::isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage)
|
||||
|
@ -314,18 +310,17 @@ namespace MWMechanics
|
|||
const float destinationX = mInitialActorPosition.x() + wanderRadius * std::cos(randomDirection);
|
||||
const float destinationY = mInitialActorPosition.y() + wanderRadius * std::sin(randomDirection);
|
||||
const float destinationZ = mInitialActorPosition.z();
|
||||
const osg::Vec3f destinationPosition(destinationX, destinationY, destinationZ);
|
||||
mDestination = osg::Vec3f(destinationX, destinationY, destinationZ);
|
||||
|
||||
// Check if land creature will walk onto water or if water creature will swim onto land
|
||||
if ((!isWaterCreature && !destinationIsAtWater(actor, mDestination)) ||
|
||||
(isWaterCreature && !destinationThroughGround(currentPosition, mDestination)))
|
||||
{
|
||||
const auto world = MWBase::Environment::get().getWorld();;
|
||||
const auto playerHalfExtents = world->getHalfExtents(world->getPlayerPtr());
|
||||
mPathFinder.buildPath(actor, currentPosition, destinationPosition, actor.getCell(),
|
||||
// Using player half extents for better performance
|
||||
const osg::Vec3f playerHalfExtents = MWBase::Environment::get().getWorld()->getHalfExtents(getPlayer());
|
||||
mPathFinder.buildPath(actor, currentPosition, mDestination, actor.getCell(),
|
||||
getPathGridGraph(actor.getCell()), playerHalfExtents, getNavigatorFlags(actor));
|
||||
mPathFinder.addPointToPath(destinationPosition);
|
||||
mPathFinder.addPointToPath(mDestination);
|
||||
|
||||
if (mPathFinder.isPathConstructed())
|
||||
{
|
||||
|
@ -520,9 +515,9 @@ namespace MWMechanics
|
|||
// Only say Idle voices when player is in LOS
|
||||
// A bit counterintuitive, likely vanilla did this to reduce the appearance of
|
||||
// voices going through walls?
|
||||
const ESM::Position& pos = actor.getRefData().getPosition();
|
||||
if (roll < x && (player.getRefData().getPosition().asVec3() - pos.asVec3()).length2()
|
||||
< 3000 * 3000 // maybe should be fAudioVoiceDefaultMaxDistance*fAudioMaxDistanceMult instead
|
||||
const osg::Vec3f playerPos(player.getRefData().getPosition().asVec3());
|
||||
const osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3());
|
||||
if (roll < x && (playerPos - actorPos).length2() < 3000 * 3000 // maybe should be fAudioVoiceDefaultMaxDistance*fAudioMaxDistanceMult instead
|
||||
&& MWBase::Environment::get().getWorld()->getLOS(player, actor))
|
||||
MWBase::Environment::get().getDialogueManager()->say(actor, "idle");
|
||||
}
|
||||
|
@ -541,13 +536,12 @@ namespace MWMechanics
|
|||
MWWorld::Ptr player = getPlayer();
|
||||
osg::Vec3f playerPos(player.getRefData().getPosition().asVec3());
|
||||
osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3());
|
||||
float playerDistSqr = (playerPos - actorPos).length2();
|
||||
|
||||
int& greetingTimer = storage.mGreetingTimer;
|
||||
AiWanderStorage::GreetingState& greetingState = storage.mSaidGreeting;
|
||||
if (greetingState == AiWanderStorage::Greet_None)
|
||||
{
|
||||
if ((playerDistSqr <= helloDistance*helloDistance) &&
|
||||
if ((playerPos - actorPos).length2() <= helloDistance*helloDistance &&
|
||||
!player.getClass().getCreatureStats(player).isDead() && MWBase::Environment::get().getWorld()->getLOS(player, actor)
|
||||
&& MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, actor))
|
||||
greetingTimer++;
|
||||
|
@ -583,7 +577,7 @@ namespace MWMechanics
|
|||
if (greetingState == AiWanderStorage::Greet_Done)
|
||||
{
|
||||
float resetDist = 2 * helloDistance;
|
||||
if (playerDistSqr >= resetDist*resetDist)
|
||||
if ((playerPos - actorPos).length2() >= resetDist*resetDist)
|
||||
greetingState = AiWanderStorage::Greet_None;
|
||||
}
|
||||
}
|
||||
|
@ -605,10 +599,10 @@ namespace MWMechanics
|
|||
ToWorldCoordinates(dest, storage.mCell->getCell());
|
||||
|
||||
// actor position is already in world coordinates
|
||||
const auto start = actorPos.asVec3();
|
||||
const osg::Vec3f start = actorPos.asVec3();
|
||||
|
||||
// don't take shortcuts for wandering
|
||||
const auto destVec3f = PathFinder::makeOsgVec3(dest);
|
||||
const osg::Vec3f destVec3f = PathFinder::makeOsgVec3(dest);
|
||||
mPathFinder.buildPathByPathgrid(start, destVec3f, actor.getCell(), getPathGridGraph(actor.getCell()));
|
||||
|
||||
if (mPathFinder.isPathConstructed())
|
||||
|
|
Loading…
Reference in a new issue