Update manual wandering to prevent actor from leaving/entering water

Water creatures will stay in the water, while land creatures will stay on land when wandering.
pull/1/head
Austin Salgat 9 years ago
parent fc03216d48
commit 84179c262f

@ -428,7 +428,7 @@ namespace MWBase
virtual bool getLOS(const MWWorld::ConstPtr& actor,const MWWorld::ConstPtr& targetActor) = 0;
///< get Line of Sight (morrowind stupid implementation)
virtual float getDistToNearestRayHit(const osg::Vec3f& from, const osg::Vec3f& dir, float maxDist) = 0;
virtual float getDistToNearestRayHit(const osg::Vec3f& from, const osg::Vec3f& dir, float maxDist, bool includeWater = false) = 0;
virtual void enableActorCollision(const MWWorld::Ptr& actor, bool enable) = 0;

@ -346,18 +346,50 @@ namespace MWMechanics
*/
void AiWander::wanderNearStart(const MWWorld::Ptr &actor, AiWanderStorage &storage, int wanderDistance) {
const ESM::Pathgrid::Point currentPosition = actor.getRefData().getPosition().pos;
const osg::Vec3f currentPositionVec3f = osg::Vec3f(currentPosition.mX, currentPosition.mY, currentPosition.mZ);
std::size_t attempts = 10; // If a unit can't wander out of water, don't want to hang here
osg::Vec3f destination;
ESM::Pathgrid::Point destinationPosition;
bool isWaterCreature = actor.getClass().isPureWaterCreature(actor);
do {
// Determine a random location within radius of original position
const float pi = 3.14159265359f;
const float wanderRadius = Misc::Rng::rollClosedProbability() * wanderDistance;
const float randomDirection = Misc::Rng::rollClosedProbability() * 2.0f * pi;
const float destinationX = mInitialActorPosition.x() + wanderRadius * std::cos(randomDirection);
const float destinationY = mInitialActorPosition.y() + wanderRadius * std::sin(randomDirection);
const float destinationZ = mInitialActorPosition.z();
destinationPosition = ESM::Pathgrid::Point(destinationX, destinationY, destinationZ);
destination = 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, destination)) ||
(isWaterCreature && destinationThroughGround(currentPositionVec3f, destination))) {
storage.mPathFinder.buildSyncedPath(currentPosition, destinationPosition, actor.getCell(), true);
storage.mPathFinder.addPointToPath(destinationPosition);
storage.setState(Wander_Walking, true);
return;
}
} while (attempts--);
}
// Determine a random location within radius of original position
const float pi = 3.14159265359f;
const float wanderRadius = Misc::Rng::rollClosedProbability() * wanderDistance;
const float randomDirection = Misc::Rng::rollClosedProbability() * 2.0f * pi;
const float destinationX = mInitialActorPosition.x() + wanderRadius * std::cos(randomDirection);
const float destinationY = mInitialActorPosition.y() + wanderRadius * std::sin(randomDirection);
ESM::Pathgrid::Point destinationPosition = ESM::Pathgrid::Point(destinationX, destinationY, mInitialActorPosition.z());
storage.mPathFinder.buildSyncedPath(currentPosition, destinationPosition, actor.getCell(), true);
storage.mPathFinder.addPointToPath(destinationPosition);
storage.setState(Wander_Walking, true);
/*
* Returns true if the position provided is above water.
*/
bool AiWander::destinationIsAtWater(const MWWorld::Ptr &actor, const osg::Vec3f& destination) {
float heightToGroundOrWater = destination.z() - MWBase::Environment::get().getWorld()->getDistToNearestRayHit(destination, osg::Vec3f(0,0,-1), 1000.0, true);
osg::Vec3f positionBelowSurface = destination;
positionBelowSurface[2] = positionBelowSurface[2] - heightToGroundOrWater - DESTINATION_TOLERANCE;
return MWBase::Environment::get().getWorld()->isUnderwater(actor.getCell(), positionBelowSurface);
}
/*
* Returns true if the start to end point travels through a collision point (land).
*/
bool AiWander::destinationThroughGround(const osg::Vec3f& startPoint, const osg::Vec3f& destination) {
return MWBase::Environment::get().getWorld()->castRay(startPoint.x(), startPoint.y(), startPoint.z(),
destination.x(), destination.y(), destination.z());
}
void AiWander::doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos)

@ -95,6 +95,8 @@ namespace MWMechanics
bool isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage);
void returnToStartLocation(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos);
void wanderNearStart(const MWWorld::Ptr &actor, AiWanderStorage &storage, int wanderDistance);
bool destinationIsAtWater(const MWWorld::Ptr &actor, const osg::Vec3f& destination);
bool destinationThroughGround(const osg::Vec3f& startPoint, const osg::Vec3f& destination);
int mDistance; // how far the actor can wander from the spawn point
int mDuration;

@ -2389,14 +2389,17 @@ namespace MWWorld
return mPhysics->getLineOfSight(actor, targetActor);
}
float World::getDistToNearestRayHit(const osg::Vec3f& from, const osg::Vec3f& dir, float maxDist)
float World::getDistToNearestRayHit(const osg::Vec3f& from, const osg::Vec3f& dir, float maxDist, bool includeWater)
{
osg::Vec3f to (dir);
to.normalize();
to = from + (to * maxDist);
MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(from, to, MWWorld::Ptr(),
MWPhysics::CollisionType_World|MWPhysics::CollisionType_HeightMap|MWPhysics::CollisionType_Door);
int collisionTypes = MWPhysics::CollisionType_World | MWPhysics::CollisionType_HeightMap | MWPhysics::CollisionType_Door;
if (includeWater) {
collisionTypes |= MWPhysics::CollisionType_Water;
}
MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(from, to, MWWorld::Ptr(), collisionTypes);
if (!result.mHit)
return maxDist;

@ -527,7 +527,7 @@ namespace MWWorld
virtual bool getLOS(const MWWorld::ConstPtr& actor,const MWWorld::ConstPtr& targetActor);
///< get Line of Sight (morrowind stupid implementation)
virtual float getDistToNearestRayHit(const osg::Vec3f& from, const osg::Vec3f& dir, float maxDist);
virtual float getDistToNearestRayHit(const osg::Vec3f& from, const osg::Vec3f& dir, float maxDist, bool includeWater = false);
virtual void enableActorCollision(const MWWorld::Ptr& actor, bool enable);

Loading…
Cancel
Save