mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-29 03:26:38 +00:00 
			
		
		
		
	Refactor AiTemporaryStorage usage
This commit is contained in:
		
							parent
							
								
									705b2dca0e
								
							
						
					
					
						commit
						ee45f54b53
					
				
					 11 changed files with 201 additions and 216 deletions
				
			
		|  | @ -4,7 +4,6 @@ | ||||||
| 
 | 
 | ||||||
| namespace MWMechanics | namespace MWMechanics | ||||||
| { | { | ||||||
| 
 |  | ||||||
|     Actor::Actor(const MWWorld::Ptr &ptr, MWRender::Animation *animation) |     Actor::Actor(const MWWorld::Ptr &ptr, MWRender::Animation *animation) | ||||||
|     { |     { | ||||||
|         mCharacterController.reset(new CharacterController(ptr, animation)); |         mCharacterController.reset(new CharacterController(ptr, animation)); | ||||||
|  | @ -19,10 +18,4 @@ namespace MWMechanics | ||||||
|     { |     { | ||||||
|         return mCharacterController.get(); |         return mCharacterController.get(); | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     AiState& Actor::getAiState() |  | ||||||
|     { |  | ||||||
|         return mAiState; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -3,8 +3,6 @@ | ||||||
| 
 | 
 | ||||||
| #include <memory> | #include <memory> | ||||||
| 
 | 
 | ||||||
| #include "aistate.hpp" |  | ||||||
| 
 |  | ||||||
| namespace MWRender | namespace MWRender | ||||||
| { | { | ||||||
|     class Animation; |     class Animation; | ||||||
|  | @ -29,12 +27,8 @@ namespace MWMechanics | ||||||
| 
 | 
 | ||||||
|         CharacterController* getCharacterController(); |         CharacterController* getCharacterController(); | ||||||
| 
 | 
 | ||||||
|         AiState& getAiState(); |  | ||||||
| 
 |  | ||||||
|     private: |     private: | ||||||
|         std::unique_ptr<CharacterController> mCharacterController; |         std::unique_ptr<CharacterController> mCharacterController; | ||||||
| 
 |  | ||||||
|         AiState mAiState; |  | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1365,7 +1365,7 @@ namespace MWMechanics | ||||||
|                         { |                         { | ||||||
|                             CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first); |                             CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first); | ||||||
|                             if (isConscious(iter->first)) |                             if (isConscious(iter->first)) | ||||||
|                                 stats.getAiSequence().execute(iter->first, *iter->second->getCharacterController(), iter->second->getAiState(), duration); |                                 stats.getAiSequence().execute(iter->first, *iter->second->getCharacterController(), duration); | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|  | @ -1993,7 +1993,7 @@ namespace MWMechanics | ||||||
|                     || ptr.getClass().getCreatureStats(ptr).isParalyzed()) |                     || ptr.getClass().getCreatureStats(ptr).isParalyzed()) | ||||||
|                 continue; |                 continue; | ||||||
|             MWMechanics::AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence(); |             MWMechanics::AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence(); | ||||||
|             seq.fastForward(ptr, it->second->getAiState()); |             seq.fastForward(ptr); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -35,74 +35,6 @@ namespace | ||||||
| 
 | 
 | ||||||
| namespace MWMechanics | namespace MWMechanics | ||||||
| { | { | ||||||
|      |  | ||||||
|     /// \brief This class holds the variables AiCombat needs which are deleted if the package becomes inactive.
 |  | ||||||
|     struct AiCombatStorage : AiTemporaryBase |  | ||||||
|     { |  | ||||||
|         float mAttackCooldown; |  | ||||||
|         float mTimerReact; |  | ||||||
|         float mTimerCombatMove; |  | ||||||
|         bool mReadyToAttack; |  | ||||||
|         bool mAttack; |  | ||||||
|         float mAttackRange; |  | ||||||
|         bool mCombatMove; |  | ||||||
|         osg::Vec3f mLastTargetPos; |  | ||||||
|         const MWWorld::CellStore* mCell; |  | ||||||
|         std::shared_ptr<Action> mCurrentAction; |  | ||||||
|         float mActionCooldown; |  | ||||||
|         float mStrength; |  | ||||||
|         bool mForceNoShortcut; |  | ||||||
|         ESM::Position mShortcutFailPos; |  | ||||||
|         MWMechanics::Movement mMovement; |  | ||||||
| 
 |  | ||||||
|         enum FleeState |  | ||||||
|         { |  | ||||||
|             FleeState_None, |  | ||||||
|             FleeState_Idle, |  | ||||||
|             FleeState_RunBlindly, |  | ||||||
|             FleeState_RunToDestination |  | ||||||
|         }; |  | ||||||
|         FleeState mFleeState; |  | ||||||
|         bool mLOS; |  | ||||||
|         float mUpdateLOSTimer; |  | ||||||
|         float mFleeBlindRunTimer; |  | ||||||
|         ESM::Pathgrid::Point mFleeDest; |  | ||||||
|          |  | ||||||
|         AiCombatStorage(): |  | ||||||
|         mAttackCooldown(0.0f), |  | ||||||
|         mTimerReact(AI_REACTION_TIME), |  | ||||||
|         mTimerCombatMove(0.0f), |  | ||||||
|         mReadyToAttack(false), |  | ||||||
|         mAttack(false), |  | ||||||
|         mAttackRange(0.0f), |  | ||||||
|         mCombatMove(false), |  | ||||||
|         mLastTargetPos(0,0,0), |  | ||||||
|         mCell(NULL), |  | ||||||
|         mCurrentAction(), |  | ||||||
|         mActionCooldown(0.0f), |  | ||||||
|         mStrength(), |  | ||||||
|         mForceNoShortcut(false), |  | ||||||
|         mShortcutFailPos(), |  | ||||||
|         mMovement(), |  | ||||||
|         mFleeState(FleeState_None), |  | ||||||
|         mLOS(false), |  | ||||||
|         mUpdateLOSTimer(0.0f), |  | ||||||
|         mFleeBlindRunTimer(0.0f) |  | ||||||
|         {} |  | ||||||
| 
 |  | ||||||
|         void startCombatMove(bool isDistantCombat, float distToTarget, float rangeAttack, const MWWorld::Ptr& actor, const MWWorld::Ptr& target); |  | ||||||
|         void updateCombatMove(float duration); |  | ||||||
|         void stopCombatMove(); |  | ||||||
|         void startAttackIfReady(const MWWorld::Ptr& actor, CharacterController& characterController,  |  | ||||||
|             const ESM::Weapon* weapon, bool distantCombat); |  | ||||||
|         void updateAttack(CharacterController& characterController); |  | ||||||
|         void stopAttack(); |  | ||||||
| 
 |  | ||||||
|         void startFleeing(); |  | ||||||
|         void stopFleeing(); |  | ||||||
|         bool isFleeing(); |  | ||||||
|     }; |  | ||||||
|      |  | ||||||
|     AiCombat::AiCombat(const MWWorld::Ptr& actor) |     AiCombat::AiCombat(const MWWorld::Ptr& actor) | ||||||
|     { |     { | ||||||
|         mTargetActorId = actor.getClass().getCreatureStats(actor).getActorId(); |         mTargetActorId = actor.getClass().getCreatureStats(actor).getActorId(); | ||||||
|  | @ -115,7 +47,7 @@ namespace MWMechanics | ||||||
| 
 | 
 | ||||||
|     void AiCombat::init() |     void AiCombat::init() | ||||||
|     { |     { | ||||||
|          | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /*
 |     /*
 | ||||||
|  |  | ||||||
|  | @ -23,7 +23,72 @@ namespace MWMechanics | ||||||
| { | { | ||||||
|     class Action; |     class Action; | ||||||
| 
 | 
 | ||||||
|     struct AiCombatStorage; |     /// \brief This class holds the variables AiCombat needs which are deleted if the package becomes inactive.
 | ||||||
|  |     struct AiCombatStorage : AiTemporaryBase | ||||||
|  |     { | ||||||
|  |         float mAttackCooldown; | ||||||
|  |         float mTimerReact; | ||||||
|  |         float mTimerCombatMove; | ||||||
|  |         bool mReadyToAttack; | ||||||
|  |         bool mAttack; | ||||||
|  |         float mAttackRange; | ||||||
|  |         bool mCombatMove; | ||||||
|  |         osg::Vec3f mLastTargetPos; | ||||||
|  |         const MWWorld::CellStore* mCell; | ||||||
|  |         std::shared_ptr<Action> mCurrentAction; | ||||||
|  |         float mActionCooldown; | ||||||
|  |         float mStrength; | ||||||
|  |         bool mForceNoShortcut; | ||||||
|  |         ESM::Position mShortcutFailPos; | ||||||
|  |         MWMechanics::Movement mMovement; | ||||||
|  | 
 | ||||||
|  |         enum FleeState | ||||||
|  |         { | ||||||
|  |             FleeState_None, | ||||||
|  |             FleeState_Idle, | ||||||
|  |             FleeState_RunBlindly, | ||||||
|  |             FleeState_RunToDestination | ||||||
|  |         }; | ||||||
|  |         FleeState mFleeState; | ||||||
|  |         bool mLOS; | ||||||
|  |         float mUpdateLOSTimer; | ||||||
|  |         float mFleeBlindRunTimer; | ||||||
|  |         ESM::Pathgrid::Point mFleeDest; | ||||||
|  | 
 | ||||||
|  |         AiCombatStorage(): | ||||||
|  |         mAttackCooldown(0.0f), | ||||||
|  |         mTimerReact(AI_REACTION_TIME), | ||||||
|  |         mTimerCombatMove(0.0f), | ||||||
|  |         mReadyToAttack(false), | ||||||
|  |         mAttack(false), | ||||||
|  |         mAttackRange(0.0f), | ||||||
|  |         mCombatMove(false), | ||||||
|  |         mLastTargetPos(0,0,0), | ||||||
|  |         mCell(NULL), | ||||||
|  |         mCurrentAction(), | ||||||
|  |         mActionCooldown(0.0f), | ||||||
|  |         mStrength(), | ||||||
|  |         mForceNoShortcut(false), | ||||||
|  |         mShortcutFailPos(), | ||||||
|  |         mMovement(), | ||||||
|  |         mFleeState(FleeState_None), | ||||||
|  |         mLOS(false), | ||||||
|  |         mUpdateLOSTimer(0.0f), | ||||||
|  |         mFleeBlindRunTimer(0.0f) | ||||||
|  |         {} | ||||||
|  | 
 | ||||||
|  |         void startCombatMove(bool isDistantCombat, float distToTarget, float rangeAttack, const MWWorld::Ptr& actor, const MWWorld::Ptr& target); | ||||||
|  |         void updateCombatMove(float duration); | ||||||
|  |         void stopCombatMove(); | ||||||
|  |         void startAttackIfReady(const MWWorld::Ptr& actor, CharacterController& characterController, | ||||||
|  |             const ESM::Weapon* weapon, bool distantCombat); | ||||||
|  |         void updateAttack(CharacterController& characterController); | ||||||
|  |         void stopAttack(); | ||||||
|  | 
 | ||||||
|  |         void startFleeing(); | ||||||
|  |         void stopFleeing(); | ||||||
|  |         bool isFleeing(); | ||||||
|  |     }; | ||||||
| 
 | 
 | ||||||
|     /// \brief Causes the actor to fight another actor
 |     /// \brief Causes the actor to fight another actor
 | ||||||
|     class AiCombat : public AiPackage |     class AiCombat : public AiPackage | ||||||
|  |  | ||||||
|  | @ -17,22 +17,6 @@ | ||||||
| namespace MWMechanics | namespace MWMechanics | ||||||
| { | { | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| struct AiFollowStorage : AiTemporaryBase |  | ||||||
| { |  | ||||||
|     float mTimer; |  | ||||||
|     bool mMoving; |  | ||||||
|     float mTargetAngleRadians; |  | ||||||
|     bool mTurnActorToTarget; |  | ||||||
| 
 |  | ||||||
|     AiFollowStorage() : |  | ||||||
|         mTimer(0.f), |  | ||||||
|         mMoving(false), |  | ||||||
|         mTargetAngleRadians(0.f), |  | ||||||
|         mTurnActorToTarget(false) |  | ||||||
|     {} |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| int AiFollow::mFollowIndexCounter = 0; | int AiFollow::mFollowIndexCounter = 0; | ||||||
| 
 | 
 | ||||||
| AiFollow::AiFollow(const std::string &actorId, float duration, float x, float y, float z) | AiFollow::AiFollow(const std::string &actorId, float duration, float x, float y, float z) | ||||||
|  |  | ||||||
|  | @ -19,6 +19,21 @@ namespace AiSequence | ||||||
| 
 | 
 | ||||||
| namespace MWMechanics | namespace MWMechanics | ||||||
| { | { | ||||||
|  |     struct AiFollowStorage : AiTemporaryBase | ||||||
|  |     { | ||||||
|  |         float mTimer; | ||||||
|  |         bool mMoving; | ||||||
|  |         float mTargetAngleRadians; | ||||||
|  |         bool mTurnActorToTarget; | ||||||
|  | 
 | ||||||
|  |         AiFollowStorage() : | ||||||
|  |             mTimer(0.f), | ||||||
|  |             mMoving(false), | ||||||
|  |             mTargetAngleRadians(0.f), | ||||||
|  |             mTurnActorToTarget(false) | ||||||
|  |         {} | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|     /// \brief AiPackage for an actor to follow another actor/the PC
 |     /// \brief AiPackage for an actor to follow another actor/the PC
 | ||||||
|     /** The AI will follow the target until a condition (time, or position) are set. Both can be disabled to cause the actor to follow the other indefinitely
 |     /** The AI will follow the target until a condition (time, or position) are set. Both can be disabled to cause the actor to follow the other indefinitely
 | ||||||
|     **/ |     **/ | ||||||
|  |  | ||||||
|  | @ -188,7 +188,7 @@ bool isActualAiPackage(int packageTypeId) | ||||||
|                    && packageTypeId != AiPackage::TypeIdInternalTravel); |                    && packageTypeId != AiPackage::TypeIdInternalTravel); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) | void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& characterController, float duration) | ||||||
| { | { | ||||||
|     if(actor != getPlayer()) |     if(actor != getPlayer()) | ||||||
|     { |     { | ||||||
|  | @ -262,7 +262,7 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac | ||||||
| 
 | 
 | ||||||
|         try |         try | ||||||
|         { |         { | ||||||
|             if (package->execute (actor,characterController,state,duration)) |             if (package->execute (actor, characterController, mAiState, duration)) | ||||||
|             { |             { | ||||||
|                 // Put repeating noncombat AI packages on the end of the stack so they can be used again
 |                 // Put repeating noncombat AI packages on the end of the stack so they can be used again
 | ||||||
|                 if (isActualAiPackage(packageTypeId) && (mRepeat || package->getRepeat())) |                 if (isActualAiPackage(packageTypeId) && (mRepeat || package->getRepeat())) | ||||||
|  | @ -494,12 +494,12 @@ void AiSequence::readState(const ESM::AiSequence::AiSequence &sequence) | ||||||
|     mLastAiPackage = sequence.mLastAiPackage; |     mLastAiPackage = sequence.mLastAiPackage; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AiSequence::fastForward(const MWWorld::Ptr& actor, AiState& state) | void AiSequence::fastForward(const MWWorld::Ptr& actor) | ||||||
| { | { | ||||||
|     if (!mPackages.empty()) |     if (!mPackages.empty()) | ||||||
|     { |     { | ||||||
|         MWMechanics::AiPackage* package = mPackages.front(); |         MWMechanics::AiPackage* package = mPackages.front(); | ||||||
|         package->fastForward(actor, state); |         package->fastForward(actor, mAiState); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -3,6 +3,8 @@ | ||||||
| 
 | 
 | ||||||
| #include <list> | #include <list> | ||||||
| 
 | 
 | ||||||
|  | #include "aistate.hpp" | ||||||
|  | 
 | ||||||
| #include <components/esm/loadnpc.hpp> | #include <components/esm/loadnpc.hpp> | ||||||
| 
 | 
 | ||||||
| namespace MWWorld | namespace MWWorld | ||||||
|  | @ -47,6 +49,7 @@ namespace MWMechanics | ||||||
| 
 | 
 | ||||||
|             /// The type of AI package that ran last
 |             /// The type of AI package that ran last
 | ||||||
|             int mLastAiPackage; |             int mLastAiPackage; | ||||||
|  |             AiState mAiState; | ||||||
| 
 | 
 | ||||||
|         public: |         public: | ||||||
|             ///Default constructor
 |             ///Default constructor
 | ||||||
|  | @ -104,10 +107,10 @@ namespace MWMechanics | ||||||
|             void stopPursuit(); |             void stopPursuit(); | ||||||
| 
 | 
 | ||||||
|             /// Execute current package, switching if needed.
 |             /// Execute current package, switching if needed.
 | ||||||
|             void execute (const MWWorld::Ptr& actor, CharacterController& characterController, MWMechanics::AiState& state, float duration); |             void execute (const MWWorld::Ptr& actor, CharacterController& characterController, float duration); | ||||||
| 
 | 
 | ||||||
|             /// Simulate the passing of time using the currently active AI package
 |             /// Simulate the passing of time using the currently active AI package
 | ||||||
|             void fastForward(const MWWorld::Ptr &actor, AiState &state); |             void fastForward(const MWWorld::Ptr &actor); | ||||||
| 
 | 
 | ||||||
|             /// Remove all packages.
 |             /// Remove all packages.
 | ||||||
|             void clear(); |             void clear(); | ||||||
|  |  | ||||||
|  | @ -51,67 +51,6 @@ namespace MWMechanics | ||||||
|         std::string("idle9"), |         std::string("idle9"), | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     /// \brief This class holds the variables AiWander needs which are deleted if the package becomes inactive.
 |  | ||||||
|     struct AiWanderStorage : AiTemporaryBase |  | ||||||
|     { |  | ||||||
|         // the z rotation angle to reach
 |  | ||||||
|         // when mTurnActorGivingGreetingToFacePlayer is true
 |  | ||||||
|         float mTargetAngleRadians; |  | ||||||
|         bool mTurnActorGivingGreetingToFacePlayer; |  | ||||||
|         float mReaction; // update some actions infrequently
 |  | ||||||
| 
 |  | ||||||
|         AiWander::GreetingState mSaidGreeting; |  | ||||||
|         int mGreetingTimer; |  | ||||||
| 
 |  | ||||||
|         const MWWorld::CellStore* mCell; // for detecting cell change
 |  | ||||||
| 
 |  | ||||||
|         // AiWander states
 |  | ||||||
|         AiWander::WanderState mState; |  | ||||||
| 
 |  | ||||||
|         bool mIsWanderingManually; |  | ||||||
|         bool mCanWanderAlongPathGrid; |  | ||||||
| 
 |  | ||||||
|         unsigned short mIdleAnimation; |  | ||||||
|         std::vector<unsigned short> mBadIdles; // Idle animations that when called cause errors
 |  | ||||||
| 
 |  | ||||||
|         // do we need to calculate allowed nodes based on mDistance
 |  | ||||||
|         bool mPopulateAvailableNodes; |  | ||||||
| 
 |  | ||||||
|         // allowed pathgrid nodes based on mDistance from the spawn point
 |  | ||||||
|         // in local coordinates of mCell
 |  | ||||||
|         std::vector<ESM::Pathgrid::Point> mAllowedNodes; |  | ||||||
| 
 |  | ||||||
|         ESM::Pathgrid::Point mCurrentNode; |  | ||||||
|         bool mTrimCurrentNode; |  | ||||||
| 
 |  | ||||||
|         float mDoorCheckDuration; |  | ||||||
|         int mStuckCount; |  | ||||||
| 
 |  | ||||||
|         AiWanderStorage(): |  | ||||||
|             mTargetAngleRadians(0), |  | ||||||
|             mTurnActorGivingGreetingToFacePlayer(false), |  | ||||||
|             mReaction(0), |  | ||||||
|             mSaidGreeting(AiWander::Greet_None), |  | ||||||
|             mGreetingTimer(0), |  | ||||||
|             mCell(NULL), |  | ||||||
|             mState(AiWander::Wander_ChooseAction), |  | ||||||
|             mIsWanderingManually(false), |  | ||||||
|             mCanWanderAlongPathGrid(true), |  | ||||||
|             mIdleAnimation(0), |  | ||||||
|             mBadIdles(), |  | ||||||
|             mPopulateAvailableNodes(true), |  | ||||||
|             mAllowedNodes(), |  | ||||||
|             mTrimCurrentNode(false), |  | ||||||
|             mDoorCheckDuration(0), // TODO: maybe no longer needed
 |  | ||||||
|             mStuckCount(0) |  | ||||||
|             {}; |  | ||||||
| 
 |  | ||||||
|         void setState(const AiWander::WanderState wanderState, const bool isManualWander = false) { |  | ||||||
|             mState = wanderState; |  | ||||||
|             mIsWanderingManually = isManualWander; |  | ||||||
|         } |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<unsigned char>& idle, bool repeat): |     AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<unsigned char>& idle, bool repeat): | ||||||
|         mDistance(distance), mDuration(duration), mRemainingDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), |         mDistance(distance), mDuration(duration), mRemainingDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), | ||||||
|         mRepeat(repeat), mStoredInitialActorPosition(false), mInitialActorPosition(osg::Vec3f(0, 0, 0)), mHasDestination(false), mDestination(osg::Vec3f(0, 0, 0)) |         mRepeat(repeat), mStoredInitialActorPosition(false), mInitialActorPosition(osg::Vec3f(0, 0, 0)), mHasDestination(false), mDestination(osg::Vec3f(0, 0, 0)) | ||||||
|  | @ -221,7 +160,7 @@ namespace MWMechanics | ||||||
|             mPathFinder.buildSyncedPath(start, dest, actor.getCell(), getPathGridGraph(actor.getCell())); |             mPathFinder.buildSyncedPath(start, dest, actor.getCell(), getPathGridGraph(actor.getCell())); | ||||||
| 
 | 
 | ||||||
|             if (mPathFinder.isPathConstructed()) |             if (mPathFinder.isPathConstructed()) | ||||||
|                 storage.setState(Wander_Walking); |                 storage.setState(AiWanderStorage::Wander_Walking); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         doPerFrameActionsForState(actor, duration, storage, pos); |         doPerFrameActionsForState(actor, duration, storage, pos); | ||||||
|  | @ -270,7 +209,7 @@ namespace MWMechanics | ||||||
| 
 | 
 | ||||||
|         if(actorCanMoveByZ && mDistance > 0) { |         if(actorCanMoveByZ && mDistance > 0) { | ||||||
|             // Typically want to idle for a short time before the next wander
 |             // Typically want to idle for a short time before the next wander
 | ||||||
|             if (Misc::Rng::rollDice(100) >= 92 && storage.mState != Wander_Walking) { |             if (Misc::Rng::rollDice(100) >= 92 && storage.mState != AiWanderStorage::Wander_Walking) { | ||||||
|                 wanderNearStart(actor, storage, mDistance); |                 wanderNearStart(actor, storage, mDistance); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  | @ -283,7 +222,7 @@ namespace MWMechanics | ||||||
|             if (Misc::Rng::rollDice(100) >= 96) { |             if (Misc::Rng::rollDice(100) >= 96) { | ||||||
|                 wanderNearStart(actor, storage, mDistance); |                 wanderNearStart(actor, storage, mDistance); | ||||||
|             } else { |             } else { | ||||||
|                 storage.setState(Wander_IdleNow); |                 storage.setState(AiWanderStorage::Wander_IdleNow); | ||||||
|             } |             } | ||||||
|         } else if (storage.mAllowedNodes.empty() && !storage.mIsWanderingManually) { |         } else if (storage.mAllowedNodes.empty() && !storage.mIsWanderingManually) { | ||||||
|             storage.mCanWanderAlongPathGrid = false; |             storage.mCanWanderAlongPathGrid = false; | ||||||
|  | @ -299,13 +238,13 @@ namespace MWMechanics | ||||||
|             mDistance = 0; |             mDistance = 0; | ||||||
| 
 | 
 | ||||||
|         // Allow interrupting a walking actor to trigger a greeting
 |         // Allow interrupting a walking actor to trigger a greeting
 | ||||||
|         WanderState& wanderState = storage.mState; |         AiWanderStorage::WanderState& wanderState = storage.mState; | ||||||
|         if ((wanderState == Wander_IdleNow) || (wanderState == Wander_Walking)) |         if ((wanderState == AiWanderStorage::Wander_IdleNow) || (wanderState == AiWanderStorage::Wander_Walking)) | ||||||
|         { |         { | ||||||
|             playGreetingIfPlayerGetsTooClose(actor, storage); |             playGreetingIfPlayerGetsTooClose(actor, storage); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if ((wanderState == Wander_MoveNow) && storage.mCanWanderAlongPathGrid) |         if ((wanderState == AiWanderStorage::Wander_MoveNow) && storage.mCanWanderAlongPathGrid) | ||||||
|         { |         { | ||||||
|             // Construct a new path if there isn't one
 |             // Construct a new path if there isn't one
 | ||||||
|             if(!mPathFinder.isPathConstructed()) |             if(!mPathFinder.isPathConstructed()) | ||||||
|  | @ -381,7 +320,7 @@ namespace MWMechanics | ||||||
| 
 | 
 | ||||||
|                 if (mPathFinder.isPathConstructed()) |                 if (mPathFinder.isPathConstructed()) | ||||||
|                 { |                 { | ||||||
|                     storage.setState(Wander_Walking, true); |                     storage.setState(AiWanderStorage::Wander_Walking, true); | ||||||
|                     mHasDestination = true; |                     mHasDestination = true; | ||||||
|                 } |                 } | ||||||
|                 return; |                 return; | ||||||
|  | @ -410,26 +349,26 @@ namespace MWMechanics | ||||||
|     void AiWander::completeManualWalking(const MWWorld::Ptr &actor, AiWanderStorage &storage) { |     void AiWander::completeManualWalking(const MWWorld::Ptr &actor, AiWanderStorage &storage) { | ||||||
|         stopWalking(actor, storage); |         stopWalking(actor, storage); | ||||||
|         mObstacleCheck.clear(); |         mObstacleCheck.clear(); | ||||||
|         storage.setState(Wander_IdleNow); |         storage.setState(AiWanderStorage::Wander_IdleNow); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void AiWander::doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos) |     void AiWander::doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos) | ||||||
|     { |     { | ||||||
|         switch (storage.mState) |         switch (storage.mState) | ||||||
|         { |         { | ||||||
|             case Wander_IdleNow: |             case AiWanderStorage::Wander_IdleNow: | ||||||
|                 onIdleStatePerFrameActions(actor, duration, storage); |                 onIdleStatePerFrameActions(actor, duration, storage); | ||||||
|                 break; |                 break; | ||||||
| 
 | 
 | ||||||
|             case Wander_Walking: |             case AiWanderStorage::Wander_Walking: | ||||||
|                 onWalkingStatePerFrameActions(actor, duration, storage, pos); |                 onWalkingStatePerFrameActions(actor, duration, storage, pos); | ||||||
|                 break; |                 break; | ||||||
| 
 | 
 | ||||||
|             case Wander_ChooseAction: |             case AiWanderStorage::Wander_ChooseAction: | ||||||
|                 onChooseActionStatePerFrameActions(actor, storage); |                 onChooseActionStatePerFrameActions(actor, storage); | ||||||
|                 break; |                 break; | ||||||
| 
 | 
 | ||||||
|             case Wander_MoveNow: |             case AiWanderStorage::Wander_MoveNow: | ||||||
|                 break;  // nothing to do
 |                 break;  // nothing to do
 | ||||||
| 
 | 
 | ||||||
|             default: |             default: | ||||||
|  | @ -451,7 +390,7 @@ namespace MWMechanics | ||||||
|             if (mDistance &&            // actor is not intended to be stationary
 |             if (mDistance &&            // actor is not intended to be stationary
 | ||||||
|                 proximityToDoor(actor, distance*1.6f)) |                 proximityToDoor(actor, distance*1.6f)) | ||||||
|             { |             { | ||||||
|                 storage.setState(Wander_MoveNow); |                 storage.setState(AiWanderStorage::Wander_MoveNow); | ||||||
|                 storage.mTrimCurrentNode = false; // just in case
 |                 storage.mTrimCurrentNode = false; // just in case
 | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|  | @ -468,13 +407,13 @@ namespace MWMechanics | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // Check if idle animation finished
 |         // Check if idle animation finished
 | ||||||
|         GreetingState& greetingState = storage.mSaidGreeting; |         AiWanderStorage::GreetingState& greetingState = storage.mSaidGreeting; | ||||||
|         if (!checkIdle(actor, storage.mIdleAnimation) && (greetingState == Greet_Done || greetingState == Greet_None)) |         if (!checkIdle(actor, storage.mIdleAnimation) && (greetingState == AiWanderStorage::Greet_Done || greetingState == AiWanderStorage::Greet_None)) | ||||||
|         { |         { | ||||||
|             if (mPathFinder.isPathConstructed()) |             if (mPathFinder.isPathConstructed()) | ||||||
|                 storage.setState(Wander_Walking); |                 storage.setState(AiWanderStorage::Wander_Walking); | ||||||
|             else |             else | ||||||
|                 storage.setState(Wander_ChooseAction); |                 storage.setState(AiWanderStorage::Wander_ChooseAction); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -485,7 +424,7 @@ namespace MWMechanics | ||||||
|         if ((!mPathFinder.isPathConstructed()) || pathTo(actor, ESM::Pathgrid::Point(mPathFinder.getPath().back()), duration, DESTINATION_TOLERANCE)) |         if ((!mPathFinder.isPathConstructed()) || pathTo(actor, ESM::Pathgrid::Point(mPathFinder.getPath().back()), duration, DESTINATION_TOLERANCE)) | ||||||
|         { |         { | ||||||
|             stopWalking(actor, storage); |             stopWalking(actor, storage); | ||||||
|             storage.setState(Wander_ChooseAction); |             storage.setState(AiWanderStorage::Wander_ChooseAction); | ||||||
|         } |         } | ||||||
|         else |         else | ||||||
|         { |         { | ||||||
|  | @ -502,7 +441,7 @@ namespace MWMechanics | ||||||
| 
 | 
 | ||||||
|         if (!idleAnimation && mDistance) |         if (!idleAnimation && mDistance) | ||||||
|         { |         { | ||||||
|             storage.setState(Wander_MoveNow); |             storage.setState(AiWanderStorage::Wander_MoveNow); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         if(idleAnimation) |         if(idleAnimation) | ||||||
|  | @ -512,13 +451,13 @@ namespace MWMechanics | ||||||
|                 if(!playIdle(actor, idleAnimation)) |                 if(!playIdle(actor, idleAnimation)) | ||||||
|                 { |                 { | ||||||
|                     storage.mBadIdles.push_back(idleAnimation); |                     storage.mBadIdles.push_back(idleAnimation); | ||||||
|                     storage.setState(Wander_ChooseAction); |                     storage.setState(AiWanderStorage::Wander_ChooseAction); | ||||||
|                     return; |                     return; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         storage.setState(Wander_IdleNow); |         storage.setState(AiWanderStorage::Wander_IdleNow); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration, ESM::Position& pos) |     void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration, ESM::Position& pos) | ||||||
|  | @ -534,7 +473,7 @@ namespace MWMechanics | ||||||
|                 trimAllowedNodes(storage.mAllowedNodes, mPathFinder); |                 trimAllowedNodes(storage.mAllowedNodes, mPathFinder); | ||||||
|                 mObstacleCheck.clear(); |                 mObstacleCheck.clear(); | ||||||
|                 stopWalking(actor, storage); |                 stopWalking(actor, storage); | ||||||
|                 storage.setState(Wander_MoveNow); |                 storage.setState(AiWanderStorage::Wander_MoveNow); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|            storage.mStuckCount++;  // TODO: maybe no longer needed
 |            storage.mStuckCount++;  // TODO: maybe no longer needed
 | ||||||
|  | @ -545,7 +484,7 @@ namespace MWMechanics | ||||||
|         { |         { | ||||||
|             mObstacleCheck.clear(); |             mObstacleCheck.clear(); | ||||||
|             stopWalking(actor, storage); |             stopWalking(actor, storage); | ||||||
|             storage.setState(Wander_ChooseAction); |             storage.setState(AiWanderStorage::Wander_ChooseAction); | ||||||
|             storage.mStuckCount = 0; |             storage.mStuckCount = 0; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -596,8 +535,8 @@ namespace MWMechanics | ||||||
|         float playerDistSqr = (playerPos - actorPos).length2(); |         float playerDistSqr = (playerPos - actorPos).length2(); | ||||||
| 
 | 
 | ||||||
|         int& greetingTimer = storage.mGreetingTimer; |         int& greetingTimer = storage.mGreetingTimer; | ||||||
|         GreetingState& greetingState = storage.mSaidGreeting; |         AiWanderStorage::GreetingState& greetingState = storage.mSaidGreeting; | ||||||
|         if (greetingState == Greet_None) |         if (greetingState == AiWanderStorage::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) | ||||||
|  | @ -606,37 +545,37 @@ namespace MWMechanics | ||||||
| 
 | 
 | ||||||
|             if (greetingTimer >= GREETING_SHOULD_START) |             if (greetingTimer >= GREETING_SHOULD_START) | ||||||
|             { |             { | ||||||
|                 greetingState = Greet_InProgress; |                 greetingState = AiWanderStorage::Greet_InProgress; | ||||||
|                 MWBase::Environment::get().getDialogueManager()->say(actor, "hello"); |                 MWBase::Environment::get().getDialogueManager()->say(actor, "hello"); | ||||||
|                 greetingTimer = 0; |                 greetingTimer = 0; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (greetingState == Greet_InProgress) |         if (greetingState == AiWanderStorage::Greet_InProgress) | ||||||
|         { |         { | ||||||
|             greetingTimer++; |             greetingTimer++; | ||||||
| 
 | 
 | ||||||
|             if (storage.mState == Wander_Walking) |             if (storage.mState == AiWanderStorage::Wander_Walking) | ||||||
|             { |             { | ||||||
|                 stopWalking(actor, storage, false); |                 stopWalking(actor, storage, false); | ||||||
|                 mObstacleCheck.clear(); |                 mObstacleCheck.clear(); | ||||||
|                 storage.setState(Wander_IdleNow); |                 storage.setState(AiWanderStorage::Wander_IdleNow); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             turnActorToFacePlayer(actorPos, playerPos, storage); |             turnActorToFacePlayer(actorPos, playerPos, storage); | ||||||
| 
 | 
 | ||||||
|             if (greetingTimer >= GREETING_SHOULD_END) |             if (greetingTimer >= GREETING_SHOULD_END) | ||||||
|             { |             { | ||||||
|                 greetingState = Greet_Done; |                 greetingState = AiWanderStorage::Greet_Done; | ||||||
|                 greetingTimer = 0; |                 greetingTimer = 0; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (greetingState == MWMechanics::AiWander::Greet_Done) |         if (greetingState == AiWanderStorage::Greet_Done) | ||||||
|         { |         { | ||||||
|             float resetDist = 2 * helloDistance; |             float resetDist = 2 * helloDistance; | ||||||
|             if (playerDistSqr >= resetDist*resetDist) |             if (playerDistSqr >= resetDist*resetDist) | ||||||
|                 greetingState = Greet_None; |                 greetingState = AiWanderStorage::Greet_None; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -676,7 +615,7 @@ namespace MWMechanics | ||||||
|                 storage.mAllowedNodes.push_back(storage.mCurrentNode); |                 storage.mAllowedNodes.push_back(storage.mCurrentNode); | ||||||
|             storage.mCurrentNode = temp; |             storage.mCurrentNode = temp; | ||||||
| 
 | 
 | ||||||
|             storage.setState(Wander_Walking); |             storage.setState(AiWanderStorage::Wander_Walking); | ||||||
|         } |         } | ||||||
|         // Choose a different node and delete this one from possible nodes because it is uncreachable:
 |         // Choose a different node and delete this one from possible nodes because it is uncreachable:
 | ||||||
|         else |         else | ||||||
|  |  | ||||||
|  | @ -21,8 +21,81 @@ namespace ESM | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| namespace MWMechanics | namespace MWMechanics | ||||||
| {        | { | ||||||
|     struct AiWanderStorage; |     /// \brief This class holds the variables AiWander needs which are deleted if the package becomes inactive.
 | ||||||
|  |     struct AiWanderStorage : AiTemporaryBase | ||||||
|  |     { | ||||||
|  |         // the z rotation angle to reach
 | ||||||
|  |         // when mTurnActorGivingGreetingToFacePlayer is true
 | ||||||
|  |         float mTargetAngleRadians; | ||||||
|  |         bool mTurnActorGivingGreetingToFacePlayer; | ||||||
|  |         float mReaction; // update some actions infrequently
 | ||||||
|  | 
 | ||||||
|  |         enum GreetingState | ||||||
|  |         { | ||||||
|  |             Greet_None, | ||||||
|  |             Greet_InProgress, | ||||||
|  |             Greet_Done | ||||||
|  |         }; | ||||||
|  |         GreetingState mSaidGreeting; | ||||||
|  |         int mGreetingTimer; | ||||||
|  | 
 | ||||||
|  |         const MWWorld::CellStore* mCell; // for detecting cell change
 | ||||||
|  | 
 | ||||||
|  |         // AiWander states
 | ||||||
|  |         enum WanderState | ||||||
|  |         { | ||||||
|  |             Wander_ChooseAction, | ||||||
|  |             Wander_IdleNow, | ||||||
|  |             Wander_MoveNow, | ||||||
|  |             Wander_Walking | ||||||
|  |         }; | ||||||
|  |         WanderState mState; | ||||||
|  | 
 | ||||||
|  |         bool mIsWanderingManually; | ||||||
|  |         bool mCanWanderAlongPathGrid; | ||||||
|  | 
 | ||||||
|  |         unsigned short mIdleAnimation; | ||||||
|  |         std::vector<unsigned short> mBadIdles; // Idle animations that when called cause errors
 | ||||||
|  | 
 | ||||||
|  |         // do we need to calculate allowed nodes based on mDistance
 | ||||||
|  |         bool mPopulateAvailableNodes; | ||||||
|  | 
 | ||||||
|  |         // allowed pathgrid nodes based on mDistance from the spawn point
 | ||||||
|  |         // in local coordinates of mCell
 | ||||||
|  |         std::vector<ESM::Pathgrid::Point> mAllowedNodes; | ||||||
|  | 
 | ||||||
|  |         ESM::Pathgrid::Point mCurrentNode; | ||||||
|  |         bool mTrimCurrentNode; | ||||||
|  | 
 | ||||||
|  |         float mDoorCheckDuration; | ||||||
|  |         int mStuckCount; | ||||||
|  | 
 | ||||||
|  |         AiWanderStorage(): | ||||||
|  |             mTargetAngleRadians(0), | ||||||
|  |             mTurnActorGivingGreetingToFacePlayer(false), | ||||||
|  |             mReaction(0), | ||||||
|  |             mSaidGreeting(Greet_None), | ||||||
|  |             mGreetingTimer(0), | ||||||
|  |             mCell(NULL), | ||||||
|  |             mState(Wander_ChooseAction), | ||||||
|  |             mIsWanderingManually(false), | ||||||
|  |             mCanWanderAlongPathGrid(true), | ||||||
|  |             mIdleAnimation(0), | ||||||
|  |             mBadIdles(), | ||||||
|  |             mPopulateAvailableNodes(true), | ||||||
|  |             mAllowedNodes(), | ||||||
|  |             mTrimCurrentNode(false), | ||||||
|  |             mDoorCheckDuration(0), // TODO: maybe no longer needed
 | ||||||
|  |             mStuckCount(0) | ||||||
|  |             {}; | ||||||
|  | 
 | ||||||
|  |         void setState(const WanderState wanderState, const bool isManualWander = false) | ||||||
|  |         { | ||||||
|  |             mState = wanderState; | ||||||
|  |             mIsWanderingManually = isManualWander; | ||||||
|  |         } | ||||||
|  |     }; | ||||||
| 
 | 
 | ||||||
|     /// \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 | ||||||
|  | @ -52,19 +125,6 @@ namespace MWMechanics | ||||||
| 
 | 
 | ||||||
|             osg::Vec3f getDestination(const MWWorld::Ptr& actor) const; |             osg::Vec3f getDestination(const MWWorld::Ptr& actor) const; | ||||||
| 
 | 
 | ||||||
|             enum GreetingState { |  | ||||||
|                 Greet_None, |  | ||||||
|                 Greet_InProgress, |  | ||||||
|                 Greet_Done |  | ||||||
|             }; |  | ||||||
| 
 |  | ||||||
|             enum WanderState { |  | ||||||
|                 Wander_ChooseAction, |  | ||||||
|                 Wander_IdleNow, |  | ||||||
|                 Wander_MoveNow, |  | ||||||
|                 Wander_Walking |  | ||||||
|             }; |  | ||||||
| 
 |  | ||||||
|         private: |         private: | ||||||
|             // NOTE: mDistance and mDuration must be set already
 |             // NOTE: mDistance and mDuration must be set already
 | ||||||
|             void init(); |             void init(); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue