mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-26 09:35:28 +00:00
Feature #1289: NPCs return to default position
Make stationary NPCs return to their previous position once combat/crime AI finishes.
This commit is contained in:
parent
3780503275
commit
9b36a13821
@ -206,7 +206,7 @@ namespace MWMechanics
|
|||||||
|
|
||||||
if (LOS)
|
if (LOS)
|
||||||
{
|
{
|
||||||
creatureStats.getAiSequence().stack(AiCombat(MWBase::Environment::get().getWorld()->getPlayerPtr()));
|
creatureStats.getAiSequence().stack(AiCombat(MWBase::Environment::get().getWorld()->getPlayerPtr()), ptr);
|
||||||
creatureStats.setHostile(true);
|
creatureStats.setHostile(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -537,7 +537,7 @@ namespace MWMechanics
|
|||||||
|
|
||||||
// TODO: Add AI to follow player and fight for him
|
// TODO: Add AI to follow player and fight for him
|
||||||
AiFollow package(ptr.getRefData().getHandle());
|
AiFollow package(ptr.getRefData().getHandle());
|
||||||
MWWorld::Class::get (ref.getPtr()).getCreatureStats (ref.getPtr()).getAiSequence().stack(package);
|
MWWorld::Class::get (ref.getPtr()).getCreatureStats (ref.getPtr()).getAiSequence().stack(package, ptr);
|
||||||
// TODO: VFX_SummonStart, VFX_SummonEnd
|
// TODO: VFX_SummonStart, VFX_SummonEnd
|
||||||
creatureStats.mSummonedCreatures.insert(std::make_pair(it->first,
|
creatureStats.mSummonedCreatures.insert(std::make_pair(it->first,
|
||||||
MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos).getRefData().getHandle()));
|
MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos).getRefData().getHandle()));
|
||||||
@ -732,7 +732,7 @@ namespace MWMechanics
|
|||||||
&& MWBase::Environment::get().getWorld()->getLOS(ptr, player)
|
&& MWBase::Environment::get().getWorld()->getLOS(ptr, player)
|
||||||
&& MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, ptr))
|
&& MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, ptr))
|
||||||
{
|
{
|
||||||
creatureStats.getAiSequence().stack(AiCombat(player));
|
creatureStats.getAiSequence().stack(AiCombat(player), ptr);
|
||||||
creatureStats.setHostile(true);
|
creatureStats.setHostile(true);
|
||||||
npcStats.setCrimeId( MWBase::Environment::get().getWorld()->getPlayer().getCrimeId() );
|
npcStats.setCrimeId( MWBase::Environment::get().getWorld()->getPlayer().getCrimeId() );
|
||||||
}
|
}
|
||||||
@ -761,9 +761,9 @@ namespace MWMechanics
|
|||||||
else if (!creatureStats.isHostile())
|
else if (!creatureStats.isHostile())
|
||||||
{
|
{
|
||||||
if (ptr.getClass().isClass(ptr, "Guard"))
|
if (ptr.getClass().isClass(ptr, "Guard"))
|
||||||
creatureStats.getAiSequence().stack(AiPersue(player.getClass().getId(player)));
|
creatureStats.getAiSequence().stack(AiPersue(player.getClass().getId(player)), ptr);
|
||||||
else
|
else
|
||||||
creatureStats.getAiSequence().stack(AiCombat(player));
|
creatureStats.getAiSequence().stack(AiCombat(player), ptr);
|
||||||
creatureStats.setHostile(true);
|
creatureStats.setHostile(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -771,7 +771,7 @@ namespace MWMechanics
|
|||||||
// if I didn't report a crime was I attacked?
|
// if I didn't report a crime was I attacked?
|
||||||
else if (creatureStats.getAttacked() && !creatureStats.isHostile())
|
else if (creatureStats.getAttacked() && !creatureStats.isHostile())
|
||||||
{
|
{
|
||||||
creatureStats.getAiSequence().stack(AiCombat(player));
|
creatureStats.getAiSequence().stack(AiCombat(player), ptr);
|
||||||
creatureStats.setHostile(true);
|
creatureStats.setHostile(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,8 +116,18 @@ void MWMechanics::AiSequence::clear()
|
|||||||
mPackages.clear();
|
mPackages.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MWMechanics::AiSequence::stack (const AiPackage& package)
|
void MWMechanics::AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor)
|
||||||
{
|
{
|
||||||
|
if (package.getTypeId() == AiPackage::TypeIdCombat || package.getTypeId() == AiPackage::TypeIdPersue)
|
||||||
|
{
|
||||||
|
// Notify AiWander of our current position so we can return to it after combat finished
|
||||||
|
for (std::list<AiPackage *>::const_iterator iter (mPackages.begin()); iter!=mPackages.end(); ++iter)
|
||||||
|
{
|
||||||
|
if ((*iter)->getTypeId() == AiPackage::TypeIdWander)
|
||||||
|
static_cast<AiWander*>(*iter)->setReturnPosition(Ogre::Vector3(actor.getRefData().getPosition().pos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for(std::list<AiPackage *>::iterator it = mPackages.begin(); it != mPackages.end(); it++)
|
for(std::list<AiPackage *>::iterator it = mPackages.begin(); it != mPackages.end(); it++)
|
||||||
{
|
{
|
||||||
if(mPackages.front()->getPriority() <= package.getPriority())
|
if(mPackages.front()->getPriority() <= package.getPriority())
|
||||||
|
@ -62,7 +62,7 @@ namespace MWMechanics
|
|||||||
void clear();
|
void clear();
|
||||||
///< Remove all packages.
|
///< Remove all packages.
|
||||||
|
|
||||||
void stack (const AiPackage& package);
|
void stack (const AiPackage& package, const MWWorld::Ptr& actor);
|
||||||
///< Add \a package to the front of the sequence (suspends current package)
|
///< Add \a package to the front of the sequence (suspends current package)
|
||||||
|
|
||||||
void queue (const AiPackage& package);
|
void queue (const AiPackage& package);
|
||||||
|
@ -37,6 +37,8 @@ namespace MWMechanics
|
|||||||
, mRotate(false)
|
, mRotate(false)
|
||||||
, mTargetAngle(0)
|
, mTargetAngle(0)
|
||||||
, mSaidGreeting(false)
|
, mSaidGreeting(false)
|
||||||
|
, mHasReturnPosition(false)
|
||||||
|
, mReturnPosition(0,0,0)
|
||||||
{
|
{
|
||||||
for(unsigned short counter = 0; counter < mIdle.size(); counter++)
|
for(unsigned short counter = 0; counter < mIdle.size(); counter++)
|
||||||
{
|
{
|
||||||
@ -330,6 +332,37 @@ namespace MWMechanics
|
|||||||
if(mDistance && cellChange)
|
if(mDistance && cellChange)
|
||||||
mDistance = 0;
|
mDistance = 0;
|
||||||
|
|
||||||
|
// For stationary NPCs, move back to the starting location if another AiPackage moved us elsewhere
|
||||||
|
if (cellChange)
|
||||||
|
mHasReturnPosition = false;
|
||||||
|
if (mDistance == 0 && mHasReturnPosition && Ogre::Vector3(pos.pos).squaredDistance(mReturnPosition) > 20*20)
|
||||||
|
{
|
||||||
|
mChooseAction = false;
|
||||||
|
mIdleNow = false;
|
||||||
|
|
||||||
|
Ogre::Vector3 destNodePos = mReturnPosition;
|
||||||
|
|
||||||
|
ESM::Pathgrid::Point dest;
|
||||||
|
dest.mX = destNodePos[0];
|
||||||
|
dest.mY = destNodePos[1];
|
||||||
|
dest.mZ = destNodePos[2];
|
||||||
|
|
||||||
|
// actor position is already in world co-ordinates
|
||||||
|
ESM::Pathgrid::Point start;
|
||||||
|
start.mX = pos.pos[0];
|
||||||
|
start.mY = pos.pos[1];
|
||||||
|
start.mZ = pos.pos[2];
|
||||||
|
|
||||||
|
// don't take shortcuts for wandering
|
||||||
|
mPathFinder.buildPath(start, dest, actor.getCell(), false);
|
||||||
|
|
||||||
|
if(mPathFinder.isPathConstructed())
|
||||||
|
{
|
||||||
|
mMoveNow = false;
|
||||||
|
mWalking = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(mChooseAction)
|
if(mChooseAction)
|
||||||
{
|
{
|
||||||
mPlayedIdle = 0;
|
mPlayedIdle = 0;
|
||||||
@ -375,7 +408,7 @@ namespace MWMechanics
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Allow interrupting a walking actor to trigger a greeting
|
// Allow interrupting a walking actor to trigger a greeting
|
||||||
if(mIdleNow || (mWalking && !mObstacleCheck.isNormalState()))
|
if(mIdleNow || (mWalking && !mObstacleCheck.isNormalState() && mDistance))
|
||||||
{
|
{
|
||||||
// Play a random voice greeting if the player gets too close
|
// Play a random voice greeting if the player gets too close
|
||||||
int hello = cStats.getAiSetting(CreatureStats::AI_Hello).getModified();
|
int hello = cStats.getAiSetting(CreatureStats::AI_Hello).getModified();
|
||||||
@ -586,5 +619,10 @@ namespace MWMechanics
|
|||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AiWander::setReturnPosition(const Ogre::Vector3& position)
|
||||||
|
{
|
||||||
|
mHasReturnPosition = true; mReturnPosition = position;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,8 +2,11 @@
|
|||||||
#define GAME_MWMECHANICS_AIWANDER_H
|
#define GAME_MWMECHANICS_AIWANDER_H
|
||||||
|
|
||||||
#include "aipackage.hpp"
|
#include "aipackage.hpp"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <OgreVector3.h>
|
||||||
|
|
||||||
#include "pathfinding.hpp"
|
#include "pathfinding.hpp"
|
||||||
#include "obstacle.hpp"
|
#include "obstacle.hpp"
|
||||||
|
|
||||||
@ -22,6 +25,10 @@ namespace MWMechanics
|
|||||||
virtual int getTypeId() const;
|
virtual int getTypeId() const;
|
||||||
///< 0: Wander
|
///< 0: Wander
|
||||||
|
|
||||||
|
void setReturnPosition (const Ogre::Vector3& position);
|
||||||
|
///< Set the position to return to for a stationary (non-wandering) actor, in case
|
||||||
|
/// another AI package moved the actor elsewhere
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void stopWalking(const MWWorld::Ptr& actor);
|
void stopWalking(const MWWorld::Ptr& actor);
|
||||||
void playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect);
|
void playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect);
|
||||||
@ -38,6 +45,10 @@ namespace MWMechanics
|
|||||||
float mGreetDistanceReset;
|
float mGreetDistanceReset;
|
||||||
float mChance;
|
float mChance;
|
||||||
|
|
||||||
|
bool mHasReturnPosition; // NOTE: Could be removed if mReturnPosition was initialized to actor position,
|
||||||
|
// if we had the actor in the AiWander constructor...
|
||||||
|
Ogre::Vector3 mReturnPosition;
|
||||||
|
|
||||||
// Cached current cell location
|
// Cached current cell location
|
||||||
int mCellX;
|
int mCellX;
|
||||||
int mCellY;
|
int mCellY;
|
||||||
|
@ -48,7 +48,7 @@ namespace MWScript
|
|||||||
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
|
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
|
||||||
|
|
||||||
MWMechanics::AiActivate activatePackage(objectID);
|
MWMechanics::AiActivate activatePackage(objectID);
|
||||||
MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSequence().stack(activatePackage);
|
MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSequence().stack(activatePackage, ptr);
|
||||||
std::cout << "AiActivate" << std::endl;
|
std::cout << "AiActivate" << std::endl;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -75,7 +75,7 @@ namespace MWScript
|
|||||||
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
|
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
|
||||||
|
|
||||||
MWMechanics::AiTravel travelPackage(x, y, z);
|
MWMechanics::AiTravel travelPackage(x, y, z);
|
||||||
MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSequence().stack(travelPackage);
|
MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSequence().stack(travelPackage, ptr);
|
||||||
|
|
||||||
std::cout << "AiTravel: " << x << ", " << y << ", " << z << std::endl;
|
std::cout << "AiTravel: " << x << ", " << y << ", " << z << std::endl;
|
||||||
}
|
}
|
||||||
@ -109,7 +109,7 @@ namespace MWScript
|
|||||||
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
|
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
|
||||||
|
|
||||||
MWMechanics::AiEscort escortPackage(actorID, duration, x, y, z);
|
MWMechanics::AiEscort escortPackage(actorID, duration, x, y, z);
|
||||||
MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSequence().stack(escortPackage);
|
MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSequence().stack(escortPackage, ptr);
|
||||||
|
|
||||||
std::cout << "AiEscort: " << x << ", " << y << ", " << z << ", " << duration
|
std::cout << "AiEscort: " << x << ", " << y << ", " << z << ", " << duration
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
@ -147,7 +147,7 @@ namespace MWScript
|
|||||||
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
|
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
|
||||||
|
|
||||||
MWMechanics::AiEscort escortPackage(actorID, cellID, duration, x, y, z);
|
MWMechanics::AiEscort escortPackage(actorID, cellID, duration, x, y, z);
|
||||||
MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSequence().stack(escortPackage);
|
MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSequence().stack(escortPackage, ptr);
|
||||||
|
|
||||||
std::cout << "AiEscort: " << x << ", " << y << ", " << z << ", " << duration
|
std::cout << "AiEscort: " << x << ", " << y << ", " << z << ", " << duration
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
@ -211,7 +211,7 @@ namespace MWScript
|
|||||||
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
|
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
|
||||||
|
|
||||||
MWMechanics::AiWander wanderPackage(range, duration, time, idleList, repeat);
|
MWMechanics::AiWander wanderPackage(range, duration, time, idleList, repeat);
|
||||||
MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSequence().stack(wanderPackage);
|
MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSequence().stack(wanderPackage, ptr);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -299,7 +299,7 @@ namespace MWScript
|
|||||||
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
|
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
|
||||||
|
|
||||||
MWMechanics::AiFollow followPackage(actorID, duration, x, y ,z);
|
MWMechanics::AiFollow followPackage(actorID, duration, x, y ,z);
|
||||||
MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSequence().stack(followPackage);
|
MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSequence().stack(followPackage, ptr);
|
||||||
|
|
||||||
std::cout << "AiFollow: " << actorID << ", " << x << ", " << y << ", " << z << ", " << duration
|
std::cout << "AiFollow: " << actorID << ", " << x << ", " << y << ", " << z << ", " << duration
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
@ -337,7 +337,7 @@ namespace MWScript
|
|||||||
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
|
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
|
||||||
|
|
||||||
MWMechanics::AiFollow followPackage(actorID, cellID, duration, x, y ,z);
|
MWMechanics::AiFollow followPackage(actorID, cellID, duration, x, y ,z);
|
||||||
MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSequence().stack(followPackage);
|
MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSequence().stack(followPackage, ptr);
|
||||||
std::cout << "AiFollow: " << actorID << ", " << x << ", " << y << ", " << z << ", " << duration
|
std::cout << "AiFollow: " << actorID << ", " << x << ", " << y << ", " << z << ", " << duration
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
@ -440,7 +440,7 @@ namespace MWScript
|
|||||||
|
|
||||||
creatureStats.setHostile(true);
|
creatureStats.setHostile(true);
|
||||||
creatureStats.getAiSequence().stack(
|
creatureStats.getAiSequence().stack(
|
||||||
MWMechanics::AiCombat(MWBase::Environment::get().getWorld()->getPtr(targetID, true) ));
|
MWMechanics::AiCombat(MWBase::Environment::get().getWorld()->getPtr(targetID, true) ), actor);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user