diff --git a/apps/openmw/mwmechanics/aistate.hpp b/apps/openmw/mwmechanics/aistate.hpp
index 4db04dc6a..6616beb1f 100644
--- a/apps/openmw/mwmechanics/aistate.hpp
+++ b/apps/openmw/mwmechanics/aistate.hpp
@@ -27,7 +27,9 @@ private:
BOOST_STATIC_ASSERT(boost::is_base_of::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:
/// \brief returns reference to stored object or deletes it and creates a fitting
@@ -103,6 +105,9 @@ public:
if(mStorage)
delete mStorage;
};
+
+
+
};
namespace MWMechanics
diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp
index b38c69cc4..b3b788899 100644
--- a/apps/openmw/mwmechanics/aiwander.cpp
+++ b/apps/openmw/mwmechanics/aiwander.cpp
@@ -39,19 +39,11 @@ namespace MWMechanics
{
// NOTE: mDistance and mDuration must be set already
- mCellX = std::numeric_limits::max();
- mCellY = std::numeric_limits::max();
- mXCell = 0;
- mYCell = 0;
- mCell = NULL;
+
mStuckCount = 0;// TODO: maybe no longer needed
mDoorCheckDuration = 0;
mTrimCurrentNode = false;
-// mReaction = 0;
-// mRotate = false;
-// mTargetAngle = 0;
- mSaidGreeting = Greet_None;
- mGreetingTimer = 0;
+
mHasReturnPosition = false;
mReturnPosition = Ogre::Vector3(0,0,0);
@@ -129,22 +121,32 @@ namespace MWMechanics
*/
bool AiWander::execute (const MWWorld::Ptr& actor, AiState& state, float duration)
{
+ // define references for readability
AiWanderStorage& storage = state.get();
- float& mTargetAngle = storage.mTargetAngle;
- bool& mRotate = storage.mRotate;
- float& mReaction = storage.mReaction;
+
+ float& targetAngle = storage.mTargetAngle;
+ 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);
if(cStats.isDead() || cStats.getHealth().getCurrent() <= 0)
return true; // Don't bother with dead actors
- bool cellChange = mCell && (actor.getCell() != mCell);
- if(!mCell || cellChange)
+ bool cellChange = storage.mCell && (actor.getCell() != storage.mCell);
+ if(!currentCell || cellChange)
{
- mCell = actor.getCell();
+ currentCell = actor.getCell();
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.setMovementFlag(CreatureStats::Flag_Run, false);
@@ -224,22 +226,22 @@ namespace MWMechanics
//#endif
}
- if (mRotate)
+ if (rotate)
{
// Reduce the turning animation glitch by using a *HUGE* value of
// epsilon... TODO: a proper fix might be in either the physics or the
// animation subsystem
- if (zTurn(actor, Ogre::Degree(mTargetAngle), Ogre::Degree(5)))
- mRotate = false;
+ if (zTurn(actor, Ogre::Degree(targetAngle), Ogre::Degree(5)))
+ rotate = false;
}
- mReaction += duration;
- if(mReaction < REACTION_INTERVAL)
+ lastReaction += duration;
+ if(lastReaction < REACTION_INTERVAL)
{
return false;
}
else
- mReaction = 0;
+ lastReaction = 0;
// NOTE: everything below get updated every REACTION_INTERVAL seconds
@@ -278,8 +280,8 @@ namespace MWMechanics
pathgrid = world->getStore().get().search(*cell);
// cache the current cell location
- mCellX = cell->mData.mX;
- mCellY = cell->mData.mY;
+ cachedCellX = cell->mData.mX;
+ cachedCellY = cell->mData.mY;
// If there is no path this actor doesn't go anywhere. See:
// https://forum.openmw.org/viewtopic.php?t=1556
@@ -293,12 +295,12 @@ namespace MWMechanics
// destinations within the allowed set of pathgrid points (nodes).
if(mDistance)
{
- mXCell = 0;
- mYCell = 0;
+ cachedCellXf = 0;
+ cachedCellYf = 0;
if(cell->isExterior())
{
- mXCell = mCellX * ESM::Land::REAL_SIZE;
- mYCell = mCellY * ESM::Land::REAL_SIZE;
+ cachedCellXf = cachedCellX * ESM::Land::REAL_SIZE;
+ cachedCellYf = cachedCellYf * ESM::Land::REAL_SIZE;
}
// 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
Ogre::Vector3 npcPos(pos.pos);
- npcPos[0] = npcPos[0] - mXCell;
- npcPos[1] = npcPos[1] - mYCell;
+ npcPos[0] = npcPos[0] - cachedCellXf;
+ npcPos[1] = npcPos[1] - cachedCellYf;
// mAllowedNodes for this actor with pathgrid point indexes based on mDistance
// NOTE: mPoints and mAllowedNodes are in local co-ordinates
@@ -439,24 +441,24 @@ namespace MWMechanics
Ogre::Vector3 actorPos(actor.getRefData().getPosition().pos);
float playerDistSqr = playerPos.squaredDistance(actorPos);
- if (mSaidGreeting == Greet_None)
+ if (greetingState == Greet_None)
{
if ((playerDistSqr <= helloDistance*helloDistance) &&
!player.getClass().getCreatureStats(player).isDead() && MWBase::Environment::get().getWorld()->getLOS(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");
- mGreetingTimer = 0;
+ greetingTimer = 0;
}
}
- if(mSaidGreeting == Greet_InProgress)
+ if(greetingState == Greet_InProgress)
{
- mGreetingTimer++;
+ greetingTimer++;
if(mWalking)
{
@@ -468,7 +470,7 @@ namespace MWMechanics
getRandomIdle();
}
- if(!mRotate)
+ if(!rotate)
{
Ogre::Vector3 dir = playerPos - actorPos;
float length = dir.length();
@@ -479,29 +481,29 @@ namespace MWMechanics
// an attempt at reducing the turning animation glitch
if(abs(abs(faceAngle) - abs(actorAngle)) >= 5) // TODO: is there a better way?
{
- mTargetAngle = faceAngle;
- mRotate = true;
+ targetAngle = faceAngle;
+ rotate = true;
}
}
- if (mGreetingTimer >= GREETING_SHOULD_END)
+ if (greetingTimer >= GREETING_SHOULD_END)
{
- mSaidGreeting = Greet_Done;
- mGreetingTimer = 0;
+ greetingState = Greet_Done;
+ greetingTimer = 0;
}
}
- if (mSaidGreeting == MWMechanics::AiWander::Greet_Done)
+ if (greetingState == MWMechanics::AiWander::Greet_Done)
{
static float fGreetDistanceReset = MWBase::Environment::get().getWorld()->getStore()
.get().find("fGreetDistanceReset")->getFloat();
if (playerDistSqr >= fGreetDistanceReset*fGreetDistanceReset)
- mSaidGreeting = Greet_None;
+ greetingState = Greet_None;
}
// 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;
mIdleNow = false;
@@ -523,8 +525,8 @@ namespace MWMechanics
// convert dest to use world co-ordinates
ESM::Pathgrid::Point dest;
- dest.mX = destNodePos[0] + mXCell;
- dest.mY = destNodePos[1] + mYCell;
+ dest.mX = destNodePos[0] + cachedCellXf;
+ dest.mY = destNodePos[1] + cachedCellYf;
dest.mZ = destNodePos[2];
// actor position is already in world co-ordinates
diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp
index beed00357..400897ed1 100644
--- a/apps/openmw/mwmechanics/aiwander.hpp
+++ b/apps/openmw/mwmechanics/aiwander.hpp
@@ -24,17 +24,8 @@ 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
@@ -50,8 +41,7 @@ namespace MWMechanics
AiWander (const ESM::AiSequence::AiWander* wander);
- // NOTE: mDistance and mDuration must be set already
- void init();
+
virtual AiPackage *clone() const;
@@ -65,7 +55,16 @@ namespace MWMechanics
virtual void writeState(ESM::AiSequence::AiSequence &sequence) const;
+
+ enum GreetingState {
+ Greet_None,
+ Greet_InProgress,
+ Greet_Done
+ };
private:
+ // NOTE: mDistance and mDuration must be set already
+ void init();
+
void stopWalking(const MWWorld::Ptr& actor);
void playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect);
bool checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect);
@@ -77,26 +76,15 @@ namespace MWMechanics
std::vector mIdle;
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,
// if we had the actor in the AiWander constructor...
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
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::max();
+ mCellY = std::numeric_limits::max();
+ mXCell = 0;
+ mYCell = 0;
+ mCell = NULL;
+ };
+ };
}
#endif