forked from teamnwah/openmw-tes3coop
Savegame: Store AiSequence
This commit is contained in:
parent
be6f1fe4fe
commit
a54ac579a5
27 changed files with 868 additions and 202 deletions
|
@ -1,5 +1,7 @@
|
||||||
#include "aiactivate.hpp"
|
#include "aiactivate.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/aisequence.hpp>
|
||||||
|
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
|
||||||
|
@ -46,3 +48,20 @@ int MWMechanics::AiActivate::getTypeId() const
|
||||||
{
|
{
|
||||||
return TypeIdActivate;
|
return TypeIdActivate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MWMechanics::AiActivate::writeState(ESM::AiSequence::AiSequence &sequence) const
|
||||||
|
{
|
||||||
|
std::auto_ptr<ESM::AiSequence::AiActivate> activate(new ESM::AiSequence::AiActivate());
|
||||||
|
activate->mTargetId = mObjectId;
|
||||||
|
|
||||||
|
ESM::AiSequence::AiPackageContainer package;
|
||||||
|
package.mType = ESM::AiSequence::Ai_Activate;
|
||||||
|
package.mPackage = activate.release();
|
||||||
|
sequence.mPackages.push_back(package);
|
||||||
|
}
|
||||||
|
|
||||||
|
MWMechanics::AiActivate::AiActivate(const ESM::AiSequence::AiActivate *activate)
|
||||||
|
: mObjectId(activate->mTargetId)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,14 @@
|
||||||
|
|
||||||
#include "pathfinding.hpp"
|
#include "pathfinding.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
namespace AiSequence
|
||||||
|
{
|
||||||
|
struct AiActivate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
/// \brief Causes actor to walk to activatable object and activate it
|
/// \brief Causes actor to walk to activatable object and activate it
|
||||||
|
@ -16,10 +24,15 @@ namespace MWMechanics
|
||||||
/// Constructor
|
/// Constructor
|
||||||
/** \param objectId Reference to object to activate **/
|
/** \param objectId Reference to object to activate **/
|
||||||
AiActivate(const std::string &objectId);
|
AiActivate(const std::string &objectId);
|
||||||
|
|
||||||
|
AiActivate(const ESM::AiSequence::AiActivate* activate);
|
||||||
|
|
||||||
virtual AiActivate *clone() const;
|
virtual AiActivate *clone() const;
|
||||||
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
||||||
virtual int getTypeId() const;
|
virtual int getTypeId() const;
|
||||||
|
|
||||||
|
virtual void writeState(ESM::AiSequence::AiSequence& sequence) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string mObjectId;
|
std::string mObjectId;
|
||||||
int mCellX;
|
int mCellX;
|
||||||
|
|
|
@ -78,8 +78,14 @@ MWMechanics::AiAvoidDoor *MWMechanics::AiAvoidDoor::clone() const
|
||||||
return new AiAvoidDoor(*this);
|
return new AiAvoidDoor(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
int MWMechanics::AiAvoidDoor::getTypeId() const
|
int MWMechanics::AiAvoidDoor::getTypeId() const
|
||||||
{
|
{
|
||||||
return TypeIdAvoidDoor;
|
return TypeIdAvoidDoor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int MWMechanics::AiAvoidDoor::getPriority() const
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
virtual int getTypeId() const;
|
virtual int getTypeId() const;
|
||||||
|
|
||||||
|
virtual unsigned int getPriority() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float mDuration;
|
float mDuration;
|
||||||
MWWorld::Ptr mDoorPtr;
|
MWWorld::Ptr mDoorPtr;
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <OgreMath.h>
|
#include <OgreMath.h>
|
||||||
#include <OgreVector3.h>
|
#include <OgreVector3.h>
|
||||||
|
|
||||||
|
#include <components/esm/aisequence.hpp>
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/timestamp.hpp"
|
#include "../mwworld/timestamp.hpp"
|
||||||
|
@ -81,23 +82,22 @@ namespace MWMechanics
|
||||||
// NOTE: MIN_DIST_TO_DOOR_SQUARED is defined in obstacle.hpp
|
// NOTE: MIN_DIST_TO_DOOR_SQUARED is defined in obstacle.hpp
|
||||||
|
|
||||||
AiCombat::AiCombat(const MWWorld::Ptr& actor) :
|
AiCombat::AiCombat(const MWWorld::Ptr& actor) :
|
||||||
mTargetActorId(actor.getClass().getCreatureStats(actor).getActorId()),
|
mTargetActorId(actor.getClass().getCreatureStats(actor).getActorId())
|
||||||
mTimerAttack(0),
|
|
||||||
mTimerReact(0),
|
|
||||||
mTimerCombatMove(0),
|
|
||||||
mFollowTarget(false),
|
|
||||||
mReadyToAttack(false),
|
|
||||||
mAttack(false),
|
|
||||||
mCombatMove(false),
|
|
||||||
mMovement(),
|
|
||||||
mForceNoShortcut(false),
|
|
||||||
mShortcutFailPos(),
|
|
||||||
mBackOffDoor(false),
|
|
||||||
mCell(NULL),
|
|
||||||
mDoorIter(actor.getCell()->get<ESM::Door>().mList.end()),
|
|
||||||
mDoors(actor.getCell()->get<ESM::Door>()),
|
|
||||||
mDoorCheckDuration(0)
|
|
||||||
{
|
{
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AiCombat::init()
|
||||||
|
{
|
||||||
|
mTimerAttack = 0;
|
||||||
|
mTimerReact = 0;
|
||||||
|
mTimerCombatMove = 0;
|
||||||
|
mFollowTarget = false;
|
||||||
|
mReadyToAttack = false;
|
||||||
|
mAttack = false;
|
||||||
|
mCombatMove = false;
|
||||||
|
mForceNoShortcut = false;
|
||||||
|
mCell = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -511,36 +511,10 @@ namespace MWMechanics
|
||||||
// coded at 250ms or 1/4 second
|
// coded at 250ms or 1/4 second
|
||||||
//
|
//
|
||||||
// TODO: Add a parameter to vary DURATION_SAME_SPOT?
|
// TODO: Add a parameter to vary DURATION_SAME_SPOT?
|
||||||
MWWorld::CellStore *cell = actor.getCell();
|
|
||||||
if((distToTarget > rangeAttack || mFollowTarget) &&
|
if((distToTarget > rangeAttack || mFollowTarget) &&
|
||||||
mObstacleCheck.check(actor, tReaction)) // check if evasive action needed
|
mObstacleCheck.check(actor, tReaction)) // check if evasive action needed
|
||||||
{
|
{
|
||||||
// first check if we're walking into a door
|
// probably walking into another NPC TODO: untested in combat situation
|
||||||
mDoorCheckDuration += 1.0f; // add time taken for obstacle check
|
|
||||||
if(mDoorCheckDuration >= DOOR_CHECK_INTERVAL && !cell->getCell()->isExterior())
|
|
||||||
{
|
|
||||||
mDoorCheckDuration = 0;
|
|
||||||
// Check all the doors in this cell
|
|
||||||
mDoors = cell->get<ESM::Door>(); // update
|
|
||||||
mDoorIter = mDoors.mList.begin();
|
|
||||||
for (; mDoorIter != mDoors.mList.end(); ++mDoorIter)
|
|
||||||
{
|
|
||||||
MWWorld::LiveCellRef<ESM::Door>& ref = *mDoorIter;
|
|
||||||
float minSqr = 1.3*1.3*MIN_DIST_TO_DOOR_SQUARED; // for legibility
|
|
||||||
if(vActorPos.squaredDistance(Ogre::Vector3(ref.mRef.getPosition().pos)) < minSqr &&
|
|
||||||
ref.mData.getLocalRotation().rot[2] < 0.4f) // even small opening
|
|
||||||
{
|
|
||||||
//std::cout<<"closed door id \""<<ref.mRef.mRefID<<"\""<<std::endl;
|
|
||||||
mBackOffDoor = true;
|
|
||||||
mObstacleCheck.clear();
|
|
||||||
if(mFollowTarget)
|
|
||||||
mFollowTarget = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else // probably walking into another NPC TODO: untested in combat situation
|
|
||||||
{
|
|
||||||
// TODO: diagonal should have same animation as walk forward
|
// TODO: diagonal should have same animation as walk forward
|
||||||
// but doesn't seem to do that?
|
// but doesn't seem to do that?
|
||||||
actor.getClass().getMovementSettings(actor).mPosition[0] = 1;
|
actor.getClass().getMovementSettings(actor).mPosition[0] = 1;
|
||||||
|
@ -554,28 +528,6 @@ namespace MWMechanics
|
||||||
// FIXME: can fool actors to stay behind doors, etc.
|
// FIXME: can fool actors to stay behind doors, etc.
|
||||||
// Related to Bug#1102 and to some degree #1155 as well
|
// Related to Bug#1102 and to some degree #1155 as well
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if(!cell->getCell()->isExterior() && !mDoors.mList.empty())
|
|
||||||
{
|
|
||||||
MWWorld::LiveCellRef<ESM::Door>& ref = *mDoorIter;
|
|
||||||
float minSqr = 1.6 * 1.6 * MIN_DIST_TO_DOOR_SQUARED; // for legibility
|
|
||||||
// TODO: add reaction to checking open doors
|
|
||||||
if(mBackOffDoor &&
|
|
||||||
vActorPos.squaredDistance(Ogre::Vector3(ref.mRef.getPosition().pos)) < minSqr)
|
|
||||||
{
|
|
||||||
mMovement.mPosition[1] = -0.2; // back off, but slowly
|
|
||||||
}
|
|
||||||
else if(mBackOffDoor &&
|
|
||||||
mDoorIter != mDoors.mList.end() &&
|
|
||||||
ref.mData.getLocalRotation().rot[2] >= 1)
|
|
||||||
{
|
|
||||||
mDoorIter = mDoors.mList.end();
|
|
||||||
mBackOffDoor = false;
|
|
||||||
//std::cout<<"open door id \""<<ref.mRef.mRefID<<"\""<<std::endl;
|
|
||||||
mMovement.mPosition[1] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -647,6 +599,23 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
return new AiCombat(*this);
|
return new AiCombat(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AiCombat::AiCombat(const ESM::AiSequence::AiCombat *combat)
|
||||||
|
{
|
||||||
|
mTargetActorId = combat->mTargetActorId;
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AiCombat::writeState(ESM::AiSequence::AiSequence &sequence) const
|
||||||
|
{
|
||||||
|
std::auto_ptr<ESM::AiSequence::AiCombat> combat(new ESM::AiSequence::AiCombat());
|
||||||
|
combat->mTargetActorId = mTargetActorId;
|
||||||
|
|
||||||
|
ESM::AiSequence::AiPackageContainer package;
|
||||||
|
package.mType = ESM::AiSequence::Ai_Combat;
|
||||||
|
package.mPackage = combat.release();
|
||||||
|
sequence.mPackages.push_back(package);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,14 @@
|
||||||
|
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
namespace AiSequence
|
||||||
|
{
|
||||||
|
struct AiCombat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
/// \brief Causes the actor to fight another actor
|
/// \brief Causes the actor to fight another actor
|
||||||
|
@ -22,6 +30,10 @@ namespace MWMechanics
|
||||||
/** \param actor Actor to fight **/
|
/** \param actor Actor to fight **/
|
||||||
AiCombat(const MWWorld::Ptr& actor);
|
AiCombat(const MWWorld::Ptr& actor);
|
||||||
|
|
||||||
|
AiCombat (const ESM::AiSequence::AiCombat* combat);
|
||||||
|
|
||||||
|
void init();
|
||||||
|
|
||||||
virtual AiCombat *clone() const;
|
virtual AiCombat *clone() const;
|
||||||
|
|
||||||
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
||||||
|
@ -33,6 +45,8 @@ namespace MWMechanics
|
||||||
///Returns target ID
|
///Returns target ID
|
||||||
MWWorld::Ptr getTarget() const;
|
MWWorld::Ptr getTarget() const;
|
||||||
|
|
||||||
|
virtual void writeState(ESM::AiSequence::AiSequence &sequence) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PathFinder mPathFinder;
|
PathFinder mPathFinder;
|
||||||
// controls duration of the actual strike
|
// controls duration of the actual strike
|
||||||
|
@ -46,7 +60,6 @@ namespace MWMechanics
|
||||||
bool mReadyToAttack, mAttack;
|
bool mReadyToAttack, mAttack;
|
||||||
bool mFollowTarget;
|
bool mFollowTarget;
|
||||||
bool mCombatMove;
|
bool mCombatMove;
|
||||||
bool mBackOffDoor;
|
|
||||||
|
|
||||||
bool mForceNoShortcut;
|
bool mForceNoShortcut;
|
||||||
ESM::Position mShortcutFailPos;
|
ESM::Position mShortcutFailPos;
|
||||||
|
@ -57,11 +70,6 @@ namespace MWMechanics
|
||||||
|
|
||||||
const MWWorld::CellStore* mCell;
|
const MWWorld::CellStore* mCell;
|
||||||
ObstacleCheck mObstacleCheck;
|
ObstacleCheck mObstacleCheck;
|
||||||
float mDoorCheckDuration;
|
|
||||||
// TODO: for some reason mDoors.searchViaHandle() returns
|
|
||||||
// null pointers, workaround by keeping an iterator
|
|
||||||
MWWorld::CellRefList<ESM::Door>::List::iterator mDoorIter;
|
|
||||||
MWWorld::CellRefList<ESM::Door>& mDoors;
|
|
||||||
|
|
||||||
void buildNewPath(const MWWorld::Ptr& actor, const MWWorld::Ptr& target);
|
void buildNewPath(const MWWorld::Ptr& actor, const MWWorld::Ptr& target);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
#include "aiescort.hpp"
|
#include "aiescort.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/aisequence.hpp>
|
||||||
|
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/mechanicsmanager.hpp"
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
|
|
||||||
#include "../mwworld/cellstore.hpp"
|
#include "../mwworld/cellstore.hpp"
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/timestamp.hpp"
|
|
||||||
|
|
||||||
#include "steering.hpp"
|
#include "steering.hpp"
|
||||||
#include "movement.hpp"
|
#include "movement.hpp"
|
||||||
|
@ -20,7 +21,7 @@
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
AiEscort::AiEscort(const std::string &actorId, int duration, float x, float y, float z)
|
AiEscort::AiEscort(const std::string &actorId, int duration, float x, float y, float z)
|
||||||
: mActorId(actorId), mX(x), mY(y), mZ(z), mDuration(duration)
|
: mActorId(actorId), mX(x), mY(y), mZ(z), mRemainingDuration(duration)
|
||||||
, mCellX(std::numeric_limits<int>::max())
|
, mCellX(std::numeric_limits<int>::max())
|
||||||
, mCellY(std::numeric_limits<int>::max())
|
, mCellY(std::numeric_limits<int>::max())
|
||||||
{
|
{
|
||||||
|
@ -29,32 +30,29 @@ namespace MWMechanics
|
||||||
// The CS Help File states that if a duration is given, the AI package will run for that long
|
// The CS Help File states that if a duration is given, 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.
|
// 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)
|
if(mX != 0 || mY != 0 || mZ != 0)
|
||||||
mDuration = 0;
|
mRemainingDuration = 0;
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MWWorld::TimeStamp startTime = MWBase::Environment::get().getWorld()->getTimeStamp();
|
|
||||||
mStartingSecond = ((startTime.getHour() - int(startTime.getHour())) * 100);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AiEscort::AiEscort(const std::string &actorId, const std::string &cellId,int duration, float x, float y, float z)
|
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)
|
: mActorId(actorId), mCellId(cellId), mX(x), mY(y), mZ(z), mRemainingDuration(duration)
|
||||||
, mCellX(std::numeric_limits<int>::max())
|
, mCellX(std::numeric_limits<int>::max())
|
||||||
, mCellY(std::numeric_limits<int>::max())
|
, mCellY(std::numeric_limits<int>::max())
|
||||||
{
|
{
|
||||||
mMaxDist = 470;
|
mMaxDist = 470;
|
||||||
|
|
||||||
// The CS Help File states that if a duration is given, the AI package will run for that long
|
// The CS Help File states that if a duration is given, 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.
|
// BUT if a location is given, it "trumps" the duration so it will simply escort to that location.
|
||||||
if(mX != 0 || mY != 0 || mZ != 0)
|
if(mX != 0 || mY != 0 || mZ != 0)
|
||||||
mDuration = 0;
|
mRemainingDuration = 0;
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MWWorld::TimeStamp startTime = MWBase::Environment::get().getWorld()->getTimeStamp();
|
|
||||||
mStartingSecond = ((startTime.getHour() - int(startTime.getHour())) * 100);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AiEscort::AiEscort(const ESM::AiSequence::AiEscort *escort)
|
||||||
|
: mActorId(escort->mTargetId), mX(escort->mData.mX), mY(escort->mData.mY), mZ(escort->mData.mZ)
|
||||||
|
, mCellX(std::numeric_limits<int>::max())
|
||||||
|
, mCellY(std::numeric_limits<int>::max())
|
||||||
|
, mCellId(escort->mCellId)
|
||||||
|
, mRemainingDuration(escort->mRemainingDuration)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -67,11 +65,10 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
// If AiEscort has ran for as long or longer then the duration specified
|
// If AiEscort has ran for as long or longer then the duration specified
|
||||||
// and the duration is not infinite, the package is complete.
|
// and the duration is not infinite, the package is complete.
|
||||||
if(mDuration != 0)
|
if(mRemainingDuration != 0)
|
||||||
{
|
{
|
||||||
MWWorld::TimeStamp current = MWBase::Environment::get().getWorld()->getTimeStamp();
|
mRemainingDuration -= duration;
|
||||||
unsigned int currentSecond = ((current.getHour() - int(current.getHour())) * 100);
|
if (duration <= 0)
|
||||||
if(currentSecond - mStartingSecond >= mDuration)
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,5 +105,21 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
return TypeIdEscort;
|
return TypeIdEscort;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AiEscort::writeState(ESM::AiSequence::AiSequence &sequence) const
|
||||||
|
{
|
||||||
|
std::auto_ptr<ESM::AiSequence::AiEscort> escort(new ESM::AiSequence::AiEscort());
|
||||||
|
escort->mData.mX = mX;
|
||||||
|
escort->mData.mY = mY;
|
||||||
|
escort->mData.mZ = mZ;
|
||||||
|
escort->mTargetId = mActorId;
|
||||||
|
escort->mRemainingDuration = mRemainingDuration;
|
||||||
|
escort->mCellId = mCellId;
|
||||||
|
|
||||||
|
ESM::AiSequence::AiPackageContainer package;
|
||||||
|
package.mType = ESM::AiSequence::Ai_Escort;
|
||||||
|
package.mPackage = escort.release();
|
||||||
|
sequence.mPackages.push_back(package);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,14 @@
|
||||||
|
|
||||||
#include "pathfinding.hpp"
|
#include "pathfinding.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
namespace AiSequence
|
||||||
|
{
|
||||||
|
struct AiEscort;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
/// \brief AI Package to have an NPC lead the player to a specific point
|
/// \brief AI Package to have an NPC lead the player to a specific point
|
||||||
|
@ -21,12 +29,16 @@ namespace MWMechanics
|
||||||
\implement AiEscortCell **/
|
\implement AiEscortCell **/
|
||||||
AiEscort(const std::string &actorId,const std::string &cellId,int duration, float x, float y, float z);
|
AiEscort(const std::string &actorId,const std::string &cellId,int duration, float x, float y, float z);
|
||||||
|
|
||||||
|
AiEscort(const ESM::AiSequence::AiEscort* escort);
|
||||||
|
|
||||||
virtual AiEscort *clone() const;
|
virtual AiEscort *clone() const;
|
||||||
|
|
||||||
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
||||||
|
|
||||||
virtual int getTypeId() const;
|
virtual int getTypeId() const;
|
||||||
|
|
||||||
|
void writeState(ESM::AiSequence::AiSequence &sequence) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string mActorId;
|
std::string mActorId;
|
||||||
std::string mCellId;
|
std::string mCellId;
|
||||||
|
@ -34,8 +46,7 @@ namespace MWMechanics
|
||||||
float mY;
|
float mY;
|
||||||
float mZ;
|
float mZ;
|
||||||
float mMaxDist;
|
float mMaxDist;
|
||||||
unsigned int mStartingSecond;
|
float mRemainingDuration; // In seconds
|
||||||
unsigned int mDuration;
|
|
||||||
|
|
||||||
PathFinder mPathFinder;
|
PathFinder mPathFinder;
|
||||||
int mCellX;
|
int mCellX;
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
#include "aifollow.hpp"
|
#include "aifollow.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <components/esm/aisequence.hpp>
|
||||||
|
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
@ -12,16 +16,16 @@
|
||||||
#include "steering.hpp"
|
#include "steering.hpp"
|
||||||
|
|
||||||
MWMechanics::AiFollow::AiFollow(const std::string &actorId,float duration, float x, float y, float z)
|
MWMechanics::AiFollow::AiFollow(const std::string &actorId,float duration, float x, float y, float z)
|
||||||
: mAlwaysFollow(false), mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId), mCellId(""), AiPackage()
|
: mAlwaysFollow(false), mRemainingDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId), mCellId("")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
MWMechanics::AiFollow::AiFollow(const std::string &actorId,const std::string &cellId,float duration, float x, float y, float z)
|
MWMechanics::AiFollow::AiFollow(const std::string &actorId,const std::string &cellId,float duration, float x, float y, float z)
|
||||||
: mAlwaysFollow(false), mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId), mCellId(cellId), AiPackage()
|
: mAlwaysFollow(false), mRemainingDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId), mCellId(cellId)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
MWMechanics::AiFollow::AiFollow(const std::string &actorId)
|
MWMechanics::AiFollow::AiFollow(const std::string &actorId)
|
||||||
: mAlwaysFollow(true), mDuration(0), mX(0), mY(0), mZ(0), mActorId(actorId), mCellId(""), AiPackage()
|
: mAlwaysFollow(true), mRemainingDuration(0), mX(0), mY(0), mZ(0), mActorId(actorId), mCellId("")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,8 +39,13 @@ bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration)
|
||||||
|
|
||||||
if(!mAlwaysFollow) //Update if you only follow for a bit
|
if(!mAlwaysFollow) //Update if you only follow for a bit
|
||||||
{
|
{
|
||||||
if(mTotalTime > mDuration && mDuration != 0) //Check if we've run out of time
|
//Check if we've run out of time
|
||||||
|
if (mRemainingDuration != 0)
|
||||||
|
{
|
||||||
|
mRemainingDuration -= duration;
|
||||||
|
if (duration <= 0)
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if((pos.pos[0]-mX)*(pos.pos[0]-mX) +
|
if((pos.pos[0]-mX)*(pos.pos[0]-mX) +
|
||||||
(pos.pos[1]-mY)*(pos.pos[1]-mY) +
|
(pos.pos[1]-mY)*(pos.pos[1]-mY) +
|
||||||
|
@ -55,7 +64,7 @@ bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Set the target desition from the actor
|
//Set the target destination from the actor
|
||||||
ESM::Pathgrid::Point dest = target.getRefData().getPosition().pos;
|
ESM::Pathgrid::Point dest = target.getRefData().getPosition().pos;
|
||||||
|
|
||||||
if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]) < 100) //Stop when you get close
|
if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]) < 100) //Stop when you get close
|
||||||
|
@ -83,7 +92,32 @@ MWMechanics::AiFollow *MWMechanics::AiFollow::clone() const
|
||||||
return new AiFollow(*this);
|
return new AiFollow(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
int MWMechanics::AiFollow::getTypeId() const
|
int MWMechanics::AiFollow::getTypeId() const
|
||||||
{
|
{
|
||||||
return TypeIdFollow;
|
return TypeIdFollow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MWMechanics::AiFollow::writeState(ESM::AiSequence::AiSequence &sequence) const
|
||||||
|
{
|
||||||
|
std::auto_ptr<ESM::AiSequence::AiFollow> follow(new ESM::AiSequence::AiFollow());
|
||||||
|
follow->mData.mX = mX;
|
||||||
|
follow->mData.mY = mY;
|
||||||
|
follow->mData.mZ = mZ;
|
||||||
|
follow->mTargetId = mActorId;
|
||||||
|
follow->mRemainingDuration = mRemainingDuration;
|
||||||
|
follow->mCellId = mCellId;
|
||||||
|
follow->mAlwaysFollow = mAlwaysFollow;
|
||||||
|
|
||||||
|
ESM::AiSequence::AiPackageContainer package;
|
||||||
|
package.mType = ESM::AiSequence::Ai_Follow;
|
||||||
|
package.mPackage = follow.release();
|
||||||
|
sequence.mPackages.push_back(package);
|
||||||
|
}
|
||||||
|
|
||||||
|
MWMechanics::AiFollow::AiFollow(const ESM::AiSequence::AiFollow *follow)
|
||||||
|
: mAlwaysFollow(follow->mAlwaysFollow), mRemainingDuration(follow->mRemainingDuration)
|
||||||
|
, mX(follow->mData.mX), mY(follow->mData.mY), mZ(follow->mData.mZ)
|
||||||
|
, mActorId(follow->mTargetId), mCellId(follow->mCellId)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,14 @@
|
||||||
#include "pathfinding.hpp"
|
#include "pathfinding.hpp"
|
||||||
#include <components/esm/defs.hpp>
|
#include <components/esm/defs.hpp>
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
namespace AiSequence
|
||||||
|
{
|
||||||
|
struct AiFollow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
/// \brief AiPackage for an actor to follow another actor/the PC
|
/// \brief AiPackage for an actor to follow another actor/the PC
|
||||||
|
@ -21,6 +29,8 @@ namespace MWMechanics
|
||||||
/// Follow Actor indefinitively
|
/// Follow Actor indefinitively
|
||||||
AiFollow(const std::string &ActorId);
|
AiFollow(const std::string &ActorId);
|
||||||
|
|
||||||
|
AiFollow(const ESM::AiSequence::AiFollow* follow);
|
||||||
|
|
||||||
virtual AiFollow *clone() const;
|
virtual AiFollow *clone() const;
|
||||||
|
|
||||||
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
||||||
|
@ -30,11 +40,13 @@ namespace MWMechanics
|
||||||
/// Returns the actor being followed
|
/// Returns the actor being followed
|
||||||
std::string getFollowedActor();
|
std::string getFollowedActor();
|
||||||
|
|
||||||
|
virtual void writeState (ESM::AiSequence::AiSequence& sequence) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// This will make the actor always follow.
|
/// This will make the actor always follow.
|
||||||
/** Thus ignoring mDuration and mX,mY,mZ (used for summoned creatures). **/
|
/** Thus ignoring mDuration and mX,mY,mZ (used for summoned creatures). **/
|
||||||
bool mAlwaysFollow;
|
bool mAlwaysFollow;
|
||||||
float mDuration;
|
float mRemainingDuration; // Seconds
|
||||||
float mX;
|
float mX;
|
||||||
float mY;
|
float mY;
|
||||||
float mZ;
|
float mZ;
|
||||||
|
|
|
@ -26,8 +26,6 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po
|
||||||
//Update various Timers
|
//Update various Timers
|
||||||
mTimer += duration; //Update timer
|
mTimer += duration; //Update timer
|
||||||
mStuckTimer += duration; //Update stuck timer
|
mStuckTimer += duration; //Update stuck timer
|
||||||
mTotalTime += duration; //Update total time following
|
|
||||||
|
|
||||||
|
|
||||||
ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
|
ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,14 @@ namespace MWWorld
|
||||||
class Ptr;
|
class Ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
namespace AiSequence
|
||||||
|
{
|
||||||
|
class AiSequence;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
/// \brief Base class for AI packages
|
/// \brief Base class for AI packages
|
||||||
|
@ -51,6 +59,8 @@ namespace MWMechanics
|
||||||
/// Higher number is higher priority (0 being the lowest)
|
/// Higher number is higher priority (0 being the lowest)
|
||||||
virtual unsigned int getPriority() const {return 0;}
|
virtual unsigned int getPriority() const {return 0;}
|
||||||
|
|
||||||
|
virtual void writeState (ESM::AiSequence::AiSequence& sequence) const {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Causes the actor to attempt to walk to the specified location
|
/// Causes the actor to attempt to walk to the specified location
|
||||||
/** \return If the actor has arrived at his destination **/
|
/** \return If the actor has arrived at his destination **/
|
||||||
|
@ -62,7 +72,6 @@ namespace MWMechanics
|
||||||
float mDoorCheckDuration;
|
float mDoorCheckDuration;
|
||||||
float mTimer;
|
float mTimer;
|
||||||
float mStuckTimer;
|
float mStuckTimer;
|
||||||
float mTotalTime;
|
|
||||||
|
|
||||||
MWWorld::Ptr mLastDoorChecked; //Used to ensure we don't try to CONSTANTLY open a door
|
MWWorld::Ptr mLastDoorChecked; //Used to ensure we don't try to CONSTANTLY open a door
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "aipursue.hpp"
|
#include "aipursue.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/aisequence.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
@ -18,6 +20,12 @@ AiPursue::AiPursue(const MWWorld::Ptr& actor)
|
||||||
: mTargetActorId(actor.getClass().getCreatureStats(actor).getActorId())
|
: mTargetActorId(actor.getClass().getCreatureStats(actor).getActorId())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AiPursue::AiPursue(const ESM::AiSequence::AiPursue *pursue)
|
||||||
|
: mTargetActorId(pursue->mTargetActorId)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
AiPursue *MWMechanics::AiPursue::clone() const
|
AiPursue *MWMechanics::AiPursue::clone() const
|
||||||
{
|
{
|
||||||
return new AiPursue(*this);
|
return new AiPursue(*this);
|
||||||
|
@ -57,4 +65,15 @@ MWWorld::Ptr AiPursue::getTarget() const
|
||||||
return MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId);
|
return MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AiPursue::writeState(ESM::AiSequence::AiSequence &sequence) const
|
||||||
|
{
|
||||||
|
std::auto_ptr<ESM::AiSequence::AiPursue> pursue(new ESM::AiSequence::AiPursue());
|
||||||
|
pursue->mTargetActorId = mTargetActorId;
|
||||||
|
|
||||||
|
ESM::AiSequence::AiPackageContainer package;
|
||||||
|
package.mType = ESM::AiSequence::Ai_Pursue;
|
||||||
|
package.mPackage = pursue.release();
|
||||||
|
sequence.mPackages.push_back(package);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace MWMechanics
|
} // namespace MWMechanics
|
||||||
|
|
|
@ -7,6 +7,14 @@
|
||||||
|
|
||||||
#include "pathfinding.hpp"
|
#include "pathfinding.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
namespace AiSequence
|
||||||
|
{
|
||||||
|
struct AiPursue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
/// \brief Makes the actor very closely follow the actor
|
/// \brief Makes the actor very closely follow the actor
|
||||||
|
@ -20,12 +28,16 @@ namespace MWMechanics
|
||||||
/** \param actor Actor to pursue **/
|
/** \param actor Actor to pursue **/
|
||||||
AiPursue(const MWWorld::Ptr& actor);
|
AiPursue(const MWWorld::Ptr& actor);
|
||||||
|
|
||||||
|
AiPursue(const ESM::AiSequence::AiPursue* pursue);
|
||||||
|
|
||||||
virtual AiPursue *clone() const;
|
virtual AiPursue *clone() const;
|
||||||
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
||||||
virtual int getTypeId() const;
|
virtual int getTypeId() const;
|
||||||
|
|
||||||
MWWorld::Ptr getTarget() const;
|
MWWorld::Ptr getTarget() const;
|
||||||
|
|
||||||
|
virtual void writeState (ESM::AiSequence::AiSequence& sequence) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
int mTargetActorId; // The actor to pursue
|
int mTargetActorId; // The actor to pursue
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
#include "aicombat.hpp"
|
#include "aicombat.hpp"
|
||||||
#include "aipursue.hpp"
|
#include "aipursue.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/aisequence.hpp>
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "creaturestats.hpp"
|
#include "creaturestats.hpp"
|
||||||
#include "npcstats.hpp"
|
#include "npcstats.hpp"
|
||||||
|
@ -258,7 +260,8 @@ void AiSequence::fill(const ESM::AIPackageList &list)
|
||||||
if (it->mType == ESM::AI_Wander)
|
if (it->mType == ESM::AI_Wander)
|
||||||
{
|
{
|
||||||
ESM::AIWander data = it->mWander;
|
ESM::AIWander data = it->mWander;
|
||||||
std::vector<int> idles;
|
std::vector<unsigned char> idles;
|
||||||
|
idles.reserve(8);
|
||||||
for (int i=0; i<8; ++i)
|
for (int i=0; i<8; ++i)
|
||||||
idles.push_back(data.mIdle[i]);
|
idles.push_back(data.mIdle[i]);
|
||||||
package = new MWMechanics::AiWander(data.mDistance, data.mDuration, data.mTimeOfDay, idles, data.mShouldRepeat);
|
package = new MWMechanics::AiWander(data.mDistance, data.mDuration, data.mTimeOfDay, idles, data.mShouldRepeat);
|
||||||
|
@ -287,4 +290,76 @@ void AiSequence::fill(const ESM::AIPackageList &list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AiSequence::writeState(ESM::AiSequence::AiSequence &sequence) const
|
||||||
|
{
|
||||||
|
for (std::list<AiPackage *>::const_iterator iter (mPackages.begin()); iter!=mPackages.end(); ++iter)
|
||||||
|
{
|
||||||
|
(*iter)->writeState(sequence);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AiSequence::readState(const ESM::AiSequence::AiSequence &sequence)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
|
||||||
|
for (std::vector<ESM::AiSequence::AiPackageContainer>::const_iterator it = sequence.mPackages.begin();
|
||||||
|
it != sequence.mPackages.end(); ++it)
|
||||||
|
{
|
||||||
|
switch (it->mType)
|
||||||
|
{
|
||||||
|
case ESM::AiSequence::Ai_Wander:
|
||||||
|
{
|
||||||
|
MWMechanics::AiWander* wander = new AiWander(
|
||||||
|
dynamic_cast<ESM::AiSequence::AiWander*>(it->mPackage));
|
||||||
|
mPackages.push_back(wander);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM::AiSequence::Ai_Travel:
|
||||||
|
{
|
||||||
|
MWMechanics::AiTravel* travel = new AiTravel(
|
||||||
|
dynamic_cast<ESM::AiSequence::AiTravel*>(it->mPackage));
|
||||||
|
mPackages.push_back(travel);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM::AiSequence::Ai_Escort:
|
||||||
|
{
|
||||||
|
MWMechanics::AiEscort* escort = new AiEscort(
|
||||||
|
dynamic_cast<ESM::AiSequence::AiEscort*>(it->mPackage));
|
||||||
|
mPackages.push_back(escort);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM::AiSequence::Ai_Follow:
|
||||||
|
{
|
||||||
|
MWMechanics::AiFollow* follow = new AiFollow(
|
||||||
|
dynamic_cast<ESM::AiSequence::AiFollow*>(it->mPackage));
|
||||||
|
mPackages.push_back(follow);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM::AiSequence::Ai_Activate:
|
||||||
|
{
|
||||||
|
MWMechanics::AiActivate* activate = new AiActivate(
|
||||||
|
dynamic_cast<ESM::AiSequence::AiActivate*>(it->mPackage));
|
||||||
|
mPackages.push_back(activate);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM::AiSequence::Ai_Combat:
|
||||||
|
{
|
||||||
|
MWMechanics::AiCombat* combat = new AiCombat(
|
||||||
|
dynamic_cast<ESM::AiSequence::AiCombat*>(it->mPackage));
|
||||||
|
mPackages.push_back(combat);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM::AiSequence::Ai_Pursue:
|
||||||
|
{
|
||||||
|
MWMechanics::AiPursue* pursue = new AiPursue(
|
||||||
|
dynamic_cast<ESM::AiSequence::AiPursue*>(it->mPackage));
|
||||||
|
mPackages.push_back(pursue);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace MWMechanics
|
} // namespace MWMechanics
|
||||||
|
|
|
@ -10,6 +10,14 @@ namespace MWWorld
|
||||||
class Ptr;
|
class Ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
namespace AiSequence
|
||||||
|
{
|
||||||
|
class AiSequence;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
class AiPackage;
|
class AiPackage;
|
||||||
|
@ -90,6 +98,9 @@ namespace MWMechanics
|
||||||
/** Typically used for loading from the ESM
|
/** Typically used for loading from the ESM
|
||||||
\see ESM::AIPackageList **/
|
\see ESM::AIPackageList **/
|
||||||
void fill (const ESM::AIPackageList& list);
|
void fill (const ESM::AIPackageList& list);
|
||||||
|
|
||||||
|
void writeState (ESM::AiSequence::AiSequence& sequence) const;
|
||||||
|
void readState (const ESM::AiSequence::AiSequence& sequence);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "aitravel.hpp"
|
#include "aitravel.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/aisequence.hpp>
|
||||||
|
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
|
||||||
|
@ -19,6 +21,15 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AiTravel::AiTravel(const ESM::AiSequence::AiTravel *travel)
|
||||||
|
: mX(travel->mData.mX), mY(travel->mData.mY), mZ(travel->mData.mZ)
|
||||||
|
, mPathFinder()
|
||||||
|
, mCellX(std::numeric_limits<int>::max())
|
||||||
|
, mCellY(std::numeric_limits<int>::max())
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
AiTravel *MWMechanics::AiTravel::clone() const
|
AiTravel *MWMechanics::AiTravel::clone() const
|
||||||
{
|
{
|
||||||
return new AiTravel(*this);
|
return new AiTravel(*this);
|
||||||
|
@ -92,5 +103,18 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
return TypeIdTravel;
|
return TypeIdTravel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AiTravel::writeState(ESM::AiSequence::AiSequence &sequence) const
|
||||||
|
{
|
||||||
|
std::auto_ptr<ESM::AiSequence::AiTravel> travel(new ESM::AiSequence::AiTravel());
|
||||||
|
travel->mData.mX = mX;
|
||||||
|
travel->mData.mY = mY;
|
||||||
|
travel->mData.mZ = mZ;
|
||||||
|
|
||||||
|
ESM::AiSequence::AiPackageContainer package;
|
||||||
|
package.mType = ESM::AiSequence::Ai_Travel;
|
||||||
|
package.mPackage = travel.release();
|
||||||
|
sequence.mPackages.push_back(package);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,14 @@
|
||||||
|
|
||||||
#include "pathfinding.hpp"
|
#include "pathfinding.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
namespace AiSequence
|
||||||
|
{
|
||||||
|
struct AiTravel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
/// \brief Causes the AI to travel to the specified point
|
/// \brief Causes the AI to travel to the specified point
|
||||||
|
@ -13,6 +21,10 @@ namespace MWMechanics
|
||||||
public:
|
public:
|
||||||
/// Default constructor
|
/// Default constructor
|
||||||
AiTravel(float x, float y, float z);
|
AiTravel(float x, float y, float z);
|
||||||
|
AiTravel(const ESM::AiSequence::AiTravel* travel);
|
||||||
|
|
||||||
|
void writeState(ESM::AiSequence::AiSequence &sequence) const;
|
||||||
|
|
||||||
virtual AiTravel *clone() const;
|
virtual AiTravel *clone() const;
|
||||||
|
|
||||||
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#include <OgreVector3.h>
|
#include <OgreVector3.h>
|
||||||
#include <OgreSceneNode.h>
|
#include <OgreSceneNode.h>
|
||||||
|
|
||||||
|
#include <components/esm/aisequence.hpp>
|
||||||
|
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/mechanicsmanager.hpp"
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
|
@ -21,32 +23,29 @@ namespace MWMechanics
|
||||||
static const int COUNT_BEFORE_RESET = 200; // TODO: maybe no longer needed
|
static const int COUNT_BEFORE_RESET = 200; // TODO: maybe no longer needed
|
||||||
static const float DOOR_CHECK_INTERVAL = 1.5f;
|
static const float DOOR_CHECK_INTERVAL = 1.5f;
|
||||||
|
|
||||||
AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<int>& idle, bool repeat):
|
AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<unsigned char>& idle, bool repeat):
|
||||||
mDistance(distance), mDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), mRepeat(repeat)
|
mDistance(distance), mDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), mRepeat(repeat)
|
||||||
, mCellX(std::numeric_limits<int>::max())
|
|
||||||
, mCellY(std::numeric_limits<int>::max())
|
|
||||||
, mXCell(0)
|
|
||||||
, mYCell(0)
|
|
||||||
, mCell(NULL)
|
|
||||||
, mStuckCount(0) // TODO: maybe no longer needed
|
|
||||||
, mDoorCheckDuration(0)
|
|
||||||
, mTrimCurrentNode(false)
|
|
||||||
, mReaction(0)
|
|
||||||
, mGreetDistanceMultiplier(0)
|
|
||||||
, mGreetDistanceReset(0)
|
|
||||||
, mChance(0)
|
|
||||||
, mRotate(false)
|
|
||||||
, mTargetAngle(0)
|
|
||||||
, mSaidGreeting(false)
|
|
||||||
, mHasReturnPosition(false)
|
|
||||||
, mReturnPosition(0,0,0)
|
|
||||||
{
|
{
|
||||||
for(unsigned short counter = 0; counter < mIdle.size(); counter++)
|
init();
|
||||||
{
|
|
||||||
if(mIdle[counter] >= 127 || mIdle[counter] < 0)
|
|
||||||
mIdle[counter] = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AiWander::init()
|
||||||
|
{
|
||||||
|
mCellX = std::numeric_limits<int>::max();
|
||||||
|
mCellY = std::numeric_limits<int>::max();
|
||||||
|
mXCell = 0;
|
||||||
|
mYCell = 0;
|
||||||
|
mCell = NULL;
|
||||||
|
mStuckCount = 0;// TODO: maybe no longer needed
|
||||||
|
mDoorCheckDuration = 0;
|
||||||
|
mTrimCurrentNode = false;
|
||||||
|
mReaction = 0;
|
||||||
|
mRotate = false;
|
||||||
|
mTargetAngle = 0;
|
||||||
|
mSaidGreeting = false;
|
||||||
|
mHasReturnPosition = false;
|
||||||
|
mReturnPosition = Ogre::Vector3(0,0,0);
|
||||||
|
|
||||||
if(mDistance < 0)
|
if(mDistance < 0)
|
||||||
mDistance = 0;
|
mDistance = 0;
|
||||||
if(mDuration < 0)
|
if(mDuration < 0)
|
||||||
|
@ -56,15 +55,6 @@ namespace MWMechanics
|
||||||
|
|
||||||
mStartTime = MWBase::Environment::get().getWorld()->getTimeStamp();
|
mStartTime = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||||
mPlayedIdle = 0;
|
mPlayedIdle = 0;
|
||||||
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
|
||||||
mIdleChanceMultiplier =
|
|
||||||
store.get<ESM::GameSetting>().find("fIdleChanceMultiplier")->getFloat();
|
|
||||||
|
|
||||||
mGreetDistanceMultiplier =
|
|
||||||
store.get<ESM::GameSetting>().find("iGreetDistanceMultiplier")->getInt();
|
|
||||||
mGreetDistanceReset =
|
|
||||||
store.get<ESM::GameSetting>().find("fGreetDistanceReset")->getFloat();
|
|
||||||
mChance = store.get<ESM::GameSetting>().find("fVoiceIdleOdds")->getFloat();
|
|
||||||
|
|
||||||
mStoredAvailableNodes = false;
|
mStoredAvailableNodes = false;
|
||||||
mChooseAction = true;
|
mChooseAction = true;
|
||||||
|
@ -219,11 +209,12 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
mReaction += duration;
|
mReaction += duration;
|
||||||
if(mReaction > 0.25f) // FIXME: hard coded constant
|
if(mReaction < 0.25f) // FIXME: hard coded constant
|
||||||
{
|
{
|
||||||
mReaction = 0;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
mReaction = 0;
|
||||||
|
|
||||||
// NOTE: everything below get updated every 0.25 seconds
|
// NOTE: everything below get updated every 0.25 seconds
|
||||||
|
|
||||||
|
@ -394,7 +385,10 @@ namespace MWMechanics
|
||||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
|
|
||||||
// Don't bother if the player is out of hearing range
|
// Don't bother if the player is out of hearing range
|
||||||
if (roll < mChance && Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(pos.pos)) < 1500*1500)
|
static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore()
|
||||||
|
.get<ESM::GameSetting>().find("fVoiceIdleOdds")->getFloat();
|
||||||
|
|
||||||
|
if (roll < fVoiceIdleOdds && Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(pos.pos)) < 1500*1500)
|
||||||
MWBase::Environment::get().getDialogueManager()->say(actor, "idle");
|
MWBase::Environment::get().getDialogueManager()->say(actor, "idle");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -406,7 +400,10 @@ namespace MWMechanics
|
||||||
// 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();
|
||||||
float helloDistance = hello;
|
float helloDistance = hello;
|
||||||
helloDistance *= mGreetDistanceMultiplier;
|
static int iGreetDistanceMultiplier =MWBase::Environment::get().getWorld()->getStore()
|
||||||
|
.get<ESM::GameSetting>().find("iGreetDistanceMultiplier")->getInt();
|
||||||
|
|
||||||
|
helloDistance *= iGreetDistanceMultiplier;
|
||||||
|
|
||||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
Ogre::Vector3 playerPos(player.getRefData().getPosition().pos);
|
Ogre::Vector3 playerPos(player.getRefData().getPosition().pos);
|
||||||
|
@ -455,7 +452,10 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (playerDistSqr >= mGreetDistanceReset*mGreetDistanceReset * mGreetDistanceMultiplier*mGreetDistanceMultiplier)
|
static float fGreetDistanceReset = MWBase::Environment::get().getWorld()->getStore()
|
||||||
|
.get<ESM::GameSetting>().find("fGreetDistanceReset")->getFloat();
|
||||||
|
|
||||||
|
if (playerDistSqr >= fGreetDistanceReset*fGreetDistanceReset * iGreetDistanceMultiplier*iGreetDistanceMultiplier)
|
||||||
mSaidGreeting = false;
|
mSaidGreeting = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -632,8 +632,11 @@ namespace MWMechanics
|
||||||
|
|
||||||
for(unsigned int counter = 0; counter < mIdle.size(); counter++)
|
for(unsigned int counter = 0; counter < mIdle.size(); counter++)
|
||||||
{
|
{
|
||||||
unsigned short idleChance = mIdleChanceMultiplier * mIdle[counter];
|
static float fIdleChanceMultiplier = MWBase::Environment::get().getWorld()->getStore()
|
||||||
unsigned short randSelect = (int)(rand() / ((double)RAND_MAX + 1) * int(100 / mIdleChanceMultiplier));
|
.get<ESM::GameSetting>().find("fIdleChanceMultiplier")->getFloat();
|
||||||
|
|
||||||
|
unsigned short idleChance = fIdleChanceMultiplier * mIdle[counter];
|
||||||
|
unsigned short randSelect = (int)(rand() / ((double)RAND_MAX + 1) * int(100 / fIdleChanceMultiplier));
|
||||||
if(randSelect < idleChance && randSelect > idleRoll)
|
if(randSelect < idleChance && randSelect > idleRoll)
|
||||||
{
|
{
|
||||||
mPlayedIdle = counter+2;
|
mPlayedIdle = counter+2;
|
||||||
|
@ -641,5 +644,37 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AiWander::writeState(ESM::AiSequence::AiSequence &sequence) const
|
||||||
|
{
|
||||||
|
std::auto_ptr<ESM::AiSequence::AiWander> wander(new ESM::AiSequence::AiWander());
|
||||||
|
wander->mData.mDistance = mDistance;
|
||||||
|
wander->mData.mDuration = mDuration;
|
||||||
|
wander->mData.mTimeOfDay = mTimeOfDay;
|
||||||
|
wander->mStartTime = mStartTime.toEsm();
|
||||||
|
assert (mIdle.size() >= 8);
|
||||||
|
for (int i=0; i<8; ++i)
|
||||||
|
wander->mData.mIdle[i] = mIdle[i];
|
||||||
|
wander->mData.mShouldRepeat = mRepeat;
|
||||||
|
|
||||||
|
ESM::AiSequence::AiPackageContainer package;
|
||||||
|
package.mType = ESM::AiSequence::Ai_Wander;
|
||||||
|
package.mPackage = wander.release();
|
||||||
|
sequence.mPackages.push_back(package);
|
||||||
|
}
|
||||||
|
|
||||||
|
AiWander::AiWander (const ESM::AiSequence::AiWander* wander)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
|
||||||
|
mDistance = wander->mData.mDistance;
|
||||||
|
mDuration = wander->mData.mDuration;
|
||||||
|
mStartTime = MWWorld::TimeStamp(wander->mStartTime);
|
||||||
|
mTimeOfDay = wander->mData.mTimeOfDay;
|
||||||
|
for (int i=0; i<8; ++i)
|
||||||
|
mIdle.push_back(wander->mData.mIdle[i]);
|
||||||
|
|
||||||
|
mRepeat = wander->mData.mShouldRepeat;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,14 @@
|
||||||
|
|
||||||
#include "../mwworld/timestamp.hpp"
|
#include "../mwworld/timestamp.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
namespace AiSequence
|
||||||
|
{
|
||||||
|
struct AiWander;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
/// \brief Causes the Actor to wander within a specified range
|
/// \brief Causes the Actor to wander within a specified range
|
||||||
|
@ -24,7 +32,11 @@ namespace MWMechanics
|
||||||
\param timeOfDay Start time of the package, if it has a duration. Currently unimplemented
|
\param timeOfDay Start time of the package, if it has a duration. Currently unimplemented
|
||||||
\param idle Chances of each idle to play (9 in total)
|
\param idle Chances of each idle to play (9 in total)
|
||||||
\param repeat Repeat wander or not **/
|
\param repeat Repeat wander or not **/
|
||||||
AiWander(int distance, int duration, int timeOfDay, const std::vector<int>& idle, bool repeat);
|
AiWander(int distance, int duration, int timeOfDay, const std::vector<unsigned char>& idle, bool repeat);
|
||||||
|
|
||||||
|
AiWander (const ESM::AiSequence::AiWander* wander);
|
||||||
|
|
||||||
|
void init();
|
||||||
|
|
||||||
virtual AiPackage *clone() const;
|
virtual AiPackage *clone() const;
|
||||||
|
|
||||||
|
@ -36,6 +48,8 @@ namespace MWMechanics
|
||||||
/** In case another AI package moved the actor elsewhere **/
|
/** In case another AI package moved the actor elsewhere **/
|
||||||
void setReturnPosition (const Ogre::Vector3& position);
|
void setReturnPosition (const Ogre::Vector3& position);
|
||||||
|
|
||||||
|
virtual void writeState(ESM::AiSequence::AiSequence &sequence) const;
|
||||||
|
|
||||||
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);
|
||||||
|
@ -45,13 +59,10 @@ namespace MWMechanics
|
||||||
int mDistance; // how far the actor can wander from the spawn point
|
int mDistance; // how far the actor can wander from the spawn point
|
||||||
int mDuration;
|
int mDuration;
|
||||||
int mTimeOfDay;
|
int mTimeOfDay;
|
||||||
std::vector<int> mIdle;
|
std::vector<unsigned char> mIdle;
|
||||||
bool mRepeat;
|
bool mRepeat;
|
||||||
|
|
||||||
bool mSaidGreeting;
|
bool mSaidGreeting;
|
||||||
int mGreetDistanceMultiplier;
|
|
||||||
float mGreetDistanceReset;
|
|
||||||
float mChance;
|
|
||||||
|
|
||||||
bool mHasReturnPosition; // NOTE: Could be removed if mReturnPosition was initialized to actor position,
|
bool mHasReturnPosition; // NOTE: Could be removed if mReturnPosition was initialized to actor position,
|
||||||
// if we had the actor in the AiWander constructor...
|
// if we had the actor in the AiWander constructor...
|
||||||
|
@ -74,7 +85,6 @@ namespace MWMechanics
|
||||||
bool mMoveNow;
|
bool mMoveNow;
|
||||||
bool mWalking;
|
bool mWalking;
|
||||||
|
|
||||||
float mIdleChanceMultiplier;
|
|
||||||
unsigned short mPlayedIdle;
|
unsigned short mPlayedIdle;
|
||||||
|
|
||||||
MWWorld::TimeStamp mStartTime;
|
MWWorld::TimeStamp mStartTime;
|
||||||
|
|
|
@ -503,6 +503,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
mSpells.writeState(state.mSpells);
|
mSpells.writeState(state.mSpells);
|
||||||
mActiveSpells.writeState(state.mActiveSpells);
|
mActiveSpells.writeState(state.mActiveSpells);
|
||||||
|
mAiSequence.writeState(state.mAiSequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreatureStats::readState (const ESM::CreatureStats& state)
|
void CreatureStats::readState (const ESM::CreatureStats& state)
|
||||||
|
@ -543,6 +544,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
mSpells.readState(state.mSpells);
|
mSpells.readState(state.mSpells);
|
||||||
mActiveSpells.readState(state.mActiveSpells);
|
mActiveSpells.readState(state.mActiveSpells);
|
||||||
|
mAiSequence.readState(state.mAiSequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreatureStats::setLastRestockTime(MWWorld::TimeStamp tradeTime)
|
void CreatureStats::setLastRestockTime(MWWorld::TimeStamp tradeTime)
|
||||||
|
|
|
@ -186,7 +186,7 @@ namespace MWScript
|
||||||
Interpreter::Type_Integer time = runtime[0].mFloat;
|
Interpreter::Type_Integer time = runtime[0].mFloat;
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
|
|
||||||
std::vector<int> idleList;
|
std::vector<unsigned char> idleList;
|
||||||
bool repeat = false;
|
bool repeat = false;
|
||||||
|
|
||||||
for(int i=1; i < 10 && arg0; ++i)
|
for(int i=1; i < 10 && arg0; ++i)
|
||||||
|
@ -194,6 +194,7 @@ namespace MWScript
|
||||||
if(!repeat)
|
if(!repeat)
|
||||||
repeat = true;
|
repeat = true;
|
||||||
Interpreter::Type_Integer idleValue = runtime[0].mInteger;
|
Interpreter::Type_Integer idleValue = runtime[0].mInteger;
|
||||||
|
idleValue = std::min(255, std::max(0, idleValue));
|
||||||
idleList.push_back(idleValue);
|
idleList.push_back(idleValue);
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
--arg0;
|
--arg0;
|
||||||
|
|
|
@ -42,6 +42,7 @@ add_component_dir (esm
|
||||||
loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter
|
loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter
|
||||||
savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap lightstate inventorystate containerstate npcstate creaturestate dialoguestate statstate
|
savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap lightstate inventorystate containerstate npcstate creaturestate dialoguestate statstate
|
||||||
npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate
|
npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate
|
||||||
|
aisequence
|
||||||
)
|
)
|
||||||
|
|
||||||
add_component_dir (misc
|
add_component_dir (misc
|
||||||
|
|
211
components/esm/aisequence.cpp
Normal file
211
components/esm/aisequence.cpp
Normal file
|
@ -0,0 +1,211 @@
|
||||||
|
#include "aisequence.hpp"
|
||||||
|
|
||||||
|
#include "esmreader.hpp"
|
||||||
|
#include "esmwriter.hpp"
|
||||||
|
|
||||||
|
#include "defs.hpp"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
namespace AiSequence
|
||||||
|
{
|
||||||
|
|
||||||
|
void AiWander::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
esm.getHNT (mData, "DATA");
|
||||||
|
esm.getHNT(mStartTime, "STAR");
|
||||||
|
}
|
||||||
|
|
||||||
|
void AiWander::save(ESMWriter &esm) const
|
||||||
|
{
|
||||||
|
esm.writeHNT ("DATA", mData);
|
||||||
|
esm.writeHNT ("STAR", mStartTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AiTravel::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
esm.getHNT (mData, "DATA");
|
||||||
|
}
|
||||||
|
|
||||||
|
void AiTravel::save(ESMWriter &esm) const
|
||||||
|
{
|
||||||
|
esm.writeHNT ("DATA", mData);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AiEscort::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
esm.getHNT (mData, "DATA");
|
||||||
|
mTargetId = esm.getHNString("TARG");
|
||||||
|
esm.getHNT (mRemainingDuration, "DURA");
|
||||||
|
mCellId = esm.getHNOString ("CELL");
|
||||||
|
}
|
||||||
|
|
||||||
|
void AiEscort::save(ESMWriter &esm) const
|
||||||
|
{
|
||||||
|
esm.writeHNT ("DATA", mData);
|
||||||
|
esm.writeHNString ("TARG", mTargetId);
|
||||||
|
esm.writeHNT ("DURA", mRemainingDuration);
|
||||||
|
if (!mCellId.empty())
|
||||||
|
esm.writeHNString ("CELL", mCellId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AiFollow::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
esm.getHNT (mData, "DATA");
|
||||||
|
mTargetId = esm.getHNString("TARG");
|
||||||
|
esm.getHNT (mRemainingDuration, "DURA");
|
||||||
|
mCellId = esm.getHNOString ("CELL");
|
||||||
|
esm.getHNT (mAlwaysFollow, "ALWY");
|
||||||
|
}
|
||||||
|
|
||||||
|
void AiFollow::save(ESMWriter &esm) const
|
||||||
|
{
|
||||||
|
esm.writeHNT ("DATA", mData);
|
||||||
|
esm.writeHNString("TARG", mTargetId);
|
||||||
|
esm.writeHNT ("DURA", mRemainingDuration);
|
||||||
|
if (!mCellId.empty())
|
||||||
|
esm.writeHNString ("CELL", mCellId);
|
||||||
|
esm.writeHNT ("ALWY", mAlwaysFollow);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AiActivate::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
mTargetId = esm.getHNString("TARG");
|
||||||
|
}
|
||||||
|
|
||||||
|
void AiActivate::save(ESMWriter &esm) const
|
||||||
|
{
|
||||||
|
esm.writeHNString("TARG", mTargetId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AiCombat::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
esm.getHNT (mTargetActorId, "TARG");
|
||||||
|
}
|
||||||
|
|
||||||
|
void AiCombat::save(ESMWriter &esm) const
|
||||||
|
{
|
||||||
|
esm.writeHNT ("TARG", mTargetActorId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AiPursue::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
esm.getHNT (mTargetActorId, "TARG");
|
||||||
|
}
|
||||||
|
|
||||||
|
void AiPursue::save(ESMWriter &esm) const
|
||||||
|
{
|
||||||
|
esm.writeHNT ("TARG", mTargetActorId);
|
||||||
|
}
|
||||||
|
|
||||||
|
AiSequence::~AiSequence()
|
||||||
|
{
|
||||||
|
for (std::vector<AiPackageContainer>::iterator it = mPackages.begin(); it != mPackages.end(); ++it)
|
||||||
|
delete it->mPackage;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AiSequence::save(ESMWriter &esm) const
|
||||||
|
{
|
||||||
|
for (std::vector<AiPackageContainer>::const_iterator it = mPackages.begin(); it != mPackages.end(); ++it)
|
||||||
|
{
|
||||||
|
esm.writeHNT ("AIPK", it->mType);
|
||||||
|
switch (it->mType)
|
||||||
|
{
|
||||||
|
case Ai_Wander:
|
||||||
|
static_cast<const AiWander*>(it->mPackage)->save(esm);
|
||||||
|
break;
|
||||||
|
case Ai_Travel:
|
||||||
|
static_cast<const AiTravel*>(it->mPackage)->save(esm);
|
||||||
|
break;
|
||||||
|
case Ai_Escort:
|
||||||
|
static_cast<const AiEscort*>(it->mPackage)->save(esm);
|
||||||
|
break;
|
||||||
|
case Ai_Follow:
|
||||||
|
static_cast<const AiFollow*>(it->mPackage)->save(esm);
|
||||||
|
break;
|
||||||
|
case Ai_Activate:
|
||||||
|
static_cast<const AiActivate*>(it->mPackage)->save(esm);
|
||||||
|
break;
|
||||||
|
case Ai_Combat:
|
||||||
|
static_cast<const AiCombat*>(it->mPackage)->save(esm);
|
||||||
|
break;
|
||||||
|
case Ai_Pursue:
|
||||||
|
static_cast<const AiPursue*>(it->mPackage)->save(esm);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AiSequence::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
while (esm.isNextSub("AIPK"))
|
||||||
|
{
|
||||||
|
int type;
|
||||||
|
esm.getHT(type);
|
||||||
|
|
||||||
|
mPackages.push_back(AiPackageContainer());
|
||||||
|
mPackages.back().mType = type;
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case Ai_Wander:
|
||||||
|
{
|
||||||
|
std::auto_ptr<AiWander> ptr (new AiWander());
|
||||||
|
ptr->load(esm);
|
||||||
|
mPackages.back().mPackage = ptr.release();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Ai_Travel:
|
||||||
|
{
|
||||||
|
std::auto_ptr<AiTravel> ptr (new AiTravel());
|
||||||
|
ptr->load(esm);
|
||||||
|
mPackages.back().mPackage = ptr.release();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Ai_Escort:
|
||||||
|
{
|
||||||
|
std::auto_ptr<AiEscort> ptr (new AiEscort());
|
||||||
|
ptr->load(esm);
|
||||||
|
mPackages.back().mPackage = ptr.release();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Ai_Follow:
|
||||||
|
{
|
||||||
|
std::auto_ptr<AiFollow> ptr (new AiFollow());
|
||||||
|
ptr->load(esm);
|
||||||
|
mPackages.back().mPackage = ptr.release();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Ai_Activate:
|
||||||
|
{
|
||||||
|
std::auto_ptr<AiActivate> ptr (new AiActivate());
|
||||||
|
ptr->load(esm);
|
||||||
|
mPackages.back().mPackage = ptr.release();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Ai_Combat:
|
||||||
|
{
|
||||||
|
std::auto_ptr<AiCombat> ptr (new AiCombat());
|
||||||
|
ptr->load(esm);
|
||||||
|
mPackages.back().mPackage = ptr.release();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Ai_Pursue:
|
||||||
|
{
|
||||||
|
std::auto_ptr<AiPursue> ptr (new AiPursue());
|
||||||
|
ptr->load(esm);
|
||||||
|
mPackages.back().mPackage = ptr.release();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
154
components/esm/aisequence.hpp
Normal file
154
components/esm/aisequence.hpp
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
#ifndef OPENMW_COMPONENTS_ESM_AISEQUENCE_H
|
||||||
|
#define OPENMW_COMPONENTS_ESM_AISEQUENCE_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "defs.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
class ESMReader;
|
||||||
|
class ESMWriter;
|
||||||
|
|
||||||
|
namespace AiSequence
|
||||||
|
{
|
||||||
|
|
||||||
|
// format 0, saved games only
|
||||||
|
// As opposed to AiPackageList, this stores the "live" version of AI packages.
|
||||||
|
|
||||||
|
enum AiPackages
|
||||||
|
{
|
||||||
|
Ai_Wander = ESM::FourCC<'W','A','N','D'>::value,
|
||||||
|
Ai_Travel = ESM::FourCC<'T','R','A','V'>::value,
|
||||||
|
Ai_Escort = ESM::FourCC<'E','S','C','O'>::value,
|
||||||
|
Ai_Follow = ESM::FourCC<'F','O','L','L'>::value,
|
||||||
|
Ai_Activate = ESM::FourCC<'A','C','T','I'>::value,
|
||||||
|
Ai_Combat = ESM::FourCC<'C','O','M','B'>::value,
|
||||||
|
Ai_Pursue = ESM::FourCC<'P','U','R','S'>::value
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct AiPackage
|
||||||
|
{
|
||||||
|
virtual ~AiPackage() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#pragma pack(push,1)
|
||||||
|
struct AiWanderData
|
||||||
|
{
|
||||||
|
short mDistance;
|
||||||
|
short mDuration;
|
||||||
|
unsigned char mTimeOfDay;
|
||||||
|
unsigned char mIdle[8];
|
||||||
|
unsigned char mShouldRepeat;
|
||||||
|
};
|
||||||
|
struct AiTravelData
|
||||||
|
{
|
||||||
|
float mX, mY, mZ;
|
||||||
|
};
|
||||||
|
struct AiEscortData
|
||||||
|
{
|
||||||
|
float mX, mY, mZ;
|
||||||
|
short mDuration;
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
struct AiWander : AiPackage
|
||||||
|
{
|
||||||
|
AiWanderData mData;
|
||||||
|
ESM::TimeStamp mStartTime;
|
||||||
|
|
||||||
|
/// \todo add more AiWander state
|
||||||
|
|
||||||
|
void load(ESMReader &esm);
|
||||||
|
void save(ESMWriter &esm) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AiTravel : AiPackage
|
||||||
|
{
|
||||||
|
AiTravelData mData;
|
||||||
|
|
||||||
|
void load(ESMReader &esm);
|
||||||
|
void save(ESMWriter &esm) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AiEscort : AiPackage
|
||||||
|
{
|
||||||
|
AiEscortData mData;
|
||||||
|
|
||||||
|
std::string mTargetId;
|
||||||
|
std::string mCellId;
|
||||||
|
float mRemainingDuration;
|
||||||
|
|
||||||
|
void load(ESMReader &esm);
|
||||||
|
void save(ESMWriter &esm) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AiFollow : AiPackage
|
||||||
|
{
|
||||||
|
AiEscortData mData;
|
||||||
|
|
||||||
|
std::string mTargetId;
|
||||||
|
std::string mCellId;
|
||||||
|
float mRemainingDuration;
|
||||||
|
|
||||||
|
bool mAlwaysFollow;
|
||||||
|
|
||||||
|
void load(ESMReader &esm);
|
||||||
|
void save(ESMWriter &esm) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AiActivate : AiPackage
|
||||||
|
{
|
||||||
|
std::string mTargetId;
|
||||||
|
|
||||||
|
void load(ESMReader &esm);
|
||||||
|
void save(ESMWriter &esm) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AiCombat : AiPackage
|
||||||
|
{
|
||||||
|
int mTargetActorId;
|
||||||
|
|
||||||
|
void load(ESMReader &esm);
|
||||||
|
void save(ESMWriter &esm) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AiPursue : AiPackage
|
||||||
|
{
|
||||||
|
int mTargetActorId;
|
||||||
|
|
||||||
|
void load(ESMReader &esm);
|
||||||
|
void save(ESMWriter &esm) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AiPackageContainer
|
||||||
|
{
|
||||||
|
int mType;
|
||||||
|
|
||||||
|
AiPackage* mPackage;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AiSequence
|
||||||
|
{
|
||||||
|
AiSequence() {}
|
||||||
|
~AiSequence();
|
||||||
|
|
||||||
|
std::vector<AiPackageContainer> mPackages;
|
||||||
|
|
||||||
|
void load (ESMReader &esm);
|
||||||
|
void save (ESMWriter &esm) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
AiSequence(const AiSequence&);
|
||||||
|
AiSequence& operator=(const AiSequence&);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -79,6 +79,7 @@ void ESM::CreatureStats::load (ESMReader &esm)
|
||||||
|
|
||||||
mSpells.load(esm);
|
mSpells.load(esm);
|
||||||
mActiveSpells.load(esm);
|
mActiveSpells.load(esm);
|
||||||
|
mAiSequence.load(esm);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESM::CreatureStats::save (ESMWriter &esm) const
|
void ESM::CreatureStats::save (ESMWriter &esm) const
|
||||||
|
@ -160,4 +161,5 @@ void ESM::CreatureStats::save (ESMWriter &esm) const
|
||||||
|
|
||||||
mSpells.save(esm);
|
mSpells.save(esm);
|
||||||
mActiveSpells.save(esm);
|
mActiveSpells.save(esm);
|
||||||
|
mAiSequence.save(esm);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include "spellstate.hpp"
|
#include "spellstate.hpp"
|
||||||
#include "activespells.hpp"
|
#include "activespells.hpp"
|
||||||
|
#include "aisequence.hpp"
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
|
@ -23,6 +24,8 @@ namespace ESM
|
||||||
StatState<int> mAttributes[8];
|
StatState<int> mAttributes[8];
|
||||||
StatState<float> mDynamic[3];
|
StatState<float> mDynamic[3];
|
||||||
|
|
||||||
|
AiSequence::AiSequence mAiSequence;
|
||||||
|
|
||||||
ESM::TimeStamp mTradeTime;
|
ESM::TimeStamp mTradeTime;
|
||||||
int mGoldPool;
|
int mGoldPool;
|
||||||
int mActorId;
|
int mActorId;
|
||||||
|
|
Loading…
Reference in a new issue