1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-02-28 16:39:39 +00:00

Replace AiPackage virtual methods by options

This commit is contained in:
elsid 2020-05-16 21:08:39 +02:00
parent 3b1c717ab9
commit 5b34ef224b
No known key found for this signature in database
GPG key ID: B845CB9FEE18AB40
26 changed files with 218 additions and 196 deletions

View file

@ -44,11 +44,6 @@ namespace MWMechanics
return false; return false;
} }
int AiActivate::getTypeId() const
{
return TypeIdActivate;
}
void AiActivate::writeState(ESM::AiSequence::AiSequence &sequence) const void AiActivate::writeState(ESM::AiSequence::AiSequence &sequence) const
{ {
std::unique_ptr<ESM::AiSequence::AiActivate> activate(new ESM::AiSequence::AiActivate()); std::unique_ptr<ESM::AiSequence::AiActivate> activate(new ESM::AiSequence::AiActivate());

View file

@ -29,7 +29,8 @@ namespace MWMechanics
AiActivate(const ESM::AiSequence::AiActivate* activate); AiActivate(const ESM::AiSequence::AiActivate* activate);
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final; 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; void writeState(ESM::AiSequence::AiSequence& sequence) const final;

View file

@ -72,16 +72,6 @@ bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, CharacterCont
return false; 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 bool MWMechanics::AiAvoidDoor::isStuck(const osg::Vec3f& actorPos) const
{ {
return (actorPos - mLastPos).length2() < 10 * 10; return (actorPos - mLastPos).length2() < 10 * 10;

View file

@ -24,12 +24,16 @@ namespace MWMechanics
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final; 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; static constexpr Options makeDefaultOptions()
{
bool canCancel() const final { return false; } AiPackage::Options options;
bool shouldCancelPreviousAi() const final { return false; } options.mPriority = 2;
options.mCanCancel = false;
options.mShouldCancelPreviousAi = false;
return options;
}
private: private:
float mDuration; float mDuration;

View file

@ -31,13 +31,3 @@ bool MWMechanics::AiBreathe::execute (const MWWorld::Ptr& actor, CharacterContro
return true; return true;
} }
int MWMechanics::AiBreathe::getTypeId() const
{
return TypeIdBreathe;
}
unsigned int MWMechanics::AiBreathe::getPriority() const
{
return 2;
}

View file

@ -12,13 +12,16 @@ namespace MWMechanics
public: public:
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final; 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; static constexpr Options makeDefaultOptions()
{
bool canCancel() const final { return false; } AiPackage::Options options;
bool shouldCancelPreviousAi() const final { return false; } options.mPriority = 2;
options.mCanCancel = false;
options.mShouldCancelPreviousAi = false;
return options;
}
}; };
} }
#endif #endif

View file

@ -89,13 +89,3 @@ MWWorld::Ptr MWMechanics::AiCast::getTarget() const
return target; return target;
} }
int MWMechanics::AiCast::getTypeId() const
{
return AiPackage::TypeIdCast;
}
unsigned int MWMechanics::AiCast::getPriority() const
{
return 3;
}

View file

@ -17,14 +17,18 @@ namespace MWMechanics
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final; 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; MWWorld::Ptr getTarget() const final;
unsigned int getPriority() const final; static constexpr Options makeDefaultOptions()
{
bool canCancel() const final { return false; } AiPackage::Options options;
bool shouldCancelPreviousAi() const final { return false; } options.mPriority = 3;
options.mCanCancel = false;
options.mShouldCancelPreviousAi = false;
return options;
}
private: private:
const std::string mTargetId; const std::string mTargetId;

View file

@ -406,16 +406,6 @@ namespace MWMechanics
} }
} }
int AiCombat::getTypeId() const
{
return TypeIdCombat;
}
unsigned int AiCombat::getPriority() const
{
return 1;
}
MWWorld::Ptr AiCombat::getTarget() const MWWorld::Ptr AiCombat::getTarget() const
{ {
return MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId); return MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId);

View file

@ -104,18 +104,22 @@ namespace MWMechanics
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final; 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 ///Returns target ID
MWWorld::Ptr getTarget() const final; MWWorld::Ptr getTarget() const final;
void writeState(ESM::AiSequence::AiSequence &sequence) const final; void writeState(ESM::AiSequence::AiSequence &sequence) const final;
bool canCancel() const final { return false; }
bool shouldCancelPreviousAi() const final { return false; }
private: private:
/// Returns true if combat should end /// Returns true if combat should end
bool attack(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, AiCombatStorage& storage, CharacterController& characterController); bool attack(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, AiCombatStorage& storage, CharacterController& characterController);

View file

@ -95,11 +95,6 @@ namespace MWMechanics
return false; return false;
} }
int AiEscort::getTypeId() const
{
return TypeIdEscort;
}
void AiEscort::writeState(ESM::AiSequence::AiSequence &sequence) const void AiEscort::writeState(ESM::AiSequence::AiSequence &sequence) const
{ {
std::unique_ptr<ESM::AiSequence::AiEscort> escort(new ESM::AiSequence::AiEscort()); std::unique_ptr<ESM::AiSequence::AiEscort> escort(new ESM::AiSequence::AiEscort());

View file

@ -32,11 +32,15 @@ namespace MWMechanics
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final; 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; } static constexpr Options makeDefaultOptions()
{
bool sideWithTarget() const final { return true; } AiPackage::Options options;
options.mUseVariableSpeed = true;
options.mSideWithTarget = true;
return options;
}
void writeState(ESM::AiSequence::AiSequence &sequence) const final; void writeState(ESM::AiSequence::AiSequence &sequence) const final;

View file

@ -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(); 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)); 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;
}

View file

@ -12,12 +12,16 @@ namespace MWMechanics
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final; 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; static constexpr Options makeDefaultOptions()
{
bool canCancel() const final { return false; } AiPackage::Options options;
bool shouldCancelPreviousAi() const final { return false; } options.mPriority = 2;
options.mCanCancel = false;
options.mShouldCancelPreviousAi = false;
return options;
}
private: private:
const float mTargetX; const float mTargetX;

View file

@ -16,25 +16,24 @@
namespace MWMechanics namespace MWMechanics
{ {
int AiFollow::mFollowIndexCounter = 0; int AiFollow::mFollowIndexCounter = 0;
AiFollow::AiFollow(const std::string &actorId, float duration, float x, float y, float z) 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++) , mCellId(""), mActive(false), mFollowIndex(mFollowIndexCounter++)
{ {
mTargetActorRefId = actorId; mTargetActorRefId = actorId;
} }
AiFollow::AiFollow(const std::string &actorId, const std::string &cellId, float duration, float x, float y, float z) 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++) , mCellId(cellId), mActive(false), mFollowIndex(mFollowIndexCounter++)
{ {
mTargetActorRefId = actorId; mTargetActorRefId = actorId;
} }
AiFollow::AiFollow(const MWWorld::Ptr& actor, float duration, float x, float y, float z) 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++) , mCellId(""), mActive(false), mFollowIndex(mFollowIndexCounter++)
{ {
mTargetActorRefId = actor.getCellRef().getRefId(); 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) 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++) , mCellId(cellId), mActive(false), mFollowIndex(mFollowIndexCounter++)
{ {
mTargetActorRefId = actor.getCellRef().getRefId(); 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) 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++) , mCellId(""), mActive(false), mFollowIndex(mFollowIndexCounter++)
{ {
mTargetActorRefId = actor.getCellRef().getRefId(); mTargetActorRefId = actor.getCellRef().getRefId();
@ -58,7 +58,8 @@ AiFollow::AiFollow(const MWWorld::Ptr& actor, bool commanded)
} }
AiFollow::AiFollow(const ESM::AiSequence::AiFollow *follow) 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. // 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. // 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. // 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; return mTargetActorRefId;
} }
int AiFollow::getTypeId() const
{
return TypeIdFollow;
}
bool AiFollow::isCommanded() const bool AiFollow::isCommanded() const
{ {
return mCommanded; return !mOptions.mShouldCancelPreviousAi;
} }
void AiFollow::writeState(ESM::AiSequence::AiSequence &sequence) const void AiFollow::writeState(ESM::AiSequence::AiSequence &sequence) const
@ -221,7 +217,7 @@ void AiFollow::writeState(ESM::AiSequence::AiSequence &sequence) const
follow->mRemainingDuration = mRemainingDuration; follow->mRemainingDuration = mRemainingDuration;
follow->mCellId = mCellId; follow->mCellId = mCellId;
follow->mAlwaysFollow = mAlwaysFollow; follow->mAlwaysFollow = mAlwaysFollow;
follow->mCommanded = mCommanded; follow->mCommanded = isCommanded();
follow->mActive = mActive; follow->mActive = mActive;
ESM::AiSequence::AiPackageContainer package; ESM::AiSequence::AiPackageContainer package;

View file

@ -53,15 +53,18 @@ namespace MWMechanics
AiFollow(const ESM::AiSequence::AiFollow* follow); 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; 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 /// Returns the actor being followed
std::string getFollowedActor(); std::string getFollowedActor();
@ -87,7 +90,6 @@ namespace MWMechanics
/// 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). **/
const bool mAlwaysFollow; const bool mAlwaysFollow;
const bool mCommanded;
const float mDuration; // Hours const float mDuration; // Hours
float mRemainingDuration; // Hours float mRemainingDuration; // Hours
const float mX; const float mX;

View file

@ -24,7 +24,9 @@
#include <osg/Quat> #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 mTimer(AI_REACTION_TIME + 1.0f), // to force initial pathbuild
mTargetActorRefId(""), mTargetActorRefId(""),
mTargetActorId(-1), mTargetActorId(-1),
@ -58,31 +60,6 @@ MWWorld::Ptr MWMechanics::AiPackage::getTarget() const
return MWWorld::Ptr(); 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() void MWMechanics::AiPackage::reset()
{ {
// reset all members // reset all members

View file

@ -55,11 +55,39 @@ namespace MWMechanics
TypeIdCast = 11 TypeIdCast = 11
}; };
///Default constructor struct Options
AiPackage(); {
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; virtual ~AiPackage() = default;
static constexpr Options makeDefaultOptions()
{
return Options{};
}
///Clones the package ///Clones the package
virtual std::unique_ptr<AiPackage> clone() const = 0; virtual std::unique_ptr<AiPackage> clone() const = 0;
@ -69,13 +97,13 @@ namespace MWMechanics
/// Returns the TypeID of the AiPackage /// Returns the TypeID of the AiPackage
/// \see enum TypeId /// \see enum TypeId
virtual int getTypeId() const = 0; TypeId getTypeId() const { return mTypeId; }
/// 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;} unsigned int getPriority() const { return mOptions.mPriority; }
/// Check if package use movement with variable speed /// 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 {} 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); }; 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) /// 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) /// 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) /// 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)? /// 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. /// 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); } virtual osg::Vec3f getDestination() const { return osg::Vec3f(0, 0, 0); }
// Return true if any loaded actor with this AI package must be active. /// Return true if any loaded actor with this AI package must be active.
virtual bool alwaysActive() const { return false; } bool alwaysActive() const { return mOptions.mAlwaysActive; }
/// Reset pathfinding state /// Reset pathfinding state
void reset(); void reset();
@ -139,6 +167,9 @@ namespace MWMechanics
DetourNavigator::Flags getNavigatorFlags(const MWWorld::Ptr& actor) const; 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 // TODO: all this does not belong here, move into temporary storage
PathFinder mPathFinder; PathFinder mPathFinder;
ObstacleCheck mObstacleCheck; ObstacleCheck mObstacleCheck;

View file

@ -66,11 +66,6 @@ bool AiPursue::execute (const MWWorld::Ptr& actor, CharacterController& characte
return false; return false;
} }
int AiPursue::getTypeId() const
{
return TypeIdPursue;
}
MWWorld::Ptr AiPursue::getTarget() const MWWorld::Ptr AiPursue::getTarget() const
{ {
return MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId); return MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId);

View file

@ -27,14 +27,20 @@ namespace MWMechanics
AiPursue(const ESM::AiSequence::AiPursue* pursue); AiPursue(const ESM::AiSequence::AiPursue* pursue);
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final; 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; MWWorld::Ptr getTarget() const final;
void writeState (ESM::AiSequence::AiSequence& sequence) const final; void writeState (ESM::AiSequence::AiSequence& sequence) const final;
bool canCancel() const final { return false; }
bool shouldCancelPreviousAi() const final { return false; }
}; };
} }
#endif #endif

View file

@ -338,7 +338,7 @@ void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor, boo
dest = actor.getRefData().getPosition().asVec3(); 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); stack(travelPackage, actor, false);
} }
@ -478,7 +478,11 @@ void AiSequence::readState(const ESM::AiSequence::AiSequence &sequence)
} }
case ESM::AiSequence::Ai_Travel: 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; break;
} }
case ESM::AiSequence::Ai_Escort: case ESM::AiSequence::Ai_Escort:

View file

@ -27,14 +27,26 @@ bool isWithinMaxRange(const osg::Vec3f& pos1, const osg::Vec3f& pos2)
namespace MWMechanics namespace MWMechanics
{ {
AiTravel::AiTravel(float x, float y, float z, bool hidden) AiTravel::AiTravel(float x, float y, float z, AiTravel*)
: mX(x),mY(y),mZ(z),mHidden(hidden) : 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) 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) bool AiTravel::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
@ -78,11 +90,6 @@ namespace MWMechanics
return false; return false;
} }
int AiTravel::getTypeId() const
{
return mHidden ? TypeIdInternalTravel : TypeIdTravel;
}
void AiTravel::fastForward(const MWWorld::Ptr& actor, AiState& state) void AiTravel::fastForward(const MWWorld::Ptr& actor, AiState& state)
{ {
if (!isWithinMaxRange(osg::Vec3f(mX, mY, mZ), actor.getRefData().getPosition().asVec3())) if (!isWithinMaxRange(osg::Vec3f(mX, mY, mZ), actor.getRefData().getPosition().asVec3()))
@ -107,5 +114,20 @@ namespace MWMechanics
package.mPackage = travel.release(); package.mPackage = travel.release();
sequence.mPackages.push_back(package); 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);
}
} }

View file

@ -13,12 +13,18 @@ namespace AiSequence
namespace MWMechanics namespace MWMechanics
{ {
struct AiInternalTravel;
/// \brief Causes the AI to travel to the specified point /// \brief Causes the AI to travel to the specified point
class AiTravel final : public TypedAiPackage<AiTravel> class AiTravel : public TypedAiPackage<AiTravel>
{ {
public: public:
/// Default constructor AiTravel(float x, float y, float z, AiTravel* derived);
AiTravel(float x, float y, float z, bool hidden = false);
AiTravel(float x, float y, float z, AiInternalTravel* derived);
AiTravel(float x, float y, float z);
AiTravel(const ESM::AiSequence::AiTravel* travel); AiTravel(const ESM::AiSequence::AiTravel* travel);
/// Simulates the passing of time /// Simulates the passing of time
@ -28,11 +34,15 @@ namespace MWMechanics
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final; 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; } static constexpr Options makeDefaultOptions()
{
bool alwaysActive() const final { return true; } AiPackage::Options options;
options.mUseVariableSpeed = true;
options.mAlwaysActive = true;
return options;
}
osg::Vec3f getDestination() const final { return osg::Vec3f(mX, mY, mZ); } osg::Vec3f getDestination() const final { return osg::Vec3f(mX, mY, mZ); }
@ -43,6 +53,17 @@ namespace MWMechanics
const bool mHidden; 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 #endif

View file

@ -113,11 +113,12 @@ namespace MWMechanics
} }
AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<unsigned char>& idle, bool repeat): 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)), mDistance(std::max(0, distance)),
mDuration(std::max(0, duration)), mDuration(std::max(0, duration)),
mRemainingDuration(duration), mTimeOfDay(timeOfDay), mRemainingDuration(duration), mTimeOfDay(timeOfDay),
mIdle(getInitialIdle(idle)), 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) mHasDestination(false), mDestination(osg::Vec3f(0, 0, 0)), mUsePathgrid(false)
{ {
} }
@ -309,11 +310,6 @@ namespace MWMechanics
return false; // AiWander package not yet completed return false; // AiWander package not yet completed
} }
bool AiWander::getRepeat() const
{
return mRepeat;
}
osg::Vec3f AiWander::getDestination(const MWWorld::Ptr& actor) const osg::Vec3f AiWander::getDestination(const MWWorld::Ptr& actor) const
{ {
if (mHasDestination) if (mHasDestination)
@ -599,11 +595,6 @@ namespace MWMechanics
} }
} }
int AiWander::getTypeId() const
{
return TypeIdWander;
}
void AiWander::stopWalking(const MWWorld::Ptr& actor) void AiWander::stopWalking(const MWWorld::Ptr& actor)
{ {
mPathFinder.clearPath(); mPathFinder.clearPath();
@ -873,7 +864,7 @@ namespace MWMechanics
assert (mIdle.size() == 8); assert (mIdle.size() == 8);
for (int i=0; i<8; ++i) for (int i=0; i<8; ++i)
wander->mData.mIdle[i] = mIdle[i]; wander->mData.mIdle[i] = mIdle[i];
wander->mData.mShouldRepeat = mRepeat; wander->mData.mShouldRepeat = mOptions.mRepeat;
wander->mStoredInitialActorPosition = mStoredInitialActorPosition; wander->mStoredInitialActorPosition = mStoredInitialActorPosition;
if (mStoredInitialActorPosition) if (mStoredInitialActorPosition)
wander->mInitialActorPosition = mInitialActorPosition; wander->mInitialActorPosition = mInitialActorPosition;
@ -885,12 +876,12 @@ namespace MWMechanics
} }
AiWander::AiWander (const ESM::AiSequence::AiWander* wander) 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)) , mDuration(std::max(static_cast<short>(0), wander->mData.mDuration))
, mRemainingDuration(wander->mDurationData.mRemainingDuration) , mRemainingDuration(wander->mDurationData.mRemainingDuration)
, mTimeOfDay(wander->mData.mTimeOfDay) , mTimeOfDay(wander->mData.mTimeOfDay)
, mIdle(getInitialIdle(wander->mData.mIdle)) , mIdle(getInitialIdle(wander->mData.mIdle))
, mRepeat(wander->mData.mShouldRepeat != 0)
, mStoredInitialActorPosition(wander->mStoredInitialActorPosition) , mStoredInitialActorPosition(wander->mStoredInitialActorPosition)
, mHasDestination(false) , mHasDestination(false)
, mDestination(osg::Vec3f(0, 0, 0)) , mDestination(osg::Vec3f(0, 0, 0))

View file

@ -93,16 +93,20 @@ namespace MWMechanics
bool execute(const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final; 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 writeState(ESM::AiSequence::AiSequence &sequence) const final;
void fastForward(const MWWorld::Ptr& actor, AiState& state) 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 MWWorld::Ptr& actor) const final;
osg::Vec3f getDestination() const final osg::Vec3f getDestination() const final
@ -139,7 +143,6 @@ namespace MWMechanics
float mRemainingDuration; float mRemainingDuration;
const int mTimeOfDay; const int mTimeOfDay;
const std::vector<unsigned char> mIdle; const std::vector<unsigned char> mIdle;
const bool mRepeat;
bool mStoredInitialActorPosition; bool mStoredInitialActorPosition;
osg::Vec3f mInitialActorPosition; // Note: an original engine does not reset coordinates even when actor changes a cell osg::Vec3f mInitialActorPosition; // Note: an original engine does not reset coordinates even when actor changes a cell

View file

@ -8,6 +8,16 @@ namespace MWMechanics
template <class T> template <class T>
struct TypedAiPackage : public AiPackage 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 virtual std::unique_ptr<AiPackage> clone() const override
{ {
return std::make_unique<T>(*static_cast<const T*>(this)); return std::make_unique<T>(*static_cast<const T*>(this));