mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-25 11:26:37 +00:00 
			
		
		
		
	Do not update mIdleState directly
This commit is contained in:
		
							parent
							
								
									929d78d6a3
								
							
						
					
					
						commit
						0136f0552b
					
				
					 2 changed files with 78 additions and 48 deletions
				
			
		|  | @ -243,7 +243,7 @@ std::string CharacterController::chooseRandomGroup (const std::string& prefix, i | ||||||
|     return prefix + toString(roll); |     return prefix + toString(roll); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void CharacterController::refreshHitRecoilAnims() | void CharacterController::refreshHitRecoilAnims(CharacterState& idle) | ||||||
| { | { | ||||||
|     bool recovery = mPtr.getClass().getCreatureStats(mPtr).getHitRecovery(); |     bool recovery = mPtr.getClass().getCreatureStats(mPtr).getHitRecovery(); | ||||||
|     bool knockdown = mPtr.getClass().getCreatureStats(mPtr).getKnockedDown(); |     bool knockdown = mPtr.getClass().getCreatureStats(mPtr).getKnockedDown(); | ||||||
|  | @ -348,14 +348,16 @@ void CharacterController::refreshHitRecoilAnims() | ||||||
|         mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, true, 1, "loop stop", "stop", 0.0f, 0); |         mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, true, 1, "loop stop", "stop", 0.0f, 0); | ||||||
|     } |     } | ||||||
|     if (mHitState != CharState_None) |     if (mHitState != CharState_None) | ||||||
|         mIdleState = CharState_None; |         idle = CharState_None; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState jump, bool force) | void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState jump, CharacterState& idle, bool force) | ||||||
| { | { | ||||||
|     if(force || jump != mJumpState) |     if(force || jump != mJumpState) | ||||||
|     { |     { | ||||||
|         mIdleState = CharState_None; |         if (jump != JumpState_None) | ||||||
|  |             idle = CharState_None; | ||||||
|  | 
 | ||||||
|         bool startAtLoop = (jump == mJumpState); |         bool startAtLoop = (jump == mJumpState); | ||||||
|         mJumpState = jump; |         mJumpState = jump; | ||||||
| 
 | 
 | ||||||
|  | @ -372,6 +374,11 @@ void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState | ||||||
|                     jumpmask = MWRender::Animation::BlendMask_LowerBody; |                     jumpmask = MWRender::Animation::BlendMask_LowerBody; | ||||||
|                     jumpAnimName = "jump"; |                     jumpAnimName = "jump"; | ||||||
| 
 | 
 | ||||||
|  |                     // Since we apply movement only for lower body, do not reset idle animations.
 | ||||||
|  |                     // For upper body there will be idle animation.
 | ||||||
|  |                     if (idle == CharState_None) | ||||||
|  |                         idle = CharState_Idle; | ||||||
|  | 
 | ||||||
|                     // For crossbow animations use 1h ones as fallback
 |                     // For crossbow animations use 1h ones as fallback
 | ||||||
|                     if (mWeaponType == WeapType_Crossbow) |                     if (mWeaponType == WeapType_Crossbow) | ||||||
|                         jumpAnimName += "1h"; |                         jumpAnimName += "1h"; | ||||||
|  | @ -406,20 +413,21 @@ void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void CharacterController::refreshMovementAnims(const WeaponInfo* weap, CharacterState movement, bool force) | void CharacterController::refreshMovementAnims(const WeaponInfo* weap, CharacterState movement, CharacterState& idle, bool force) | ||||||
| { | { | ||||||
|     if(force || movement != mMovementState) |  | ||||||
|     { |  | ||||||
|         mMovementState = movement; |  | ||||||
|     std::string movementAnimName; |     std::string movementAnimName; | ||||||
|         MWRender::Animation::BlendMask movemask = MWRender::Animation::BlendMask_All; |     MWRender::Animation::BlendMask movemask; | ||||||
|         const StateInfo *movestate = std::find_if(sMovementList, sMovementListEnd, FindCharState(mMovementState)); |     const StateInfo *movestate; | ||||||
|  |     if(force || movement != mMovementState || idle != mIdleState) | ||||||
|  |     { | ||||||
|  |         movemask = MWRender::Animation::BlendMask_All; | ||||||
|  |         movestate = std::find_if(sMovementList, sMovementListEnd, FindCharState(movement)); | ||||||
|         if(movestate != sMovementListEnd) |         if(movestate != sMovementListEnd) | ||||||
|         { |         { | ||||||
|             movementAnimName = movestate->groupname; |             movementAnimName = movestate->groupname; | ||||||
|             if(weap != sWeaponTypeListEnd && movementAnimName.find("swim") == std::string::npos) |             if(weap != sWeaponTypeListEnd && movementAnimName.find("swim") == std::string::npos) | ||||||
|             { |             { | ||||||
|                 if (mWeaponType == WeapType_Spell && (mMovementState == CharState_TurnLeft || mMovementState == CharState_TurnRight)) // Spellcasting stance turning is a special case
 |                 if (mWeaponType == WeapType_Spell && (movement == CharState_TurnLeft || movement == CharState_TurnRight)) // Spellcasting stance turning is a special case
 | ||||||
|                     movementAnimName = weap->shortgroup + movementAnimName; |                     movementAnimName = weap->shortgroup + movementAnimName; | ||||||
|                 else |                 else | ||||||
|                     movementAnimName += weap->shortgroup; |                     movementAnimName += weap->shortgroup; | ||||||
|  | @ -429,12 +437,24 @@ void CharacterController::refreshMovementAnims(const WeaponInfo* weap, Character | ||||||
|                     movemask = MWRender::Animation::BlendMask_LowerBody; |                     movemask = MWRender::Animation::BlendMask_LowerBody; | ||||||
|                     movementAnimName = movestate->groupname; |                     movementAnimName = movestate->groupname; | ||||||
| 
 | 
 | ||||||
|  |                     // Since we apply movement only for lower body, do not reset idle animations.
 | ||||||
|  |                     // For upper body there will be idle animation.
 | ||||||
|  |                     if (idle == CharState_None) | ||||||
|  |                         idle = CharState_Idle; | ||||||
|  | 
 | ||||||
|                     // For crossbow animations use 1h ones as fallback
 |                     // For crossbow animations use 1h ones as fallback
 | ||||||
|                     if (mWeaponType == WeapType_Crossbow) |                     if (mWeaponType == WeapType_Crossbow) | ||||||
|                         movementAnimName += "1h"; |                         movementAnimName += "1h"; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|  |     if(force || movement != mMovementState) | ||||||
|  |     { | ||||||
|  |         mMovementState = movement; | ||||||
|  |         if(movestate != sMovementListEnd) | ||||||
|  |         { | ||||||
|             if(!mAnimation->hasAnimation(movementAnimName)) |             if(!mAnimation->hasAnimation(movementAnimName)) | ||||||
|             { |             { | ||||||
|                 std::string::size_type swimpos = movementAnimName.find("swim"); |                 std::string::size_type swimpos = movementAnimName.find("swim"); | ||||||
|  | @ -532,7 +552,15 @@ void CharacterController::refreshMovementAnims(const WeaponInfo* weap, Character | ||||||
| 
 | 
 | ||||||
| void CharacterController::refreshIdleAnims(const WeaponInfo* weap, CharacterState idle, bool force) | void CharacterController::refreshIdleAnims(const WeaponInfo* weap, CharacterState idle, bool force) | ||||||
| { | { | ||||||
|     if(force || idle != mIdleState || mIdleState == CharState_None || (!mAnimation->isPlaying(mCurrentIdle) && mAnimQueue.empty())) |     // FIXME: if one of the below states is close to their last animation frame (i.e. will be disabled in the coming update),
 | ||||||
|  |     // the idle animation should be displayed
 | ||||||
|  |     if (((mUpperBodyState != UpperCharState_Nothing && mUpperBodyState != UpperCharState_WeapEquiped) | ||||||
|  |             || (mMovementState != CharState_None && !isTurning()) | ||||||
|  |             || mHitState != CharState_None) | ||||||
|  |             && !mPtr.getClass().isBipedal(mPtr)) | ||||||
|  |         idle = CharState_None; | ||||||
|  | 
 | ||||||
|  |     if(force || idle != mIdleState || (!mAnimation->isPlaying(mCurrentIdle) && mAnimQueue.empty())) | ||||||
|     { |     { | ||||||
|         mIdleState = idle; |         mIdleState = idle; | ||||||
|         size_t numLoops = ~0ul; |         size_t numLoops = ~0ul; | ||||||
|  | @ -591,24 +619,16 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat | ||||||
|         return; |         return; | ||||||
| 
 | 
 | ||||||
|     if (mPtr.getClass().isActor()) |     if (mPtr.getClass().isActor()) | ||||||
|         refreshHitRecoilAnims(); |         refreshHitRecoilAnims(idle); | ||||||
| 
 | 
 | ||||||
|     const WeaponInfo *weap = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(mWeaponType)); |     const WeaponInfo *weap = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(mWeaponType)); | ||||||
|     if (!mPtr.getClass().hasInventoryStore(mPtr)) |     if (!mPtr.getClass().hasInventoryStore(mPtr)) | ||||||
|         weap = sWeaponTypeListEnd; |         weap = sWeaponTypeListEnd; | ||||||
| 
 | 
 | ||||||
|     refreshJumpAnims(weap, jump, force); |     refreshJumpAnims(weap, jump, idle, force); | ||||||
|     refreshMovementAnims(weap, movement, force); |     refreshMovementAnims(weap, movement, idle, force); | ||||||
| 
 | 
 | ||||||
|     // idle handled last as it can depend on the other states
 |     // idle handled last as it can depend on the other states
 | ||||||
|     // FIXME: if one of the below states is close to their last animation frame (i.e. will be disabled in the coming update),
 |  | ||||||
|     // the idle animation should be displayed
 |  | ||||||
|     if (((mUpperBodyState != UpperCharState_Nothing && mUpperBodyState != UpperCharState_WeapEquiped) |  | ||||||
|             || (mMovementState != CharState_None && !isTurning()) |  | ||||||
|             || mHitState != CharState_None) |  | ||||||
|             && !mPtr.getClass().isBipedal(mPtr)) |  | ||||||
|         idle = CharState_None; |  | ||||||
| 
 |  | ||||||
|     refreshIdleAnims(weap, idle, force); |     refreshIdleAnims(weap, idle, force); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1200,7 +1220,7 @@ bool CharacterController::updateCarriedLeftVisible(WeaponType weaptype) const | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool CharacterController::updateWeaponState() | bool CharacterController::updateWeaponState(CharacterState& idle) | ||||||
| { | { | ||||||
|     const MWWorld::Class &cls = mPtr.getClass(); |     const MWWorld::Class &cls = mPtr.getClass(); | ||||||
|     CreatureStats &stats = cls.getCreatureStats(mPtr); |     CreatureStats &stats = cls.getCreatureStats(mPtr); | ||||||
|  | @ -1570,11 +1590,11 @@ bool CharacterController::updateWeaponState() | ||||||
| 
 | 
 | ||||||
|         // We should reset player's idle animation in the first-person mode.
 |         // We should reset player's idle animation in the first-person mode.
 | ||||||
|         if (resetIdle && mPtr == player && MWBase::Environment::get().getWorld()->isFirstPerson()) |         if (resetIdle && mPtr == player && MWBase::Environment::get().getWorld()->isFirstPerson()) | ||||||
|             mIdleState = CharState_None; |             idle = CharState_None; | ||||||
| 
 | 
 | ||||||
|         // In other cases we should not break swim and sneak animations
 |         // In other cases we should not break swim and sneak animations
 | ||||||
|         if (resetIdle && mIdleState != CharState_IdleSneak && mIdleState != CharState_IdleSwim) |         if (resetIdle && mIdleState != CharState_IdleSneak && mIdleState != CharState_IdleSwim) | ||||||
|             mIdleState = CharState_None; |             idle = CharState_None; | ||||||
| 
 | 
 | ||||||
|         animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete); |         animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete); | ||||||
|         if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack && !isKnockedDown()) |         if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack && !isKnockedDown()) | ||||||
|  | @ -2085,7 +2105,12 @@ void CharacterController::update(float duration) | ||||||
|                                          : (sneak ? CharState_SneakBack |                                          : (sneak ? CharState_SneakBack | ||||||
|                                                   : (isrunning ? CharState_RunBack : CharState_WalkBack))); |                                                   : (isrunning ? CharState_RunBack : CharState_WalkBack))); | ||||||
|             } |             } | ||||||
|             else if(rot.z() != 0.0f && !sneak && !(mPtr == getPlayer() && MWBase::Environment::get().getWorld()->isFirstPerson())) |             else if(rot.z() != 0.0f) | ||||||
|  |             { | ||||||
|  |                 // It seems only bipedal actors use turning animations.
 | ||||||
|  |                 // Also do not use turning animations in the first-person view and when sneaking.
 | ||||||
|  |                 bool isFirstPlayer = mPtr == getPlayer() && MWBase::Environment::get().getWorld()->isFirstPerson(); | ||||||
|  |                 if (!sneak && !isFirstPlayer && mPtr.getClass().isBipedal(mPtr)) | ||||||
|                 { |                 { | ||||||
|                     if(rot.z() > rotationThreshold) |                     if(rot.z() > rotationThreshold) | ||||||
|                         movestate = inwater ? CharState_SwimTurnRight : CharState_TurnRight; |                         movestate = inwater ? CharState_SwimTurnRight : CharState_TurnRight; | ||||||
|  | @ -2093,6 +2118,7 @@ void CharacterController::update(float duration) | ||||||
|                         movestate = inwater ? CharState_SwimTurnLeft : CharState_TurnLeft; |                         movestate = inwater ? CharState_SwimTurnLeft : CharState_TurnLeft; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         // Player can not use smooth turning as NPCs, so we play turning animation a bit to avoid jittering
 |         // Player can not use smooth turning as NPCs, so we play turning animation a bit to avoid jittering
 | ||||||
|         if (mPtr == getPlayer()) |         if (mPtr == getPlayer()) | ||||||
|  | @ -2108,7 +2134,11 @@ void CharacterController::update(float duration) | ||||||
|         } |         } | ||||||
|         else |         else | ||||||
|         { |         { | ||||||
|  |             if (mPtr.getClass().isBipedal(mPtr)) | ||||||
|  |             { | ||||||
|  |                 if (mTurnAnimationThreshold > 0) | ||||||
|                     mTurnAnimationThreshold -= duration; |                     mTurnAnimationThreshold -= duration; | ||||||
|  | 
 | ||||||
|                 if (movestate == CharState_TurnRight || movestate == CharState_TurnLeft || |                 if (movestate == CharState_TurnRight || movestate == CharState_TurnLeft || | ||||||
|                     movestate == CharState_SwimTurnRight || movestate == CharState_SwimTurnLeft) |                     movestate == CharState_SwimTurnRight || movestate == CharState_SwimTurnLeft) | ||||||
|                 { |                 { | ||||||
|  | @ -2120,19 +2150,19 @@ void CharacterController::update(float duration) | ||||||
|                     movestate = mMovementState; |                     movestate = mMovementState; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         if(movestate != CharState_None && !isTurning()) |         if(movestate != CharState_None && !isTurning()) | ||||||
|             clearAnimQueue(); |             clearAnimQueue(); | ||||||
| 
 | 
 | ||||||
|         if(mAnimQueue.empty() || inwater || sneak) |         if(mAnimQueue.empty() || inwater || sneak) | ||||||
|         { |         { | ||||||
|             // Note: turning animations should not interrupt idle ones.
 |             // Note: turning animations should not interrupt idle ones
 | ||||||
|             // Also movement should not stop idle animation for spellcasting stance.
 |  | ||||||
|             if (inwater) |             if (inwater) | ||||||
|                 idlestate = CharState_IdleSwim; |                 idlestate = CharState_IdleSwim; | ||||||
|             else if (sneak && !inJump) |             else if (sneak && !inJump) | ||||||
|                 idlestate = CharState_IdleSneak; |                 idlestate = CharState_IdleSneak; | ||||||
|             else if (movestate != CharState_None && !isTurning() && mWeaponType != WeapType_Spell) |             else if (movestate != CharState_None && !isTurning()) | ||||||
|                 idlestate = CharState_None; |                 idlestate = CharState_None; | ||||||
|             else |             else | ||||||
|                 idlestate = CharState_Idle; |                 idlestate = CharState_Idle; | ||||||
|  | @ -2144,7 +2174,7 @@ void CharacterController::update(float duration) | ||||||
|         { |         { | ||||||
|             // bipedal means hand-to-hand could be used (which is handled in updateWeaponState). an existing InventoryStore means an actual weapon could be used.
 |             // bipedal means hand-to-hand could be used (which is handled in updateWeaponState). an existing InventoryStore means an actual weapon could be used.
 | ||||||
|             if(cls.isBipedal(mPtr) || cls.hasInventoryStore(mPtr)) |             if(cls.isBipedal(mPtr) || cls.hasInventoryStore(mPtr)) | ||||||
|                 forcestateupdate = updateWeaponState() || forcestateupdate; |                 forcestateupdate = updateWeaponState(idlestate) || forcestateupdate; | ||||||
|             else |             else | ||||||
|                 forcestateupdate = updateCreatureState() || forcestateupdate; |                 forcestateupdate = updateCreatureState() || forcestateupdate; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -213,14 +213,14 @@ class CharacterController : public MWRender::Animation::TextKeyListener | ||||||
|     void setAttackTypeBasedOnMovement(); |     void setAttackTypeBasedOnMovement(); | ||||||
| 
 | 
 | ||||||
|     void refreshCurrentAnims(CharacterState idle, CharacterState movement, JumpingState jump, bool force=false); |     void refreshCurrentAnims(CharacterState idle, CharacterState movement, JumpingState jump, bool force=false); | ||||||
|     void refreshHitRecoilAnims(); |     void refreshHitRecoilAnims(CharacterState& idle); | ||||||
|     void refreshJumpAnims(const WeaponInfo* weap, JumpingState jump, bool force=false); |     void refreshJumpAnims(const WeaponInfo* weap, JumpingState jump, CharacterState& idle, bool force=false); | ||||||
|     void refreshMovementAnims(const WeaponInfo* weap, CharacterState movement, bool force=false); |     void refreshMovementAnims(const WeaponInfo* weap, CharacterState movement, CharacterState& idle, bool force=false); | ||||||
|     void refreshIdleAnims(const WeaponInfo* weap, CharacterState idle, bool force=false); |     void refreshIdleAnims(const WeaponInfo* weap, CharacterState idle, bool force=false); | ||||||
| 
 | 
 | ||||||
|     void clearAnimQueue(bool clearPersistAnims = false); |     void clearAnimQueue(bool clearPersistAnims = false); | ||||||
| 
 | 
 | ||||||
|     bool updateWeaponState(); |     bool updateWeaponState(CharacterState& idle); | ||||||
|     bool updateCreatureState(); |     bool updateCreatureState(); | ||||||
|     void updateIdleStormState(bool inwater); |     void updateIdleStormState(bool inwater); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue