diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index da6aec0be..af62d56a1 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -25,6 +25,7 @@ #include "npcstats.hpp" #include "creaturestats.hpp" #include "movement.hpp" +#include "character.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -1153,7 +1154,7 @@ namespace MWMechanics updateCrimePersuit(iter->first, duration); if (iter->first != player) - iter->first.getClass().getCreatureStats(iter->first).getAiSequence().execute(iter->first, duration); + iter->first.getClass().getCreatureStats(iter->first).getAiSequence().execute(iter->first,iter->second->getAiState(), duration); CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first); if(!stats.isDead()) diff --git a/apps/openmw/mwmechanics/aiactivate.cpp b/apps/openmw/mwmechanics/aiactivate.cpp index 54bcd67b5..9e25084d3 100644 --- a/apps/openmw/mwmechanics/aiactivate.cpp +++ b/apps/openmw/mwmechanics/aiactivate.cpp @@ -21,7 +21,7 @@ MWMechanics::AiActivate *MWMechanics::AiActivate::clone() const { return new AiActivate(*this); } -bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor,float duration) +bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor, AiState& state, float duration) { ESM::Position pos = actor.getRefData().getPosition(); //position of the actor const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtr(mObjectId, false); //The target to follow diff --git a/apps/openmw/mwmechanics/aiactivate.hpp b/apps/openmw/mwmechanics/aiactivate.hpp index 2a0f67709..e25afe285 100644 --- a/apps/openmw/mwmechanics/aiactivate.hpp +++ b/apps/openmw/mwmechanics/aiactivate.hpp @@ -28,7 +28,7 @@ namespace MWMechanics AiActivate(const ESM::AiSequence::AiActivate* activate); virtual AiActivate *clone() const; - virtual bool execute (const MWWorld::Ptr& actor,float duration); + virtual bool execute (const MWWorld::Ptr& actor, AiState& state, float duration); virtual int getTypeId() const; virtual void writeState(ESM::AiSequence::AiSequence& sequence) const; diff --git a/apps/openmw/mwmechanics/aiavoiddoor.cpp b/apps/openmw/mwmechanics/aiavoiddoor.cpp index 7cb4f1c25..b9954337d 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.cpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.cpp @@ -18,7 +18,7 @@ MWMechanics::AiAvoidDoor::AiAvoidDoor(const MWWorld::Ptr& doorPtr) } -bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor,float duration) +bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, AiState& state, float duration) { ESM::Position pos = actor.getRefData().getPosition(); diff --git a/apps/openmw/mwmechanics/aiavoiddoor.hpp b/apps/openmw/mwmechanics/aiavoiddoor.hpp index 2374fbc1b..7590c8fcb 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.hpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.hpp @@ -20,7 +20,7 @@ namespace MWMechanics virtual AiAvoidDoor *clone() const; - virtual bool execute (const MWWorld::Ptr& actor,float duration); + virtual bool execute (const MWWorld::Ptr& actor, AiState& state, float duration); virtual int getTypeId() const; diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 0bea76c58..1784398f1 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -170,7 +170,7 @@ namespace MWMechanics * Use the Observer Pattern to co-ordinate attacks, provide intelligence on * whether the target was hit, etc. */ - bool AiCombat::execute (const MWWorld::Ptr& actor,float duration) + bool AiCombat::execute (const MWWorld::Ptr& actor, AiState& state, float duration) { //General description if(actor.getClass().getCreatureStats(actor).isDead()) diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index 916a1a1d5..198458d51 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -42,7 +42,7 @@ namespace MWMechanics virtual AiCombat *clone() const; - virtual bool execute (const MWWorld::Ptr& actor,float duration); + virtual bool execute (const MWWorld::Ptr& actor, AiState& state, float duration); virtual int getTypeId() const; diff --git a/apps/openmw/mwmechanics/aiescort.cpp b/apps/openmw/mwmechanics/aiescort.cpp index 324bef322..c89cfe492 100644 --- a/apps/openmw/mwmechanics/aiescort.cpp +++ b/apps/openmw/mwmechanics/aiescort.cpp @@ -64,7 +64,7 @@ namespace MWMechanics return new AiEscort(*this); } - bool AiEscort::execute (const MWWorld::Ptr& actor,float duration) + bool AiEscort::execute (const MWWorld::Ptr& actor, AiState& state, float duration) { // If AiEscort has ran for as long or longer then the duration specified // and the duration is not infinite, the package is complete. diff --git a/apps/openmw/mwmechanics/aiescort.hpp b/apps/openmw/mwmechanics/aiescort.hpp index 820df969f..ecf4475e0 100644 --- a/apps/openmw/mwmechanics/aiescort.hpp +++ b/apps/openmw/mwmechanics/aiescort.hpp @@ -33,7 +33,7 @@ namespace MWMechanics virtual AiEscort *clone() const; - virtual bool execute (const MWWorld::Ptr& actor,float duration); + virtual bool execute (const MWWorld::Ptr& actor, AiState& state, float duration); virtual int getTypeId() const; diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp index abde80c71..f309dc740 100644 --- a/apps/openmw/mwmechanics/aifollow.cpp +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -41,7 +41,7 @@ MWMechanics::AiFollow::AiFollow(const ESM::AiSequence::AiFollow *follow) } -bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration) +bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor, AiState& state, float duration) { MWWorld::Ptr target = getTarget(); diff --git a/apps/openmw/mwmechanics/aifollow.hpp b/apps/openmw/mwmechanics/aifollow.hpp index 483901b69..d5dd42826 100644 --- a/apps/openmw/mwmechanics/aifollow.hpp +++ b/apps/openmw/mwmechanics/aifollow.hpp @@ -35,7 +35,7 @@ namespace MWMechanics virtual AiFollow *clone() const; - virtual bool execute (const MWWorld::Ptr& actor,float duration); + virtual bool execute (const MWWorld::Ptr& actor, AiState& state, float duration); virtual int getTypeId() const; diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index ff3e84b98..df970f801 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -6,6 +6,7 @@ #include "../mwbase/world.hpp" #include "obstacle.hpp" +#include "aistate.hpp" namespace MWWorld { @@ -20,8 +21,10 @@ namespace ESM } } + namespace MWMechanics { + /// \brief Base class for AI packages class AiPackage { @@ -50,7 +53,7 @@ namespace MWMechanics /// Updates and runs the package (Should run every frame) /// \return Package completed? - virtual bool execute (const MWWorld::Ptr& actor,float duration) = 0; + virtual bool execute (const MWWorld::Ptr& actor, AiState& state, float duration) = 0; /// Returns the TypeID of the AiPackage /// \see enum TypeId diff --git a/apps/openmw/mwmechanics/aipursue.cpp b/apps/openmw/mwmechanics/aipursue.cpp index 3ef0e8e96..0c3de9643 100644 --- a/apps/openmw/mwmechanics/aipursue.cpp +++ b/apps/openmw/mwmechanics/aipursue.cpp @@ -30,7 +30,7 @@ AiPursue *MWMechanics::AiPursue::clone() const { return new AiPursue(*this); } -bool AiPursue::execute (const MWWorld::Ptr& actor, float duration) +bool AiPursue::execute (const MWWorld::Ptr& actor, AiState& state, float duration) { if(actor.getClass().getCreatureStats(actor).isDead()) return true; diff --git a/apps/openmw/mwmechanics/aipursue.hpp b/apps/openmw/mwmechanics/aipursue.hpp index a6eef2984..493a27985 100644 --- a/apps/openmw/mwmechanics/aipursue.hpp +++ b/apps/openmw/mwmechanics/aipursue.hpp @@ -31,7 +31,7 @@ namespace MWMechanics AiPursue(const ESM::AiSequence::AiPursue* pursue); virtual AiPursue *clone() const; - virtual bool execute (const MWWorld::Ptr& actor,float duration); + virtual bool execute (const MWWorld::Ptr& actor, AiState& state, float duration); virtual int getTypeId() const; MWWorld::Ptr getTarget() const; diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index d76e513f6..990145c8d 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -2,6 +2,7 @@ #include "aisequence.hpp" #include "aipackage.hpp" +#include "aistate.hpp" #include "aiwander.hpp" #include "aiescort.hpp" @@ -146,7 +147,7 @@ bool AiSequence::isPackageDone() const return mDone; } -void AiSequence::execute (const MWWorld::Ptr& actor,float duration) +void AiSequence::execute (const MWWorld::Ptr& actor, AiState& state,float duration) { if(actor != MWBase::Environment::get().getWorld()->getPlayerPtr() && !actor.getClass().getCreatureStats(actor).getKnockedDown()) @@ -208,7 +209,7 @@ void AiSequence::execute (const MWWorld::Ptr& actor,float duration) } } - if (package->execute (actor,duration)) + if (package->execute (actor,state,duration)) { // To account for the rare case where AiPackage::execute() queued another AI package // (e.g. AiPursue executing a dialogue script that uses startCombat) diff --git a/apps/openmw/mwmechanics/aisequence.hpp b/apps/openmw/mwmechanics/aisequence.hpp index 56f5dee31..055c1f99d 100644 --- a/apps/openmw/mwmechanics/aisequence.hpp +++ b/apps/openmw/mwmechanics/aisequence.hpp @@ -4,6 +4,7 @@ #include #include +//#include "aistate.hpp" namespace MWWorld { @@ -18,9 +19,15 @@ namespace ESM } } +template< class Base > class DerivedClassStorage; + namespace MWMechanics { class AiPackage; + + + class AiTemporaryBase; + typedef DerivedClassStorage AiState; /// \brief Sequence of AI-packages for a single actor /** The top-most AI package is run each frame. When completed, it is removed from the stack. **/ @@ -88,7 +95,7 @@ namespace MWMechanics void stopPursuit(); /// Execute current package, switching if needed. - void execute (const MWWorld::Ptr& actor,float duration); + void execute (const MWWorld::Ptr& actor, MWMechanics::AiState& state, float duration); /// Remove all packages. void clear(); diff --git a/apps/openmw/mwmechanics/aistate.hpp b/apps/openmw/mwmechanics/aistate.hpp new file mode 100644 index 000000000..4db04dc6a --- /dev/null +++ b/apps/openmw/mwmechanics/aistate.hpp @@ -0,0 +1,120 @@ +#ifndef AISTATE_H +#define AISTATE_H + +#include +#include + +// c++11 replacement +#include +#include + + +/// \brief stores an object of any class derived from Base +template< class Base > +class DerivedClassStorage +{ +private: + Base* mStorage; + + // assert that Derived is derived from Base. + template< class Derived > + void assert_derived() + { + // c++11: + // static_assert( std::is_base_of , "DerivedClassStorage may only store derived classes" ); + + // boost: + BOOST_STATIC_ASSERT(boost::is_base_of::value);//,"DerivedClassStorage may only store derived classes"); + } + + DerivedClassStorage( const DerivedClassStorage& ); + +public: + /// \brief returns reference to stored object or deletes it and creates a fitting + template< class Derived > + Derived& get() + { + assert_derived(); + + Derived* result = dynamic_cast(mStorage); + + if(!result) + { + if(mStorage) + delete mStorage; + mStorage = result = new Derived(); + } + + //return a reference to the (new allocated) object + return *result; + } + + template< class Derived > + void store( const Derived& payload ) + { + assert_derived(); + if(mStorage) + delete mStorage; + mStorage = new Derived(payload); + } + + /// \brief takes ownership of the passed object + template< class Derived > + void moveIn( Derived* p ) + { + assert_derived(); + if(mStorage) + delete mStorage; + mStorage = p; + } + + /// \brief gives away ownership of object. Throws exception if storage does not contain Derived or is empty. + template< class Derived > + Derived* moveOut() + { + assert_derived(); + + + if(!mStorage) + throw std::runtime_error("Cant move out: empty storage."); + + Derived* result = dynamic_cast(mStorage); + + if(!mStorage) + throw std::runtime_error("Cant move out: wrong type requested."); + + return result; + } + + bool empty() const + { + return mStorage == NULL; + } + + const std::type_info& getType() const + { + return typeid(mStorage); + } + + + DerivedClassStorage():mStorage(NULL){}; + ~DerivedClassStorage() + { + if(mStorage) + delete mStorage; + }; +}; + +namespace MWMechanics +{ + /// \brief base class for the temporary storage of AiPackages + struct AiTemporaryBase + { + virtual ~AiTemporaryBase(){}; + }; + + /// \brief Container for AI package status + typedef DerivedClassStorage AiState; +} + +#endif // AISTATE_H diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 7278e74f2..e5d58a563 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -37,7 +37,7 @@ namespace MWMechanics return new AiTravel(*this); } - bool AiTravel::execute (const MWWorld::Ptr& actor,float duration) + bool AiTravel::execute (const MWWorld::Ptr& actor, AiState& state, float duration) { MWBase::World *world = MWBase::Environment::get().getWorld(); ESM::Position pos = actor.getRefData().getPosition(); diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp index 91ee30253..3b12e9433 100644 --- a/apps/openmw/mwmechanics/aitravel.hpp +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -27,7 +27,7 @@ namespace MWMechanics virtual AiTravel *clone() const; - virtual bool execute (const MWWorld::Ptr& actor,float duration); + virtual bool execute (const MWWorld::Ptr& actor, AiState& state, float duration); virtual int getTypeId() const; diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index aee3e654d..b38c69cc4 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -18,6 +18,8 @@ #include "steering.hpp" #include "movement.hpp" + + namespace MWMechanics { static const int COUNT_BEFORE_RESET = 200; // TODO: maybe no longer needed @@ -45,9 +47,9 @@ namespace MWMechanics mStuckCount = 0;// TODO: maybe no longer needed mDoorCheckDuration = 0; mTrimCurrentNode = false; - mReaction = 0; - mRotate = false; - mTargetAngle = 0; +// mReaction = 0; +// mRotate = false; +// mTargetAngle = 0; mSaidGreeting = Greet_None; mGreetingTimer = 0; mHasReturnPosition = false; @@ -125,8 +127,13 @@ namespace MWMechanics * actors will enter combat (i.e. no longer wandering) and different pathfinding * will kick in. */ - bool AiWander::execute (const MWWorld::Ptr& actor,float duration) + bool AiWander::execute (const MWWorld::Ptr& actor, AiState& state, float duration) { + AiWanderStorage& storage = state.get(); + float& mTargetAngle = storage.mTargetAngle; + bool& mRotate = storage.mRotate; + float& mReaction = storage.mReaction; + MWMechanics::CreatureStats& cStats = actor.getClass().getCreatureStats(actor); if(cStats.isDead() || cStats.getHealth().getCurrent() <= 0) return true; // Don't bother with dead actors diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 59a51446e..beed00357 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -12,6 +12,9 @@ #include "../mwworld/timestamp.hpp" + +#include "aistate.hpp" + namespace ESM { namespace AiSequence @@ -22,6 +25,17 @@ namespace ESM namespace MWMechanics { + /// \brief Temporary values used by AiWander + struct AiWanderStorage : AiTemporaryBase + { + // the z rotation angle (degrees) we want to reach + // used every frame when mRotate is true + float mTargetAngle; + bool mRotate; + float mReaction; // update some actions infrequently + AiWanderStorage():mTargetAngle(0),mRotate(false),mReaction(0){}; + }; + /// \brief Causes the Actor to wander within a specified range class AiWander : public AiPackage { @@ -41,7 +55,7 @@ namespace MWMechanics virtual AiPackage *clone() const; - virtual bool execute (const MWWorld::Ptr& actor,float duration); + virtual bool execute (const MWWorld::Ptr& actor, AiState& state, float duration); virtual int getTypeId() const; @@ -109,11 +123,7 @@ namespace MWMechanics float mDoorCheckDuration; int mStuckCount; - // the z rotation angle (degrees) we want to reach - // used every frame when mRotate is true - float mTargetAngle; - bool mRotate; - float mReaction; // update some actions infrequently + }; } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 550cae5fc..2a14c53b9 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -6,6 +6,7 @@ #include #include "../mwworld/ptr.hpp" +#include "aistate.hpp" namespace MWWorld { @@ -138,6 +139,9 @@ class CharacterController { MWWorld::Ptr mPtr; MWRender::Animation *mAnimation; + + // + AiState mAiState; typedef std::deque > AnimationQueue; AnimationQueue mAnimQueue; @@ -218,6 +222,8 @@ public: { return mDeathState != CharState_None; } void forceStateUpdate(); + + AiState& getAiState() { return mAiState; } }; void getWeaponGroup(WeaponType weaptype, std::string &group);