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 | ||||
| { | ||||
| 
 | ||||
|     Actor::Actor(const MWWorld::Ptr &ptr, MWRender::Animation *animation) | ||||
|     { | ||||
|         mCharacterController.reset(new CharacterController(ptr, animation)); | ||||
|  | @ -19,10 +18,4 @@ namespace MWMechanics | |||
|     { | ||||
|         return mCharacterController.get(); | ||||
|     } | ||||
| 
 | ||||
|     AiState& Actor::getAiState() | ||||
|     { | ||||
|         return mAiState; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -3,8 +3,6 @@ | |||
| 
 | ||||
| #include <memory> | ||||
| 
 | ||||
| #include "aistate.hpp" | ||||
| 
 | ||||
| namespace MWRender | ||||
| { | ||||
|     class Animation; | ||||
|  | @ -29,12 +27,8 @@ namespace MWMechanics | |||
| 
 | ||||
|         CharacterController* getCharacterController(); | ||||
| 
 | ||||
|         AiState& getAiState(); | ||||
| 
 | ||||
|     private: | ||||
|         std::unique_ptr<CharacterController> mCharacterController; | ||||
| 
 | ||||
|         AiState mAiState; | ||||
|     }; | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -1365,7 +1365,7 @@ namespace MWMechanics | |||
|                         { | ||||
|                             CreatureStats &stats = iter->first.getClass().getCreatureStats(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()) | ||||
|                 continue; | ||||
|             MWMechanics::AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence(); | ||||
|             seq.fastForward(ptr, it->second->getAiState()); | ||||
|             seq.fastForward(ptr); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -35,74 +35,6 @@ namespace | |||
| 
 | ||||
| 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) | ||||
|     { | ||||
|         mTargetActorId = actor.getClass().getCreatureStats(actor).getActorId(); | ||||
|  |  | |||
|  | @ -23,7 +23,72 @@ namespace MWMechanics | |||
| { | ||||
|     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
 | ||||
|     class AiCombat : public AiPackage | ||||
|  |  | |||
|  | @ -17,22 +17,6 @@ | |||
| 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; | ||||
| 
 | ||||
| AiFollow::AiFollow(const std::string &actorId, float duration, float x, float y, float z) | ||||
|  |  | |||
|  | @ -19,6 +19,21 @@ namespace AiSequence | |||
| 
 | ||||
| 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
 | ||||
|     /** 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); | ||||
| } | ||||
| 
 | ||||
| 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()) | ||||
|     { | ||||
|  | @ -262,7 +262,7 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac | |||
| 
 | ||||
|         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
 | ||||
|                 if (isActualAiPackage(packageTypeId) && (mRepeat || package->getRepeat())) | ||||
|  | @ -494,12 +494,12 @@ void AiSequence::readState(const ESM::AiSequence::AiSequence &sequence) | |||
|     mLastAiPackage = sequence.mLastAiPackage; | ||||
| } | ||||
| 
 | ||||
| void AiSequence::fastForward(const MWWorld::Ptr& actor, AiState& state) | ||||
| void AiSequence::fastForward(const MWWorld::Ptr& actor) | ||||
| { | ||||
|     if (!mPackages.empty()) | ||||
|     { | ||||
|         MWMechanics::AiPackage* package = mPackages.front(); | ||||
|         package->fastForward(actor, state); | ||||
|         package->fastForward(actor, mAiState); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,6 +3,8 @@ | |||
| 
 | ||||
| #include <list> | ||||
| 
 | ||||
| #include "aistate.hpp" | ||||
| 
 | ||||
| #include <components/esm/loadnpc.hpp> | ||||
| 
 | ||||
| namespace MWWorld | ||||
|  | @ -47,6 +49,7 @@ namespace MWMechanics | |||
| 
 | ||||
|             /// The type of AI package that ran last
 | ||||
|             int mLastAiPackage; | ||||
|             AiState mAiState; | ||||
| 
 | ||||
|         public: | ||||
|             ///Default constructor
 | ||||
|  | @ -104,10 +107,10 @@ namespace MWMechanics | |||
|             void stopPursuit(); | ||||
| 
 | ||||
|             /// 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
 | ||||
|             void fastForward(const MWWorld::Ptr &actor, AiState &state); | ||||
|             void fastForward(const MWWorld::Ptr &actor); | ||||
| 
 | ||||
|             /// Remove all packages.
 | ||||
|             void clear(); | ||||
|  |  | |||
|  | @ -51,67 +51,6 @@ namespace MWMechanics | |||
|         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): | ||||
|         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)) | ||||
|  | @ -221,7 +160,7 @@ namespace MWMechanics | |||
|             mPathFinder.buildSyncedPath(start, dest, actor.getCell(), getPathGridGraph(actor.getCell())); | ||||
| 
 | ||||
|             if (mPathFinder.isPathConstructed()) | ||||
|                 storage.setState(Wander_Walking); | ||||
|                 storage.setState(AiWanderStorage::Wander_Walking); | ||||
|         } | ||||
| 
 | ||||
|         doPerFrameActionsForState(actor, duration, storage, pos); | ||||
|  | @ -270,7 +209,7 @@ namespace MWMechanics | |||
| 
 | ||||
|         if(actorCanMoveByZ && mDistance > 0) { | ||||
|             // 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); | ||||
|             } | ||||
| 
 | ||||
|  | @ -283,7 +222,7 @@ namespace MWMechanics | |||
|             if (Misc::Rng::rollDice(100) >= 96) { | ||||
|                 wanderNearStart(actor, storage, mDistance); | ||||
|             } else { | ||||
|                 storage.setState(Wander_IdleNow); | ||||
|                 storage.setState(AiWanderStorage::Wander_IdleNow); | ||||
|             } | ||||
|         } else if (storage.mAllowedNodes.empty() && !storage.mIsWanderingManually) { | ||||
|             storage.mCanWanderAlongPathGrid = false; | ||||
|  | @ -299,13 +238,13 @@ namespace MWMechanics | |||
|             mDistance = 0; | ||||
| 
 | ||||
|         // Allow interrupting a walking actor to trigger a greeting
 | ||||
|         WanderState& wanderState = storage.mState; | ||||
|         if ((wanderState == Wander_IdleNow) || (wanderState == Wander_Walking)) | ||||
|         AiWanderStorage::WanderState& wanderState = storage.mState; | ||||
|         if ((wanderState == AiWanderStorage::Wander_IdleNow) || (wanderState == AiWanderStorage::Wander_Walking)) | ||||
|         { | ||||
|             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
 | ||||
|             if(!mPathFinder.isPathConstructed()) | ||||
|  | @ -381,7 +320,7 @@ namespace MWMechanics | |||
| 
 | ||||
|                 if (mPathFinder.isPathConstructed()) | ||||
|                 { | ||||
|                     storage.setState(Wander_Walking, true); | ||||
|                     storage.setState(AiWanderStorage::Wander_Walking, true); | ||||
|                     mHasDestination = true; | ||||
|                 } | ||||
|                 return; | ||||
|  | @ -410,26 +349,26 @@ namespace MWMechanics | |||
|     void AiWander::completeManualWalking(const MWWorld::Ptr &actor, AiWanderStorage &storage) { | ||||
|         stopWalking(actor, storage); | ||||
|         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) | ||||
|     { | ||||
|         switch (storage.mState) | ||||
|         { | ||||
|             case Wander_IdleNow: | ||||
|             case AiWanderStorage::Wander_IdleNow: | ||||
|                 onIdleStatePerFrameActions(actor, duration, storage); | ||||
|                 break; | ||||
| 
 | ||||
|             case Wander_Walking: | ||||
|             case AiWanderStorage::Wander_Walking: | ||||
|                 onWalkingStatePerFrameActions(actor, duration, storage, pos); | ||||
|                 break; | ||||
| 
 | ||||
|             case Wander_ChooseAction: | ||||
|             case AiWanderStorage::Wander_ChooseAction: | ||||
|                 onChooseActionStatePerFrameActions(actor, storage); | ||||
|                 break; | ||||
| 
 | ||||
|             case Wander_MoveNow: | ||||
|             case AiWanderStorage::Wander_MoveNow: | ||||
|                 break;  // nothing to do
 | ||||
| 
 | ||||
|             default: | ||||
|  | @ -451,7 +390,7 @@ namespace MWMechanics | |||
|             if (mDistance &&            // actor is not intended to be stationary
 | ||||
|                 proximityToDoor(actor, distance*1.6f)) | ||||
|             { | ||||
|                 storage.setState(Wander_MoveNow); | ||||
|                 storage.setState(AiWanderStorage::Wander_MoveNow); | ||||
|                 storage.mTrimCurrentNode = false; // just in case
 | ||||
|                 return; | ||||
|             } | ||||
|  | @ -468,13 +407,13 @@ namespace MWMechanics | |||
|         } | ||||
| 
 | ||||
|         // Check if idle animation finished
 | ||||
|         GreetingState& greetingState = storage.mSaidGreeting; | ||||
|         if (!checkIdle(actor, storage.mIdleAnimation) && (greetingState == Greet_Done || greetingState == Greet_None)) | ||||
|         AiWanderStorage::GreetingState& greetingState = storage.mSaidGreeting; | ||||
|         if (!checkIdle(actor, storage.mIdleAnimation) && (greetingState == AiWanderStorage::Greet_Done || greetingState == AiWanderStorage::Greet_None)) | ||||
|         { | ||||
|             if (mPathFinder.isPathConstructed()) | ||||
|                 storage.setState(Wander_Walking); | ||||
|                 storage.setState(AiWanderStorage::Wander_Walking); | ||||
|             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)) | ||||
|         { | ||||
|             stopWalking(actor, storage); | ||||
|             storage.setState(Wander_ChooseAction); | ||||
|             storage.setState(AiWanderStorage::Wander_ChooseAction); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|  | @ -502,7 +441,7 @@ namespace MWMechanics | |||
| 
 | ||||
|         if (!idleAnimation && mDistance) | ||||
|         { | ||||
|             storage.setState(Wander_MoveNow); | ||||
|             storage.setState(AiWanderStorage::Wander_MoveNow); | ||||
|             return; | ||||
|         } | ||||
|         if(idleAnimation) | ||||
|  | @ -512,13 +451,13 @@ namespace MWMechanics | |||
|                 if(!playIdle(actor, idleAnimation)) | ||||
|                 { | ||||
|                     storage.mBadIdles.push_back(idleAnimation); | ||||
|                     storage.setState(Wander_ChooseAction); | ||||
|                     storage.setState(AiWanderStorage::Wander_ChooseAction); | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         storage.setState(Wander_IdleNow); | ||||
|         storage.setState(AiWanderStorage::Wander_IdleNow); | ||||
|     } | ||||
| 
 | ||||
|     void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration, ESM::Position& pos) | ||||
|  | @ -534,7 +473,7 @@ namespace MWMechanics | |||
|                 trimAllowedNodes(storage.mAllowedNodes, mPathFinder); | ||||
|                 mObstacleCheck.clear(); | ||||
|                 stopWalking(actor, storage); | ||||
|                 storage.setState(Wander_MoveNow); | ||||
|                 storage.setState(AiWanderStorage::Wander_MoveNow); | ||||
|             } | ||||
| 
 | ||||
|            storage.mStuckCount++;  // TODO: maybe no longer needed
 | ||||
|  | @ -545,7 +484,7 @@ namespace MWMechanics | |||
|         { | ||||
|             mObstacleCheck.clear(); | ||||
|             stopWalking(actor, storage); | ||||
|             storage.setState(Wander_ChooseAction); | ||||
|             storage.setState(AiWanderStorage::Wander_ChooseAction); | ||||
|             storage.mStuckCount = 0; | ||||
|         } | ||||
|     } | ||||
|  | @ -596,8 +535,8 @@ namespace MWMechanics | |||
|         float playerDistSqr = (playerPos - actorPos).length2(); | ||||
| 
 | ||||
|         int& greetingTimer = storage.mGreetingTimer; | ||||
|         GreetingState& greetingState = storage.mSaidGreeting; | ||||
|         if (greetingState == Greet_None) | ||||
|         AiWanderStorage::GreetingState& greetingState = storage.mSaidGreeting; | ||||
|         if (greetingState == AiWanderStorage::Greet_None) | ||||
|         { | ||||
|             if ((playerDistSqr <= helloDistance*helloDistance) && | ||||
|                 !player.getClass().getCreatureStats(player).isDead() && MWBase::Environment::get().getWorld()->getLOS(player, actor) | ||||
|  | @ -606,37 +545,37 @@ namespace MWMechanics | |||
| 
 | ||||
|             if (greetingTimer >= GREETING_SHOULD_START) | ||||
|             { | ||||
|                 greetingState = Greet_InProgress; | ||||
|                 greetingState = AiWanderStorage::Greet_InProgress; | ||||
|                 MWBase::Environment::get().getDialogueManager()->say(actor, "hello"); | ||||
|                 greetingTimer = 0; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (greetingState == Greet_InProgress) | ||||
|         if (greetingState == AiWanderStorage::Greet_InProgress) | ||||
|         { | ||||
|             greetingTimer++; | ||||
| 
 | ||||
|             if (storage.mState == Wander_Walking) | ||||
|             if (storage.mState == AiWanderStorage::Wander_Walking) | ||||
|             { | ||||
|                 stopWalking(actor, storage, false); | ||||
|                 mObstacleCheck.clear(); | ||||
|                 storage.setState(Wander_IdleNow); | ||||
|                 storage.setState(AiWanderStorage::Wander_IdleNow); | ||||
|             } | ||||
| 
 | ||||
|             turnActorToFacePlayer(actorPos, playerPos, storage); | ||||
| 
 | ||||
|             if (greetingTimer >= GREETING_SHOULD_END) | ||||
|             { | ||||
|                 greetingState = Greet_Done; | ||||
|                 greetingState = AiWanderStorage::Greet_Done; | ||||
|                 greetingTimer = 0; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (greetingState == MWMechanics::AiWander::Greet_Done) | ||||
|         if (greetingState == AiWanderStorage::Greet_Done) | ||||
|         { | ||||
|             float resetDist = 2 * helloDistance; | ||||
|             if (playerDistSqr >= resetDist*resetDist) | ||||
|                 greetingState = Greet_None; | ||||
|                 greetingState = AiWanderStorage::Greet_None; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -676,7 +615,7 @@ namespace MWMechanics | |||
|                 storage.mAllowedNodes.push_back(storage.mCurrentNode); | ||||
|             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:
 | ||||
|         else | ||||
|  |  | |||
|  | @ -22,7 +22,80 @@ namespace ESM | |||
| 
 | ||||
| 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
 | ||||
|     class AiWander : public AiPackage | ||||
|  | @ -52,19 +125,6 @@ namespace MWMechanics | |||
| 
 | ||||
|             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: | ||||
|             // NOTE: mDistance and mDuration must be set already
 | ||||
|             void init(); | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue