mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 19:29:56 +00:00
Pathfinding Overhaul - Master cleanup! Cleaned pathfinding entirely, all AI packages that are implemented as well, Increased buffer! This makes the intro guard no longer walk into you or go to far into the room (not tested against vanilla distances but it seems accurate enough until the next itteration of pathfinding fixes).
This commit is contained in:
parent
a4caec56cf
commit
09beafd044
4 changed files with 515 additions and 494 deletions
|
@ -13,8 +13,9 @@ namespace
|
|||
{
|
||||
float sgn(float a)
|
||||
{
|
||||
if(a > 0) return 1.0;
|
||||
else return -1.0;
|
||||
if(a > 0)
|
||||
return 1.0;
|
||||
return -1.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,151 +25,156 @@ namespace
|
|||
TODO: Take account for actors being in different cells.
|
||||
*/
|
||||
|
||||
MWMechanics::AiEscort::AiEscort(const std::string &actorId,int duration, float x, float y, float z)
|
||||
: mActorId(actorId), mX(x), mY(y), mZ(z), mDuration(duration)
|
||||
namespace MWMechanics
|
||||
{
|
||||
mMaxDist = 470;
|
||||
|
||||
// The CS Help File states that if a duration is givin, the AI package will run for that long
|
||||
// BUT if a location is givin, it "trumps" the duration so it will simply escort to that location.
|
||||
if(mX != 0 || mY != 0 || mZ != 0)
|
||||
mDuration = 0;
|
||||
|
||||
else
|
||||
AiEscort::AiEscort(const std::string &actorId, int duration, float x, float y, float z)
|
||||
: mActorId(actorId), mX(x), mY(y), mZ(z), mDuration(duration)
|
||||
{
|
||||
MWWorld::TimeStamp startTime = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
mStartingSecond = ((startTime.getHour() - int(startTime.getHour())) * 100);
|
||||
}
|
||||
}
|
||||
|
||||
MWMechanics::AiEscort::AiEscort(const std::string &actorId,const std::string &cellId,int duration, float x, float y, float z)
|
||||
: mActorId(actorId), mCellId(cellId), mX(x), mY(y), mZ(z), mDuration(duration)
|
||||
{
|
||||
mMaxDist = 470;
|
||||
|
||||
// The CS Help File states that if a duration is givin, the AI package will run for that long
|
||||
// BUT if a location is givin, it "trumps" the duration so it will simply escort to that location.
|
||||
if(mX != 0 || mY != 0 || mZ != 0)
|
||||
mDuration = 0;
|
||||
|
||||
else
|
||||
{
|
||||
MWWorld::TimeStamp startTime = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
mStartingSecond = ((startTime.getHour() - int(startTime.getHour())) * 100);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MWMechanics::AiEscort *MWMechanics::AiEscort::clone() const
|
||||
{
|
||||
return new AiEscort(*this);
|
||||
}
|
||||
|
||||
bool MWMechanics::AiEscort::execute (const MWWorld::Ptr& actor)
|
||||
{
|
||||
// If AiEscort has ran for as long or longer then the duration specified
|
||||
// and the duration is not infinite, the package is complete.
|
||||
if(mDuration != 0)
|
||||
{
|
||||
MWWorld::TimeStamp current = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
unsigned int currentSecond = ((current.getHour() - int(current.getHour())) * 100);
|
||||
if(currentSecond - mStartingSecond >= mDuration)
|
||||
return true;
|
||||
}
|
||||
|
||||
ESM::Position pos = actor.getRefData().getPosition();
|
||||
bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY;
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
const ESM::Pathgrid *pathgrid =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*actor.getCell()->mCell);
|
||||
|
||||
|
||||
if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX)
|
||||
{
|
||||
int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX);
|
||||
// Check if actor is near the border of an inactive cell. If so, disable AiEscort.
|
||||
// FIXME: This *should* pause the AiEscort package instead of terminating it.
|
||||
if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE / 2. - 200))
|
||||
{
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY)
|
||||
{
|
||||
int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY);
|
||||
// Check if actor is near the border of an inactive cell. If so, disable AiEscort.
|
||||
// FIXME: This *should* pause the AiEscort package instead of terminating it.
|
||||
if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE / 2. - 200))
|
||||
{
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(!mPathFinder.isPathConstructed() || cellChange)
|
||||
{
|
||||
cellX = actor.getCell()->mCell->mData.mX;
|
||||
cellY = actor.getCell()->mCell->mData.mY;
|
||||
float xCell = 0;
|
||||
float yCell = 0;
|
||||
if (actor.getCell()->mCell->isExterior())
|
||||
{
|
||||
xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE;
|
||||
yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE;
|
||||
}
|
||||
|
||||
ESM::Pathgrid::Point dest;
|
||||
dest.mX = mX;
|
||||
dest.mY = mY;
|
||||
dest.mZ = mZ;
|
||||
|
||||
ESM::Pathgrid::Point start;
|
||||
start.mX = pos.pos[0];
|
||||
start.mY = pos.pos[1];
|
||||
start.mZ = pos.pos[2];
|
||||
|
||||
mPathFinder.buildPath(start, dest, pathgrid, xCell, yCell, 1);
|
||||
}
|
||||
|
||||
if(mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]))
|
||||
{
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
const MWWorld::Ptr follower = MWBase::Environment::get().getWorld()->getPtr(mActorId, false);
|
||||
const float* const leaderPos = actor.getRefData().getPosition().pos;
|
||||
const float* const followerPos = follower.getRefData().getPosition().pos;
|
||||
double differenceBetween[3];
|
||||
|
||||
for (short i = 0; i < 3; ++i)
|
||||
differenceBetween[i] = (leaderPos[i] - followerPos[i]);
|
||||
|
||||
float distanceBetweenResult =
|
||||
(differenceBetween[0] * differenceBetween[0]) + (differenceBetween[1] * differenceBetween[1]) + (differenceBetween[2] * differenceBetween[2]);
|
||||
|
||||
if(distanceBetweenResult <= mMaxDist * mMaxDist)
|
||||
{
|
||||
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1]);
|
||||
MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false);
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
|
||||
mMaxDist = 470;
|
||||
|
||||
// The CS Help File states that if a duration is givin, the AI package will run for that long
|
||||
// BUT if a location is givin, it "trumps" the duration so it will simply escort to that location.
|
||||
if(mX != 0 || mY != 0 || mZ != 0)
|
||||
mDuration = 0;
|
||||
|
||||
else
|
||||
{
|
||||
MWWorld::TimeStamp startTime = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
mStartingSecond = ((startTime.getHour() - int(startTime.getHour())) * 100);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
AiEscort::AiEscort(const std::string &actorId, const std::string &cellId,int duration, float x, float y, float z)
|
||||
: mActorId(actorId), mCellId(cellId), mX(x), mY(y), mZ(z), mDuration(duration)
|
||||
{
|
||||
// Stop moving if the player is to far away
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle3", 0, 1);
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
mMaxDist = 330;
|
||||
mMaxDist = 470;
|
||||
|
||||
// The CS Help File states that if a duration is givin, the AI package will run for that long
|
||||
// BUT if a location is givin, it "trumps" the duration so it will simply escort to that location.
|
||||
if(mX != 0 || mY != 0 || mZ != 0)
|
||||
mDuration = 0;
|
||||
|
||||
else
|
||||
{
|
||||
MWWorld::TimeStamp startTime = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
mStartingSecond = ((startTime.getHour() - int(startTime.getHour())) * 100);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int MWMechanics::AiEscort::getTypeId() const
|
||||
{
|
||||
return 2;
|
||||
|
||||
AiEscort *MWMechanics::AiEscort::clone() const
|
||||
{
|
||||
return new AiEscort(*this);
|
||||
}
|
||||
|
||||
bool AiEscort::execute (const MWWorld::Ptr& actor)
|
||||
{
|
||||
// If AiEscort has ran for as long or longer then the duration specified
|
||||
// and the duration is not infinite, the package is complete.
|
||||
if(mDuration != 0)
|
||||
{
|
||||
MWWorld::TimeStamp current = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
unsigned int currentSecond = ((current.getHour() - int(current.getHour())) * 100);
|
||||
if(currentSecond - mStartingSecond >= mDuration)
|
||||
return true;
|
||||
}
|
||||
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
ESM::Position pos = actor.getRefData().getPosition();
|
||||
bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY;
|
||||
const ESM::Pathgrid *pathgrid =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*actor.getCell()->mCell);
|
||||
|
||||
if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX)
|
||||
{
|
||||
int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX);
|
||||
// Check if actor is near the border of an inactive cell. If so, disable AiEscort.
|
||||
// FIXME: This *should* pause the AiEscort package instead of terminating it.
|
||||
if(sideX * (pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE /
|
||||
2.0 - 200))
|
||||
{
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY)
|
||||
{
|
||||
int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY);
|
||||
// Check if actor is near the border of an inactive cell. If so, disable AiEscort.
|
||||
// FIXME: This *should* pause the AiEscort package instead of terminating it.
|
||||
if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE /
|
||||
2.0 - 200))
|
||||
{
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(!mPathFinder.isPathConstructed() || cellChange)
|
||||
{
|
||||
cellX = actor.getCell()->mCell->mData.mX;
|
||||
cellY = actor.getCell()->mCell->mData.mY;
|
||||
float xCell = 0;
|
||||
float yCell = 0;
|
||||
if (actor.getCell()->mCell->isExterior())
|
||||
{
|
||||
xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE;
|
||||
yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE;
|
||||
}
|
||||
|
||||
ESM::Pathgrid::Point dest;
|
||||
dest.mX = mX;
|
||||
dest.mY = mY;
|
||||
dest.mZ = mZ;
|
||||
|
||||
ESM::Pathgrid::Point start;
|
||||
start.mX = pos.pos[0];
|
||||
start.mY = pos.pos[1];
|
||||
start.mZ = pos.pos[2];
|
||||
|
||||
mPathFinder.buildPath(start, dest, pathgrid, xCell, yCell, true);
|
||||
}
|
||||
|
||||
if(mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]))
|
||||
{
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
const MWWorld::Ptr follower = MWBase::Environment::get().getWorld()->getPtr(mActorId, false);
|
||||
const float* const leaderPos = actor.getRefData().getPosition().pos;
|
||||
const float* const followerPos = follower.getRefData().getPosition().pos;
|
||||
double differenceBetween[3];
|
||||
|
||||
for (short counter = 0; counter < 3; counter++)
|
||||
differenceBetween[counter] = (leaderPos[counter] - followerPos[counter]);
|
||||
|
||||
float distanceBetweenResult =
|
||||
(differenceBetween[0] * differenceBetween[0]) + (differenceBetween[1] * differenceBetween[1]) + (differenceBetween[2] *
|
||||
differenceBetween[2]);
|
||||
|
||||
if(distanceBetweenResult <= mMaxDist * mMaxDist)
|
||||
{
|
||||
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
|
||||
MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false);
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
|
||||
mMaxDist = 470;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Stop moving if the player is to far away
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle3", 0, 1);
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
mMaxDist = 330;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int AiEscort::getTypeId() const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,99 +2,106 @@
|
|||
|
||||
#include "movement.hpp"
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/player.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
float sgn(float a)
|
||||
{
|
||||
if(a > 0) return 1.;
|
||||
else return -1.;
|
||||
if(a > 0)
|
||||
return 1.0;
|
||||
return -1.0;
|
||||
}
|
||||
}
|
||||
|
||||
MWMechanics::AiTravel::AiTravel(float x, float y, float z)
|
||||
: mX(x),mY(y),mZ(z),mPathFinder()
|
||||
namespace MWMechanics
|
||||
{
|
||||
}
|
||||
AiTravel::AiTravel(float x, float y, float z)
|
||||
: mX(x),mY(y),mZ(z),mPathFinder()
|
||||
{
|
||||
}
|
||||
|
||||
MWMechanics::AiTravel *MWMechanics::AiTravel::clone() const
|
||||
{
|
||||
return new AiTravel(*this);
|
||||
}
|
||||
AiTravel *MWMechanics::AiTravel::clone() const
|
||||
{
|
||||
return new AiTravel(*this);
|
||||
}
|
||||
|
||||
bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor)
|
||||
{
|
||||
const ESM::Pathgrid *pathgrid =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*actor.getCell()->mCell);
|
||||
|
||||
ESM::Position pos = actor.getRefData().getPosition();
|
||||
bool AiTravel::execute (const MWWorld::Ptr& actor)
|
||||
{
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
ESM::Position pos = actor.getRefData().getPosition();
|
||||
bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY;
|
||||
const ESM::Pathgrid *pathgrid =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*actor.getCell()->mCell);
|
||||
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX)
|
||||
{
|
||||
int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX);
|
||||
//check if actor is near the border of an inactive cell. If so, disable aitravel.
|
||||
if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX*(ESM::Land::REAL_SIZE/2. - 200))
|
||||
if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX)
|
||||
{
|
||||
int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX);
|
||||
//check if actor is near the border of an inactive cell. If so, disable aitravel.
|
||||
if(sideX * (pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE /
|
||||
2.0 - 200))
|
||||
{
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY)
|
||||
{
|
||||
int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY);
|
||||
//check if actor is near the border of an inactive cell. If so, disable aitravel.
|
||||
if(sideY * (pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE /
|
||||
2.0 - 200))
|
||||
{
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!mPathFinder.isPathConstructed() || cellChange)
|
||||
{
|
||||
cellX = actor.getCell()->mCell->mData.mX;
|
||||
cellY = actor.getCell()->mCell->mData.mY;
|
||||
float xCell = 0;
|
||||
float yCell = 0;
|
||||
|
||||
if (actor.getCell()->mCell->isExterior())
|
||||
{
|
||||
xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE;
|
||||
yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE;
|
||||
}
|
||||
|
||||
ESM::Pathgrid::Point dest;
|
||||
dest.mX = mX;
|
||||
dest.mY = mY;
|
||||
dest.mZ = mZ;
|
||||
|
||||
ESM::Pathgrid::Point start;
|
||||
start.mX = pos.pos[0];
|
||||
start.mY = pos.pos[1];
|
||||
start.mZ = pos.pos[2];
|
||||
|
||||
mPathFinder.buildPath(start, dest, pathgrid, xCell, yCell, true);
|
||||
}
|
||||
|
||||
if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2]))
|
||||
{
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
|
||||
MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false);
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
|
||||
|
||||
return false;
|
||||
}
|
||||
if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY)
|
||||
|
||||
int AiTravel::getTypeId() const
|
||||
{
|
||||
int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY);
|
||||
//check if actor is near the border of an inactive cell. If so, disable aitravel.
|
||||
if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY*(ESM::Land::REAL_SIZE/2. - 200))
|
||||
{
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
return true;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(!mPathFinder.isPathConstructed() ||cellChange)
|
||||
{
|
||||
cellX = actor.getCell()->mCell->mData.mX;
|
||||
cellY = actor.getCell()->mCell->mData.mY;
|
||||
float xCell = 0;
|
||||
float yCell = 0;
|
||||
if (actor.getCell()->mCell->isExterior())
|
||||
{
|
||||
xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE;
|
||||
yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE;
|
||||
}
|
||||
|
||||
ESM::Pathgrid::Point dest;
|
||||
dest.mX = mX;
|
||||
dest.mY = mY;
|
||||
dest.mZ = mZ;
|
||||
|
||||
ESM::Pathgrid::Point start;
|
||||
start.mX = pos.pos[0];
|
||||
start.mY = pos.pos[1];
|
||||
start.mZ = pos.pos[2];
|
||||
|
||||
mPathFinder.buildPath(start, dest, pathgrid, xCell, yCell, 1);
|
||||
}
|
||||
|
||||
if(mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]))
|
||||
{
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1]);
|
||||
MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false);
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int MWMechanics::AiTravel::getTypeId() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -14,316 +14,324 @@ namespace
|
|||
{
|
||||
float sgn(float a)
|
||||
{
|
||||
if(a > 0) return 1.0;
|
||||
else return -1.0;
|
||||
if(a > 0)
|
||||
return 1.0;
|
||||
return -1.0;
|
||||
}
|
||||
}
|
||||
|
||||
MWMechanics::AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<int>& idle, bool repeat):
|
||||
mDistance(distance), mDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), mRepeat(repeat)
|
||||
namespace MWMechanics
|
||||
{
|
||||
for(unsigned short counter = 0; counter < mIdle.size(); counter++)
|
||||
AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<int>& idle, bool repeat):
|
||||
mDistance(distance), mDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), mRepeat(repeat)
|
||||
{
|
||||
if(mIdle[counter] >= 127 || mIdle[counter] < 0)
|
||||
mIdle[counter] = 0;
|
||||
}
|
||||
|
||||
if(mDistance < 0)
|
||||
mDistance = 0;
|
||||
if(mDuration < 0)
|
||||
mDuration = 0;
|
||||
if(mDuration == 0)
|
||||
mTimeOfDay = 0;
|
||||
|
||||
srand(time(NULL));
|
||||
mStartTime = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
mPlayedIdle = 0;
|
||||
mPathgrid = NULL;
|
||||
mIdleChanceMultiplier =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fIdleChanceMultiplier")->getFloat();
|
||||
|
||||
mStoredAvailableNodes = false;
|
||||
mChooseAction = true;
|
||||
mIdleNow = false;
|
||||
mMoveNow = false;
|
||||
mWalking = false;
|
||||
}
|
||||
|
||||
MWMechanics::AiPackage * MWMechanics::AiWander::clone() const
|
||||
{
|
||||
return new AiWander(*this);
|
||||
}
|
||||
|
||||
bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor)
|
||||
{
|
||||
if(mDuration)
|
||||
{
|
||||
// End package if duration is complete or mid-night hits:
|
||||
MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
if(currentTime.getHour() >= mStartTime.getHour() + mDuration)
|
||||
for(unsigned short counter = 0; counter < mIdle.size(); counter++)
|
||||
{
|
||||
if(!mRepeat)
|
||||
{
|
||||
stopWalking(actor);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
mStartTime = currentTime;
|
||||
if(mIdle[counter] >= 127 || mIdle[counter] < 0)
|
||||
mIdle[counter] = 0;
|
||||
}
|
||||
else if(int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay())
|
||||
{
|
||||
if(!mRepeat)
|
||||
{
|
||||
stopWalking(actor);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
mStartTime = currentTime;
|
||||
}
|
||||
}
|
||||
|
||||
ESM::Position pos = actor.getRefData().getPosition();
|
||||
|
||||
if(!mStoredAvailableNodes)
|
||||
{
|
||||
mStoredAvailableNodes = true;
|
||||
mPathgrid =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*actor.getCell()->mCell);
|
||||
|
||||
mCellX = actor.getCell()->mCell->mData.mX;
|
||||
mCellY = actor.getCell()->mCell->mData.mY;
|
||||
|
||||
if(!mPathgrid)
|
||||
mDistance = 0;
|
||||
else if(mPathgrid->mPoints.empty())
|
||||
if(mDistance < 0)
|
||||
mDistance = 0;
|
||||
if(mDuration < 0)
|
||||
mDuration = 0;
|
||||
if(mDuration == 0)
|
||||
mTimeOfDay = 0;
|
||||
|
||||
if(mDistance)
|
||||
{
|
||||
mXCell = 0;
|
||||
mYCell = 0;
|
||||
if(actor.getCell()->mCell->isExterior())
|
||||
{
|
||||
mXCell = mCellX * ESM::Land::REAL_SIZE;
|
||||
mYCell = mCellY * ESM::Land::REAL_SIZE;
|
||||
}
|
||||
|
||||
Ogre::Vector3 npcPos(actor.getRefData().getPosition().pos);
|
||||
npcPos[0] = npcPos[0] - mXCell;
|
||||
npcPos[1] = npcPos[1] - mYCell;
|
||||
|
||||
for(unsigned int counter = 0; counter < mPathgrid->mPoints.size(); counter++)
|
||||
{
|
||||
Ogre::Vector3 nodePos(mPathgrid->mPoints[counter].mX, mPathgrid->mPoints[counter].mY, mPathgrid->mPoints[counter].mZ);
|
||||
if(npcPos.squaredDistance(nodePos) <= mDistance * mDistance)
|
||||
mAllowedNodes.push_back(mPathgrid->mPoints[counter]);
|
||||
}
|
||||
if(!mAllowedNodes.empty())
|
||||
{
|
||||
Ogre::Vector3 firstNodePos(mAllowedNodes[0].mX, mAllowedNodes[0].mY, mAllowedNodes[0].mZ);
|
||||
float closestNode = npcPos.squaredDistance(firstNodePos);
|
||||
unsigned int index = 0;
|
||||
for(unsigned int counterThree = 1; counterThree < mAllowedNodes.size(); counterThree++)
|
||||
{
|
||||
Ogre::Vector3 nodePos(mAllowedNodes[counterThree].mX, mAllowedNodes[counterThree].mY, mAllowedNodes[counterThree].mZ);
|
||||
float tempDist = npcPos.squaredDistance(nodePos);
|
||||
if(tempDist < closestNode)
|
||||
index = counterThree;
|
||||
}
|
||||
mCurrentNode = mAllowedNodes[index];
|
||||
mAllowedNodes.erase(mAllowedNodes.begin() + index);
|
||||
}
|
||||
|
||||
if(mAllowedNodes.empty())
|
||||
mDistance = 0;
|
||||
}
|
||||
}
|
||||
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
bool cellChange = actor.getCell()->mCell->mData.mX != mCellX || actor.getCell()->mCell->mData.mY != mCellY;
|
||||
|
||||
if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX)
|
||||
{
|
||||
int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX);
|
||||
// Check if actor is near the border of an inactive cell. If so, disable AiWander.
|
||||
// FIXME: This *should* pause the AiWander package instead of terminating it.
|
||||
if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE / 2.0 - 200))
|
||||
{
|
||||
stopWalking(actor);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY)
|
||||
{
|
||||
int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY);
|
||||
// Check if actor is near the border of an inactive cell. If so, disable AiWander.
|
||||
// FIXME: This *should* pause the AiWander package instead of terminating it.
|
||||
if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE / 2.0 - 200))
|
||||
{
|
||||
stopWalking(actor);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't try to move if you are in a new cell (ie: positioncell command called) but still play idles.
|
||||
if(mDistance && (cellChange || (mCellX != actor.getCell()->mCell->mData.mX || mCellY != actor.getCell()->mCell->mData.mY)))
|
||||
mDistance = 0;
|
||||
|
||||
if(mChooseAction)
|
||||
{
|
||||
srand(time(NULL));
|
||||
mStartTime = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
mPlayedIdle = 0;
|
||||
unsigned short idleRoll = 0;
|
||||
mPathgrid = NULL;
|
||||
mIdleChanceMultiplier =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fIdleChanceMultiplier")->getFloat();
|
||||
|
||||
for(unsigned int counter = 1; counter < mIdle.size(); counter++)
|
||||
mStoredAvailableNodes = false;
|
||||
mChooseAction = true;
|
||||
mIdleNow = false;
|
||||
mMoveNow = false;
|
||||
mWalking = false;
|
||||
}
|
||||
|
||||
AiPackage * MWMechanics::AiWander::clone() const
|
||||
{
|
||||
return new AiWander(*this);
|
||||
}
|
||||
|
||||
bool AiWander::execute (const MWWorld::Ptr& actor)
|
||||
{
|
||||
if(mDuration)
|
||||
{
|
||||
unsigned short idleChance = mIdleChanceMultiplier * mIdle[counter];
|
||||
unsigned short randSelect = (int)(rand() / ((double)RAND_MAX + 1) * int(100 / mIdleChanceMultiplier));
|
||||
if(randSelect < idleChance && randSelect > idleRoll)
|
||||
// End package if duration is complete or mid-night hits:
|
||||
MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
if(currentTime.getHour() >= mStartTime.getHour() + mDuration)
|
||||
{
|
||||
mPlayedIdle = counter;
|
||||
idleRoll = randSelect;
|
||||
if(!mRepeat)
|
||||
{
|
||||
stopWalking(actor);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
mStartTime = currentTime;
|
||||
}
|
||||
else if(int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay())
|
||||
{
|
||||
if(!mRepeat)
|
||||
{
|
||||
stopWalking(actor);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
mStartTime = currentTime;
|
||||
}
|
||||
}
|
||||
|
||||
if(!mPlayedIdle && mDistance)
|
||||
{
|
||||
mChooseAction = false;
|
||||
mMoveNow = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander:
|
||||
MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
mStartTime = currentTime;
|
||||
playIdle(actor, mPlayedIdle + 1);
|
||||
mChooseAction = false;
|
||||
mIdleNow = true;
|
||||
}
|
||||
}
|
||||
ESM::Position pos = actor.getRefData().getPosition();
|
||||
|
||||
if(mIdleNow)
|
||||
{
|
||||
if(!checkIdle(actor, mPlayedIdle + 1))
|
||||
if(!mStoredAvailableNodes)
|
||||
{
|
||||
mStoredAvailableNodes = true;
|
||||
mPathgrid =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*actor.getCell()->mCell);
|
||||
|
||||
mCellX = actor.getCell()->mCell->mData.mX;
|
||||
mCellY = actor.getCell()->mCell->mData.mY;
|
||||
|
||||
if(!mPathgrid)
|
||||
mDistance = 0;
|
||||
else if(mPathgrid->mPoints.empty())
|
||||
mDistance = 0;
|
||||
|
||||
if(mDistance)
|
||||
{
|
||||
mXCell = 0;
|
||||
mYCell = 0;
|
||||
if(actor.getCell()->mCell->isExterior())
|
||||
{
|
||||
mXCell = mCellX * ESM::Land::REAL_SIZE;
|
||||
mYCell = mCellY * ESM::Land::REAL_SIZE;
|
||||
}
|
||||
|
||||
Ogre::Vector3 npcPos(actor.getRefData().getPosition().pos);
|
||||
npcPos[0] = npcPos[0] - mXCell;
|
||||
npcPos[1] = npcPos[1] - mYCell;
|
||||
|
||||
for(unsigned int counter = 0; counter < mPathgrid->mPoints.size(); counter++)
|
||||
{
|
||||
Ogre::Vector3 nodePos(mPathgrid->mPoints[counter].mX, mPathgrid->mPoints[counter].mY,
|
||||
mPathgrid->mPoints[counter].mZ);
|
||||
if(npcPos.squaredDistance(nodePos) <= mDistance * mDistance)
|
||||
mAllowedNodes.push_back(mPathgrid->mPoints[counter]);
|
||||
}
|
||||
if(!mAllowedNodes.empty())
|
||||
{
|
||||
Ogre::Vector3 firstNodePos(mAllowedNodes[0].mX, mAllowedNodes[0].mY, mAllowedNodes[0].mZ);
|
||||
float closestNode = npcPos.squaredDistance(firstNodePos);
|
||||
unsigned int index = 0;
|
||||
for(unsigned int counterThree = 1; counterThree < mAllowedNodes.size(); counterThree++)
|
||||
{
|
||||
Ogre::Vector3 nodePos(mAllowedNodes[counterThree].mX, mAllowedNodes[counterThree].mY,
|
||||
mAllowedNodes[counterThree].mZ);
|
||||
float tempDist = npcPos.squaredDistance(nodePos);
|
||||
if(tempDist < closestNode)
|
||||
index = counterThree;
|
||||
}
|
||||
mCurrentNode = mAllowedNodes[index];
|
||||
mAllowedNodes.erase(mAllowedNodes.begin() + index);
|
||||
}
|
||||
|
||||
if(mAllowedNodes.empty())
|
||||
mDistance = 0;
|
||||
}
|
||||
}
|
||||
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
bool cellChange = actor.getCell()->mCell->mData.mX != mCellX || actor.getCell()->mCell->mData.mY != mCellY;
|
||||
|
||||
if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX)
|
||||
{
|
||||
int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX);
|
||||
// Check if actor is near the border of an inactive cell. If so, disable AiWander.
|
||||
// FIXME: This *should* pause the AiWander package instead of terminating it.
|
||||
if(sideX * (pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE /
|
||||
2.0 - 200))
|
||||
{
|
||||
stopWalking(actor);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY)
|
||||
{
|
||||
int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY);
|
||||
// Check if actor is near the border of an inactive cell. If so, disable AiWander.
|
||||
// FIXME: This *should* pause the AiWander package instead of terminating it.
|
||||
if(sideY * (pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE /
|
||||
2.0 - 200))
|
||||
{
|
||||
stopWalking(actor);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't try to move if you are in a new cell (ie: positioncell command called) but still play idles.
|
||||
if(mDistance && (cellChange || (mCellX != actor.getCell()->mCell->mData.mX || mCellY != actor.getCell()->mCell->mData.mY)))
|
||||
mDistance = 0;
|
||||
|
||||
if(mChooseAction)
|
||||
{
|
||||
mPlayedIdle = 0;
|
||||
mIdleNow = false;
|
||||
mChooseAction = true;
|
||||
}
|
||||
}
|
||||
unsigned short idleRoll = 0;
|
||||
|
||||
if(mMoveNow && mDistance)
|
||||
{
|
||||
if(!mPathFinder.isPathConstructed())
|
||||
{
|
||||
unsigned int randNode = (int)(rand() / ((double)RAND_MAX + 1) * mAllowedNodes.size());
|
||||
Ogre::Vector3 destNodePos(mAllowedNodes[randNode].mX, mAllowedNodes[randNode].mY, mAllowedNodes[randNode].mZ);
|
||||
|
||||
ESM::Pathgrid::Point dest;
|
||||
dest.mX = destNodePos[0] + mXCell;
|
||||
dest.mY = destNodePos[1] + mYCell;
|
||||
dest.mZ = destNodePos[2];
|
||||
|
||||
ESM::Pathgrid::Point start;
|
||||
start.mX = pos.pos[0];
|
||||
start.mY = pos.pos[1];
|
||||
start.mZ = pos.pos[2];
|
||||
|
||||
mPathFinder.buildPath(start, dest, mPathgrid, mXCell, mYCell, 0);
|
||||
|
||||
if(mPathFinder.isPathConstructed())
|
||||
for(unsigned int counter = 1; counter < mIdle.size(); counter++)
|
||||
{
|
||||
// Remove this node as an option and add back the previously used node (stops NPC from picking the same node):
|
||||
ESM::Pathgrid::Point temp = mAllowedNodes[randNode];
|
||||
mAllowedNodes.erase(mAllowedNodes.begin() + randNode);
|
||||
mAllowedNodes.push_back(mCurrentNode);
|
||||
mCurrentNode = temp;
|
||||
|
||||
mMoveNow = false;
|
||||
mWalking = true;
|
||||
unsigned short idleChance = mIdleChanceMultiplier * mIdle[counter];
|
||||
unsigned short randSelect = (int)(rand() / ((double)RAND_MAX + 1) * int(100 / mIdleChanceMultiplier));
|
||||
if(randSelect < idleChance && randSelect > idleRoll)
|
||||
{
|
||||
mPlayedIdle = counter;
|
||||
idleRoll = randSelect;
|
||||
}
|
||||
}
|
||||
|
||||
if(!mPlayedIdle && mDistance)
|
||||
{
|
||||
mChooseAction = false;
|
||||
mMoveNow = true;
|
||||
}
|
||||
// Choose a different node and delete this one from possible nodes because it is uncreachable:
|
||||
else
|
||||
mAllowedNodes.erase(mAllowedNodes.begin() + randNode);
|
||||
{
|
||||
// Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander:
|
||||
MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
mStartTime = currentTime;
|
||||
playIdle(actor, mPlayedIdle + 1);
|
||||
mChooseAction = false;
|
||||
mIdleNow = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(mWalking)
|
||||
{
|
||||
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1]);
|
||||
MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false);
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
|
||||
|
||||
// Unclog path nodes by allowing the NPC to be a small distance away from the center. This way two NPCs can be
|
||||
// at the same path node at the same time and both will complete instead of endlessly walking into eachother:
|
||||
Ogre::Vector3 destNodePos(mCurrentNode.mX, mCurrentNode.mY, mCurrentNode.mZ);
|
||||
Ogre::Vector3 actorPos(actor.getRefData().getPosition().pos);
|
||||
actorPos[0] = actorPos[0] - mXCell;
|
||||
actorPos[1] = actorPos[1] - mYCell;
|
||||
float distance = actorPos.squaredDistance(destNodePos);
|
||||
|
||||
if(distance < 1200 || mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2]))
|
||||
if(mIdleNow)
|
||||
{
|
||||
stopWalking(actor);
|
||||
mMoveNow = false;
|
||||
mWalking = false;
|
||||
mChooseAction = true;
|
||||
if(!checkIdle(actor, mPlayedIdle + 1))
|
||||
{
|
||||
mPlayedIdle = 0;
|
||||
mIdleNow = false;
|
||||
mChooseAction = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(mMoveNow && mDistance)
|
||||
{
|
||||
if(!mPathFinder.isPathConstructed())
|
||||
{
|
||||
unsigned int randNode = (int)(rand() / ((double)RAND_MAX + 1) * mAllowedNodes.size());
|
||||
Ogre::Vector3 destNodePos(mAllowedNodes[randNode].mX, mAllowedNodes[randNode].mY, mAllowedNodes[randNode].mZ);
|
||||
|
||||
ESM::Pathgrid::Point dest;
|
||||
dest.mX = destNodePos[0] + mXCell;
|
||||
dest.mY = destNodePos[1] + mYCell;
|
||||
dest.mZ = destNodePos[2];
|
||||
|
||||
ESM::Pathgrid::Point start;
|
||||
start.mX = pos.pos[0];
|
||||
start.mY = pos.pos[1];
|
||||
start.mZ = pos.pos[2];
|
||||
|
||||
mPathFinder.buildPath(start, dest, mPathgrid, mXCell, mYCell, false);
|
||||
|
||||
if(mPathFinder.isPathConstructed())
|
||||
{
|
||||
// Remove this node as an option and add back the previously used node (stops NPC from picking the same node):
|
||||
ESM::Pathgrid::Point temp = mAllowedNodes[randNode];
|
||||
mAllowedNodes.erase(mAllowedNodes.begin() + randNode);
|
||||
mAllowedNodes.push_back(mCurrentNode);
|
||||
mCurrentNode = temp;
|
||||
|
||||
mMoveNow = false;
|
||||
mWalking = true;
|
||||
}
|
||||
// Choose a different node and delete this one from possible nodes because it is uncreachable:
|
||||
else
|
||||
mAllowedNodes.erase(mAllowedNodes.begin() + randNode);
|
||||
}
|
||||
}
|
||||
|
||||
if(mWalking)
|
||||
{
|
||||
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
|
||||
MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle,false);
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
|
||||
|
||||
// Unclog path nodes by allowing the NPC to be a small distance away from the center. This way two NPCs can be
|
||||
// at the same path node at the same time and both will complete instead of endlessly walking into eachother:
|
||||
Ogre::Vector3 destNodePos(mCurrentNode.mX, mCurrentNode.mY, mCurrentNode.mZ);
|
||||
Ogre::Vector3 actorPos(actor.getRefData().getPosition().pos);
|
||||
actorPos[0] = actorPos[0] - mXCell;
|
||||
actorPos[1] = actorPos[1] - mYCell;
|
||||
float distance = actorPos.squaredDistance(destNodePos);
|
||||
|
||||
if(distance < 1200 || mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2]))
|
||||
{
|
||||
stopWalking(actor);
|
||||
mMoveNow = false;
|
||||
mWalking = false;
|
||||
mChooseAction = true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int MWMechanics::AiWander::getTypeId() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MWMechanics::AiWander::stopWalking(const MWWorld::Ptr& actor)
|
||||
{
|
||||
mPathFinder.clearPath();
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
}
|
||||
|
||||
void MWMechanics::AiWander::playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect)
|
||||
{
|
||||
if(idleSelect == 2)
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle2", 0, 1);
|
||||
else if(idleSelect == 3)
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle3", 0, 1);
|
||||
else if(idleSelect == 4)
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle4", 0, 1);
|
||||
else if(idleSelect == 5)
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle5", 0, 1);
|
||||
else if(idleSelect == 6)
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle6", 0, 1);
|
||||
else if(idleSelect == 7)
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle7", 0, 1);
|
||||
else if(idleSelect == 8)
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle8", 0, 1);
|
||||
else if(idleSelect == 9)
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle9", 0, 1);
|
||||
}
|
||||
|
||||
bool MWMechanics::AiWander::checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect)
|
||||
{
|
||||
if(idleSelect == 2)
|
||||
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle2");
|
||||
else if(idleSelect == 3)
|
||||
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle3");
|
||||
else if(idleSelect == 4)
|
||||
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle4");
|
||||
else if(idleSelect == 5)
|
||||
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle5");
|
||||
else if(idleSelect == 6)
|
||||
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle6");
|
||||
else if(idleSelect == 7)
|
||||
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle7");
|
||||
else if(idleSelect == 8)
|
||||
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle8");
|
||||
else if(idleSelect == 9)
|
||||
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle9");
|
||||
else
|
||||
return false;
|
||||
int AiWander::getTypeId() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AiWander::stopWalking(const MWWorld::Ptr& actor)
|
||||
{
|
||||
mPathFinder.clearPath();
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
}
|
||||
|
||||
void AiWander::playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect)
|
||||
{
|
||||
if(idleSelect == 2)
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle2", 0, 1);
|
||||
else if(idleSelect == 3)
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle3", 0, 1);
|
||||
else if(idleSelect == 4)
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle4", 0, 1);
|
||||
else if(idleSelect == 5)
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle5", 0, 1);
|
||||
else if(idleSelect == 6)
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle6", 0, 1);
|
||||
else if(idleSelect == 7)
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle7", 0, 1);
|
||||
else if(idleSelect == 8)
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle8", 0, 1);
|
||||
else if(idleSelect == 9)
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle9", 0, 1);
|
||||
}
|
||||
|
||||
bool AiWander::checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect)
|
||||
{
|
||||
if(idleSelect == 2)
|
||||
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle2");
|
||||
else if(idleSelect == 3)
|
||||
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle3");
|
||||
else if(idleSelect == 4)
|
||||
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle4");
|
||||
else if(idleSelect == 5)
|
||||
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle5");
|
||||
else if(idleSelect == 6)
|
||||
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle6");
|
||||
else if(idleSelect == 7)
|
||||
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle7");
|
||||
else if(idleSelect == 8)
|
||||
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle8");
|
||||
else if(idleSelect == 9)
|
||||
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle9");
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -205,7 +205,7 @@ namespace MWMechanics
|
|||
return true;
|
||||
|
||||
ESM::Pathgrid::Point nextPoint = *mPath.begin();
|
||||
if(distanceZCorrected(nextPoint, x, y, z) < 20)
|
||||
if(distanceZCorrected(nextPoint, x, y, z) < 40)
|
||||
{
|
||||
mPath.pop_front();
|
||||
if(mPath.empty())
|
||||
|
|
Loading…
Reference in a new issue