Ai pursue now controls guards pursuit of crimes

Should extend AiActivate in the future
This commit is contained in:
Jeffrey Haines 2014-04-02 00:18:22 -04:00
parent 50dac98a2b
commit 7c0b51fb7e
11 changed files with 171 additions and 19 deletions

View file

@ -67,7 +67,7 @@ add_openmw_dir (mwclass
add_openmw_dir (mwmechanics
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow
drawstate spells activespells npcstats aipackage aisequence aipersue alchemy aiwander aitravel aifollow
aiescort aiactivate aicombat repair enchanting pathfinding security spellsuccess spellcasting
disease pickpocket levelledlist combat steering
)

View file

@ -9,11 +9,9 @@
#include "steering.hpp"
#include "movement.hpp"
#include "creaturestats.hpp"
MWMechanics::AiActivate::AiActivate(const std::string &objectId, int arg)
: mObjectId(objectId),
mArg(arg)
MWMechanics::AiActivate::AiActivate(const std::string &objectId)
: mObjectId(objectId)
{
}
MWMechanics::AiActivate *MWMechanics::AiActivate::clone() const
@ -27,9 +25,6 @@ bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor,float duration)
Movement &movement = actor.getClass().getMovementSettings(actor);
const ESM::Cell *cell = actor.getCell()->getCell();
if (mArg == 1) // run to actor
actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
MWWorld::Ptr player = world->getPlayerPtr();
if(cell->mData.mX != player.getCell()->getCell()->mData.mX)
{

View file

@ -12,7 +12,7 @@ namespace MWMechanics
class AiActivate : public AiPackage
{
public:
AiActivate(const std::string &objectId, int arg);
AiActivate(const std::string &objectId);
virtual AiActivate *clone() const;
virtual bool execute (const MWWorld::Ptr& actor,float duration);
///< \return Package completed?
@ -20,7 +20,6 @@ namespace MWMechanics
private:
std::string mObjectId;
int mArg;
PathFinder mPathFinder;
int mCellX;

View file

@ -19,7 +19,8 @@ namespace MWMechanics
TypeIdEscort = 2,
TypeIdFollow = 3,
TypeIdActivate = 4,
TypeIdCombat = 5
TypeIdCombat = 5,
TypeIdPersue = 6
};
virtual ~AiPackage();

View file

@ -0,0 +1,108 @@
#include "aipersue.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/action.hpp"
#include "../mwworld/cellstore.hpp"
#include "steering.hpp"
#include "movement.hpp"
#include "creaturestats.hpp"
MWMechanics::AiPersue::AiPersue(const std::string &objectId)
: mObjectId(objectId)
{
}
MWMechanics::AiPersue *MWMechanics::AiPersue::clone() const
{
return new AiPersue(*this);
}
bool MWMechanics::AiPersue::execute (const MWWorld::Ptr& actor,float duration)
{
//TODO: Guards should not dialague with player after crime reset
MWBase::World *world = MWBase::Environment::get().getWorld();
ESM::Position pos = actor.getRefData().getPosition();
Movement &movement = actor.getClass().getMovementSettings(actor);
const ESM::Cell *cell = actor.getCell()->getCell();
actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
MWWorld::Ptr player = world->getPlayerPtr();
if(cell->mData.mX != player.getCell()->getCell()->mData.mX)
{
int sideX = PathFinder::sgn(cell->mData.mX - player.getCell()->getCell()->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))
{
movement.mPosition[1] = 0;
return false;
}
}
if(cell->mData.mY != player.getCell()->getCell()->mData.mY)
{
int sideY = PathFinder::sgn(cell->mData.mY - player.getCell()->getCell()->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))
{
movement.mPosition[1] = 0;
return false;
}
}
MWWorld::Ptr target = world->getPtr(mObjectId,false);
ESM::Position targetPos = target.getRefData().getPosition();
bool cellChange = cell->mData.mX != mCellX || cell->mData.mY != mCellY;
if(!mPathFinder.isPathConstructed() || cellChange)
{
mCellX = cell->mData.mX;
mCellY = cell->mData.mY;
ESM::Pathgrid::Point dest;
dest.mX = targetPos.pos[0];
dest.mY = targetPos.pos[1];
dest.mZ = targetPos.pos[2];
ESM::Pathgrid::Point start;
start.mX = pos.pos[0];
start.mY = pos.pos[1];
start.mZ = pos.pos[2];
mPathFinder.buildPath(start, dest, actor.getCell(), true);
}
if((pos.pos[0]-targetPos.pos[0])*(pos.pos[0]-targetPos.pos[0])+
(pos.pos[1]-targetPos.pos[1])*(pos.pos[1]-targetPos.pos[1])+
(pos.pos[2]-targetPos.pos[2])*(pos.pos[2]-targetPos.pos[2]) < 200*200)
{
movement.mPosition[1] = 0;
MWWorld::Ptr target = world->getPtr(mObjectId,false);
MWWorld::Class::get(target).activate(target,actor).get()->execute(actor);
return true;
}
if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2]))
{
movement.mPosition[1] = 0;
MWWorld::Ptr target = world->getPtr(mObjectId,false);
MWWorld::Class::get(target).activate(target,actor).get()->execute(actor);
return true;
}
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
zTurn(actor, Ogre::Degree(zAngle));
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
movement.mPosition[1] = 1;
return false;
}
int MWMechanics::AiPersue::getTypeId() const
{
return TypeIdPersue;
}

