Addded the parts of AiWander that I fully understand to the temporary storage.

The rest should be done by someone who has a clearer overview over the class.
deque
terrorfisch 10 years ago
parent 0871d45790
commit 4391c1fd00

@ -27,7 +27,9 @@ private:
BOOST_STATIC_ASSERT(boost::is_base_of<Base,Derived>::value);//,"DerivedClassStorage may only store derived classes"); BOOST_STATIC_ASSERT(boost::is_base_of<Base,Derived>::value);//,"DerivedClassStorage may only store derived classes");
} }
DerivedClassStorage( const DerivedClassStorage& ); //if needed you have to provide a clone member function
DerivedClassStorage( const DerivedClassStorage& other );
DerivedClassStorage& operator=( const DerivedClassStorage& );
public: public:
/// \brief returns reference to stored object or deletes it and creates a fitting /// \brief returns reference to stored object or deletes it and creates a fitting
@ -103,6 +105,9 @@ public:
if(mStorage) if(mStorage)
delete mStorage; delete mStorage;
}; };
}; };
namespace MWMechanics namespace MWMechanics

@ -39,19 +39,11 @@ namespace MWMechanics
{ {
// NOTE: mDistance and mDuration must be set already // NOTE: mDistance and mDuration must be set already
mCellX = std::numeric_limits<int>::max();
mCellY = std::numeric_limits<int>::max();
mXCell = 0;
mYCell = 0;
mCell = NULL;
mStuckCount = 0;// TODO: maybe no longer needed mStuckCount = 0;// TODO: maybe no longer needed
mDoorCheckDuration = 0; mDoorCheckDuration = 0;
mTrimCurrentNode = false; mTrimCurrentNode = false;
// mReaction = 0;
// mRotate = false;
// mTargetAngle = 0;
mSaidGreeting = Greet_None;
mGreetingTimer = 0;
mHasReturnPosition = false; mHasReturnPosition = false;
mReturnPosition = Ogre::Vector3(0,0,0); mReturnPosition = Ogre::Vector3(0,0,0);
@ -129,22 +121,32 @@ namespace MWMechanics
*/ */
bool AiWander::execute (const MWWorld::Ptr& actor, AiState& state, float duration) bool AiWander::execute (const MWWorld::Ptr& actor, AiState& state, float duration)
{ {
// define references for readability
AiWanderStorage& storage = state.get<AiWanderStorage>(); AiWanderStorage& storage = state.get<AiWanderStorage>();
float& mTargetAngle = storage.mTargetAngle;
bool& mRotate = storage.mRotate; float& targetAngle = storage.mTargetAngle;
float& mReaction = storage.mReaction; bool& rotate = storage.mRotate;
float& lastReaction = storage.mReaction;
AiWander::GreetingState& greetingState = storage.mSaidGreeting;
int& greetingTimer = storage.mGreetingTimer;
int& cachedCellX = storage.mCellX;
int& cachedCellY = storage.mCellY;
float& cachedCellXf = storage.mXCell;
float& cachedCellYf = storage.mYCell;
const MWWorld::CellStore*& currentCell = storage.mCell;
MWMechanics::CreatureStats& cStats = actor.getClass().getCreatureStats(actor); MWMechanics::CreatureStats& cStats = actor.getClass().getCreatureStats(actor);
if(cStats.isDead() || cStats.getHealth().getCurrent() <= 0) if(cStats.isDead() || cStats.getHealth().getCurrent() <= 0)
return true; // Don't bother with dead actors return true; // Don't bother with dead actors
bool cellChange = mCell && (actor.getCell() != mCell); bool cellChange = storage.mCell && (actor.getCell() != storage.mCell);
if(!mCell || cellChange) if(!currentCell || cellChange)
{ {
mCell = actor.getCell(); currentCell = actor.getCell();
mStoredAvailableNodes = false; // prob. not needed since mDistance = 0 mStoredAvailableNodes = false; // prob. not needed since mDistance = 0
} }
const ESM::Cell *cell = mCell->getCell(); const ESM::Cell *cell = currentCell->getCell();
cStats.setDrawState(DrawState_Nothing); cStats.setDrawState(DrawState_Nothing);
cStats.setMovementFlag(CreatureStats::Flag_Run, false); cStats.setMovementFlag(CreatureStats::Flag_Run, false);
@ -224,22 +226,22 @@ namespace MWMechanics
//#endif //#endif
} }
if (mRotate) if (rotate)
{ {
// Reduce the turning animation glitch by using a *HUGE* value of // Reduce the turning animation glitch by using a *HUGE* value of
// epsilon... TODO: a proper fix might be in either the physics or the // epsilon... TODO: a proper fix might be in either the physics or the
// animation subsystem // animation subsystem
if (zTurn(actor, Ogre::Degree(mTargetAngle), Ogre::Degree(5))) if (zTurn(actor, Ogre::Degree(targetAngle), Ogre::Degree(5)))
mRotate = false; rotate = false;
} }
mReaction += duration; lastReaction += duration;
if(mReaction < REACTION_INTERVAL) if(lastReaction < REACTION_INTERVAL)
{ {
return false; return false;
} }
else else
mReaction = 0; lastReaction = 0;
// NOTE: everything below get updated every REACTION_INTERVAL seconds // NOTE: everything below get updated every REACTION_INTERVAL seconds
@ -278,8 +280,8 @@ namespace MWMechanics
pathgrid = world->getStore().get<ESM::Pathgrid>().search(*cell); pathgrid = world->getStore().get<ESM::Pathgrid>().search(*cell);
// cache the current cell location // cache the current cell location
mCellX = cell->mData.mX; cachedCellX = cell->mData.mX;
mCellY = cell->mData.mY; cachedCellY = cell->mData.mY;
// If there is no path this actor doesn't go anywhere. See: // If there is no path this actor doesn't go anywhere. See:
// https://forum.openmw.org/viewtopic.php?t=1556 // https://forum.openmw.org/viewtopic.php?t=1556
@ -293,12 +295,12 @@ namespace MWMechanics
// destinations within the allowed set of pathgrid points (nodes). // destinations within the allowed set of pathgrid points (nodes).
if(mDistance) if(mDistance)
{ {
mXCell = 0; cachedCellXf = 0;
mYCell = 0; cachedCellYf = 0;
if(cell->isExterior()) if(cell->isExterior())
{ {
mXCell = mCellX * ESM::Land::REAL_SIZE; cachedCellXf = cachedCellX * ESM::Land::REAL_SIZE;
mYCell = mCellY * ESM::Land::REAL_SIZE; cachedCellYf = cachedCellYf * ESM::Land::REAL_SIZE;
} }
// FIXME: There might be a bug here. The allowed node points are // FIXME: There might be a bug here. The allowed node points are
@ -308,8 +310,8 @@ namespace MWMechanics
// //
// convert npcPos to local (i.e. cell) co-ordinates // convert npcPos to local (i.e. cell) co-ordinates
Ogre::Vector3 npcPos(pos.pos); Ogre::Vector3 npcPos(pos.pos);
npcPos[0] = npcPos[0] - mXCell; npcPos[0] = npcPos[0] - cachedCellXf;
npcPos[1] = npcPos[1] - mYCell; npcPos[1] = npcPos[1] - cachedCellYf;
// mAllowedNodes for this actor with pathgrid point indexes based on mDistance // mAllowedNodes for this actor with pathgrid point indexes based on mDistance
// NOTE: mPoints and mAllowedNodes are in local co-ordinates // NOTE: mPoints and mAllowedNodes are in local co-ordinates
@ -439,24 +441,24 @@ namespace MWMechanics
Ogre::Vector3 actorPos(actor.getRefData().getPosition().pos); Ogre::Vector3 actorPos(actor.getRefData().getPosition().pos);
float playerDistSqr = playerPos.squaredDistance(actorPos); float playerDistSqr = playerPos.squaredDistance(actorPos);
if (mSaidGreeting == Greet_None) if (greetingState == Greet_None)
{ {
if ((playerDistSqr <= helloDistance*helloDistance) && if ((playerDistSqr <= helloDistance*helloDistance) &&
!player.getClass().getCreatureStats(player).isDead() && MWBase::Environment::get().getWorld()->getLOS(player, actor) !player.getClass().getCreatureStats(player).isDead() && MWBase::Environment::get().getWorld()->getLOS(player, actor)
&& MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, actor)) && MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, actor))
mGreetingTimer++; greetingTimer++;
if (mGreetingTimer >= GREETING_SHOULD_START) if (greetingTimer >= GREETING_SHOULD_START)
{ {
mSaidGreeting = Greet_InProgress; greetingState = Greet_InProgress;
MWBase::Environment::get().getDialogueManager()->say(actor, "hello"); MWBase::Environment::get().getDialogueManager()->say(actor, "hello");
mGreetingTimer = 0; greetingTimer = 0;
} }
} }
if(mSaidGreeting == Greet_InProgress) if(greetingState == Greet_InProgress)
{ {
mGreetingTimer++; greetingTimer++;
if(mWalking) if(mWalking)
{ {
@ -468,7 +470,7 @@ namespace MWMechanics
getRandomIdle(); getRandomIdle();
} }
if(!mRotate) if(!rotate)
{ {
Ogre::Vector3 dir = playerPos - actorPos; Ogre::Vector3 dir = playerPos - actorPos;
float length = dir.length(); float length = dir.length();
@ -479,29 +481,29 @@ namespace MWMechanics
// an attempt at reducing the turning animation glitch // an attempt at reducing the turning animation glitch
if(abs(abs(faceAngle) - abs(actorAngle)) >= 5) // TODO: is there a better way? if(abs(abs(faceAngle) - abs(actorAngle)) >= 5) // TODO: is there a better way?
{ {
mTargetAngle = faceAngle; targetAngle = faceAngle;
mRotate = true; rotate = true;
} }
} }
if (mGreetingTimer >= GREETING_SHOULD_END) if (greetingTimer >= GREETING_SHOULD_END)
{ {
mSaidGreeting = Greet_Done; greetingState = Greet_Done;
mGreetingTimer = 0; greetingTimer = 0;
} }
} }
if (mSaidGreeting == MWMechanics::AiWander::Greet_Done) if (greetingState == MWMechanics::AiWander::Greet_Done)
{ {
static float fGreetDistanceReset = MWBase::Environment::get().getWorld()->getStore() static float fGreetDistanceReset = MWBase::Environment::get().getWorld()->getStore()
.get<ESM::GameSetting>().find("fGreetDistanceReset")->getFloat(); .get<ESM::GameSetting>().find("fGreetDistanceReset")->getFloat();
if (playerDistSqr >= fGreetDistanceReset*fGreetDistanceReset) if (playerDistSqr >= fGreetDistanceReset*fGreetDistanceReset)
mSaidGreeting = Greet_None; greetingState = Greet_None;
} }
// Check if idle animation finished // Check if idle animation finished
if(!checkIdle(actor, mPlayedIdle) && (playerDistSqr > helloDistance*helloDistance || mSaidGreeting == MWMechanics::AiWander::Greet_Done)) if(!checkIdle(actor, mPlayedIdle) && (playerDistSqr > helloDistance*helloDistance || greetingState == MWMechanics::AiWander::Greet_Done))
{ {
mPlayedIdle = 0; mPlayedIdle = 0;
mIdleNow = false; mIdleNow = false;
@ -523,8 +525,8 @@ namespace MWMechanics
// convert dest to use world co-ordinates // convert dest to use world co-ordinates
ESM::Pathgrid::Point dest; ESM::Pathgrid::Point dest;
dest.mX = destNodePos[0] + mXCell; dest.mX = destNodePos[0] + cachedCellXf;
dest.mY = destNodePos[1] + mYCell; dest.mY = destNodePos[1] + cachedCellYf;
dest.mZ = destNodePos[2]; dest.mZ = destNodePos[2];
// actor position is already in world co-ordinates // actor position is already in world co-ordinates

@ -24,17 +24,8 @@ namespace ESM
} }
namespace MWMechanics 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 /// \brief Causes the Actor to wander within a specified range
class AiWander : public AiPackage class AiWander : public AiPackage
@ -50,8 +41,7 @@ namespace MWMechanics
AiWander (const ESM::AiSequence::AiWander* wander); AiWander (const ESM::AiSequence::AiWander* wander);
// NOTE: mDistance and mDuration must be set already
void init();
virtual AiPackage *clone() const; virtual AiPackage *clone() const;
@ -65,7 +55,16 @@ namespace MWMechanics
virtual void writeState(ESM::AiSequence::AiSequence &sequence) const; virtual void writeState(ESM::AiSequence::AiSequence &sequence) const;
enum GreetingState {
Greet_None,
Greet_InProgress,
Greet_Done
};
private: private:
// NOTE: mDistance and mDuration must be set already
void init();
void stopWalking(const MWWorld::Ptr& actor); void stopWalking(const MWWorld::Ptr& actor);
void playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); void playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect);
bool checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); bool checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect);
@ -77,26 +76,15 @@ namespace MWMechanics
std::vector<unsigned char> mIdle; std::vector<unsigned char> mIdle;
bool mRepeat; bool mRepeat;
enum GreetingState {
Greet_None,
Greet_InProgress,
Greet_Done
};
GreetingState mSaidGreeting;
int mGreetingTimer;
bool mHasReturnPosition; // NOTE: Could be removed if mReturnPosition was initialized to actor position, bool mHasReturnPosition; // NOTE: Could be removed if mReturnPosition was initialized to actor position,
// if we had the actor in the AiWander constructor... // if we had the actor in the AiWander constructor...
Ogre::Vector3 mReturnPosition; Ogre::Vector3 mReturnPosition;
// Cached current cell location
int mCellX;
int mCellY;
// Cell location multiplied by ESM::Land::REAL_SIZE
float mXCell;
float mYCell;
const MWWorld::CellStore* mCell; // for detecting cell change
// if false triggers calculating allowed nodes based on mDistance // if false triggers calculating allowed nodes based on mDistance
bool mStoredAvailableNodes; bool mStoredAvailableNodes;
@ -125,6 +113,41 @@ 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
AiWander::GreetingState mSaidGreeting;
int mGreetingTimer;
// Cached current cell location
int mCellX;
int mCellY;
// Cell location multiplied by ESM::Land::REAL_SIZE
float mXCell;
float mYCell;
const MWWorld::CellStore* mCell; // for detecting cell change
AiWanderStorage():mTargetAngle(0),mRotate(false),mReaction(0)
{
mSaidGreeting = AiWander::Greet_None;
mGreetingTimer = 0;
mCellX = std::numeric_limits<int>::max();
mCellY = std::numeric_limits<int>::max();
mXCell = 0;
mYCell = 0;
mCell = NULL;
};
};
} }
#endif #endif

Loading…
Cancel
Save