Avoid killing AIWander and AITravel when far away

This fixes the problem of certain NPCs not wandering because they
happened to spawn near a cell border away from the player, which
immediately "completed" the wander package.

AIWander can't cause NPCs to cross cell boundaries, so there's no risk
of them walking into an unloaded to. AITravel will now simply stop
moving, and resume later when the cell is loaded.
pull/51/head
Chris Robinson 12 years ago
parent 2391c591b3
commit f9dbce685a

@ -33,46 +33,48 @@ namespace MWMechanics
bool AiTravel::execute (const MWWorld::Ptr& actor)
{
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
MWBase::World *world = MWBase::Environment::get().getWorld();
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);
Movement &movement = actor.getClass().getMovementSettings(actor);
const ESM::Cell *cell = actor.getCell()->mCell;
if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX)
MWWorld::Ptr player = world->getPlayer().getPlayer();
if(cell->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))
int sideX = sgn(cell->mData.mX - player.getCell()->mCell->mData.mX);
//check if actor is near the border of an inactive cell. If so, stop walking.
if(sideX * (pos.pos[0] - cell->mData.mX*ESM::Land::REAL_SIZE) >
sideX * (ESM::Land::REAL_SIZE/2.0f - 200.0f))
{
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
return true;
movement.mPosition[1] = 0;
return false;
}
}
if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY)
if(cell->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))
int sideY = sgn(cell->mData.mY - player.getCell()->mCell->mData.mY);
//check if actor is near the border of an inactive cell. If so, stop walking.
if(sideY * (pos.pos[1] - cell->mData.mY*ESM::Land::REAL_SIZE) >
sideY * (ESM::Land::REAL_SIZE/2.0f - 200.0f))
{
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
return true;
movement.mPosition[1] = 0;
return false;
}
}
const ESM::Pathgrid *pathgrid = world->getStore().get<ESM::Pathgrid>().search(*cell);
bool cellChange = cell->mData.mX != cellX || cell->mData.mY != cellY;
if(!mPathFinder.isPathConstructed() || cellChange)
{
cellX = actor.getCell()->mCell->mData.mX;
cellY = actor.getCell()->mCell->mData.mY;
cellX = cell->mData.mX;
cellY = cell->mData.mY;
float xCell = 0;
float yCell = 0;
if (actor.getCell()->mCell->isExterior())
if(cell->isExterior())
{
xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE;
yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE;
xCell = cell->mData.mX * ESM::Land::REAL_SIZE;
yCell = cell->mData.mY * ESM::Land::REAL_SIZE;
}
ESM::Pathgrid::Point dest;
@ -90,13 +92,13 @@ namespace MWMechanics
if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2]))
{
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
movement.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;
world->rotateObject(actor, 0, 0, zAngle, false);
movement.mPosition[1] = 1;
return false;
}

@ -65,10 +65,11 @@ namespace MWMechanics
bool AiWander::execute (const MWWorld::Ptr& actor)
{
MWBase::World *world = MWBase::Environment::get().getWorld();
if(mDuration)
{
// End package if duration is complete or mid-night hits:
MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp();
MWWorld::TimeStamp currentTime = world->getTimeStamp();
if(currentTime.getHour() >= mStartTime.getHour() + mDuration)
{
if(!mRepeat)
@ -96,8 +97,7 @@ namespace MWMechanics
if(!mStoredAvailableNodes)
{
mStoredAvailableNodes = true;
mPathgrid =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*actor.getCell()->mCell);
mPathgrid = world->getStore().get<ESM::Pathgrid>().search(*actor.getCell()->mCell);
mCellX = actor.getCell()->mCell->mData.mX;
mCellY = actor.getCell()->mCell->mData.mY;
@ -150,37 +150,8 @@ namespace MWMechanics
}
}
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)))
if(mDistance && (mCellX != actor.getCell()->mCell->mData.mX || mCellY != actor.getCell()->mCell->mData.mY))
mDistance = 0;
if(mChooseAction)
@ -207,7 +178,7 @@ namespace MWMechanics
else
{
// Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander:
MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp();
MWWorld::TimeStamp currentTime = world->getTimeStamp();
mStartTime = currentTime;
playIdle(actor, mPlayedIdle);
mChooseAction = false;
@ -264,7 +235,7 @@ namespace MWMechanics
if(mWalking)
{
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle,false);
world->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
@ -275,7 +246,7 @@ namespace MWMechanics
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(distance < 32*32 || mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2]))
{
stopWalking(actor);
mMoveNow = false;

Loading…
Cancel
Save