mirror of
https://github.com/OpenMW/openmw.git
synced 2025-02-21 11:39:44 +00:00
Merge pull request #2891 from elsid/ai_packages_options
Replace AiPackage virtual methods by options
This commit is contained in:
commit
d5d385fe9e
26 changed files with 218 additions and 196 deletions
|
@ -44,11 +44,6 @@ namespace MWMechanics
|
|||
return false;
|
||||
}
|
||||
|
||||
int AiActivate::getTypeId() const
|
||||
{
|
||||
return TypeIdActivate;
|
||||
}
|
||||
|
||||
void AiActivate::writeState(ESM::AiSequence::AiSequence &sequence) const
|
||||
{
|
||||
std::unique_ptr<ESM::AiSequence::AiActivate> activate(new ESM::AiSequence::AiActivate());
|
||||
|
|
|
@ -29,7 +29,8 @@ namespace MWMechanics
|
|||
AiActivate(const ESM::AiSequence::AiActivate* activate);
|
||||
|
||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
int getTypeId() const final;
|
||||
|
||||
static constexpr TypeId getTypeId() { return TypeIdActivate; }
|
||||
|
||||
void writeState(ESM::AiSequence::AiSequence& sequence) const final;
|
||||
|
||||
|
|
|
@ -72,16 +72,6 @@ bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, CharacterCont
|
|||
return false;
|
||||
}
|
||||
|
||||
int MWMechanics::AiAvoidDoor::getTypeId() const
|
||||
{
|
||||
return TypeIdAvoidDoor;
|
||||
}
|
||||
|
||||
unsigned int MWMechanics::AiAvoidDoor::getPriority() const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
bool MWMechanics::AiAvoidDoor::isStuck(const osg::Vec3f& actorPos) const
|
||||
{
|
||||
return (actorPos - mLastPos).length2() < 10 * 10;
|
||||
|
|
|
@ -24,12 +24,16 @@ namespace MWMechanics
|
|||
|
||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
|
||||
int getTypeId() const final;
|
||||
static constexpr TypeId getTypeId() { return TypeIdAvoidDoor; }
|
||||
|
||||
unsigned int getPriority() const final;
|
||||
|
||||
bool canCancel() const final { return false; }
|
||||
bool shouldCancelPreviousAi() const final { return false; }
|
||||
static constexpr Options makeDefaultOptions()
|
||||
{
|
||||
AiPackage::Options options;
|
||||
options.mPriority = 2;
|
||||
options.mCanCancel = false;
|
||||
options.mShouldCancelPreviousAi = false;
|
||||
return options;
|
||||
}
|
||||
|
||||
private:
|
||||
float mDuration;
|
||||
|
|
|
@ -31,13 +31,3 @@ bool MWMechanics::AiBreathe::execute (const MWWorld::Ptr& actor, CharacterContro
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
int MWMechanics::AiBreathe::getTypeId() const
|
||||
{
|
||||
return TypeIdBreathe;
|
||||
}
|
||||
|
||||
unsigned int MWMechanics::AiBreathe::getPriority() const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
|
|
@ -12,13 +12,16 @@ namespace MWMechanics
|
|||
public:
|
||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
|
||||
int getTypeId() const final;
|
||||
static constexpr TypeId getTypeId() { return TypeIdBreathe; }
|
||||
|
||||
unsigned int getPriority() const final;
|
||||
|
||||
bool canCancel() const final { return false; }
|
||||
bool shouldCancelPreviousAi() const final { return false; }
|
||||
static constexpr Options makeDefaultOptions()
|
||||
{
|
||||
AiPackage::Options options;
|
||||
options.mPriority = 2;
|
||||
options.mCanCancel = false;
|
||||
options.mShouldCancelPreviousAi = false;
|
||||
return options;
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -89,13 +89,3 @@ MWWorld::Ptr MWMechanics::AiCast::getTarget() const
|
|||
|
||||
return target;
|
||||
}
|
||||
|
||||
int MWMechanics::AiCast::getTypeId() const
|
||||
{
|
||||
return AiPackage::TypeIdCast;
|
||||
}
|
||||
|
||||
unsigned int MWMechanics::AiCast::getPriority() const
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
|
|
@ -17,14 +17,18 @@ namespace MWMechanics
|
|||
|
||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
|
||||
int getTypeId() const final;
|
||||
static constexpr TypeId getTypeId() { return TypeIdCast; }
|
||||
|
||||
MWWorld::Ptr getTarget() const final;
|
||||
|
||||
unsigned int getPriority() const final;
|
||||
|
||||
bool canCancel() const final { return false; }
|
||||
bool shouldCancelPreviousAi() const final { return false; }
|
||||
static constexpr Options makeDefaultOptions()
|
||||
{
|
||||
AiPackage::Options options;
|
||||
options.mPriority = 3;
|
||||
options.mCanCancel = false;
|
||||
options.mShouldCancelPreviousAi = false;
|
||||
return options;
|
||||
}
|
||||
|
||||
private:
|
||||
const std::string mTargetId;
|
||||
|
|
|
@ -406,16 +406,6 @@ namespace MWMechanics
|
|||
}
|
||||
}
|
||||
|
||||
int AiCombat::getTypeId() const
|
||||
{
|
||||
return TypeIdCombat;
|
||||
}
|
||||
|
||||
unsigned int AiCombat::getPriority() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
MWWorld::Ptr AiCombat::getTarget() const
|
||||
{
|
||||
return MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId);
|
||||
|
|
|
@ -104,18 +104,22 @@ namespace MWMechanics
|
|||
|
||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
|
||||
int getTypeId() const final;
|
||||
static constexpr TypeId getTypeId() { return TypeIdCombat; }
|
||||
|
||||
unsigned int getPriority() const final;
|
||||
static constexpr Options makeDefaultOptions()
|
||||
{
|
||||
AiPackage::Options options;
|
||||
options.mPriority = 1;
|
||||
options.mCanCancel = false;
|
||||
options.mShouldCancelPreviousAi = false;
|
||||
return options;
|
||||
}
|
||||
|
||||
///Returns target ID
|
||||
MWWorld::Ptr getTarget() const final;
|
||||
|
||||
void writeState(ESM::AiSequence::AiSequence &sequence) const final;
|
||||
|
||||
bool canCancel() const final { return false; }
|
||||
bool shouldCancelPreviousAi() const final { return false; }
|
||||
|
||||
private:
|
||||
/// Returns true if combat should end
|
||||
bool attack(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, AiCombatStorage& storage, CharacterController& characterController);
|
||||
|
|
|
@ -95,11 +95,6 @@ namespace MWMechanics
|
|||
return false;
|
||||
}
|
||||
|
||||
int AiEscort::getTypeId() const
|
||||
{
|
||||
return TypeIdEscort;
|
||||
}
|
||||
|
||||
void AiEscort::writeState(ESM::AiSequence::AiSequence &sequence) const
|
||||
{
|
||||
std::unique_ptr<ESM::AiSequence::AiEscort> escort(new ESM::AiSequence::AiEscort());
|
||||
|
|
|
@ -32,11 +32,15 @@ namespace MWMechanics
|
|||
|
||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
|
||||
int getTypeId() const final;
|
||||
static constexpr TypeId getTypeId() { return TypeIdEscort; }
|
||||
|
||||
bool useVariableSpeed() const final { return true; }
|
||||
|
||||
bool sideWithTarget() const final { return true; }
|
||||
static constexpr Options makeDefaultOptions()
|
||||
{
|
||||
AiPackage::Options options;
|
||||
options.mUseVariableSpeed = true;
|
||||
options.mSideWithTarget = true;
|
||||
return options;
|
||||
}
|
||||
|
||||
void writeState(ESM::AiSequence::AiSequence &sequence) const final;
|
||||
|
||||
|
|
|
@ -14,13 +14,3 @@ bool MWMechanics::AiFace::execute(const MWWorld::Ptr& actor, MWMechanics::Charac
|
|||
osg::Vec3f dir = osg::Vec3f(mTargetX, mTargetY, 0) - actor.getRefData().getPosition().asVec3();
|
||||
return zTurn(actor, std::atan2(dir.x(), dir.y()), osg::DegreesToRadians(3.f));
|
||||
}
|
||||
|
||||
int MWMechanics::AiFace::getTypeId() const
|
||||
{
|
||||
return AiPackage::TypeIdFace;
|
||||
}
|
||||
|
||||
unsigned int MWMechanics::AiFace::getPriority() const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
|
|
@ -12,12 +12,16 @@ namespace MWMechanics
|
|||
|
||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
|
||||
int getTypeId() const final;
|
||||
static constexpr TypeId getTypeId() { return TypeIdFace; }
|
||||
|
||||
unsigned int getPriority() const final;
|
||||
|
||||
bool canCancel() const final { return false; }
|
||||
bool shouldCancelPreviousAi() const final { return false; }
|
||||
static constexpr Options makeDefaultOptions()
|
||||
{
|
||||
AiPackage::Options options;
|
||||
options.mPriority = 2;
|
||||
options.mCanCancel = false;
|
||||
options.mShouldCancelPreviousAi = false;
|
||||
return options;
|
||||
}
|
||||
|
||||
private:
|
||||
const float mTargetX;
|
||||
|
|
|
@ -16,25 +16,24 @@
|
|||
|
||||
namespace MWMechanics
|
||||
{
|
||||
|
||||
int AiFollow::mFollowIndexCounter = 0;
|
||||
|
||||
AiFollow::AiFollow(const std::string &actorId, float duration, float x, float y, float z)
|
||||
: mAlwaysFollow(false), mCommanded(false), mDuration(duration), mRemainingDuration(duration), mX(x), mY(y), mZ(z)
|
||||
: mAlwaysFollow(false), mDuration(duration), mRemainingDuration(duration), mX(x), mY(y), mZ(z)
|
||||
, mCellId(""), mActive(false), mFollowIndex(mFollowIndexCounter++)
|
||||
{
|
||||
mTargetActorRefId = actorId;
|
||||
}
|
||||
|
||||
AiFollow::AiFollow(const std::string &actorId, const std::string &cellId, float duration, float x, float y, float z)
|
||||
: mAlwaysFollow(false), mCommanded(false), mDuration(duration), mRemainingDuration(duration), mX(x), mY(y), mZ(z)
|
||||
: mAlwaysFollow(false), mDuration(duration), mRemainingDuration(duration), mX(x), mY(y), mZ(z)
|
||||
, mCellId(cellId), mActive(false), mFollowIndex(mFollowIndexCounter++)
|
||||
{
|
||||
mTargetActorRefId = actorId;
|
||||
}
|
||||
|
||||
AiFollow::AiFollow(const MWWorld::Ptr& actor, float duration, float x, float y, float z)
|
||||
: mAlwaysFollow(false), mCommanded(false), mDuration(duration), mRemainingDuration(duration), mX(x), mY(y), mZ(z)
|
||||
: mAlwaysFollow(false), mDuration(duration), mRemainingDuration(duration), mX(x), mY(y), mZ(z)
|
||||
, mCellId(""), mActive(false), mFollowIndex(mFollowIndexCounter++)
|
||||
{
|
||||
mTargetActorRefId = actor.getCellRef().getRefId();
|
||||
|
@ -42,7 +41,7 @@ AiFollow::AiFollow(const MWWorld::Ptr& actor, float duration, float x, float y,
|
|||
}
|
||||
|
||||
AiFollow::AiFollow(const MWWorld::Ptr& actor, const std::string &cellId, float duration, float x, float y, float z)
|
||||
: mAlwaysFollow(false), mCommanded(false), mDuration(duration), mRemainingDuration(duration), mX(x), mY(y), mZ(z)
|
||||
: mAlwaysFollow(false), mDuration(duration), mRemainingDuration(duration), mX(x), mY(y), mZ(z)
|
||||
, mCellId(cellId), mActive(false), mFollowIndex(mFollowIndexCounter++)
|
||||
{
|
||||
mTargetActorRefId = actor.getCellRef().getRefId();
|
||||
|
@ -50,7 +49,8 @@ AiFollow::AiFollow(const MWWorld::Ptr& actor, const std::string &cellId, float d
|
|||
}
|
||||
|
||||
AiFollow::AiFollow(const MWWorld::Ptr& actor, bool commanded)
|
||||
: mAlwaysFollow(true), mCommanded(commanded), mDuration(0), mRemainingDuration(0), mX(0), mY(0), mZ(0)
|
||||
: TypedAiPackage<AiFollow>(makeDefaultOptions().withShouldCancelPreviousAi(!commanded))
|
||||
, mAlwaysFollow(true), mDuration(0), mRemainingDuration(0), mX(0), mY(0), mZ(0)
|
||||
, mCellId(""), mActive(false), mFollowIndex(mFollowIndexCounter++)
|
||||
{
|
||||
mTargetActorRefId = actor.getCellRef().getRefId();
|
||||
|
@ -58,7 +58,8 @@ AiFollow::AiFollow(const MWWorld::Ptr& actor, bool commanded)
|
|||
}
|
||||
|
||||
AiFollow::AiFollow(const ESM::AiSequence::AiFollow *follow)
|
||||
: mAlwaysFollow(follow->mAlwaysFollow), mCommanded(follow->mCommanded)
|
||||
: TypedAiPackage<AiFollow>(makeDefaultOptions().withShouldCancelPreviousAi(!follow->mCommanded))
|
||||
, mAlwaysFollow(follow->mAlwaysFollow)
|
||||
// mDuration isn't saved in the save file, so just giving it "1" for now if the package had a duration.
|
||||
// The exact value of mDuration only matters for repeating packages.
|
||||
// Previously mRemainingDuration could be negative even when mDuration was 0. Checking for > 0 should fix old saves.
|
||||
|
@ -200,14 +201,9 @@ std::string AiFollow::getFollowedActor()
|
|||
return mTargetActorRefId;
|
||||
}
|
||||
|
||||
int AiFollow::getTypeId() const
|
||||
{
|
||||
return TypeIdFollow;
|
||||
}
|
||||
|
||||
bool AiFollow::isCommanded() const
|
||||
{
|
||||
return mCommanded;
|
||||
return !mOptions.mShouldCancelPreviousAi;
|
||||
}
|
||||
|
||||
void AiFollow::writeState(ESM::AiSequence::AiSequence &sequence) const
|
||||
|
@ -221,7 +217,7 @@ void AiFollow::writeState(ESM::AiSequence::AiSequence &sequence) const
|
|||
follow->mRemainingDuration = mRemainingDuration;
|
||||
follow->mCellId = mCellId;
|
||||
follow->mAlwaysFollow = mAlwaysFollow;
|
||||
follow->mCommanded = mCommanded;
|
||||
follow->mCommanded = isCommanded();
|
||||
follow->mActive = mActive;
|
||||
|
||||
ESM::AiSequence::AiPackageContainer package;
|
||||
|
|
|
@ -53,15 +53,18 @@ namespace MWMechanics
|
|||
|
||||
AiFollow(const ESM::AiSequence::AiFollow* follow);
|
||||
|
||||
bool sideWithTarget() const final { return true; }
|
||||
bool followTargetThroughDoors() const final { return true; }
|
||||
bool shouldCancelPreviousAi() const final { return !mCommanded; }
|
||||
|
||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
|
||||
int getTypeId() const final;
|
||||
static constexpr TypeId getTypeId() { return TypeIdFollow; }
|
||||
|
||||
bool useVariableSpeed() const final { return true; }
|
||||
static constexpr Options makeDefaultOptions()
|
||||
{
|
||||
AiPackage::Options options;
|
||||
options.mUseVariableSpeed = true;
|
||||
options.mSideWithTarget = true;
|
||||
options.mFollowTargetThroughDoors = true;
|
||||
return options;
|
||||
}
|
||||
|
||||
/// Returns the actor being followed
|
||||
std::string getFollowedActor();
|
||||
|
@ -87,7 +90,6 @@ namespace MWMechanics
|
|||
/// This will make the actor always follow.
|
||||
/** Thus ignoring mDuration and mX,mY,mZ (used for summoned creatures). **/
|
||||
const bool mAlwaysFollow;
|
||||
const bool mCommanded;
|
||||
const float mDuration; // Hours
|
||||
float mRemainingDuration; // Hours
|
||||
const float mX;
|
||||
|
|
|
@ -24,7 +24,9 @@
|
|||
|
||||
#include <osg/Quat>
|
||||
|
||||
MWMechanics::AiPackage::AiPackage() :
|
||||
MWMechanics::AiPackage::AiPackage(TypeId typeId, const Options& options) :
|
||||
mTypeId(typeId),
|
||||
mOptions(options),
|
||||
mTimer(AI_REACTION_TIME + 1.0f), // to force initial pathbuild
|
||||
mTargetActorRefId(""),
|
||||
mTargetActorId(-1),
|
||||
|
@ -58,31 +60,6 @@ MWWorld::Ptr MWMechanics::AiPackage::getTarget() const
|
|||
return MWWorld::Ptr();
|
||||
}
|
||||
|
||||
bool MWMechanics::AiPackage::sideWithTarget() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MWMechanics::AiPackage::followTargetThroughDoors() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MWMechanics::AiPackage::canCancel() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MWMechanics::AiPackage::shouldCancelPreviousAi() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MWMechanics::AiPackage::getRepeat() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void MWMechanics::AiPackage::reset()
|
||||
{
|
||||
// reset all members
|
||||
|
|
|
@ -55,11 +55,39 @@ namespace MWMechanics
|
|||
TypeIdCast = 11
|
||||
};
|
||||
|
||||
///Default constructor
|
||||
AiPackage();
|
||||
struct Options
|
||||
{
|
||||
unsigned int mPriority = 0;
|
||||
bool mUseVariableSpeed = false;
|
||||
bool mSideWithTarget = false;
|
||||
bool mFollowTargetThroughDoors = false;
|
||||
bool mCanCancel = true;
|
||||
bool mShouldCancelPreviousAi = true;
|
||||
bool mRepeat = false;
|
||||
bool mAlwaysActive = false;
|
||||
|
||||
constexpr Options withRepeat(bool value)
|
||||
{
|
||||
mRepeat = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr Options withShouldCancelPreviousAi(bool value)
|
||||
{
|
||||
mShouldCancelPreviousAi = value;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
AiPackage(TypeId typeId, const Options& options);
|
||||
|
||||
virtual ~AiPackage() = default;
|
||||
|
||||
static constexpr Options makeDefaultOptions()
|
||||
{
|
||||
return Options{};
|
||||
}
|
||||
|
||||
///Clones the package
|
||||
virtual std::unique_ptr<AiPackage> clone() const = 0;
|
||||
|
||||
|
@ -69,13 +97,13 @@ namespace MWMechanics
|
|||
|
||||
/// Returns the TypeID of the AiPackage
|
||||
/// \see enum TypeId
|
||||
virtual int getTypeId() const = 0;
|
||||
TypeId getTypeId() const { return mTypeId; }
|
||||
|
||||
/// Higher number is higher priority (0 being the lowest)
|
||||
virtual unsigned int getPriority() const {return 0;}
|
||||
unsigned int getPriority() const { return mOptions.mPriority; }
|
||||
|
||||
/// Check if package use movement with variable speed
|
||||
virtual bool useVariableSpeed() const { return false;}
|
||||
bool useVariableSpeed() const { return mOptions.mUseVariableSpeed; }
|
||||
|
||||
virtual void writeState (ESM::AiSequence::AiSequence& sequence) const {}
|
||||
|
||||
|
@ -89,24 +117,24 @@ namespace MWMechanics
|
|||
virtual osg::Vec3f getDestination(const MWWorld::Ptr& actor) const { return osg::Vec3f(0, 0, 0); };
|
||||
|
||||
/// Return true if having this AiPackage makes the actor side with the target in fights (default false)
|
||||
virtual bool sideWithTarget() const;
|
||||
bool sideWithTarget() const { return mOptions.mSideWithTarget; }
|
||||
|
||||
/// Return true if the actor should follow the target through teleport doors (default false)
|
||||
virtual bool followTargetThroughDoors() const;
|
||||
bool followTargetThroughDoors() const { return mOptions.mFollowTargetThroughDoors; }
|
||||
|
||||
/// Can this Ai package be canceled? (default true)
|
||||
virtual bool canCancel() const;
|
||||
bool canCancel() const { return mOptions.mCanCancel; }
|
||||
|
||||
/// Upon adding this Ai package, should the Ai Sequence attempt to cancel previous Ai packages (default true)?
|
||||
virtual bool shouldCancelPreviousAi() const;
|
||||
bool shouldCancelPreviousAi() const { return mOptions.mShouldCancelPreviousAi; }
|
||||
|
||||
/// Return true if this package should repeat. Currently only used for Wander packages.
|
||||
virtual bool getRepeat() const;
|
||||
bool getRepeat() const { return mOptions.mRepeat; }
|
||||
|
||||
virtual osg::Vec3f getDestination() const { return osg::Vec3f(0, 0, 0); }
|
||||
|
||||
// Return true if any loaded actor with this AI package must be active.
|
||||
virtual bool alwaysActive() const { return false; }
|
||||
/// Return true if any loaded actor with this AI package must be active.
|
||||
bool alwaysActive() const { return mOptions.mAlwaysActive; }
|
||||
|
||||
/// Reset pathfinding state
|
||||
void reset();
|
||||
|
@ -139,6 +167,9 @@ namespace MWMechanics
|
|||
|
||||
DetourNavigator::Flags getNavigatorFlags(const MWWorld::Ptr& actor) const;
|
||||
|
||||
const TypeId mTypeId;
|
||||
const Options mOptions;
|
||||
|
||||
// TODO: all this does not belong here, move into temporary storage
|
||||
PathFinder mPathFinder;
|
||||
ObstacleCheck mObstacleCheck;
|
||||
|
|
|
@ -66,11 +66,6 @@ bool AiPursue::execute (const MWWorld::Ptr& actor, CharacterController& characte
|
|||
return false;
|
||||
}
|
||||
|
||||
int AiPursue::getTypeId() const
|
||||
{
|
||||
return TypeIdPursue;
|
||||
}
|
||||
|
||||
MWWorld::Ptr AiPursue::getTarget() const
|
||||
{
|
||||
return MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId);
|
||||
|
|
|
@ -27,14 +27,20 @@ namespace MWMechanics
|
|||
AiPursue(const ESM::AiSequence::AiPursue* pursue);
|
||||
|
||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
int getTypeId() const final;
|
||||
|
||||
static constexpr TypeId getTypeId() { return TypeIdPursue; }
|
||||
|
||||
static constexpr Options makeDefaultOptions()
|
||||
{
|
||||
AiPackage::Options options;
|
||||
options.mCanCancel = false;
|
||||
options.mShouldCancelPreviousAi = false;
|
||||
return options;
|
||||
}
|
||||
|
||||
MWWorld::Ptr getTarget() const final;
|
||||
|
||||
void writeState (ESM::AiSequence::AiSequence& sequence) const final;
|
||||
|
||||
bool canCancel() const final { return false; }
|
||||
bool shouldCancelPreviousAi() const final { return false; }
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -338,7 +338,7 @@ void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor, boo
|
|||
dest = actor.getRefData().getPosition().asVec3();
|
||||
}
|
||||
|
||||
MWMechanics::AiTravel travelPackage(dest.x(), dest.y(), dest.z(), true);
|
||||
MWMechanics::AiInternalTravel travelPackage(dest.x(), dest.y(), dest.z());
|
||||
stack(travelPackage, actor, false);
|
||||
}
|
||||
|
||||
|
@ -478,7 +478,11 @@ void AiSequence::readState(const ESM::AiSequence::AiSequence &sequence)
|
|||
}
|
||||
case ESM::AiSequence::Ai_Travel:
|
||||
{
|
||||
package.reset(new AiTravel(static_cast<ESM::AiSequence::AiTravel*>(it->mPackage)));
|
||||
const auto source = static_cast<const ESM::AiSequence::AiTravel*>(it->mPackage);
|
||||
if (source->mHidden)
|
||||
package.reset(new AiInternalTravel(source));
|
||||
else
|
||||
package.reset(new AiTravel(source));
|
||||
break;
|
||||
}
|
||||
case ESM::AiSequence::Ai_Escort:
|
||||
|
|
|
@ -27,14 +27,26 @@ bool isWithinMaxRange(const osg::Vec3f& pos1, const osg::Vec3f& pos2)
|
|||
|
||||
namespace MWMechanics
|
||||
{
|
||||
AiTravel::AiTravel(float x, float y, float z, bool hidden)
|
||||
: mX(x),mY(y),mZ(z),mHidden(hidden)
|
||||
AiTravel::AiTravel(float x, float y, float z, AiTravel*)
|
||||
: mX(x), mY(y), mZ(z), mHidden(false)
|
||||
{
|
||||
}
|
||||
|
||||
AiTravel::AiTravel(float x, float y, float z, AiInternalTravel* derived)
|
||||
: TypedAiPackage<AiTravel>(derived), mX(x), mY(y), mZ(z), mHidden(true)
|
||||
{
|
||||
}
|
||||
|
||||
AiTravel::AiTravel(float x, float y, float z)
|
||||
: AiTravel(x, y, z, this)
|
||||
{
|
||||
}
|
||||
|
||||
AiTravel::AiTravel(const ESM::AiSequence::AiTravel *travel)
|
||||
: mX(travel->mData.mX), mY(travel->mData.mY), mZ(travel->mData.mZ), mHidden(travel->mHidden)
|
||||
: mX(travel->mData.mX), mY(travel->mData.mY), mZ(travel->mData.mZ), mHidden(false)
|
||||
{
|
||||
// Hidden ESM::AiSequence::AiTravel package should be converted into MWMechanics::AiInternalTravel type
|
||||
assert(!travel->mHidden);
|
||||
}
|
||||
|
||||
bool AiTravel::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
|
||||
|
@ -78,11 +90,6 @@ namespace MWMechanics
|
|||
return false;
|
||||
}
|
||||
|
||||
int AiTravel::getTypeId() const
|
||||
{
|
||||
return mHidden ? TypeIdInternalTravel : TypeIdTravel;
|
||||
}
|
||||
|
||||
void AiTravel::fastForward(const MWWorld::Ptr& actor, AiState& state)
|
||||
{
|
||||
if (!isWithinMaxRange(osg::Vec3f(mX, mY, mZ), actor.getRefData().getPosition().asVec3()))
|
||||
|
@ -107,5 +114,20 @@ namespace MWMechanics
|
|||
package.mPackage = travel.release();
|
||||
sequence.mPackages.push_back(package);
|
||||
}
|
||||
|
||||
AiInternalTravel::AiInternalTravel(float x, float y, float z)
|
||||
: AiTravel(x, y, z, this)
|
||||
{
|
||||
}
|
||||
|
||||
AiInternalTravel::AiInternalTravel(const ESM::AiSequence::AiTravel* travel)
|
||||
: AiTravel(travel->mData.mX, travel->mData.mY, travel->mData.mZ, this)
|
||||
{
|
||||
}
|
||||
|
||||
std::unique_ptr<AiPackage> AiInternalTravel::clone() const
|
||||
{
|
||||
return std::make_unique<AiInternalTravel>(*this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,12 +13,18 @@ namespace AiSequence
|
|||
|
||||
namespace MWMechanics
|
||||
{
|
||||
struct AiInternalTravel;
|
||||
|
||||
/// \brief Causes the AI to travel to the specified point
|
||||
class AiTravel final : public TypedAiPackage<AiTravel>
|
||||
class AiTravel : public TypedAiPackage<AiTravel>
|
||||
{
|
||||
public:
|
||||
/// Default constructor
|
||||
AiTravel(float x, float y, float z, bool hidden = false);
|
||||
AiTravel(float x, float y, float z, AiTravel* derived);
|
||||
|
||||
AiTravel(float x, float y, float z, AiInternalTravel* derived);
|
||||
|
||||
AiTravel(float x, float y, float z);
|
||||
|
||||
AiTravel(const ESM::AiSequence::AiTravel* travel);
|
||||
|
||||
/// Simulates the passing of time
|
||||
|
@ -28,11 +34,15 @@ namespace MWMechanics
|
|||
|
||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
|
||||
int getTypeId() const final;
|
||||
static constexpr TypeId getTypeId() { return TypeIdTravel; }
|
||||
|
||||
bool useVariableSpeed() const final { return true; }
|
||||
|
||||
bool alwaysActive() const final { return true; }
|
||||
static constexpr Options makeDefaultOptions()
|
||||
{
|
||||
AiPackage::Options options;
|
||||
options.mUseVariableSpeed = true;
|
||||
options.mAlwaysActive = true;
|
||||
return options;
|
||||
}
|
||||
|
||||
osg::Vec3f getDestination() const final { return osg::Vec3f(mX, mY, mZ); }
|
||||
|
||||
|
@ -43,6 +53,17 @@ namespace MWMechanics
|
|||
|
||||
const bool mHidden;
|
||||
};
|
||||
|
||||
struct AiInternalTravel final : public AiTravel
|
||||
{
|
||||
AiInternalTravel(float x, float y, float z);
|
||||
|
||||
explicit AiInternalTravel(const ESM::AiSequence::AiTravel* travel);
|
||||
|
||||
static constexpr TypeId getTypeId() { return TypeIdInternalTravel; }
|
||||
|
||||
std::unique_ptr<AiPackage> clone() const final;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -113,11 +113,12 @@ namespace MWMechanics
|
|||
}
|
||||
|
||||
AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<unsigned char>& idle, bool repeat):
|
||||
TypedAiPackage<AiWander>(makeDefaultOptions().withRepeat(repeat)),
|
||||
mDistance(std::max(0, distance)),
|
||||
mDuration(std::max(0, duration)),
|
||||
mRemainingDuration(duration), mTimeOfDay(timeOfDay),
|
||||
mIdle(getInitialIdle(idle)),
|
||||
mRepeat(repeat), mStoredInitialActorPosition(false), mInitialActorPosition(osg::Vec3f(0, 0, 0)),
|
||||
mStoredInitialActorPosition(false), mInitialActorPosition(osg::Vec3f(0, 0, 0)),
|
||||
mHasDestination(false), mDestination(osg::Vec3f(0, 0, 0)), mUsePathgrid(false)
|
||||
{
|
||||
}
|
||||
|
@ -309,11 +310,6 @@ namespace MWMechanics
|
|||
return false; // AiWander package not yet completed
|
||||
}
|
||||
|
||||
bool AiWander::getRepeat() const
|
||||
{
|
||||
return mRepeat;
|
||||
}
|
||||
|
||||
osg::Vec3f AiWander::getDestination(const MWWorld::Ptr& actor) const
|
||||
{
|
||||
if (mHasDestination)
|
||||
|
@ -599,11 +595,6 @@ namespace MWMechanics
|
|||
}
|
||||
}
|
||||
|
||||
int AiWander::getTypeId() const
|
||||
{
|
||||
return TypeIdWander;
|
||||
}
|
||||
|
||||
void AiWander::stopWalking(const MWWorld::Ptr& actor)
|
||||
{
|
||||
mPathFinder.clearPath();
|
||||
|
@ -873,7 +864,7 @@ namespace MWMechanics
|
|||
assert (mIdle.size() == 8);
|
||||
for (int i=0; i<8; ++i)
|
||||
wander->mData.mIdle[i] = mIdle[i];
|
||||
wander->mData.mShouldRepeat = mRepeat;
|
||||
wander->mData.mShouldRepeat = mOptions.mRepeat;
|
||||
wander->mStoredInitialActorPosition = mStoredInitialActorPosition;
|
||||
if (mStoredInitialActorPosition)
|
||||
wander->mInitialActorPosition = mInitialActorPosition;
|
||||
|
@ -885,12 +876,12 @@ namespace MWMechanics
|
|||
}
|
||||
|
||||
AiWander::AiWander (const ESM::AiSequence::AiWander* wander)
|
||||
: mDistance(std::max(static_cast<short>(0), wander->mData.mDistance))
|
||||
: TypedAiPackage<AiWander>(makeDefaultOptions().withRepeat(wander->mData.mShouldRepeat != 0))
|
||||
, mDistance(std::max(static_cast<short>(0), wander->mData.mDistance))
|
||||
, mDuration(std::max(static_cast<short>(0), wander->mData.mDuration))
|
||||
, mRemainingDuration(wander->mDurationData.mRemainingDuration)
|
||||
, mTimeOfDay(wander->mData.mTimeOfDay)
|
||||
, mIdle(getInitialIdle(wander->mData.mIdle))
|
||||
, mRepeat(wander->mData.mShouldRepeat != 0)
|
||||
, mStoredInitialActorPosition(wander->mStoredInitialActorPosition)
|
||||
, mHasDestination(false)
|
||||
, mDestination(osg::Vec3f(0, 0, 0))
|
||||
|
|
|
@ -93,16 +93,20 @@ namespace MWMechanics
|
|||
|
||||
bool execute(const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
|
||||
int getTypeId() const final;
|
||||
static constexpr TypeId getTypeId() { return TypeIdWander; }
|
||||
|
||||
bool useVariableSpeed() const final { return true; }
|
||||
static constexpr Options makeDefaultOptions()
|
||||
{
|
||||
AiPackage::Options options;
|
||||
options.mUseVariableSpeed = true;
|
||||
options.mRepeat = false;
|
||||
return options;
|
||||
}
|
||||
|
||||
void writeState(ESM::AiSequence::AiSequence &sequence) const final;
|
||||
|
||||
void fastForward(const MWWorld::Ptr& actor, AiState& state) final;
|
||||
|
||||
bool getRepeat() const final;
|
||||
|
||||
osg::Vec3f getDestination(const MWWorld::Ptr& actor) const final;
|
||||
|
||||
osg::Vec3f getDestination() const final
|
||||
|
@ -139,7 +143,6 @@ namespace MWMechanics
|
|||
float mRemainingDuration;
|
||||
const int mTimeOfDay;
|
||||
const std::vector<unsigned char> mIdle;
|
||||
const bool mRepeat;
|
||||
|
||||
bool mStoredInitialActorPosition;
|
||||
osg::Vec3f mInitialActorPosition; // Note: an original engine does not reset coordinates even when actor changes a cell
|
||||
|
@ -174,7 +177,7 @@ namespace MWMechanics
|
|||
static const std::string sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1];
|
||||
|
||||
static int OffsetToPreventOvercrowding();
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,6 +8,16 @@ namespace MWMechanics
|
|||
template <class T>
|
||||
struct TypedAiPackage : public AiPackage
|
||||
{
|
||||
TypedAiPackage() :
|
||||
AiPackage(T::getTypeId(), T::makeDefaultOptions()) {}
|
||||
|
||||
TypedAiPackage(const Options& options) :
|
||||
AiPackage(T::getTypeId(), options) {}
|
||||
|
||||
template <class Derived>
|
||||
TypedAiPackage(Derived*) :
|
||||
AiPackage(Derived::getTypeId(), Derived::makeDefaultOptions()) {}
|
||||
|
||||
virtual std::unique_ptr<AiPackage> clone() const override
|
||||
{
|
||||
return std::make_unique<T>(*static_cast<const T*>(this));
|
||||
|
|
Loading…
Reference in a new issue