diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 20011b0d9..f7977dc59 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -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 ) diff --git a/apps/openmw/mwmechanics/aiactivate.cpp b/apps/openmw/mwmechanics/aiactivate.cpp index 472bca88f..8610cf4b2 100644 --- a/apps/openmw/mwmechanics/aiactivate.cpp +++ b/apps/openmw/mwmechanics/aiactivate.cpp @@ -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) { diff --git a/apps/openmw/mwmechanics/aiactivate.hpp b/apps/openmw/mwmechanics/aiactivate.hpp index aa8725db2..fd54869f6 100644 --- a/apps/openmw/mwmechanics/aiactivate.hpp +++ b/apps/openmw/mwmechanics/aiactivate.hpp @@ -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; diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 74c77bf97..8e015da15 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -19,7 +19,8 @@ namespace MWMechanics TypeIdEscort = 2, TypeIdFollow = 3, TypeIdActivate = 4, - TypeIdCombat = 5 + TypeIdCombat = 5, + TypeIdPersue = 6 }; virtual ~AiPackage(); diff --git a/apps/openmw/mwmechanics/aipersue.cpp b/apps/openmw/mwmechanics/aipersue.cpp new file mode 100644 index 000000000..21239860f --- /dev/null +++ b/apps/openmw/mwmechanics/aipersue.cpp @@ -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; +} diff --git a/apps/openmw/mwmechanics/aipersue.hpp b/apps/openmw/mwmechanics/aipersue.hpp new file mode 100644 index 000000000..3fd708ab3 --- /dev/null +++ b/apps/openmw/mwmechanics/aipersue.hpp @@ -0,0 +1,29 @@ +#ifndef GAME_MWMECHANICS_AIPERSUE_H +#define GAME_MWMECHANICS_AIPERSUE_H + +#include "aipackage.hpp" +#include + +#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 diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index ba69b8098..c67367a6c 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -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) { diff --git a/apps/openmw/mwmechanics/aisequence.hpp b/apps/openmw/mwmechanics/aisequence.hpp index 62f48f981..07b7c898c 100644 --- a/apps/openmw/mwmechanics/aisequence.hpp +++ b/apps/openmw/mwmechanics/aisequence.hpp @@ -49,6 +49,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? diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 4d1fca72d..6b9d6902e 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -13,6 +13,7 @@ #include "../mwworld/player.hpp" #include "aicombat.hpp" +#include "aipersue.hpp" #include "aiactivate.hpp" #include @@ -838,8 +839,6 @@ namespace MWMechanics std::vector neighbors; mActors.getObjectsInRange(Ogre::Vector3(ptr.getRefData().getPosition().pos), esmStore.get().find("fAlarmRadius")->getInt(), neighbors); - - // Did anyone see the crime? for (std::vector::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? diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 898788bf1..8314d011a 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -47,7 +47,7 @@ namespace MWScript // discard additional arguments (reset), because we have no idea what they mean. for (unsigned int i=0; i buttons; @@ -2776,10 +2780,15 @@ namespace MWWorld std::vector neighbors = ptr.getClass().getCreatureStats(ptr).getPlayerWitnesses(); for (std::vector::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(); }