mirror of
https://github.com/OpenMW/openmw.git
synced 2025-02-01 11:45:34 +00:00
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.
This commit is contained in:
parent
0871d45790
commit
4391c1fd00
3 changed files with 107 additions and 77 deletions
|
@ -27,7 +27,9 @@ private:
|
|||
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:
|
||||
/// \brief returns reference to stored object or deletes it and creates a fitting
|
||||
|
@ -103,6 +105,9 @@ public:
|
|||
if(mStorage)
|
||||
delete mStorage;
|
||||
};
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
namespace MWMechanics
|
||||
|
|
|
@ -39,19 +39,11 @@ namespace MWMechanics
|
|||
{
|
||||
// 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
|
||||
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<AiWanderStorage>();
|
||||
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<ESM::Pathgrid>().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<ESM::GameSetting>().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
|
||||
|
|
|
@ -25,16 +25,7 @@ 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<unsigned char> 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<int>::max();
|
||||
mCellY = std::numeric_limits<int>::max();
|
||||
mXCell = 0;
|
||||
mYCell = 0;
|
||||
mCell = NULL;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue