forked from mirror/openmw-tes3mp
Draft how to move temporary package state to CharacterController.
Example for a few values shown in AiWander.
This commit is contained in:
parent
9ab8d0a8e6
commit
0871d45790
22 changed files with 184 additions and 29 deletions
|
@ -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())
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <list>
|
||||
|
||||
#include <components/esm/loadnpc.hpp>
|
||||
//#include "aistate.hpp"
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
|
@ -18,9 +19,15 @@ namespace ESM
|
|||
}
|
||||
}
|
||||
|
||||
template< class Base > class DerivedClassStorage;
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
class AiPackage;
|
||||
|
||||
|
||||
class AiTemporaryBase;
|
||||
typedef DerivedClassStorage<AiTemporaryBase> 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();
|
||||
|
|
120
apps/openmw/mwmechanics/aistate.hpp
Normal file
120
apps/openmw/mwmechanics/aistate.hpp
Normal file
|
@ -0,0 +1,120 @@
|
|||
#ifndef AISTATE_H
|
||||
#define AISTATE_H
|
||||
|
||||
#include <typeinfo>
|
||||
#include <stdexcept>
|
||||
|
||||
// c++11 replacement
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/type_traits/is_base_of.hpp>
|
||||
|
||||
|
||||
/// \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<Base,Derived> , "DerivedClassStorage may only store derived classes" );
|
||||
|
||||
// boost:
|
||||
BOOST_STATIC_ASSERT(boost::is_base_of<Base,Derived>::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>();
|
||||
|
||||
Derived* result = dynamic_cast<Derived*>(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<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<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<Derived>();
|
||||
|
||||
|
||||
if(!mStorage)
|
||||
throw std::runtime_error("Cant move out: empty storage.");
|
||||
|
||||
Derived* result = dynamic_cast<Derived*>(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<AiTemporaryBase> AiState;
|
||||
}
|
||||
|
||||
#endif // AISTATE_H
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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<AiWanderStorage>();
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <components/esm/loadmgef.hpp>
|
||||
|
||||
#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<std::pair<std::string,size_t> > 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);
|
||||
|
|
Loading…
Reference in a new issue