From 4391c1fd004308ceed6391df1de6d4180ed61d16 Mon Sep 17 00:00:00 2001 From: terrorfisch Date: Wed, 8 Oct 2014 22:11:45 +0200 Subject: [PATCH] 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. --- apps/openmw/mwmechanics/aistate.hpp | 7 +- apps/openmw/mwmechanics/aiwander.cpp | 100 ++++++++++++++------------- apps/openmw/mwmechanics/aiwander.hpp | 77 +++++++++++++-------- 3 files changed, 107 insertions(+), 77 deletions(-) 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