View file

@ -0,0 +1,29 @@
#ifndef GAME_MWMECHANICS_AIPERSUE_H
#define GAME_MWMECHANICS_AIPERSUE_H
#include "aipackage.hpp"
#include <string>
#include "pathfinding.hpp"
namespace MWMechanics
{
class AiPersue : public AiPackage
{
public:
AiPersue(const std::string &objectId);
virtual AiPersue *clone() const;
virtual bool execute (const MWWorld::Ptr& actor,float duration);
///< \return Package completed?
virtual int getTypeId() const;
private:
std::string mObjectId;
PathFinder mPathFinder;
int mCellX;
int mCellY;
};
}
#endif

View file

@ -73,6 +73,15 @@ void MWMechanics::AiSequence::stopCombat()
}
}
void MWMechanics::AiSequence::stopPersue()
{
while (getTypeId() == AiPackage::TypeIdPersue)
{
delete *mPackages.begin();
mPackages.erase (mPackages.begin());
}
}
bool MWMechanics::AiSequence::isPackageDone() const
{
return mDone;
@ -161,7 +170,7 @@ void MWMechanics::AiSequence::fill(const ESM::AIPackageList &list)
else if (it->mType == ESM::AI_Activate)
{
ESM::AIActivate data = it->mActivate;
package = new MWMechanics::AiActivate(data.mName.toString(), 0);
package = new MWMechanics::AiActivate(data.mName.toString());
}
else //if (it->mType == ESM::AI_Follow)
{

View file

@ -50,6 +50,9 @@ namespace MWMechanics
void stopCombat();
///< Removes all combat packages until first non-combat or stack empty.
void stopPersue();
///< Removes all persue packages until first non-persue or stack empty.
bool isPackageDone() const;
///< Has a package been completed during the last update?

View file

@ -13,6 +13,7 @@
#include "../mwworld/player.hpp"
#include "aicombat.hpp"
#include "aipersue.hpp"
#include "aiactivate.hpp"
#include <OgreSceneNode.h>
@ -838,8 +839,6 @@ namespace MWMechanics
std::vector<MWWorld::Ptr> neighbors;
mActors.getObjectsInRange(Ogre::Vector3(ptr.getRefData().getPosition().pos),
esmStore.get<ESM::GameSetting>().find("fAlarmRadius")->getInt(), neighbors);
// Did anyone see the crime?
for (std::vector<MWWorld::Ptr>::iterator it = neighbors.begin(); it != neighbors.end(); ++it)
{
if (*it == ptr) // Not the player
@ -880,12 +879,12 @@ namespace MWMechanics
{
creatureStats1.getAiSequence().stack(AiCombat(ptr));
creatureStats1.setHostile(true);
creatureStats1.getAiSequence().execute(*it,0);
creatureStats1.getAiSequence().execute(*it1,0);
}
else // will the guard persue the player?
{
creatureStats1.getAiSequence().stack(AiActivate(ptr.getClass().getId(ptr), 1));
creatureStats1.getAiSequence().execute(*it,0);
creatureStats1.getAiSequence().stack(AiPersue(ptr.getClass().getId(ptr)));
creatureStats1.getAiSequence().execute(*it1,0);
}
}
// will the witness fight the player?

View file

@ -47,7 +47,7 @@ namespace MWScript
// discard additional arguments (reset), because we have no idea what they mean.
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
MWMechanics::AiActivate activatePackage(objectID, 0);
MWMechanics::AiActivate activatePackage(objectID);
MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSequence().stack(activatePackage);
std::cout << "AiActivate" << std::endl;
}

View file

@ -29,6 +29,7 @@
#include "../mwmechanics/spellcasting.hpp"
#include "../mwmechanics/levelledlist.hpp"
#include "../mwmechanics/combat.hpp"
#include "../mwmechanics/actors.hpp"
#include "../mwrender/sky.hpp"
#include "../mwrender/animation.hpp"
@ -2762,6 +2763,9 @@ namespace MWWorld
message += "\n" + skillMsg;
}
// sleep the player, this doesn't work
//player.getClass().calculateRestoration(player, days, true);
resetCrimes(player);
std::vector<std::string> buttons;
@ -2776,10 +2780,15 @@ namespace MWWorld
std::vector<MWWorld::Ptr> neighbors = ptr.getClass().getCreatureStats(ptr).getPlayerWitnesses();
for (std::vector<MWWorld::Ptr>::iterator it = neighbors.begin(); it != neighbors.end(); ++it)
{
// This to reset for each witness:
// Reset states
// TODO: More research is needed to complete this list
it->getClass().getCreatureStats(*it).setHostile(false);
it->getClass().getCreatureStats(*it).setAlarmed(false);
// Stop guard persue
if(it->getClass().isClass(*it, "Guard"))
it->getClass().getCreatureStats(*it).getAiSequence().stopPersue();
}
ptr.getClass().getCreatureStats(ptr).resetPlayerWitnesses();
}