mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 22:23:51 +00:00
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.
This commit is contained in:
parent
fc03216d48
commit
84179c262f
5 changed files with 52 additions and 15 deletions
|
@ -428,7 +428,7 @@ namespace MWBase
|
||||||
virtual bool getLOS(const MWWorld::ConstPtr& actor,const MWWorld::ConstPtr& targetActor) = 0;
|
virtual bool getLOS(const MWWorld::ConstPtr& actor,const MWWorld::ConstPtr& targetActor) = 0;
|
||||||
///< get Line of Sight (morrowind stupid implementation)
|
///< 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;
|
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) {
|
void AiWander::wanderNearStart(const MWWorld::Ptr &actor, AiWanderStorage &storage, int wanderDistance) {
|
||||||
const ESM::Pathgrid::Point currentPosition = actor.getRefData().getPosition().pos;
|
const ESM::Pathgrid::Point currentPosition = actor.getRefData().getPosition().pos;
|
||||||
|
const osg::Vec3f currentPositionVec3f = osg::Vec3f(currentPosition.mX, currentPosition.mY, currentPosition.mZ);
|
||||||
|
|
||||||
// Determine a random location within radius of original position
|
std::size_t attempts = 10; // If a unit can't wander out of water, don't want to hang here
|
||||||
const float pi = 3.14159265359f;
|
osg::Vec3f destination;
|
||||||
const float wanderRadius = Misc::Rng::rollClosedProbability() * wanderDistance;
|
ESM::Pathgrid::Point destinationPosition;
|
||||||
const float randomDirection = Misc::Rng::rollClosedProbability() * 2.0f * pi;
|
bool isWaterCreature = actor.getClass().isPureWaterCreature(actor);
|
||||||
const float destinationX = mInitialActorPosition.x() + wanderRadius * std::cos(randomDirection);
|
do {
|
||||||
const float destinationY = mInitialActorPosition.y() + wanderRadius * std::sin(randomDirection);
|
// Determine a random location within radius of original position
|
||||||
ESM::Pathgrid::Point destinationPosition = ESM::Pathgrid::Point(destinationX, destinationY, mInitialActorPosition.z());
|
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);
|
||||||
|
|
||||||
storage.mPathFinder.buildSyncedPath(currentPosition, destinationPosition, actor.getCell(), true);
|
// Check if land creature will walk onto water or if water creature will swim onto land
|
||||||
storage.mPathFinder.addPointToPath(destinationPosition);
|
if ((!isWaterCreature && !destinationIsAtWater(actor, destination)) ||
|
||||||
storage.setState(Wander_Walking, true);
|
(isWaterCreature && destinationThroughGround(currentPositionVec3f, destination))) {
|
||||||
|
storage.mPathFinder.buildSyncedPath(currentPosition, destinationPosition, actor.getCell(), true);
|
||||||
|
storage.mPathFinder.addPointToPath(destinationPosition);
|
||||||
|
storage.setState(Wander_Walking, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} while (attempts--);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
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);
|
bool isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage);
|
||||||
void returnToStartLocation(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos);
|
void returnToStartLocation(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos);
|
||||||
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 destinationThroughGround(const osg::Vec3f& startPoint, const osg::Vec3f& destination);
|
||||||
|
|
||||||
int mDistance; // how far the actor can wander from the spawn point
|
int mDistance; // how far the actor can wander from the spawn point
|
||||||
int mDuration;
|
int mDuration;
|
||||||
|
|
|
@ -2389,14 +2389,17 @@ namespace MWWorld
|
||||||
return mPhysics->getLineOfSight(actor, targetActor);
|
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);
|
osg::Vec3f to (dir);
|
||||||
to.normalize();
|
to.normalize();
|
||||||
to = from + (to * maxDist);
|
to = from + (to * maxDist);
|
||||||
|
|
||||||
MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(from, to, MWWorld::Ptr(),
|
int collisionTypes = MWPhysics::CollisionType_World | MWPhysics::CollisionType_HeightMap | MWPhysics::CollisionType_Door;
|
||||||
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)
|
if (!result.mHit)
|
||||||
return maxDist;
|
return maxDist;
|
||||||
|
|
|
@ -527,7 +527,7 @@ namespace MWWorld
|
||||||
virtual bool getLOS(const MWWorld::ConstPtr& actor,const MWWorld::ConstPtr& targetActor);
|
virtual bool getLOS(const MWWorld::ConstPtr& actor,const MWWorld::ConstPtr& targetActor);
|
||||||
///< get Line of Sight (morrowind stupid implementation)
|
///< 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);
|
virtual void enableActorCollision(const MWWorld::Ptr& actor, bool enable);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue