From 5b34ef224bfe31e07c32c343f34e1f9a490f72dc Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 16 May 2020 21:08:39 +0200 Subject: [PATCH] Replace AiPackage virtual methods by options --- apps/openmw/mwmechanics/aiactivate.cpp | 5 -- apps/openmw/mwmechanics/aiactivate.hpp | 3 +- apps/openmw/mwmechanics/aiavoiddoor.cpp | 10 ---- apps/openmw/mwmechanics/aiavoiddoor.hpp | 14 ++++-- apps/openmw/mwmechanics/aibreathe.cpp | 10 ---- apps/openmw/mwmechanics/aibreathe.hpp | 15 +++--- apps/openmw/mwmechanics/aicast.cpp | 10 ---- apps/openmw/mwmechanics/aicast.hpp | 14 ++++-- apps/openmw/mwmechanics/aicombat.cpp | 10 ---- apps/openmw/mwmechanics/aicombat.hpp | 14 ++++-- apps/openmw/mwmechanics/aiescort.cpp | 5 -- apps/openmw/mwmechanics/aiescort.hpp | 12 +++-- apps/openmw/mwmechanics/aiface.cpp | 10 ---- apps/openmw/mwmechanics/aiface.hpp | 14 ++++-- apps/openmw/mwmechanics/aifollow.cpp | 24 ++++------ apps/openmw/mwmechanics/aifollow.hpp | 16 ++++--- apps/openmw/mwmechanics/aipackage.cpp | 29 ++---------- apps/openmw/mwmechanics/aipackage.hpp | 55 +++++++++++++++++----- apps/openmw/mwmechanics/aipursue.cpp | 5 -- apps/openmw/mwmechanics/aipursue.hpp | 14 ++++-- apps/openmw/mwmechanics/aisequence.cpp | 8 +++- apps/openmw/mwmechanics/aitravel.cpp | 38 +++++++++++---- apps/openmw/mwmechanics/aitravel.hpp | 35 +++++++++++--- apps/openmw/mwmechanics/aiwander.cpp | 19 ++------ apps/openmw/mwmechanics/aiwander.hpp | 15 +++--- apps/openmw/mwmechanics/typedaipackage.hpp | 10 ++++ 26 files changed, 218 insertions(+), 196 deletions(-) diff --git a/apps/openmw/mwmechanics/aiactivate.cpp b/apps/openmw/mwmechanics/aiactivate.cpp index 6764eba23..b4ddf0c03 100644 --- a/apps/openmw/mwmechanics/aiactivate.cpp +++ b/apps/openmw/mwmechanics/aiactivate.cpp @@ -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 activate(new ESM::AiSequence::AiActivate()); diff --git a/apps/openmw/mwmechanics/aiactivate.hpp b/apps/openmw/mwmechanics/aiactivate.hpp index 5a96f4cdb..b263e74a6 100644 --- a/apps/openmw/mwmechanics/aiactivate.hpp +++ b/apps/openmw/mwmechanics/aiactivate.hpp @@ -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; diff --git a/apps/openmw/mwmechanics/aiavoiddoor.cpp b/apps/openmw/mwmechanics/aiavoiddoor.cpp index 9cdb8d90b..d8517c5c9 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.cpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.cpp @@ -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; diff --git a/apps/openmw/mwmechanics/aiavoiddoor.hpp b/apps/openmw/mwmechanics/aiavoiddoor.hpp index fdbf7ebc7..72cde1026 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.hpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.hpp @@ -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; diff --git a/apps/openmw/mwmechanics/aibreathe.cpp b/apps/openmw/mwmechanics/aibreathe.cpp index 5cb81b3d8..15251e125 100644 --- a/apps/openmw/mwmechanics/aibreathe.cpp +++ b/apps/openmw/mwmechanics/aibreathe.cpp @@ -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; -} diff --git a/apps/openmw/mwmechanics/aibreathe.hpp b/apps/openmw/mwmechanics/aibreathe.hpp index 6e3bb912a..2a04ab2ad 100644 --- a/apps/openmw/mwmechanics/aibreathe.hpp +++ b/apps/openmw/mwmechanics/aibreathe.hpp @@ -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 - diff --git a/apps/openmw/mwmechanics/aicast.cpp b/apps/openmw/mwmechanics/aicast.cpp index cc4c03bf1..9ad7b4c56 100644 --- a/apps/openmw/mwmechanics/aicast.cpp +++ b/apps/openmw/mwmechanics/aicast.cpp @@ -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; -} diff --git a/apps/openmw/mwmechanics/aicast.hpp b/apps/openmw/mwmechanics/aicast.hpp index cdf7db2bf..22575c7bc 100644 --- a/apps/openmw/mwmechanics/aicast.hpp +++ b/apps/openmw/mwmechanics/aicast.hpp @@ -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; diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 4a3c7aee6..883a8cc1c 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -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); diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index 2ef0298fc..ef8782ae1 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -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); diff --git a/apps/openmw/mwmechanics/aiescort.cpp b/apps/openmw/mwmechanics/aiescort.cpp index 216547f58..5dc1e44db 100644 --- a/apps/openmw/mwmechanics/aiescort.cpp +++ b/apps/openmw/mwmechanics/aiescort.cpp @@ -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 escort(new ESM::AiSequence::AiEscort()); diff --git a/apps/openmw/mwmechanics/aiescort.hpp b/apps/openmw/mwmechanics/aiescort.hpp index c12de1fac..42558bf7c 100644 --- a/apps/openmw/mwmechanics/aiescort.hpp +++ b/apps/openmw/mwmechanics/aiescort.hpp @@ -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; diff --git a/apps/openmw/mwmechanics/aiface.cpp b/apps/openmw/mwmechanics/aiface.cpp index 0bfd00c87..17b18babc 100644 --- a/apps/openmw/mwmechanics/aiface.cpp +++ b/apps/openmw/mwmechanics/aiface.cpp @@ -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; -} diff --git a/apps/openmw/mwmechanics/aiface.hpp b/apps/openmw/mwmechanics/aiface.hpp index 516dd18dc..3a9a482c0 100644 --- a/apps/openmw/mwmechanics/aiface.hpp +++ b/apps/openmw/mwmechanics/aiface.hpp @@ -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; diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp index eb5b595ab..a9e43b3c3 100644 --- a/apps/openmw/mwmechanics/aifollow.cpp +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -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(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(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; diff --git a/apps/openmw/mwmechanics/aifollow.hpp b/apps/openmw/mwmechanics/aifollow.hpp index 865f4171b..b4cf88be8 100644 --- a/apps/openmw/mwmechanics/aifollow.hpp +++ b/apps/openmw/mwmechanics/aifollow.hpp @@ -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; diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index dca882a3b..66b41db54 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -24,7 +24,9 @@ #include -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 diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 873ad1c29..c32fb93aa 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -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 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; diff --git a/apps/openmw/mwmechanics/aipursue.cpp b/apps/openmw/mwmechanics/aipursue.cpp index 76b4ac0c9..7aa2a9554 100644 --- a/apps/openmw/mwmechanics/aipursue.cpp +++ b/apps/openmw/mwmechanics/aipursue.cpp @@ -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); diff --git a/apps/openmw/mwmechanics/aipursue.hpp b/apps/openmw/mwmechanics/aipursue.hpp index 6898a8dd3..6031f84fb 100644 --- a/apps/openmw/mwmechanics/aipursue.hpp +++ b/apps/openmw/mwmechanics/aipursue.hpp @@ -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 diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 9f5d4ccaf..4a23dc788 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -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(it->mPackage))); + const auto source = static_cast(it->mPackage); + if (source->mHidden) + package.reset(new AiInternalTravel(source)); + else + package.reset(new AiTravel(source)); break; } case ESM::AiSequence::Ai_Escort: diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index ea65f4670..b2a506ca6 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -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(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 AiInternalTravel::clone() const + { + return std::make_unique(*this); + } } diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp index 4f785e237..3049801cd 100644 --- a/apps/openmw/mwmechanics/aitravel.hpp +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -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 + class AiTravel : public TypedAiPackage { 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 clone() const final; + }; } #endif diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 584131bbe..fd978717e 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -113,11 +113,12 @@ namespace MWMechanics } AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector& idle, bool repeat): + TypedAiPackage(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(0), wander->mData.mDistance)) + : TypedAiPackage(makeDefaultOptions().withRepeat(wander->mData.mShouldRepeat != 0)) + , mDistance(std::max(static_cast(0), wander->mData.mDistance)) , mDuration(std::max(static_cast(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)) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 8eb735205..8171107d9 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -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 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 diff --git a/apps/openmw/mwmechanics/typedaipackage.hpp b/apps/openmw/mwmechanics/typedaipackage.hpp index e2b5f8688..c959f4d68 100644 --- a/apps/openmw/mwmechanics/typedaipackage.hpp +++ b/apps/openmw/mwmechanics/typedaipackage.hpp @@ -8,6 +8,16 @@ namespace MWMechanics template struct TypedAiPackage : public AiPackage { + TypedAiPackage() : + AiPackage(T::getTypeId(), T::makeDefaultOptions()) {} + + TypedAiPackage(const Options& options) : + AiPackage(T::getTypeId(), options) {} + + template + TypedAiPackage(Derived*) : + AiPackage(Derived::getTypeId(), Derived::makeDefaultOptions()) {} + virtual std::unique_ptr clone() const override { return std::make_unique(*static_cast(this));