Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2920 lines
101 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "csgo_playeranimstate.h"
  8. #include "iplayeranimstate.h"
  9. #include "animation.h"
  10. #include "weapon_csbase.h"
  11. #include "gamemovement.h"
  12. #include "in_buttons.h"
  13. #ifdef CLIENT_DLL
  14. #include "c_cs_player.h"
  15. #else
  16. #include "cs_player.h"
  17. #include "ilagcompensationmanager.h"
  18. #endif
  19. extern CUtlSymbolTable g_ActivityModifiersTable;
  20. float ClampCycle( float flCycleIn )
  21. {
  22. flCycleIn -= int(flCycleIn);
  23. if ( flCycleIn < 0 )
  24. {
  25. flCycleIn += 1;
  26. }
  27. else if ( flCycleIn > 1 )
  28. {
  29. flCycleIn -= 1;
  30. }
  31. return flCycleIn;
  32. }
  33. CCSGOPlayerAnimState *CreateCSGOPlayerAnimstate( CBaseAnimatingOverlay *pEntity )
  34. {
  35. CCSPlayer *pPlayer = ToCSPlayer( pEntity );
  36. Assert( pPlayer );
  37. CCSGOPlayerAnimState *pRet = new CCSGOPlayerAnimState( pPlayer );
  38. return pRet;
  39. }
  40. #define CURRENT_ANIMSTATE_VERSION 2
  41. CCSGOPlayerAnimState::CCSGOPlayerAnimState( CCSPlayer *pPlayer )
  42. {
  43. m_pPlayer = pPlayer;
  44. Assert( m_pPlayer );
  45. m_cachedModelIndex = -1;
  46. m_nAnimstateModelVersion = CURRENT_ANIMSTATE_VERSION;
  47. Reset();
  48. }
  49. #define CSGO_ANIM_AIMMATRIX_DEFAULT_YAW_MAX 58.0f
  50. #define CSGO_ANIM_AIMMATRIX_DEFAULT_YAW_MIN -58.0f
  51. #define CSGO_ANIM_AIMMATRIX_DEFAULT_PITCH_MAX 90.0f
  52. #define CSGO_ANIM_AIMMATRIX_DEFAULT_PITCH_MIN -90.0f
  53. void CCSGOPlayerAnimState::Reset( void )
  54. {
  55. Assert( m_pPlayer );
  56. #ifndef CLIENT_DLL
  57. m_pPlayer->SetNumAnimOverlays( ANIMATION_LAYER_COUNT );
  58. #endif
  59. ApplyLayerOrderPreset( get_animlayerpreset( Default ), true );
  60. #ifdef CLIENT_DLL
  61. m_iLastUpdateFrame = 0;
  62. m_flStepHeightLeft = 0;
  63. m_flStepHeightRight = 0;
  64. #endif
  65. #ifndef CLIENT_DLL
  66. m_flFlashedAmountEaseOutStart = 0;
  67. m_flFlashedAmountEaseOutEnd = 0;
  68. #endif
  69. m_pWeapon = m_pPlayer->GetActiveCSWeapon();
  70. m_pWeaponLast = m_pWeapon;
  71. #ifdef CLIENT_DLL
  72. m_pWeaponLastBoneSetup = m_pWeapon;
  73. m_flEyePositionSmoothLerp = 0;
  74. m_flStrafeChangeWeightSmoothFalloff = 0;
  75. m_bFirstFootPlantSinceInit = true;
  76. #endif
  77. m_flLastUpdateTime = 0;
  78. m_flLastUpdateIncrement = 0;
  79. m_flEyeYaw = 0;
  80. m_flEyePitch = 0;
  81. m_flFootYaw = 0;
  82. m_flFootYawLast = 0;
  83. m_flMoveYaw = 0;
  84. m_flMoveYawIdeal = 0;
  85. m_flMoveYawCurrentToIdeal = 0;
  86. #ifndef CLIENT_DLL
  87. m_pPlayer->m_flLowerBodyYawTarget.Set( 0 );
  88. m_flLowerBodyRealignTimer = 0;
  89. #endif
  90. m_tStandWalkAim.Init();
  91. m_tStandWalkAim.m_flHowLongToWaitUntilTransitionCanBlendIn = 0.4f;
  92. m_tStandWalkAim.m_flHowLongToWaitUntilTransitionCanBlendOut = 0.2f;
  93. m_tStandRunAim.Init();
  94. m_tStandRunAim.m_flHowLongToWaitUntilTransitionCanBlendIn = 0.2f;
  95. m_tStandRunAim.m_flHowLongToWaitUntilTransitionCanBlendOut = 0.4f;
  96. m_tCrouchWalkAim.Init();
  97. m_tCrouchWalkAim.m_flHowLongToWaitUntilTransitionCanBlendIn = 0.3f;
  98. m_tCrouchWalkAim.m_flHowLongToWaitUntilTransitionCanBlendOut = 0.3f;
  99. m_flPrimaryCycle = 0;
  100. m_flMoveWeight = 0;
  101. m_flMoveWeightSmoothed = 0;
  102. m_flAnimDuckAmount = 0;
  103. m_flDuckAdditional = 0; // for when we duck a bit after landing from a jump
  104. m_flRecrouchWeight = 0;
  105. m_vecPositionCurrent.Init();
  106. m_vecPositionLast.Init();
  107. m_vecVelocity.Init();
  108. m_vecVelocityNormalized.Init();
  109. m_vecVelocityNormalizedNonZero.Init();
  110. m_flVelocityLengthXY = 0;
  111. m_flVelocityLengthZ = 0;
  112. m_flSpeedAsPortionOfRunTopSpeed = 0;
  113. m_flSpeedAsPortionOfWalkTopSpeed = 0;
  114. m_flSpeedAsPortionOfCrouchTopSpeed = 0;
  115. m_flDurationMoving = 0;
  116. m_flDurationStill = 0;
  117. m_bOnGround = true;
  118. #ifndef CLIENT_DLL
  119. m_bJumping = false;
  120. #endif
  121. m_flLandAnimMultiplier = 1.0f;
  122. m_flLeftGroundHeight = 0;
  123. m_bLanding = false;
  124. m_flJumpToFall = 0;
  125. m_flDurationInAir = 0;
  126. m_flWalkToRunTransition = 0;
  127. m_bLandedOnGroundThisFrame = false;
  128. m_bLeftTheGroundThisFrame = false;
  129. m_flInAirSmoothValue = 0;
  130. m_bOnLadder = false;
  131. m_flLadderWeight = 0;
  132. m_flLadderSpeed = 0;
  133. m_bWalkToRunTransitionState = ANIM_TRANSITION_WALK_TO_RUN;
  134. m_bDefuseStarted = false;
  135. m_bPlantAnimStarted = false;
  136. m_bTwitchAnimStarted = false;
  137. m_bAdjustStarted = false;
  138. m_flNextTwitchTime = 0;
  139. m_flTimeOfLastKnownInjury = 0;
  140. m_flLastVelocityTestTime = 0;
  141. m_vecVelocityLast.Init();
  142. m_vecTargetAcceleration.Init();
  143. m_vecAcceleration.Init();
  144. m_flAccelerationWeight = 0;
  145. m_flAimMatrixTransition = 0;
  146. m_flAimMatrixTransitionDelay = 0;
  147. m_bFlashed = 0;
  148. m_flStrafeChangeWeight = 0;
  149. m_flStrafeChangeTargetWeight = 0;
  150. m_flStrafeChangeCycle = 0;
  151. m_nStrafeSequence = -1;
  152. m_bStrafeChanging = false;
  153. m_flDurationStrafing = 0;
  154. m_flFootLerp = 0;
  155. m_bFeetCrossed = false;
  156. m_bPlayerIsAccelerating = false;
  157. #ifndef CLIENT_DLL
  158. m_bDeployRateLimiting = false;
  159. #endif
  160. m_flDurationMoveWeightIsTooHigh = 0;
  161. m_flStaticApproachSpeed = 80;
  162. m_flStutterStep = 0;
  163. m_nPreviousMoveState = 0;
  164. m_flActionWeightBiasRemainder = 0;
  165. m_flAimYawMin = CSGO_ANIM_AIMMATRIX_DEFAULT_YAW_MIN;
  166. m_flAimYawMax = CSGO_ANIM_AIMMATRIX_DEFAULT_YAW_MAX;
  167. m_flAimPitchMin = CSGO_ANIM_AIMMATRIX_DEFAULT_PITCH_MIN;
  168. m_flAimPitchMax = CSGO_ANIM_AIMMATRIX_DEFAULT_PITCH_MAX;
  169. //m_flMoveWalkWeight = 0;
  170. //m_flMoveCrouchWalkWeight = 0;
  171. //m_flMoveRunWeight = 0;
  172. m_ActivityModifiers.Purge();
  173. m_bFirstRunSinceInit = true;
  174. #ifdef CLIENT_DLL
  175. m_flCameraSmoothHeight = 0;
  176. m_bSmoothHeightValid = false;
  177. m_flLastTimeVelocityOverTen = 0;
  178. m_pPlayer->ClearAnimLODflags();
  179. #endif
  180. }
  181. #define bonesnapshot_def( _name, _val ) const float _name = _val;
  182. #define bonesnapshot_get( _name ) _name
  183. bonesnapshot_def( cl_bonesnapshot_speed_weaponchange, 0.25 )
  184. bonesnapshot_def( cl_bonesnapshot_speed_strafestart, 0.15 )
  185. bonesnapshot_def( cl_bonesnapshot_speed_movebegin, 0.3 )
  186. bonesnapshot_def( cl_bonesnapshot_speed_ladderenter, 0.25 )
  187. bonesnapshot_def( cl_bonesnapshot_speed_ladderexit, 0.1 )
  188. #define CSGO_ANIM_DEPLOY_RATELIMIT 0.15f
  189. #define CSGO_ANIM_DUCK_APPROACH_SPEED_DOWN 3.1f
  190. #define CSGO_ANIM_DUCK_APPROACH_SPEED_UP 6.0f
  191. void CCSGOPlayerAnimState::Update( float eyeYaw, float eyePitch, bool bForce )
  192. {
  193. if ( !m_pPlayer )
  194. return;
  195. if ( !m_pPlayer->IsAlive() )
  196. return;
  197. if ( !CacheSequences() )
  198. return;
  199. {
  200. // Apply recoil angle to aim matrix so bullets still come out of the gun straight while spraying
  201. eyePitch = AngleNormalize( eyePitch + m_pPlayer->m_flThirdpersonRecoil );
  202. }
  203. // don't need to update animstate if we already have this curtime
  204. if ( !bForce && ( m_flLastUpdateTime == gpGlobals->curtime || m_nLastUpdateFrame == gpGlobals->framecount ) )
  205. return;
  206. m_flLastUpdateIncrement = Max( 0.0f, gpGlobals->curtime - m_flLastUpdateTime ); // negative values possible when clocks on client and server go out of sync..
  207. #ifdef CLIENT_DLL
  208. // suspend bonecache invalidation
  209. C_BaseAnimating::EnableInvalidateBoneCache( false );
  210. #endif
  211. m_flEyeYaw = AngleNormalize( eyeYaw );
  212. m_flEyePitch = AngleNormalize( eyePitch );
  213. m_vecPositionCurrent = m_pPlayer->GetAbsOrigin();
  214. m_pWeapon = m_pPlayer->GetActiveCSWeapon();
  215. // purge layer dispatches on weapon change and init
  216. if ( m_pWeapon != m_pWeaponLast || m_bFirstRunSinceInit )
  217. {
  218. #ifdef CLIENT_DLL
  219. // changing weapons will change the pose of leafy bones like fingers. The next time we
  220. // set up this player's bones, treat it like a clean first setup.
  221. m_pPlayer->m_nComputedLODframe = 0;
  222. #endif
  223. for ( int i=0; i < ANIMATION_LAYER_COUNT; i++ )
  224. {
  225. CAnimationLayer *pLayer = m_pPlayer->GetAnimOverlay( i, USE_ANIMLAYER_RAW_INDEX );
  226. if ( pLayer )
  227. {
  228. pLayer->m_pDispatchedStudioHdr = NULL;
  229. pLayer->m_nDispatchedSrc = ACT_INVALID;
  230. pLayer->m_nDispatchedDst = ACT_INVALID;
  231. }
  232. }
  233. }
  234. #ifdef CLIENT_DLL
  235. if ( IsPreCrouchUpdateDemo() )
  236. {
  237. // compatibility for old demos using old crouch values
  238. float flTargetDuck = (m_pPlayer->GetFlags() & ( FL_ANIMDUCKING )) ? 1.0f : m_flDuckAdditional;
  239. m_flAnimDuckAmount = Approach( flTargetDuck, m_flAnimDuckAmount, m_flLastUpdateIncrement * ( (m_flAnimDuckAmount < flTargetDuck) ? CSGO_ANIM_DUCK_APPROACH_SPEED_DOWN : CSGO_ANIM_DUCK_APPROACH_SPEED_UP ) );
  240. m_flAnimDuckAmount = clamp( m_flAnimDuckAmount, 0, 1 );
  241. }
  242. else
  243. #endif
  244. {
  245. m_flAnimDuckAmount = clamp( Approach( clamp( m_pPlayer->m_flDuckAmount + m_flDuckAdditional, 0, 1), m_flAnimDuckAmount, m_flLastUpdateIncrement * 6.0f ), 0, 1 );
  246. }
  247. // no matter what, we're always playing 'default' underneath
  248. {
  249. MDLCACHE_CRITICAL_SECTION();
  250. m_pPlayer->SetSequence( 0 );
  251. m_pPlayer->SetPlaybackRate( 0 );
  252. m_pPlayer->SetCycle( 0 );
  253. }
  254. // all the layers get set up here
  255. SetUpVelocity(); // calculate speed and set up body yaw values
  256. SetUpAimMatrix(); // aim matrices are full body, so they not only point the weapon down the eye dir, they can crouch the idle player
  257. SetUpWeaponAction(); // firing, reloading, silencer-swapping, deploying
  258. SetUpMovement(); // jumping, climbing, ground locomotion, post-weapon crouch-stand
  259. SetUpAliveloop(); // breathe and fidget
  260. SetUpWholeBodyAction(); // defusing, planting, whole-body custom events
  261. SetUpFlashedReaction(); // shield eyes from flashbang
  262. SetUpFlinch(); // flinch when shot
  263. SetUpLean(); // lean into acceleration
  264. #ifdef CLIENT_DLL
  265. // zero-sequences are un-set and should have zero weight on the client
  266. for ( int i=0; i < ANIMATION_LAYER_COUNT; i++ )
  267. {
  268. CAnimationLayer *pLayer = m_pPlayer->GetAnimOverlay( i, USE_ANIMLAYER_RAW_INDEX );
  269. if ( pLayer && pLayer->GetSequence() == 0 )
  270. pLayer->SetWeight(0);
  271. }
  272. #endif
  273. // force abs angles on client and server to line up hitboxes
  274. m_pPlayer->SetAbsAngles( QAngle( 0, m_flFootYaw, 0 ) );
  275. #ifdef CLIENT_DLL
  276. // restore bonecache invalidation
  277. C_BaseAnimating::EnableInvalidateBoneCache( true );
  278. #endif
  279. m_pWeaponLast = m_pWeapon;
  280. m_vecPositionLast = m_vecPositionCurrent;
  281. m_bFirstRunSinceInit = false;
  282. m_flLastUpdateTime = gpGlobals->curtime;
  283. m_nLastUpdateFrame = gpGlobals->framecount;
  284. }
  285. float CCSGOPlayerAnimState::LerpCrouchWalkRun( float flCrouchVal, float flWalkVal, float flRunVal )
  286. {
  287. // lerp between three separate magic numbers intended for each state
  288. return Lerp( m_flAnimDuckAmount, Lerp( m_flWalkToRunTransition, flWalkVal, flRunVal ), flCrouchVal );
  289. }
  290. #define HYPEREXTENSION_LIMIT 34.2 // The length of a CS player's leg (hip to ankle) when nearly fully extended
  291. #define HYPEREXTENSION_LIMIT_SQR HYPEREXTENSION_LIMIT * HYPEREXTENSION_LIMIT
  292. #define FOOT_SAFE_ZONE_LEFT_SQR 7 * 7
  293. #define FOOT_SAFE_ZONE_RIGHT_SQR 8 * 8
  294. #define ANKLE_HEIGHT 4.5f
  295. #define FOOT_PROXIMITY_LIMIT_SQR 12 * 12 // don't let feet come to rest this close together
  296. #define LATERAL_BLENDOUT_HEIGHT 1
  297. #define LATERAL_BLENDIN_TIME 20
  298. #define LATERAL_BLENDOUT_TIME 6
  299. #define FIRSTPERSON_TO_THIRDPERSON_VERTICAL_TOLERANCE_MIN 4.0f
  300. #define FIRSTPERSON_TO_THIRDPERSON_VERTICAL_TOLERANCE_MAX 10.0f
  301. #ifdef CLIENT_DLL
  302. extern ConVar cl_camera_height_restriction_debug;
  303. #endif
  304. void CCSGOPlayerAnimState::ModifyEyePosition( Vector& vecInputEyePos )
  305. {
  306. if ( !m_pPlayer )
  307. return;
  308. #ifdef CLIENT_DLL
  309. if ( IsPreCrouchUpdateDemo() )
  310. return;
  311. #endif
  312. // The local player sets up their third-person bones to locate the position of their head,
  313. // then this position is used to softly bound the vertical camera position for the client.
  314. if ( !m_bLanding && m_flAnimDuckAmount == 0 )
  315. {
  316. #ifdef CLIENT_DLL
  317. m_bSmoothHeightValid = false;
  318. #endif
  319. return;
  320. }
  321. int nHeadBone = m_pPlayer->LookupBone( "head_0" );
  322. if ( nHeadBone != -1 )
  323. {
  324. Vector vecHeadPos;
  325. QAngle temp;
  326. m_pPlayer->GetBonePosition( nHeadBone, vecHeadPos, temp );
  327. vecHeadPos.z += 1.7f;
  328. #ifdef CLIENT_DLL
  329. if ( cl_camera_height_restriction_debug.GetBool() )
  330. {
  331. Vector vecTemp = Vector( vecInputEyePos.x, vecInputEyePos.y, vecHeadPos.z + FIRSTPERSON_TO_THIRDPERSON_VERTICAL_TOLERANCE_MAX );
  332. debugoverlay->AddLineOverlay( vecTemp, vecTemp + Vector(0,20,0), 255, 0, 255, true, gpGlobals->frametime );
  333. vecTemp = Vector( vecInputEyePos.x, vecInputEyePos.y, vecHeadPos.z + FIRSTPERSON_TO_THIRDPERSON_VERTICAL_TOLERANCE_MIN );
  334. debugoverlay->AddLineOverlay( vecTemp, vecTemp + Vector(0,20,0), 0, 0, 255, true, gpGlobals->frametime );
  335. vecTemp = Vector( vecInputEyePos.x, vecInputEyePos.y, vecInputEyePos.z );
  336. debugoverlay->AddLineOverlay( vecTemp, vecTemp + Vector(0,20,0), 255, 0, 0, true, gpGlobals->frametime );
  337. //vecTemp = Vector( vecInputEyePos.x, vecInputEyePos.y, vecHeadPos.z - FIRSTPERSON_TO_THIRDPERSON_VERTICAL_TOLERANCE_MIN );
  338. //debugoverlay->AddLineOverlay( vecTemp, vecTemp + Vector(0,20,0), 0, 0, 255, true, gpGlobals->frametime );
  339. //vecTemp = Vector( vecInputEyePos.x, vecInputEyePos.y, vecHeadPos.z - FIRSTPERSON_TO_THIRDPERSON_VERTICAL_TOLERANCE_MAX );
  340. //debugoverlay->AddLineOverlay( vecTemp, vecTemp + Vector(0,20,0), 255, 0, 255, true, gpGlobals->frametime );
  341. }
  342. #endif
  343. // Only correct the eye if the camera is ABOVE the head. If the camera is below the head, that's unlikely
  344. // to be advantageous for the local player.
  345. if ( vecHeadPos.z < vecInputEyePos.z )
  346. {
  347. float flLerp = SimpleSplineRemapValClamped( abs( vecInputEyePos.z - vecHeadPos.z ),
  348. FIRSTPERSON_TO_THIRDPERSON_VERTICAL_TOLERANCE_MIN,
  349. FIRSTPERSON_TO_THIRDPERSON_VERTICAL_TOLERANCE_MAX,
  350. 0.0f, 1.0f );
  351. vecInputEyePos.z = Lerp( flLerp, vecInputEyePos.z, vecHeadPos.z );
  352. }
  353. #ifdef CLIENT_DLL
  354. if ( cl_camera_height_restriction_debug.GetBool() )
  355. {
  356. Vector vecTemp = Vector( vecInputEyePos.x, vecInputEyePos.y, vecInputEyePos.z );
  357. debugoverlay->AddLineOverlay( vecTemp, vecTemp + Vector(0,20,0), 0, 255, 0, true, gpGlobals->frametime );
  358. }
  359. // when fully crouched on the client, floor the camera height under the input z within a vertical range so it doesn't 'bob' continuously
  360. if ( m_flAnimDuckAmount >= 1 )
  361. {
  362. if ( m_bSmoothHeightValid )
  363. {
  364. float flHardCamHeight = m_pPlayer->GetAbsOrigin().z + VEC_DUCK_VIEW.z;
  365. if ( vecInputEyePos.z < flHardCamHeight )
  366. {
  367. m_flCameraSmoothHeight = clamp( MIN( m_flCameraSmoothHeight, vecInputEyePos.z ), vecInputEyePos.z - clamp( flHardCamHeight - vecInputEyePos.z, 0.0f, 3.0f ), vecInputEyePos.z );
  368. vecInputEyePos.z = m_flCameraSmoothHeight;
  369. }
  370. else
  371. {
  372. m_flCameraSmoothHeight = flHardCamHeight;
  373. }
  374. if ( cl_camera_height_restriction_debug.GetBool() )
  375. {
  376. Vector vecTemp = Vector( vecInputEyePos.x, vecInputEyePos.y, vecInputEyePos.z );
  377. debugoverlay->AddLineOverlay( vecTemp, vecTemp + Vector(0,30,0), 255, 255, 255, true, gpGlobals->frametime );
  378. }
  379. }
  380. else
  381. {
  382. m_flCameraSmoothHeight = vecInputEyePos.z;
  383. m_bSmoothHeightValid = true;
  384. }
  385. }
  386. else
  387. {
  388. m_bSmoothHeightValid = false;
  389. }
  390. #endif
  391. }
  392. }
  393. #ifdef CLIENT_DLL
  394. void CCSGOPlayerAnimState::OnClientWeaponChange( CWeaponCSBase* pCurrentWeapon )
  395. {
  396. if ( !m_bFirstRunSinceInit && ( pCurrentWeapon != m_pWeaponLastBoneSetup ) &&
  397. !m_pPlayer->IsAnyBoneSnapshotPending() &&
  398. m_pPlayer->m_boneSnapshots[ BONESNAPSHOT_UPPER_BODY ].GetCurrentWeight() <= 0 &&
  399. m_pPlayer->m_boneSnapshots[ BONESNAPSHOT_ENTIRE_BODY ].GetCurrentWeight() <= 0 )
  400. {
  401. m_pWeaponLastBoneSetup = pCurrentWeapon;
  402. if ( m_flSpeedAsPortionOfWalkTopSpeed > 0.25f )
  403. {
  404. m_pPlayer->m_boneSnapshots[ BONESNAPSHOT_UPPER_BODY ].SetShouldCapture( bonesnapshot_get( cl_bonesnapshot_speed_weaponchange ) );
  405. }
  406. else
  407. {
  408. m_pPlayer->m_boneSnapshots[ BONESNAPSHOT_ENTIRE_BODY ].SetShouldCapture( bonesnapshot_get( cl_bonesnapshot_speed_weaponchange ) );
  409. }
  410. }
  411. }
  412. inline bool CCSGOPlayerAnimState::LayerToIndex( const CAnimationLayer* pLayer, int &nIndex )
  413. {
  414. for ( int i=0; i < ANIMATION_LAYER_COUNT; i++ )
  415. {
  416. if ( pLayer == m_pPlayer->GetAnimOverlay( m_pLayerOrderPreset[i], USE_ANIMLAYER_RAW_INDEX ) )
  417. {
  418. nIndex = i;
  419. return true;
  420. }
  421. }
  422. return false;
  423. }
  424. void CCSGOPlayerAnimState::NotifyOnLayerChangeSequence( const CAnimationLayer* pLayer, const int nNewSequence )
  425. {
  426. int nIndex;
  427. if ( !LayerToIndex( pLayer, nIndex ) )
  428. return;
  429. animstate_layer_t nLayerIndex = (animstate_layer_t)nIndex;
  430. //todo: more hooks for pre-bonesetup sequence changes
  431. // bone snapshot land/climb transitions
  432. if ( !m_bFirstRunSinceInit && nLayerIndex == ANIMATION_LAYER_MOVEMENT_LAND_OR_CLIMB )
  433. {
  434. int nLastSequence = pLayer->GetSequence();
  435. if ( nLastSequence > 0 && nLastSequence != nNewSequence )
  436. {
  437. if ( m_pPlayer->GetSequenceActivity( nLastSequence ) == ACT_CSGO_CLIMB_LADDER )
  438. {
  439. m_pPlayer->m_boneSnapshots[BONESNAPSHOT_ENTIRE_BODY].SetShouldCapture( bonesnapshot_get( cl_bonesnapshot_speed_ladderexit ) );
  440. }
  441. else if ( m_pPlayer->GetSequenceActivity( nNewSequence ) == ACT_CSGO_CLIMB_LADDER )
  442. {
  443. m_pPlayer->m_boneSnapshots[BONESNAPSHOT_ENTIRE_BODY].SetShouldCapture( bonesnapshot_get( cl_bonesnapshot_speed_ladderenter ) );
  444. }
  445. }
  446. }
  447. }
  448. void CCSGOPlayerAnimState::NotifyOnLayerChangeWeight( const CAnimationLayer* pLayer, const float flNewWeight )
  449. {
  450. int nIndex;
  451. if ( !LayerToIndex( pLayer, nIndex ) )
  452. return;
  453. animstate_layer_t nLayerIndex = (animstate_layer_t)nIndex;
  454. //todo: more hooks for pre-bonesetup sequence changes
  455. if ( nLayerIndex == ANIMATION_LAYER_MOVEMENT_MOVE )
  456. {
  457. m_flMoveWeight = flNewWeight;
  458. }
  459. }
  460. void CCSGOPlayerAnimState::NotifyOnLayerChangeCycle( const CAnimationLayer* pLayer, const float flNewcycle )
  461. {
  462. int nIndex;
  463. if ( !LayerToIndex( pLayer, nIndex ) )
  464. return;
  465. animstate_layer_t nLayerIndex = (animstate_layer_t)nIndex;
  466. //todo: more hooks for pre-bonesetup sequence changes
  467. if ( nLayerIndex == ANIMATION_LAYER_MOVEMENT_MOVE )
  468. {
  469. m_flPrimaryCycle = flNewcycle;
  470. }
  471. }
  472. inline float CCSGOPlayerAnimState::FootBarrierEq( float flIn, float flMinWidth )
  473. {
  474. return (( Sqr(flIn) * 0.02f ) + MIN( flMinWidth, 3 )) * MIN( m_flSpeedAsPortionOfCrouchTopSpeed, 1 );
  475. }
  476. void CCSGOPlayerAnimState::DoProceduralFootPlant( matrix3x4a_t boneToWorld[], mstudioikchain_t *pLeftFootChain, mstudioikchain_t *pRightFootChain, BoneVector pos[] )
  477. {
  478. if ( !m_pPlayer )
  479. return;
  480. if ( m_bOnGround && m_flInAirSmoothValue >= 1 && !m_bOnLadder )
  481. {
  482. if ( m_pPlayer->GetGroundEntity() && !m_pPlayer->GetGroundEntity()->IsWorld() )
  483. return;
  484. int nLeftFootBoneIndex = pLeftFootChain->pLink( 2 )->bone;
  485. int nRightFootBoneIndex = pRightFootChain->pLink( 2 )->bone;
  486. int nLeftLockIndex = m_pPlayer->LookupBone( "lfoot_lock" );
  487. int nRightLockIndex = m_pPlayer->LookupBone( "rfoot_lock" );
  488. if ( nLeftLockIndex > 0 && nRightLockIndex > 0 )
  489. {
  490. m_footLeft.m_vecPosAnim = boneToWorld[nLeftFootBoneIndex].GetOrigin();
  491. m_footRight.m_vecPosAnim = boneToWorld[nRightFootBoneIndex].GetOrigin();
  492. //debugoverlay->AddBoxOverlay( m_footLeft.m_vecPosAnim, Vector(-5,-5,0), Vector(5,5,0), QAngle(0,0,0), 255, 0, 0, 0, 0 );
  493. //debugoverlay->AddBoxOverlay( m_footRight.m_vecPosAnim, Vector(-5,-5,0), Vector(5,5,0), QAngle(0,0,0), 255, 0, 0, 0, 0 );
  494. Vector vecPlayerOrigin = m_pPlayer->GetAbsOrigin();
  495. // reset the procedural locations if this is the first computation or they haven't been computed recently
  496. if ( m_bFirstFootPlantSinceInit || abs(gpGlobals->framecount - m_iLastUpdateFrame) > 10 )
  497. {
  498. m_footLeft.Init( m_footLeft.m_vecPosAnim );
  499. m_footRight.Init( m_footRight.m_vecPosAnim );
  500. m_footLeft.m_vecPlantVel = m_vecVelocityNormalizedNonZero;
  501. m_footRight.m_vecPlantVel = m_vecVelocityNormalizedNonZero;
  502. m_iLastUpdateFrame = gpGlobals->framecount;
  503. m_bFirstFootPlantSinceInit = false;
  504. return;
  505. }
  506. // use the ik lock driver bones to determine if a new foot plant location has been triggered
  507. #define FOOT_LOCK_THRESHOLD 0.7f
  508. bool bLeftFootLockWasBelowThreshold = m_footLeft.m_flLockAmount < FOOT_LOCK_THRESHOLD;
  509. bool bRightFootLockWasBelowThreshold = m_footRight.m_flLockAmount < FOOT_LOCK_THRESHOLD;
  510. m_footLeft.m_flLockAmount = Approach( clamp( abs(pos[nLeftLockIndex].y), 0, 1 ), m_footLeft.m_flLockAmount, gpGlobals->frametime * 10.0f );
  511. m_footRight.m_flLockAmount = Approach( clamp( abs(pos[nRightLockIndex].y), 0, 1 ), m_footRight.m_flLockAmount, gpGlobals->frametime * 10.0f );
  512. bool bLeftFootLockIsAboveThreshold = m_footLeft.m_flLockAmount >= FOOT_LOCK_THRESHOLD;
  513. bool bRightFootLockIsAboveThreshold = m_footRight.m_flLockAmount >= FOOT_LOCK_THRESHOLD;
  514. // for a short duration after each foot-plant, the feet are not allowed to deviate laterally from the player velocity at the time of the plant
  515. float flLeftTimeLerp = RemapValClamped( m_footLeft.m_flLastPlantTime, gpGlobals->curtime, gpGlobals->curtime-0.4f, 1.0f, 0.0f );
  516. float flRightTimeLerp = RemapValClamped( m_footRight.m_flLastPlantTime, gpGlobals->curtime, gpGlobals->curtime-0.4f, 1.0f, 0.0f );
  517. flLeftTimeLerp = Gain( flLeftTimeLerp, 0.8f );
  518. flRightTimeLerp = Gain( flRightTimeLerp, 0.8f );
  519. //debugoverlay->AddBoxOverlay( m_footLeft.m_vecPosPlant, Vector(-5,-5,0)*flLeftTimeLerp, Vector(5,5,0)*flLeftTimeLerp, QAngle(0,0,0), 0, 255, 255, 0, 0 );
  520. //debugoverlay->AddBoxOverlay( m_footRight.m_vecPosPlant, Vector(-5,-5,0)*flRightTimeLerp, Vector(5,5,0)*flRightTimeLerp, QAngle(0,0,0), 255, 255, 0, 0, 0 );
  521. Vector vecLeftPtOnVelLine;
  522. Vector vecRightPtOnVelLine;
  523. CalcClosestPointOnLine( m_footLeft.m_vecPosAnim, m_footLeft.m_vecPosPlant, m_footLeft.m_vecPosPlant + m_footLeft.m_vecPlantVel, vecLeftPtOnVelLine );
  524. CalcClosestPointOnLine( m_footRight.m_vecPosAnim, m_footRight.m_vecPosPlant, m_footRight.m_vecPosPlant + m_footRight.m_vecPlantVel, vecRightPtOnVelLine );
  525. Vector vecLeftTarget = Lerp( flLeftTimeLerp, m_footLeft.m_vecPosAnim, vecLeftPtOnVelLine );
  526. Vector vecRightTarget = Lerp( flRightTimeLerp, m_footRight.m_vecPosAnim, vecRightPtOnVelLine );
  527. // check for foot plants for next frame
  528. if ( bLeftFootLockIsAboveThreshold && bLeftFootLockWasBelowThreshold )
  529. {
  530. m_footLeft.m_vecPosPlant = vecLeftTarget;
  531. m_footLeft.m_flLastPlantTime = gpGlobals->curtime;
  532. m_footLeft.m_vecPlantVel = m_vecVelocityNormalizedNonZero;
  533. }
  534. if ( bRightFootLockIsAboveThreshold && bRightFootLockWasBelowThreshold )
  535. {
  536. m_footRight.m_vecPosPlant = vecRightTarget;
  537. m_footRight.m_flLastPlantTime = gpGlobals->curtime;
  538. m_footRight.m_vecPlantVel = m_vecVelocityNormalizedNonZero;
  539. }
  540. // always inherit animated z (only foot-stepping below modifies this)
  541. vecLeftTarget.z = m_footLeft.m_vecPosAnim.z;
  542. vecRightTarget.z = m_footRight.m_vecPosAnim.z;
  543. // the feet are not allowed to exceed 3x the instantaneous velocity of the player (prevents pose-popping when mashing keys)
  544. float flFrametime = MAX( gpGlobals->frametime, 0.0001f );
  545. float flLeftDeltaVel = MAX( ( m_footLeft.m_vecPosAnimLast - vecLeftTarget ).Length() / flFrametime, 0.0001f );
  546. float flRightDeltaVel = MAX( ( m_footRight.m_vecPosAnimLast - vecRightTarget ).Length() / flFrametime, 0.0001f );
  547. float flVelLimitLeft = m_flVelocityLengthXY * 3.0f;
  548. float flVelLimitRight = m_flVelocityLengthXY * 3.0f;
  549. if ( m_flVelocityLengthXY > 10.0f )
  550. {
  551. m_flLastTimeVelocityOverTen = gpGlobals->curtime;
  552. }
  553. float flTimeStill = gpGlobals->curtime - m_flLastTimeVelocityOverTen;
  554. // when standing mostly still, alternately raise the velocity limit floor, which makes the feet 'shuffle-step'
  555. if ( m_flVelocityLengthXY <= 10.0f )
  556. {
  557. float flEyeFootAngleDiff = abs( AngleDiff(m_flEyeYaw, m_flFootYaw) );
  558. if ( flEyeFootAngleDiff > 56.0f || flTimeStill < 1.0f ) // when turning rapidly, allow the feet to step faster
  559. {
  560. float flFmod = fmod( gpGlobals->curtime, 0.33f );
  561. if ( flFmod < 0.16f )
  562. {
  563. flVelLimitLeft = 110.0f;
  564. }
  565. else if ( flFmod >= 0.17f )
  566. {
  567. flVelLimitRight = 130.0f;
  568. }
  569. }
  570. else
  571. {
  572. float flFmod = fmod( gpGlobals->curtime, 0.66f );
  573. if ( flFmod > 0.02 && flFmod < 0.31f )
  574. {
  575. flVelLimitLeft = 80.0f;
  576. }
  577. else if ( flFmod > 0.35 && flFmod < 0.64f )
  578. {
  579. flVelLimitRight = 70.0f;
  580. }
  581. }
  582. // less fudge-factor when crouching, so allow the feet to catch up faster
  583. if ( m_flAnimDuckAmount > 0.5f )
  584. {
  585. flVelLimitLeft *= 2.0f;
  586. flVelLimitRight *= 2.0f;
  587. }
  588. // also lift the feet a bit on their way to their target
  589. //if ( flVelLimitLeft > 0 )
  590. //{
  591. // float flDistToLeft = RemapValClamped( m_footLeft.m_vecPosAnimLast.DistTo( m_footLeft.m_vecPosAnim ), 0.0f, 30.0f, 0.0f, 1.0f );
  592. // vecLeftTarget.z += SmoothCurve( flDistToLeft ) * 14.0f;
  593. //}
  594. //if ( flVelLimitRight> 0 )
  595. //{
  596. // float flDistToRight = RemapValClamped( m_footRight.m_vecPosAnimLast.DistTo( m_footRight.m_vecPosAnim ), 0.0f, 30.0f, 0.0f, 1.0f );
  597. // vecRightTarget.z += SmoothCurve( flDistToRight ) * 14.0f;
  598. //}
  599. }
  600. // restrict foot velocity
  601. if ( flLeftDeltaVel > flVelLimitLeft )
  602. vecLeftTarget = Lerp( flVelLimitLeft / flLeftDeltaVel, m_footLeft.m_vecPosAnimLast, vecLeftTarget );
  603. if ( flRightDeltaVel > flVelLimitRight )
  604. vecRightTarget = Lerp( flVelLimitRight / flRightDeltaVel, m_footRight.m_vecPosAnimLast, vecRightTarget );
  605. // spawn oddities like lowering the player artificially without allowing them to fall can move the player
  606. // but it doesn't count as a teleport, so their velocity remains zero... long story short this causes the
  607. // target z values to catch up instead of reset and it looks weird. I'm clamping their range here:
  608. vecLeftTarget.z = clamp( vecLeftTarget.z, m_footLeft.m_vecPosAnim.z - 2.0f, m_footLeft.m_vecPosAnim.z + 6.0f );
  609. vecRightTarget.z = clamp( vecRightTarget.z, m_footRight.m_vecPosAnim.z - 2.0f, m_footRight.m_vecPosAnim.z + 6.0f );
  610. // sanity-check the result and throw out the positions if they're super weird
  611. // (we might have been teleported or pvs went nuts or there was a bunch of packet loss -
  612. // point being it's easier and more reliable to error check than try to prevent the input cases.
  613. int nLeftHipBoneIndex = pLeftFootChain->pLink( 0 )->bone;
  614. int nRightHipBoneIndex = pRightFootChain->pLink( 0 )->bone;
  615. if ( nLeftHipBoneIndex > 0 && nRightHipBoneIndex > 0 )
  616. {
  617. if ( boneToWorld[nLeftHipBoneIndex].GetOrigin().DistToSqr( vecLeftTarget ) > 1400 ||
  618. boneToWorld[nRightHipBoneIndex].GetOrigin().DistToSqr( vecRightTarget ) > 1400 )
  619. {
  620. //debugoverlay->AddLineOverlay( boneToWorld[nLeftHipBoneIndex].GetOrigin(), vecLeftTarget, 255,0,0, true, 5 );
  621. //debugoverlay->AddLineOverlay( boneToWorld[nRightHipBoneIndex].GetOrigin(), vecRightTarget, 255,0,0, true, 5 );
  622. // if either foot is way out of range, bail and reset them both
  623. m_footLeft.Init( m_footLeft.m_vecPosAnim );
  624. m_footRight.Init( m_footRight.m_vecPosAnim );
  625. m_footLeft.m_vecPlantVel = m_vecVelocityNormalizedNonZero;
  626. m_footRight.m_vecPlantVel = m_vecVelocityNormalizedNonZero;
  627. m_iLastUpdateFrame = gpGlobals->framecount;
  628. m_bFirstFootPlantSinceInit = false;
  629. return;
  630. }
  631. }
  632. if ( vecLeftTarget.DistToSqr( m_footLeft.m_vecPosAnim ) > (12 * 12) )
  633. {
  634. vecLeftTarget = m_footLeft.m_vecPosAnim + (( vecLeftTarget - m_footLeft.m_vecPosAnim ).Normalized() * 12.0f);
  635. //debugoverlay->AddLineOverlay( vecLeftTarget, m_footLeft.m_vecPosAnim, 0, 255, 0, true, 0 );
  636. }
  637. if ( vecRightTarget.DistToSqr( m_footRight.m_vecPosAnim ) > (12 * 12) )
  638. {
  639. vecRightTarget = m_footRight.m_vecPosAnim + ((vecRightTarget - m_footRight.m_vecPosAnim).Normalized() * 12.0f);
  640. //debugoverlay->AddLineOverlay( vecRightTarget, m_footRight.m_vecPosAnim, 0, 255, 0, true, 0 );
  641. }
  642. // place the foot bones at the newly computed locations (ik will solve the knees)
  643. boneToWorld[nLeftFootBoneIndex].SetOrigin( vecLeftTarget );
  644. boneToWorld[nRightFootBoneIndex].SetOrigin( vecRightTarget );
  645. //debugoverlay->AddBoxOverlay( vecLeftTarget, Vector(-5,-5,0), Vector(5,5,0), QAngle(0,0,0), 0, 255, 0, 0, 0 );
  646. //debugoverlay->AddBoxOverlay(vecRightTarget, Vector(-5,-5,0), Vector(5,5,0), QAngle(0,0,0), 0, 255, 0, 0, 0 );
  647. m_footLeft.m_vecPosAnimLast = vecLeftTarget;
  648. m_footRight.m_vecPosAnimLast = vecRightTarget;
  649. }
  650. if ( m_iLastUpdateFrame < gpGlobals->framecount )
  651. {
  652. m_iLastUpdateFrame = gpGlobals->framecount;
  653. }
  654. }
  655. }
  656. #endif
  657. void CCSGOPlayerAnimState::SetUpLean( void )
  658. {
  659. // lean the body into velocity derivative (acceleration) to simulate maintaining a center of gravity
  660. float flInterval = gpGlobals->curtime - m_flLastVelocityTestTime;
  661. if ( flInterval > 0.025f )
  662. {
  663. flInterval = MIN( flInterval, 0.1f );
  664. m_flLastVelocityTestTime = gpGlobals->curtime;
  665. m_vecTargetAcceleration = ( m_pPlayer->GetLocalVelocity() - m_vecVelocityLast ) / flInterval;
  666. m_vecTargetAcceleration.z = 0;
  667. m_vecVelocityLast = m_pPlayer->GetLocalVelocity();
  668. }
  669. m_vecAcceleration = Approach( m_vecTargetAcceleration, m_vecAcceleration, m_flLastUpdateIncrement * 800.0f );
  670. //#ifdef CLIENT_DLL
  671. // debugoverlay->AddLineOverlay( m_vecPositionCurrent, m_vecPositionCurrent + m_vecAcceleration, 255,0,0, 255, 1, m_flLastUpdateIncrement );
  672. //#else
  673. // debugoverlay->AddLineOverlay( m_vecPositionCurrent, m_vecPositionCurrent + m_vecAcceleration, 0,0,255, 255, 1.5, m_flLastUpdateIncrement );
  674. //#endif
  675. QAngle temp;
  676. VectorAngles( m_vecAcceleration, Vector(0,0,1), temp );
  677. m_flAccelerationWeight = clamp( (m_vecAcceleration.Length() / CS_PLAYER_SPEED_RUN) * m_flSpeedAsPortionOfRunTopSpeed, 0, 1 );
  678. m_flAccelerationWeight *= (1.0f - m_flLadderWeight);
  679. m_tPoseParamMappings[ PLAYER_POSE_PARAM_LEAN_YAW ].SetValue( m_pPlayer, AngleNormalize( m_flFootYaw - temp[YAW] ) );
  680. if ( GetLayerSequence( ANIMATION_LAYER_LEAN ) <= 0 )
  681. {
  682. MDLCACHE_CRITICAL_SECTION();
  683. SetLayerSequence( ANIMATION_LAYER_LEAN, m_pPlayer->LookupSequence( "lean" ) );
  684. }
  685. SetLayerWeight( ANIMATION_LAYER_LEAN, m_flAccelerationWeight );
  686. }
  687. void CCSGOPlayerAnimState::SetUpFlinch( void )
  688. {
  689. #ifndef CLIENT_DLL
  690. if ( m_flTimeOfLastKnownInjury < m_pPlayer->GetTimeOfLastInjury() )
  691. {
  692. m_flTimeOfLastKnownInjury = m_pPlayer->GetTimeOfLastInjury();
  693. // flinches override flinches of their own priority
  694. bool bNoFlinchIsPlaying = ( IsLayerSequenceCompleted( ANIMATION_LAYER_FLINCH ) || GetLayerWeight( ANIMATION_LAYER_FLINCH ) <= 0 );
  695. bool bHeadshotIsPlaying = ( !bNoFlinchIsPlaying && GetLayerActivity(ANIMATION_LAYER_FLINCH) == ACT_CSGO_FLINCH_HEAD );
  696. if ( m_pPlayer->GetLastDamageTypeFlags() & DMG_BURN )
  697. {
  698. if ( bNoFlinchIsPlaying )
  699. {
  700. SetLayerSequence( ANIMATION_LAYER_FLINCH, SelectSequenceFromActMods( ACT_CSGO_FLINCH_MOLOTOV ) );
  701. // clear out all the flinch-related actmods now we selected a sequence
  702. UpdateActivityModifiers();
  703. }
  704. }
  705. else if ( bNoFlinchIsPlaying || !bHeadshotIsPlaying || m_pPlayer->LastHitGroup() == HITGROUP_HEAD )
  706. {
  707. RelativeDamagedDirection_t damageDir = m_pPlayer->GetLastInjuryRelativeDirection();
  708. bool bLeft = false;
  709. bool bRight = false;
  710. switch (damageDir) {
  711. case DAMAGED_DIR_NONE:
  712. case DAMAGED_DIR_FRONT:
  713. {
  714. AddActivityModifier( "front" );
  715. break;
  716. }
  717. case DAMAGED_DIR_BACK:
  718. {
  719. AddActivityModifier( "back" );
  720. break;
  721. }
  722. case DAMAGED_DIR_LEFT:
  723. {
  724. AddActivityModifier( "left" );
  725. bLeft = true;
  726. break;
  727. }
  728. case DAMAGED_DIR_RIGHT:
  729. {
  730. AddActivityModifier( "right" );
  731. bRight = true;
  732. break;
  733. }
  734. }
  735. switch (m_pPlayer->LastHitGroup()) {
  736. case HITGROUP_HEAD:
  737. {
  738. AddActivityModifier( "head" );
  739. break;
  740. }
  741. case HITGROUP_CHEST:
  742. {
  743. AddActivityModifier( "chest" );
  744. break;
  745. }
  746. case HITGROUP_LEFTARM:
  747. {
  748. if ( !bLeft ) { AddActivityModifier( "left" ); }
  749. AddActivityModifier( "arm" );
  750. break;
  751. }
  752. case HITGROUP_RIGHTARM:
  753. {
  754. if ( !bRight ) { AddActivityModifier( "right" ); }
  755. AddActivityModifier( "arm" );
  756. break;
  757. }
  758. case HITGROUP_GENERIC:
  759. case HITGROUP_STOMACH:
  760. {
  761. AddActivityModifier( "gut" );
  762. break;
  763. }
  764. case HITGROUP_LEFTLEG:
  765. {
  766. if ( !bLeft ) { AddActivityModifier( "left" ); }
  767. AddActivityModifier( "leg" );
  768. break;
  769. }
  770. case HITGROUP_RIGHTLEG:
  771. {
  772. if ( !bRight ) { AddActivityModifier( "right" ); }
  773. AddActivityModifier( "leg" );
  774. break;
  775. }
  776. }
  777. SetLayerSequence( ANIMATION_LAYER_FLINCH, SelectSequenceFromActMods( (m_pPlayer->LastHitGroup() == HITGROUP_HEAD) ? ACT_CSGO_FLINCH_HEAD : ACT_CSGO_FLINCH ) );
  778. // clear out all the flinch-related actmods now we selected a sequence
  779. UpdateActivityModifiers();
  780. }
  781. }
  782. if ( GetLayerSequence( ANIMATION_LAYER_FLINCH ) > 0 )
  783. {
  784. SetLayerWeight( ANIMATION_LAYER_FLINCH, GetLayerIdealWeightFromSeqCycle( ANIMATION_LAYER_FLINCH ) );
  785. }
  786. else
  787. {
  788. SetLayerWeight( ANIMATION_LAYER_FLINCH, 0 );
  789. }
  790. #endif
  791. IncrementLayerCycle( ANIMATION_LAYER_FLINCH, false );
  792. }
  793. void CCSGOPlayerAnimState::SetUpFlashedReaction( void )
  794. {
  795. animstate_layer_t nLayer = ANIMATION_LAYER_FLASHED;
  796. #ifndef CLIENT_DLL
  797. if ( m_flFlashedAmountEaseOutEnd < gpGlobals->curtime )
  798. {
  799. SetLayerWeight( nLayer, 0 );
  800. m_bFlashed = false;
  801. }
  802. else
  803. {
  804. if ( !m_bFlashed )
  805. {
  806. SetLayerSequence( nLayer, SelectSequenceFromActMods( ACT_CSGO_FLASHBANG_REACTION ) );
  807. m_bFlashed = true;
  808. }
  809. float flFlashedAmount = RemapValClamped( gpGlobals->curtime, m_flFlashedAmountEaseOutStart, m_flFlashedAmountEaseOutEnd, 1, 0 );
  810. // TODO: make flashed anims look nicer by using a cycle, like the old ones
  811. //SetLayerCycle( nLayer, 1.0f - flFlashedAmount );
  812. SetLayerCycle( nLayer, 0 );
  813. SetLayerRate( nLayer, 0 );
  814. float flWeightPrevious = GetLayerWeight( nLayer );
  815. float flWeightNew = SimpleSpline(flFlashedAmount);
  816. SetLayerWeight( nLayer, flWeightNew );
  817. SetLayerWeightRate( nLayer, (flWeightNew >= flWeightPrevious) ? 0 : flWeightPrevious );
  818. }
  819. #else
  820. if ( GetLayerWeight( nLayer ) > 0 )
  821. {
  822. CAnimationLayer *pLayer = m_pPlayer->GetAnimOverlay( nLayer, USE_ANIMLAYER_RAW_INDEX );
  823. if ( pLayer && pLayer->GetWeightDeltaRate() < 0 )
  824. IncrementLayerWeight( nLayer );
  825. }
  826. #endif
  827. }
  828. #define CSGO_ANIM_BOMBPLANT_ABORT_SPEED 12.0f
  829. #define CSGO_ANIM_DEFUSE_ABORT_SPEED 8.0f
  830. #define CSGO_ANIM_TWITCH_ABORT_SPEED 6.0f
  831. #define CSGO_ANIM_BOMBPLANT_BLEND_RATE 1.2f
  832. void CCSGOPlayerAnimState::SetUpWholeBodyAction( void )
  833. {
  834. animstate_layer_t nLayer = ANIMATION_LAYER_WHOLE_BODY;
  835. #ifndef CLIENT_DLL
  836. // Whole body anims are for custom events that typically take over the entire body of the player.
  837. // At the moment, they're used for idle twitches in freeze time, defusing and bomb-planting,
  838. // and probably taunts in the near future.
  839. //if ( !m_bDefuseStarted &&
  840. // !m_bPlantAnimStarted &&
  841. // m_flNextTwitchTime <= gpGlobals->curtime &&
  842. // AreTwitchesAllowed() )
  843. //{
  844. // // roll for a twitch anim
  845. // bool bFirstInit = ( m_flNextTwitchTime == 0 );
  846. // m_flNextTwitchTime = gpGlobals->curtime + RandomFloat( 8, 16 );
  847. //
  848. // if ( !bFirstInit && !m_bTwitchAnimStarted && m_bOnGround )
  849. // {
  850. // // start the twitch anim
  851. // SetLayerSequence( nLayer, SelectSequenceFromActMods( ACT_CSGO_TWITCH_BUYZONE ) );
  852. // m_bTwitchAnimStarted = true;
  853. // }
  854. //}
  855. if ( m_pPlayer->GetTeamNumber() == TEAM_CT && m_pPlayer->m_bIsDefusing ) // should be defusing
  856. {
  857. if ( !m_bDefuseStarted )
  858. {
  859. // we are now defusing and need to start the anim
  860. SetLayerSequence( nLayer, SelectSequenceFromActMods( m_pPlayer->HasDefuser() ? ACT_CSGO_DEFUSE_WITH_KIT : ACT_CSGO_DEFUSE ) );
  861. m_bDefuseStarted = true;
  862. }
  863. else
  864. {
  865. IncrementLayerCycleWeightRateGeneric(nLayer);
  866. }
  867. }
  868. else if ( GetLayerActivity( nLayer ) == ACT_CSGO_DEFUSE || GetLayerActivity( nLayer ) == ACT_CSGO_DEFUSE_WITH_KIT )
  869. {
  870. // should NOT be defusing but IS
  871. if ( GetLayerWeight( nLayer ) > 0 )
  872. {
  873. float flCurrentWeight = GetLayerWeight( nLayer );
  874. SetLayerWeight( nLayer, Approach( 0, flCurrentWeight, m_flLastUpdateIncrement * CSGO_ANIM_DEFUSE_ABORT_SPEED ) );
  875. SetLayerWeightRate( nLayer, flCurrentWeight );
  876. }
  877. m_bDefuseStarted = false;
  878. }
  879. else if ( GetLayerActivity( nLayer ) == ACT_CSGO_PLANT_BOMB ) // is planting
  880. {
  881. if ( m_pWeapon && !m_pWeapon->IsA( WEAPON_C4 ) )
  882. m_bPlantAnimStarted = false; // cancel planting if we're not holding c4
  883. if ( m_bPlantAnimStarted ) // plant in progress
  884. {
  885. // Inlined IncrementLayerCycleWeightRateGeneric() so we can tune the layering weight when crouch-planting the bomb.
  886. //
  887. // Instead of setting the weight to GetLayerIdealWeightFromSeqCycle, we approach that value which smoothly blends to
  888. // the bomb plant animation. This means that the 'standing' part of the animation doesn't get overly blended to when
  889. // planting the animation from a crouched position. In addition, if you are in thirdperson camera, the crouch is
  890. // predicted but the plant animation is server-side. So we do this blend regardless of the crouch state because it
  891. // could differ between the client and the server.
  892. //
  893. // This does mean that fine detail in the beginning of the plant animation is lost. Fortunately there isn't much of
  894. // that at the moment.
  895. float flWeightPrevious = GetLayerWeight( nLayer );
  896. IncrementLayerCycle( nLayer, false );
  897. SetLayerWeight( nLayer, Approach( GetLayerIdealWeightFromSeqCycle( nLayer ), flWeightPrevious, m_flLastUpdateIncrement * CSGO_ANIM_BOMBPLANT_BLEND_RATE ) );
  898. SetLayerWeightRate( nLayer, flWeightPrevious );
  899. m_bPlantAnimStarted = !( IsLayerSequenceCompleted( nLayer ) );
  900. }
  901. else
  902. {
  903. if ( GetLayerWeight( nLayer ) > 0 )
  904. {
  905. //bomb plant aborted, pull out the weight
  906. float flCurrentWeight = GetLayerWeight( nLayer );
  907. SetLayerWeight( nLayer, Approach( 0, flCurrentWeight, m_flLastUpdateIncrement * CSGO_ANIM_BOMBPLANT_ABORT_SPEED ) );
  908. SetLayerWeightRate( nLayer, flCurrentWeight );
  909. }
  910. m_bPlantAnimStarted = false;
  911. }
  912. }
  913. //else if ( GetLayerActivity( nLayer ) == ACT_CSGO_TWITCH_BUYZONE || GetLayerActivity( nLayer ) == ACT_CSGO_TWITCH ) // twitching
  914. //{
  915. // if ( m_pWeapon && m_pWeapon != m_pWeaponLast )
  916. // m_bTwitchAnimStarted = false; // cancel twitches if weapon changes
  917. //
  918. // if ( m_bTwitchAnimStarted && AreTwitchesAllowed() )
  919. // {
  920. // IncrementLayerCycleWeightRateGeneric(nLayer);
  921. // m_bTwitchAnimStarted = !( IsLayerSequenceCompleted( nLayer ) );
  922. // }
  923. // else
  924. // {
  925. // if ( GetLayerWeight( nLayer ) > 0 )
  926. // {
  927. // float flCurrentWeight = GetLayerWeight( nLayer );
  928. // SetLayerWeight( nLayer, Approach( 0, flCurrentWeight, m_flLastUpdateIncrement * CSGO_ANIM_TWITCH_ABORT_SPEED ) );
  929. // SetLayerWeightRate( nLayer, flCurrentWeight );
  930. // }
  931. // m_bTwitchAnimStarted = false;
  932. // }
  933. //}
  934. else
  935. {
  936. // fallback
  937. SetLayerCycle( nLayer, 0.999f );
  938. SetLayerWeight( nLayer, 0 );
  939. SetLayerWeightRate( nLayer, 0 );
  940. }
  941. #else
  942. if ( GetLayerWeight( nLayer ) > 0 )
  943. {
  944. IncrementLayerCycle( nLayer, false );
  945. IncrementLayerWeight( nLayer );
  946. }
  947. #endif
  948. }
  949. void CCSGOPlayerAnimState::SetUpAliveloop( void )
  950. {
  951. animstate_layer_t nLayer = ANIMATION_LAYER_ALIVELOOP;
  952. #ifndef CLIENT_DLL
  953. if ( GetLayerActivity( nLayer ) != ACT_CSGO_ALIVE_LOOP )
  954. {
  955. // first time init
  956. MDLCACHE_CRITICAL_SECTION();
  957. SetLayerSequence( nLayer, SelectSequenceFromActMods( ACT_CSGO_ALIVE_LOOP ) );
  958. SetLayerCycle( nLayer, RandomFloat( 0, 1 ) );
  959. CAnimationLayer *pLayer = m_pPlayer->GetAnimOverlay( nLayer, USE_ANIMLAYER_RAW_INDEX );
  960. if ( pLayer )
  961. {
  962. float flNewRate = m_pPlayer->GetSequenceCycleRate( m_pPlayer->GetModelPtr(), pLayer->GetSequence() );
  963. flNewRate *= RandomFloat( 0.8f, 1.1f );
  964. SetLayerRate( nLayer, flNewRate );
  965. }
  966. }
  967. else
  968. {
  969. if ( m_pWeapon && m_pWeapon != m_pWeaponLast )
  970. {
  971. //re-roll act on weapon change
  972. float flRetainCycle = GetLayerCycle( nLayer );
  973. SetLayerSequence( nLayer, SelectSequenceFromActMods( ACT_CSGO_ALIVE_LOOP ) );
  974. SetLayerCycle( nLayer, flRetainCycle );
  975. }
  976. else if ( IsLayerSequenceCompleted( nLayer ) )
  977. {
  978. //re-roll rate
  979. MDLCACHE_CRITICAL_SECTION();
  980. CAnimationLayer *pLayer = m_pPlayer->GetAnimOverlay( nLayer, USE_ANIMLAYER_RAW_INDEX );
  981. if ( pLayer )
  982. {
  983. float flNewRate = m_pPlayer->GetSequenceCycleRate( m_pPlayer->GetModelPtr(), pLayer->GetSequence() );
  984. flNewRate *= RandomFloat( 0.8f, 1.1f );
  985. SetLayerRate( nLayer, flNewRate );
  986. }
  987. }
  988. else
  989. {
  990. float flWeightOutPoseBreaker = RemapValClamped( m_flSpeedAsPortionOfRunTopSpeed, 0.55f, 0.9f, 1.0f, 0.0f );
  991. SetLayerWeight( nLayer, flWeightOutPoseBreaker );
  992. }
  993. }
  994. #endif
  995. IncrementLayerCycle( nLayer, true );
  996. //SetLayerWeight( nLayer, 1 );
  997. }
  998. void CCSGOPlayerAnimState::SetUpWeaponAction( void )
  999. {
  1000. animstate_layer_t nLayer = ANIMATION_LAYER_WEAPON_ACTION;
  1001. #ifndef CLIENT_DLL
  1002. bool bDoIncrement = true;
  1003. if ( m_pWeapon && m_bDeployRateLimiting && GetLayerActivity( nLayer ) == ACT_CSGO_DEPLOY )
  1004. {
  1005. m_pWeapon->ShowWeaponWorldModel( false );
  1006. if ( GetLayerCycle( nLayer ) >= CSGO_ANIM_DEPLOY_RATELIMIT )
  1007. {
  1008. m_bDeployRateLimiting = false;
  1009. SetLayerSequence( nLayer, SelectSequenceFromActMods( ACT_CSGO_DEPLOY ) );
  1010. //SetLayerRate( nLayer, GetLayerRate( nLayer ) * 1.5f );
  1011. SetLayerWeight( nLayer, 0 );
  1012. bDoIncrement = false;
  1013. }
  1014. }
  1015. // fixme: this is a hack to fix all-body weapon actions that need to transition into crouch or stand poses they weren't built for.
  1016. // This only matters for idle animation - the move layer is itself a kind of 're-crouch' and 're-stand' layer itself.
  1017. if ( m_nAnimstateModelVersion < 2 )
  1018. {
  1019. // old re-crouch behavior
  1020. // fixme: this is a hack to fix the all-body weapon action that wants to crouch case. There's no fix for the crouching all-body action that wants to stand
  1021. if ( m_flAnimDuckAmount > 0 && GetLayerWeight(nLayer) > 0 && !LayerSequenceHasActMod( nLayer, "crouch" ) )
  1022. {
  1023. if ( GetLayerSequence( ANIMATION_LAYER_WEAPON_ACTION_RECROUCH ) <= 0 )
  1024. SetLayerSequence( ANIMATION_LAYER_WEAPON_ACTION_RECROUCH, m_pPlayer->LookupSequence( "recrouch_generic" ) );
  1025. SetLayerWeight( ANIMATION_LAYER_WEAPON_ACTION_RECROUCH, GetLayerWeight(nLayer) * m_flAnimDuckAmount );
  1026. }
  1027. else
  1028. {
  1029. SetLayerWeight( ANIMATION_LAYER_WEAPON_ACTION_RECROUCH, 0 );
  1030. }
  1031. }
  1032. else
  1033. {
  1034. // newer version with "re-stand" blended into the re-crouch.
  1035. float flTargetRecrouchWeight = 0;
  1036. if ( GetLayerWeight(nLayer) > 0 )
  1037. {
  1038. if ( GetLayerSequence( ANIMATION_LAYER_WEAPON_ACTION_RECROUCH ) <= 0 )
  1039. SetLayerSequence( ANIMATION_LAYER_WEAPON_ACTION_RECROUCH, m_pPlayer->LookupSequence( "recrouch_generic" ) );
  1040. if ( LayerSequenceHasActMod( nLayer, "crouch" ) )
  1041. {
  1042. // this is a crouching anim. It might be the only anim available, or it's just lasted long enough that the
  1043. // player stood up after it started. If we're standing up at all, we need to force the stand pose artificially.
  1044. if ( m_flAnimDuckAmount < 1 )
  1045. flTargetRecrouchWeight = GetLayerWeight(nLayer) * (1.0f - m_flAnimDuckAmount);
  1046. }
  1047. else
  1048. {
  1049. // this is NOT a crouching anim. Still if it's not a whole-body anim it might work fine when crouched though,
  1050. // and not actually need the re-crouch. How to detect this?
  1051. // We can't trust this anim to crouch the player since it's not tagged as a crouch anim. So we need to force the
  1052. // crouch pose artificially.
  1053. if ( m_flAnimDuckAmount > 0 )
  1054. flTargetRecrouchWeight = GetLayerWeight(nLayer) * m_flAnimDuckAmount;
  1055. }
  1056. }
  1057. else
  1058. {
  1059. if ( GetLayerWeight( ANIMATION_LAYER_WEAPON_ACTION_RECROUCH ) > 0 )
  1060. flTargetRecrouchWeight = Approach( 0, GetLayerWeight( ANIMATION_LAYER_WEAPON_ACTION_RECROUCH ), m_flLastUpdateIncrement * 4 );
  1061. }
  1062. SetLayerWeight( ANIMATION_LAYER_WEAPON_ACTION_RECROUCH, flTargetRecrouchWeight );
  1063. }
  1064. if ( bDoIncrement )
  1065. {
  1066. // increment the action
  1067. IncrementLayerCycle( nLayer, false );
  1068. float flWeightPrev = GetLayerWeight( nLayer );
  1069. float flDesiredWeight = GetLayerIdealWeightFromSeqCycle( nLayer );
  1070. SetLayerWeight( nLayer, flDesiredWeight );
  1071. SetLayerWeightRate( nLayer, flWeightPrev );
  1072. }
  1073. #else
  1074. // client
  1075. if ( GetLayerWeight( nLayer ) > 0 )
  1076. {
  1077. IncrementLayerCycle( nLayer, false );
  1078. IncrementLayerWeight( nLayer );
  1079. }
  1080. #endif
  1081. // set weapon sequence and cycle so dispatched events hit
  1082. CAnimationLayer *pWeaponLayer = m_pPlayer->GetAnimOverlay( nLayer, USE_ANIMLAYER_RAW_INDEX );
  1083. if ( pWeaponLayer && m_pWeapon )
  1084. {
  1085. CBaseWeaponWorldModel *pWeaponWorldModel = m_pWeapon->m_hWeaponWorldModel.Get();
  1086. if ( pWeaponWorldModel )
  1087. {
  1088. MDLCACHE_CRITICAL_SECTION();
  1089. if ( pWeaponLayer->m_nDispatchedDst > 0 && pWeaponLayer->GetWeight() > 0 ) // fixme: does the weight check make 0-frame events fail? Added a check below just in case.
  1090. {
  1091. pWeaponWorldModel->SetSequence( pWeaponLayer->m_nDispatchedDst );
  1092. pWeaponWorldModel->SetCycle( pWeaponLayer->GetCycle() );
  1093. pWeaponWorldModel->SetPlaybackRate( pWeaponLayer->GetPlaybackRate() );
  1094. #ifndef CLIENT_DLL
  1095. pWeaponWorldModel->DispatchAnimEvents( pWeaponWorldModel );
  1096. #endif
  1097. }
  1098. else
  1099. {
  1100. #ifndef CLIENT_DLL
  1101. if ( pWeaponWorldModel->GetCycle() != 0 )
  1102. pWeaponWorldModel->DispatchAnimEvents( pWeaponWorldModel );
  1103. #endif
  1104. pWeaponWorldModel->SetSequence( 0 );
  1105. pWeaponWorldModel->SetCycle( 0 );
  1106. pWeaponWorldModel->SetPlaybackRate( 0 );
  1107. }
  1108. }
  1109. }
  1110. }
  1111. #define CSGO_ANIM_WALK_TO_RUN_TRANSITION_SPEED 2.0f
  1112. #define CSGO_ANIM_ONGROUND_FUZZY_APPROACH 8.0f
  1113. #define CSGO_ANIM_ONGROUND_FUZZY_APPROACH_CROUCH 16.0f
  1114. #define CSGO_ANIM_LADDER_CLIMB_COVERAGE 100.0f
  1115. #define CSGO_ANIM_RUN_ANIM_PLAYBACK_MULTIPLIER 0.85f
  1116. void CCSGOPlayerAnimState::SetUpMovement( void )
  1117. {
  1118. MDLCACHE_CRITICAL_SECTION();
  1119. if ( m_flWalkToRunTransition > 0 && m_flWalkToRunTransition < 1 )
  1120. {
  1121. //currently transitioning between walk and run
  1122. if ( m_bWalkToRunTransitionState == ANIM_TRANSITION_WALK_TO_RUN )
  1123. {
  1124. m_flWalkToRunTransition += m_flLastUpdateIncrement * CSGO_ANIM_WALK_TO_RUN_TRANSITION_SPEED;
  1125. }
  1126. else // m_bWalkToRunTransitionState == ANIM_TRANSITION_RUN_TO_WALK
  1127. {
  1128. m_flWalkToRunTransition -= m_flLastUpdateIncrement * CSGO_ANIM_WALK_TO_RUN_TRANSITION_SPEED;
  1129. }
  1130. m_flWalkToRunTransition = clamp( m_flWalkToRunTransition, 0, 1 );
  1131. }
  1132. if ( m_flVelocityLengthXY > (CS_PLAYER_SPEED_RUN*CS_PLAYER_SPEED_WALK_MODIFIER) && m_bWalkToRunTransitionState == ANIM_TRANSITION_RUN_TO_WALK )
  1133. {
  1134. //crossed the walk to run threshold
  1135. m_bWalkToRunTransitionState = ANIM_TRANSITION_WALK_TO_RUN;
  1136. m_flWalkToRunTransition = MAX( 0.01f, m_flWalkToRunTransition );
  1137. }
  1138. else if ( m_flVelocityLengthXY < (CS_PLAYER_SPEED_RUN*CS_PLAYER_SPEED_WALK_MODIFIER) && m_bWalkToRunTransitionState == ANIM_TRANSITION_WALK_TO_RUN )
  1139. {
  1140. //crossed the run to walk threshold
  1141. m_bWalkToRunTransitionState = ANIM_TRANSITION_RUN_TO_WALK;
  1142. m_flWalkToRunTransition = MIN( 0.99f, m_flWalkToRunTransition );
  1143. }
  1144. if ( m_nAnimstateModelVersion < 2 )
  1145. {
  1146. m_tPoseParamMappings[ PLAYER_POSE_PARAM_RUN ].SetValue( m_pPlayer, m_flWalkToRunTransition );
  1147. }
  1148. else
  1149. {
  1150. m_tPoseParamMappings[ PLAYER_POSE_PARAM_MOVE_BLEND_WALK ].SetValue( m_pPlayer, (1.0f - m_flWalkToRunTransition) * (1.0f - m_flAnimDuckAmount) );
  1151. m_tPoseParamMappings[ PLAYER_POSE_PARAM_MOVE_BLEND_RUN ].SetValue( m_pPlayer, (m_flWalkToRunTransition) * (1.0f - m_flAnimDuckAmount) );
  1152. m_tPoseParamMappings[ PLAYER_POSE_PARAM_MOVE_BLEND_CROUCH_WALK ].SetValue( m_pPlayer, m_flAnimDuckAmount );
  1153. }
  1154. char szWeaponMoveSeq[MAX_ANIMSTATE_ANIMNAME_CHARS];
  1155. V_sprintf_safe( szWeaponMoveSeq, "move_%s", GetWeaponPrefix() );
  1156. int nWeaponMoveSeq = m_pPlayer->LookupSequence( szWeaponMoveSeq );
  1157. if ( nWeaponMoveSeq == -1 )
  1158. {
  1159. nWeaponMoveSeq = m_pPlayer->LookupSequence( "move" );
  1160. }
  1161. Assert( nWeaponMoveSeq > 0 );
  1162. if ( m_pPlayer->m_iMoveState != m_nPreviousMoveState )
  1163. {
  1164. m_flStutterStep += 10;
  1165. }
  1166. m_nPreviousMoveState = m_pPlayer->m_iMoveState;
  1167. m_flStutterStep = clamp( Approach( 0, m_flStutterStep, m_flLastUpdateIncrement * 40 ), 0, 100 );
  1168. // recompute moveweight
  1169. float flTargetMoveWeight = Lerp( m_flAnimDuckAmount, clamp(m_flSpeedAsPortionOfWalkTopSpeed, 0, 1), clamp(m_flSpeedAsPortionOfCrouchTopSpeed, 0, 1) );
  1170. //flTargetMoveWeight *= RemapValClamped( m_flStutterStep, 90, 100, 1, 0 );
  1171. if ( m_flMoveWeight <= flTargetMoveWeight )
  1172. {
  1173. m_flMoveWeight = flTargetMoveWeight;
  1174. }
  1175. else
  1176. {
  1177. m_flMoveWeight = Approach( flTargetMoveWeight, m_flMoveWeight, m_flLastUpdateIncrement * RemapValClamped( m_flStutterStep, 0.0f, 100.0f, 2, 20 ) );
  1178. }
  1179. Vector vecMoveYawDir;
  1180. AngleVectors( QAngle(0, AngleNormalize( m_flFootYaw + m_flMoveYaw + 180 ), 0), &vecMoveYawDir );
  1181. float flYawDeltaAbsDot = abs( DotProduct( m_vecVelocityNormalizedNonZero, vecMoveYawDir ) );
  1182. m_flMoveWeight *= Bias( flYawDeltaAbsDot, 0.2 );
  1183. float flMoveWeightWithAirSmooth = m_flMoveWeight * m_flInAirSmoothValue;
  1184. // dampen move weight for landings
  1185. flMoveWeightWithAirSmooth *= MAX( (1.0f - GetLayerWeight( ANIMATION_LAYER_MOVEMENT_LAND_OR_CLIMB ) ), 0.55f );
  1186. float flMoveCycleRate = 0;
  1187. if ( m_flVelocityLengthXY > 0 )
  1188. {
  1189. flMoveCycleRate = m_pPlayer->GetSequenceCycleRate( m_pPlayer->GetModelPtr(), nWeaponMoveSeq );
  1190. float flSequenceGroundSpeed = MAX( m_pPlayer->GetSequenceMoveDist( m_pPlayer->GetModelPtr(), nWeaponMoveSeq ) / ( 1.0f / flMoveCycleRate ), 0.001f );
  1191. flMoveCycleRate *= m_flVelocityLengthXY / flSequenceGroundSpeed;
  1192. flMoveCycleRate *= Lerp( m_flWalkToRunTransition, 1.0f, CSGO_ANIM_RUN_ANIM_PLAYBACK_MULTIPLIER );
  1193. }
  1194. float flLocalCycleIncrement = (flMoveCycleRate * m_flLastUpdateIncrement);
  1195. m_flPrimaryCycle = ClampCycle( m_flPrimaryCycle + flLocalCycleIncrement );
  1196. flMoveWeightWithAirSmooth = clamp( flMoveWeightWithAirSmooth, 0, 1 );
  1197. UpdateAnimLayer( ANIMATION_LAYER_MOVEMENT_MOVE, nWeaponMoveSeq, flLocalCycleIncrement, flMoveWeightWithAirSmooth, m_flPrimaryCycle );
  1198. #ifndef CLIENT_DLL
  1199. // blend in a strafe direction-change pose when the player changes strafe dir
  1200. // get the user's left and right button pressed states
  1201. bool moveRight = ( m_pPlayer->m_nButtons & ( IN_MOVERIGHT ) ) != 0;
  1202. bool moveLeft = ( m_pPlayer->m_nButtons & ( IN_MOVELEFT ) ) != 0;
  1203. bool moveForward = ( m_pPlayer->m_nButtons & ( IN_FORWARD ) ) != 0;
  1204. bool moveBackward = ( m_pPlayer->m_nButtons & ( IN_BACK ) ) != 0;
  1205. //Vector vForward, vRight;
  1206. //AngleVectors( QAngle(0,m_flEyeYaw,0), &vForward, &vRight, NULL );
  1207. //vForward *= 10;
  1208. //vRight *= 10;
  1209. //if ( moveRight )
  1210. // debugoverlay->AddTriangleOverlay( m_vecPositionCurrent + vRight * 2, m_vecPositionCurrent - vForward, m_vecPositionCurrent + vForward, 200, 0, 0, 255, true, 0 );
  1211. //if ( moveLeft )
  1212. // debugoverlay->AddTriangleOverlay( m_vecPositionCurrent - vRight * 2, m_vecPositionCurrent + vForward, m_vecPositionCurrent - vForward, 200, 0, 0, 255, true, 0 );
  1213. //if ( moveForward )
  1214. // debugoverlay->AddTriangleOverlay( m_vecPositionCurrent + vForward * 2, m_vecPositionCurrent + vRight, m_vecPositionCurrent - vRight, 200, 0, 0, 255, true, 0 );
  1215. //if ( moveBackward )
  1216. // debugoverlay->AddTriangleOverlay( m_vecPositionCurrent - vForward * 2, m_vecPositionCurrent + vRight, m_vecPositionCurrent - vRight, 200, 0, 0, 255, true, 0 );
  1217. Vector vecForward;
  1218. Vector vecRight;
  1219. AngleVectors( QAngle(0,m_flFootYaw,0), &vecForward, &vecRight, NULL );
  1220. vecRight.NormalizeInPlace();
  1221. float flVelToRightDot = DotProduct( m_vecVelocityNormalizedNonZero, vecRight );
  1222. float flVelToForwardDot = DotProduct( m_vecVelocityNormalizedNonZero, vecForward );
  1223. // We're interested in if the player's desired direction (indicated by their held buttons) is opposite their current velocity.
  1224. // This indicates a strafing direction change in progress.
  1225. bool bStrafeRight = ( m_flSpeedAsPortionOfWalkTopSpeed >= 0.73f && moveRight && !moveLeft && flVelToRightDot < -0.63f );
  1226. bool bStrafeLeft = ( m_flSpeedAsPortionOfWalkTopSpeed >= 0.73f && moveLeft && !moveRight && flVelToRightDot > 0.63f );
  1227. bool bStrafeForward = ( m_flSpeedAsPortionOfWalkTopSpeed >= 0.65f && moveForward && !moveBackward && flVelToForwardDot < -0.55f );
  1228. bool bStrafeBackward = ( m_flSpeedAsPortionOfWalkTopSpeed >= 0.65f && moveBackward && !moveForward && flVelToForwardDot > 0.55f );
  1229. m_pPlayer->m_bStrafing = ( bStrafeRight || bStrafeLeft || bStrafeForward || bStrafeBackward );
  1230. #endif
  1231. if ( m_pPlayer->m_bStrafing )
  1232. {
  1233. if ( !m_bStrafeChanging )
  1234. {
  1235. m_flDurationStrafing = 0;
  1236. #ifdef CLIENT_DLL
  1237. if ( !m_bFirstRunSinceInit && !m_bStrafeChanging && m_bOnGround && m_pPlayer->m_boneSnapshots[BONESNAPSHOT_UPPER_BODY].GetCurrentWeight() <= 0 )
  1238. {
  1239. m_pPlayer->m_boneSnapshots[BONESNAPSHOT_UPPER_BODY].SetShouldCapture( bonesnapshot_get( cl_bonesnapshot_speed_strafestart ) );
  1240. }
  1241. #endif
  1242. }
  1243. m_bStrafeChanging = true;
  1244. m_flStrafeChangeWeight = Approach( 1, m_flStrafeChangeWeight, m_flLastUpdateIncrement * 20 );
  1245. m_flStrafeChangeCycle = Approach( 0, m_flStrafeChangeCycle, m_flLastUpdateIncrement * 10 );
  1246. m_tPoseParamMappings[ PLAYER_POSE_PARAM_STRAFE_DIR ].SetValue( m_pPlayer, AngleNormalize( m_flMoveYaw ) );
  1247. //float flCross = m_tPoseParamMappings[ PLAYER_POSE_PARAM_STRAFE_CROSS ].GetValue( m_pPlayer );
  1248. //flCross = clamp( Approach( m_bFeetCrossed ? 1 : 0, flCross, m_flLastUpdateIncrement * 10 ), 0, 1);
  1249. //m_tPoseParamMappings[ PLAYER_POSE_PARAM_STRAFE_CROSS ].SetValue( m_pPlayer, flCross );
  1250. //m_tPoseParamMappings[ PLAYER_POSE_PARAM_STRAFE_CROSS ].SetValue( m_pPlayer, 0 );
  1251. }
  1252. else if ( m_flStrafeChangeWeight > 0 )
  1253. {
  1254. m_flDurationStrafing += m_flLastUpdateIncrement;
  1255. if ( m_flDurationStrafing > 0.08f )
  1256. m_flStrafeChangeWeight = Approach( 0, m_flStrafeChangeWeight, m_flLastUpdateIncrement * 5 );
  1257. m_nStrafeSequence = m_pPlayer->LookupSequence( "strafe" );
  1258. float flRate = m_pPlayer->GetSequenceCycleRate( m_pPlayer->GetModelPtr(), m_nStrafeSequence );
  1259. m_flStrafeChangeCycle = clamp( m_flStrafeChangeCycle + m_flLastUpdateIncrement * flRate, 0, 1 );
  1260. }
  1261. if ( m_flStrafeChangeWeight <= 0 )
  1262. {
  1263. m_bStrafeChanging = false;
  1264. }
  1265. // keep track of if the player is on the ground, and if the player has just touched or left the ground since the last check
  1266. bool bPreviousGroundState = m_bOnGround;
  1267. m_bOnGround = ( m_pPlayer->GetFlags() & FL_ONGROUND );
  1268. m_bLandedOnGroundThisFrame = ( !m_bFirstRunSinceInit && bPreviousGroundState != m_bOnGround && m_bOnGround );
  1269. m_bLeftTheGroundThisFrame = ( bPreviousGroundState != m_bOnGround && !m_bOnGround );
  1270. float flDistanceFell = 0;
  1271. if ( m_bLeftTheGroundThisFrame )
  1272. {
  1273. m_flLeftGroundHeight = m_vecPositionCurrent.z;
  1274. }
  1275. if ( m_bLandedOnGroundThisFrame )
  1276. {
  1277. flDistanceFell = abs( m_flLeftGroundHeight - m_vecPositionCurrent.z );
  1278. float flDistanceFallNormalizedBiasRange = Bias( RemapValClamped( flDistanceFell, 12.0f, 72.0f, 0.0f, 1.0f ), 0.4f );
  1279. //Msg( "Fell %f units, ratio is %f. ", flDistanceFell, flDistanceFallNormalizedBiasRange );
  1280. //Msg( "Fell for %f secs, multiplier is %f\n", m_flDurationInAir, m_flLandAnimMultiplier );
  1281. m_flLandAnimMultiplier = clamp( Bias( m_flDurationInAir, 0.3f ), 0.1f, 1.0f );
  1282. m_flDuckAdditional = MAX( m_flLandAnimMultiplier, flDistanceFallNormalizedBiasRange );
  1283. //Msg( "m_flDuckAdditional is %f\n", m_flDuckAdditional );
  1284. }
  1285. else
  1286. {
  1287. m_flDuckAdditional = Approach( 0, m_flDuckAdditional, m_flLastUpdateIncrement * 2 );
  1288. }
  1289. // the in-air smooth value is a fuzzier representation of if the player is on the ground or not.
  1290. // It will approach 1 when the player is on the ground and 0 when in the air. Useful for blending jump animations.
  1291. m_flInAirSmoothValue = Approach( m_bOnGround ? 1 : 0, m_flInAirSmoothValue, Lerp( m_flAnimDuckAmount, CSGO_ANIM_ONGROUND_FUZZY_APPROACH, CSGO_ANIM_ONGROUND_FUZZY_APPROACH_CROUCH ) * m_flLastUpdateIncrement );
  1292. m_flInAirSmoothValue = clamp( m_flInAirSmoothValue, 0, 1 );
  1293. m_flStrafeChangeWeight *= ( 1.0f - m_flAnimDuckAmount );
  1294. m_flStrafeChangeWeight *= m_flInAirSmoothValue;
  1295. m_flStrafeChangeWeight = clamp( m_flStrafeChangeWeight, 0, 1 );
  1296. //if ( m_flStrafeChangeWeight > 0 && flMoveWeightWithAirSmooth <= 0.01f )
  1297. //{
  1298. // if ( flStrafePose > 0.5f )
  1299. // {
  1300. // m_flPrimaryCycle = m_pPlayer->GetFirstSequenceAnimTag( nWeaponMoveSeq, ANIMTAG_STARTCYCLE_W, 0, 1 );
  1301. // }
  1302. // else
  1303. // {
  1304. // m_flPrimaryCycle = m_pPlayer->GetFirstSequenceAnimTag( nWeaponMoveSeq, ANIMTAG_STARTCYCLE_E, 0, 1 );
  1305. // }
  1306. //}
  1307. if ( m_nStrafeSequence != -1 )
  1308. UpdateAnimLayer( ANIMATION_LAYER_MOVEMENT_STRAFECHANGE, m_nStrafeSequence, 0, m_flStrafeChangeWeight, m_flStrafeChangeCycle );
  1309. //ladders
  1310. bool bPreviouslyOnLadder = m_bOnLadder;
  1311. m_bOnLadder = !m_bOnGround && m_pPlayer->GetMoveType() == MOVETYPE_LADDER;
  1312. bool bStartedLadderingThisFrame = ( !bPreviouslyOnLadder && m_bOnLadder );
  1313. bool bStoppedLadderingThisFrame = ( bPreviouslyOnLadder && !m_bOnLadder );
  1314. if ( bStartedLadderingThisFrame || bStoppedLadderingThisFrame )
  1315. {
  1316. #ifdef CLIENT_DLL
  1317. //m_footLeft.m_flLateralWeight = 0;
  1318. //m_footRight.m_flLateralWeight = 0;
  1319. #endif
  1320. }
  1321. if ( m_flLadderWeight > 0 || m_bOnLadder )
  1322. {
  1323. #ifndef CLIENT_DLL
  1324. if ( bStartedLadderingThisFrame )
  1325. {
  1326. SetLayerSequence( ANIMATION_LAYER_MOVEMENT_LAND_OR_CLIMB, SelectSequenceFromActMods( ACT_CSGO_CLIMB_LADDER ) );
  1327. }
  1328. #endif
  1329. if ( abs(m_flVelocityLengthZ) > 100 )
  1330. {
  1331. m_flLadderSpeed = Approach( 1, m_flLadderSpeed, m_flLastUpdateIncrement * 10.0f );
  1332. }
  1333. else
  1334. {
  1335. m_flLadderSpeed = Approach( 0, m_flLadderSpeed, m_flLastUpdateIncrement * 10.0f );
  1336. }
  1337. m_flLadderSpeed = clamp( m_flLadderSpeed, 0, 1 );
  1338. if ( m_bOnLadder )
  1339. {
  1340. m_flLadderWeight = Approach( 1, m_flLadderWeight, m_flLastUpdateIncrement * 5.0f );
  1341. }
  1342. else
  1343. {
  1344. m_flLadderWeight = Approach( 0, m_flLadderWeight, m_flLastUpdateIncrement * 10.0f );
  1345. }
  1346. m_flLadderWeight = clamp( m_flLadderWeight, 0, 1 );
  1347. Vector vecLadderNormal = m_pPlayer->GetLadderNormal();
  1348. QAngle angLadder;
  1349. VectorAngles( vecLadderNormal, angLadder );
  1350. float flLadderYaw = AngleDiff( angLadder.y, m_flFootYaw );
  1351. m_tPoseParamMappings[ PLAYER_POSE_PARAM_LADDER_YAW ].SetValue( m_pPlayer, flLadderYaw );
  1352. //float flPlayerZ = m_pPlayer->GetAbsOrigin().z;
  1353. //float flLadderClimbCycle = fmod( abs(flPlayerZ), 80.0f ) / 80.0f;
  1354. //flLadderClimbCycle = ClampCycle( flPlayerZ < 0 ? (1.0f - flLadderClimbCycle) : flLadderClimbCycle );
  1355. float flLadderClimbCycle = GetLayerCycle( ANIMATION_LAYER_MOVEMENT_LAND_OR_CLIMB );
  1356. flLadderClimbCycle += (m_vecPositionCurrent.z - m_vecPositionLast.z) * Lerp( m_flLadderSpeed, 0.010f, 0.004f );
  1357. m_tPoseParamMappings[ PLAYER_POSE_PARAM_LADDER_SPEED ].SetValue( m_pPlayer, m_flLadderSpeed );
  1358. if ( GetLayerActivity( ANIMATION_LAYER_MOVEMENT_LAND_OR_CLIMB ) == ACT_CSGO_CLIMB_LADDER )
  1359. {
  1360. SetLayerWeight( ANIMATION_LAYER_MOVEMENT_LAND_OR_CLIMB, m_flLadderWeight );
  1361. }
  1362. SetLayerCycle( ANIMATION_LAYER_MOVEMENT_LAND_OR_CLIMB, flLadderClimbCycle );
  1363. // fade out jump if we're climbing
  1364. if ( m_bOnLadder )
  1365. {
  1366. float flIdealJumpWeight = 1.0f - m_flLadderWeight;
  1367. if ( GetLayerWeight( ANIMATION_LAYER_MOVEMENT_JUMP_OR_FALL ) > flIdealJumpWeight )
  1368. {
  1369. SetLayerWeight( ANIMATION_LAYER_MOVEMENT_JUMP_OR_FALL, flIdealJumpWeight );
  1370. }
  1371. }
  1372. }
  1373. else
  1374. {
  1375. m_flLadderSpeed = 0;
  1376. }
  1377. //jumping
  1378. if ( m_bOnGround )
  1379. {
  1380. if ( !m_bLanding && (m_bLandedOnGroundThisFrame || bStoppedLadderingThisFrame) )
  1381. {
  1382. #ifndef CLIENT_DLL
  1383. SetLayerSequence( ANIMATION_LAYER_MOVEMENT_LAND_OR_CLIMB, SelectSequenceFromActMods( (m_flDurationInAir>1) ? ACT_CSGO_LAND_HEAVY : ACT_CSGO_LAND_LIGHT ) );
  1384. #endif
  1385. SetLayerCycle( ANIMATION_LAYER_MOVEMENT_LAND_OR_CLIMB, 0 );
  1386. m_bLanding = true;
  1387. }
  1388. m_flDurationInAir = 0;
  1389. if ( m_bLanding && GetLayerActivity(ANIMATION_LAYER_MOVEMENT_LAND_OR_CLIMB) != ACT_CSGO_CLIMB_LADDER )
  1390. {
  1391. #ifndef CLIENT_DLL
  1392. m_bJumping = false;
  1393. #endif
  1394. IncrementLayerCycle( ANIMATION_LAYER_MOVEMENT_LAND_OR_CLIMB, false );
  1395. IncrementLayerCycle( ANIMATION_LAYER_MOVEMENT_JUMP_OR_FALL, false );
  1396. m_tPoseParamMappings[ PLAYER_POSE_PARAM_JUMP_FALL ].SetValue( m_pPlayer, 0 );
  1397. if ( IsLayerSequenceCompleted( ANIMATION_LAYER_MOVEMENT_LAND_OR_CLIMB ) )
  1398. {
  1399. m_bLanding = false;
  1400. SetLayerWeight( ANIMATION_LAYER_MOVEMENT_LAND_OR_CLIMB, 0 );
  1401. //SetLayerRate( ANIMATION_LAYER_MOVEMENT_LAND_OR_CLIMB, 1.0f );
  1402. SetLayerWeight( ANIMATION_LAYER_MOVEMENT_JUMP_OR_FALL, 0 );
  1403. m_flLandAnimMultiplier = 1.0f;
  1404. }
  1405. else
  1406. {
  1407. float flLandWeight = GetLayerIdealWeightFromSeqCycle( ANIMATION_LAYER_MOVEMENT_LAND_OR_CLIMB ) * m_flLandAnimMultiplier;
  1408. // if we hit the ground crouched, reduce the land animation as a function of crouch, since the land animations move the head up a bit ( and this is undesirable )
  1409. flLandWeight *= clamp( (1.0f - m_flAnimDuckAmount), 0.2f, 1.0f );
  1410. SetLayerWeight( ANIMATION_LAYER_MOVEMENT_LAND_OR_CLIMB, flLandWeight );
  1411. // fade out jump because land is taking over
  1412. float flCurrentJumpFallWeight = GetLayerWeight( ANIMATION_LAYER_MOVEMENT_JUMP_OR_FALL );
  1413. if ( flCurrentJumpFallWeight > 0 )
  1414. {
  1415. flCurrentJumpFallWeight = Approach( 0, flCurrentJumpFallWeight, m_flLastUpdateIncrement * 10.0f );
  1416. SetLayerWeight( ANIMATION_LAYER_MOVEMENT_JUMP_OR_FALL, flCurrentJumpFallWeight );
  1417. }
  1418. }
  1419. }
  1420. #ifndef CLIENT_DLL
  1421. if ( !m_bLanding && !m_bJumping && m_flLadderWeight <= 0 )
  1422. {
  1423. SetLayerWeight( ANIMATION_LAYER_MOVEMENT_LAND_OR_CLIMB, 0 );
  1424. }
  1425. #endif
  1426. }
  1427. else if ( !m_bOnLadder )
  1428. {
  1429. m_bLanding = false;
  1430. // we're in the air
  1431. if ( m_bLeftTheGroundThisFrame || bStoppedLadderingThisFrame )
  1432. {
  1433. #ifndef CLIENT_DLL
  1434. // If entered the air by jumping, then we already set the jump activity.
  1435. // But if we're in the air because we strolled off a ledge or the floor collapsed or something,
  1436. // we need to set the fall activity here.
  1437. if ( !m_bJumping )
  1438. {
  1439. SetLayerSequence( ANIMATION_LAYER_MOVEMENT_JUMP_OR_FALL, SelectSequenceFromActMods( ACT_CSGO_FALL ) );
  1440. }
  1441. #endif
  1442. m_flDurationInAir = 0;
  1443. }
  1444. m_flDurationInAir += m_flLastUpdateIncrement;
  1445. //#ifndef CLIENT_DLL
  1446. // Msg( "%f\n", m_flDurationInAir );
  1447. //#endif
  1448. IncrementLayerCycle( ANIMATION_LAYER_MOVEMENT_JUMP_OR_FALL, false );
  1449. // increase jump weight
  1450. float flJumpWeight = GetLayerWeight( ANIMATION_LAYER_MOVEMENT_JUMP_OR_FALL );
  1451. float flNextJumpWeight = GetLayerIdealWeightFromSeqCycle( ANIMATION_LAYER_MOVEMENT_JUMP_OR_FALL );
  1452. if ( flNextJumpWeight > flJumpWeight )
  1453. {
  1454. SetLayerWeight( ANIMATION_LAYER_MOVEMENT_JUMP_OR_FALL, flNextJumpWeight );
  1455. }
  1456. // bash any lingering land weight to zero
  1457. float flLingeringLandWeight = GetLayerWeight( ANIMATION_LAYER_MOVEMENT_LAND_OR_CLIMB );
  1458. if ( flLingeringLandWeight > 0 )
  1459. {
  1460. flLingeringLandWeight *= smoothstep_bounds( 0.2f, 0.0f, m_flDurationInAir );
  1461. SetLayerWeight( ANIMATION_LAYER_MOVEMENT_LAND_OR_CLIMB, flLingeringLandWeight );
  1462. }
  1463. // blend jump into fall. This is a no-op if we're playing a fall anim.
  1464. m_tPoseParamMappings[ PLAYER_POSE_PARAM_JUMP_FALL ].SetValue( m_pPlayer, clamp(smoothstep_bounds( 0.72f, 1.52f, m_flDurationInAir ),0,1) );
  1465. }
  1466. }
  1467. Activity CCSGOPlayerAnimState::GetLayerActivity( animstate_layer_t nLayerIndex )
  1468. {
  1469. MDLCACHE_CRITICAL_SECTION();
  1470. CAnimationLayer *pLayer = m_pPlayer->GetAnimOverlay( nLayerIndex, USE_ANIMLAYER_RAW_INDEX );
  1471. if ( pLayer )
  1472. return (Activity)GetSequenceActivity( m_pPlayer->GetModelPtr(), pLayer->GetSequence() );
  1473. return ACT_INVALID;
  1474. }
  1475. bool CCSGOPlayerAnimState::IsLayerSequenceCompleted( animstate_layer_t nLayerIndex )
  1476. {
  1477. CAnimationLayer *pLayer = m_pPlayer->GetAnimOverlay( nLayerIndex, USE_ANIMLAYER_RAW_INDEX );
  1478. if ( pLayer )
  1479. return ( (pLayer->GetCycle() + (m_flLastUpdateIncrement * pLayer->GetPlaybackRate())) >= 1 );
  1480. return false;
  1481. }
  1482. void CCSGOPlayerAnimState::SetLayerRate( animstate_layer_t nLayerIndex, float flRate )
  1483. {
  1484. CAnimationLayer *pLayer = m_pPlayer->GetAnimOverlay( nLayerIndex, USE_ANIMLAYER_RAW_INDEX );
  1485. if ( pLayer )
  1486. pLayer->SetPlaybackRate( flRate );
  1487. }
  1488. void CCSGOPlayerAnimState::SetLayerCycle( animstate_layer_t nLayerIndex, float flCycle )
  1489. {
  1490. CAnimationLayer *pLayer = m_pPlayer->GetAnimOverlay( nLayerIndex, USE_ANIMLAYER_RAW_INDEX );
  1491. if ( pLayer )
  1492. pLayer->SetCycle( ClampCycle( flCycle ) );
  1493. }
  1494. void CCSGOPlayerAnimState::IncrementLayerCycleWeightRateGeneric( animstate_layer_t nLayerIndex )
  1495. {
  1496. float flWeightPrevious = GetLayerWeight( nLayerIndex );
  1497. IncrementLayerCycle( nLayerIndex, false );
  1498. SetLayerWeight( nLayerIndex, GetLayerIdealWeightFromSeqCycle( nLayerIndex ) );
  1499. SetLayerWeightRate( nLayerIndex, flWeightPrevious );
  1500. }
  1501. void CCSGOPlayerAnimState::IncrementLayerCycle( animstate_layer_t nLayerIndex, bool bAllowLoop )
  1502. {
  1503. CAnimationLayer *pLayer = m_pPlayer->GetAnimOverlay( nLayerIndex, USE_ANIMLAYER_RAW_INDEX );
  1504. if ( !pLayer )
  1505. return;
  1506. if ( abs(pLayer->GetPlaybackRate()) <= 0 )
  1507. return;
  1508. float flCurrentCycle = pLayer->GetCycle();
  1509. flCurrentCycle += m_flLastUpdateIncrement * pLayer->GetPlaybackRate();
  1510. if ( !bAllowLoop && flCurrentCycle >= 1 )
  1511. {
  1512. flCurrentCycle = 0.999f;
  1513. }
  1514. pLayer->SetCycle( ClampCycle( flCurrentCycle ) );
  1515. }
  1516. void CCSGOPlayerAnimState::IncrementLayerWeight( animstate_layer_t nLayerIndex )
  1517. {
  1518. CAnimationLayer *pLayer = m_pPlayer->GetAnimOverlay( nLayerIndex, USE_ANIMLAYER_RAW_INDEX );
  1519. if ( !pLayer )
  1520. return;
  1521. if ( abs(pLayer->GetWeightDeltaRate()) <= 0 )
  1522. return;
  1523. float flCurrentWeight = pLayer->GetWeight();
  1524. flCurrentWeight += m_flLastUpdateIncrement * pLayer->GetWeightDeltaRate();
  1525. flCurrentWeight = clamp( flCurrentWeight, 0, 1 );
  1526. pLayer->SetWeight( flCurrentWeight );
  1527. }
  1528. void CCSGOPlayerAnimState::SetLayerSequence( animstate_layer_t nLayerIndex, int nSequence )
  1529. {
  1530. Assert( nSequence > 1 );
  1531. if ( nSequence > 1 )
  1532. {
  1533. MDLCACHE_CRITICAL_SECTION();
  1534. CAnimationLayer *pLayer = m_pPlayer->GetAnimOverlay( nLayerIndex, USE_ANIMLAYER_RAW_INDEX );
  1535. if ( !pLayer )
  1536. return;
  1537. pLayer->SetSequence( nSequence );
  1538. float flPlaybackRate = m_pPlayer->GetLayerSequenceCycleRate( pLayer, nSequence );
  1539. pLayer->SetPlaybackRate( flPlaybackRate );
  1540. pLayer->SetCycle( 0 );
  1541. pLayer->SetWeight( 0 );
  1542. UpdateLayerOrderPreset( nLayerIndex, nSequence );
  1543. #ifndef CLIENT_DLL
  1544. pLayer->m_fFlags |= ANIM_LAYER_ACTIVE;
  1545. #endif
  1546. }
  1547. }
  1548. float CCSGOPlayerAnimState::GetLayerIdealWeightFromSeqCycle( animstate_layer_t nLayerIndex )
  1549. {
  1550. MDLCACHE_CRITICAL_SECTION();
  1551. CAnimationLayer *pLayer = m_pPlayer->GetAnimOverlay( nLayerIndex, USE_ANIMLAYER_RAW_INDEX );
  1552. if ( !pLayer )
  1553. return 0;
  1554. mstudioseqdesc_t &seqdesc = m_pPlayer->GetModelPtr()->pSeqdesc( pLayer->GetSequence() );
  1555. float flCycle = pLayer->GetCycle();
  1556. if ( flCycle >= 0.999f )
  1557. flCycle = 1;
  1558. float flEaseIn = seqdesc.fadeintime;
  1559. float flEaseOut = seqdesc.fadeouttime;
  1560. float flIdealWeight = 1;
  1561. if ( flEaseIn > 0 && flCycle < flEaseIn )
  1562. {
  1563. flIdealWeight = smoothstep_bounds( 0, flEaseIn, flCycle );
  1564. }
  1565. else if ( flEaseOut < 1 && flCycle > flEaseOut )
  1566. {
  1567. flIdealWeight = smoothstep_bounds( 1.0f, flEaseOut, flCycle );
  1568. }
  1569. if ( flIdealWeight < 0.0015f )
  1570. return 0;
  1571. return (clamp( flIdealWeight, 0, 1));
  1572. }
  1573. float CCSGOPlayerAnimState::GetLayerCycle( animstate_layer_t nLayerIndex )
  1574. {
  1575. CAnimationLayer *pLayer = m_pPlayer->GetAnimOverlay( nLayerIndex, USE_ANIMLAYER_RAW_INDEX );
  1576. if ( pLayer )
  1577. return pLayer->GetCycle();
  1578. return 0;
  1579. }
  1580. int CCSGOPlayerAnimState::GetLayerSequence( animstate_layer_t nLayerIndex )
  1581. {
  1582. CAnimationLayer *pLayer = m_pPlayer->GetAnimOverlay( nLayerIndex, USE_ANIMLAYER_RAW_INDEX );
  1583. if ( pLayer )
  1584. return pLayer->GetSequence();
  1585. return 0;
  1586. }
  1587. float CCSGOPlayerAnimState::GetLayerRate( animstate_layer_t nLayerIndex )
  1588. {
  1589. CAnimationLayer *pLayer = m_pPlayer->GetAnimOverlay( nLayerIndex, USE_ANIMLAYER_RAW_INDEX );
  1590. if ( pLayer )
  1591. return pLayer->GetPlaybackRate();
  1592. return 0;
  1593. }
  1594. float CCSGOPlayerAnimState::GetLayerWeight( animstate_layer_t nLayerIndex )
  1595. {
  1596. CAnimationLayer *pLayer = m_pPlayer->GetAnimOverlay( nLayerIndex, USE_ANIMLAYER_RAW_INDEX );
  1597. if ( pLayer )
  1598. return pLayer->GetWeight();
  1599. return 0;
  1600. }
  1601. void CCSGOPlayerAnimState::SetLayerWeight( animstate_layer_t nLayerIndex, float flWeight )
  1602. {
  1603. CAnimationLayer *pLayer = m_pPlayer->GetAnimOverlay( nLayerIndex, USE_ANIMLAYER_RAW_INDEX );
  1604. if ( !pLayer )
  1605. return;
  1606. pLayer->SetWeight( clamp( flWeight, 0, 1) );
  1607. #ifndef CLIENT_DLL
  1608. pLayer->m_fFlags |= ANIM_LAYER_ACTIVE;
  1609. #endif
  1610. }
  1611. void CCSGOPlayerAnimState::SetLayerWeightRate( animstate_layer_t nLayerIndex, float flPrevious )
  1612. {
  1613. if ( m_flLastUpdateIncrement == 0 )
  1614. return;
  1615. CAnimationLayer *pLayer = m_pPlayer->GetAnimOverlay( nLayerIndex, USE_ANIMLAYER_RAW_INDEX );
  1616. if ( !pLayer )
  1617. return;
  1618. float flNewRate = ( pLayer->GetWeight() - flPrevious ) / m_flLastUpdateIncrement;
  1619. pLayer->SetWeightDeltaRate( flNewRate );
  1620. }
  1621. void CCSGOPlayerAnimState::UpdateAnimLayer( animstate_layer_t nLayerIndex, int nSequence, float flPlaybackRate, float flWeight, float flCycle )
  1622. {
  1623. AssertOnce( flWeight >= 0 && flWeight <= 1 );
  1624. AssertOnce( flCycle >= 0 && flCycle <= 1 );
  1625. Assert( nSequence > 1 );
  1626. Assert( nSequence > 1 );
  1627. if ( nSequence > 1 )
  1628. {
  1629. MDLCACHE_CRITICAL_SECTION();
  1630. CAnimationLayer *pLayer = m_pPlayer->GetAnimOverlay( nLayerIndex, USE_ANIMLAYER_RAW_INDEX );
  1631. if ( !pLayer )
  1632. return;
  1633. pLayer->SetSequence( nSequence );
  1634. pLayer->SetPlaybackRate( flPlaybackRate );
  1635. pLayer->SetCycle( clamp( flCycle, 0, 1) );
  1636. pLayer->SetWeight( clamp( flWeight, 0, 1) );
  1637. UpdateLayerOrderPreset( nLayerIndex, nSequence );
  1638. #ifndef CLIENT_DLL
  1639. pLayer->m_fFlags |= ANIM_LAYER_ACTIVE;
  1640. #endif
  1641. }
  1642. }
  1643. void CCSGOPlayerAnimState::ApplyLayerOrderPreset( animlayerpreset nNewPreset, bool bForce )
  1644. {
  1645. if ( !bForce && m_pLayerOrderPreset == nNewPreset )
  1646. return;
  1647. m_pLayerOrderPreset = nNewPreset;
  1648. for ( int i=0; i < ANIMATION_LAYER_COUNT; i++ )
  1649. {
  1650. CAnimationLayer *pLayer = m_pPlayer->GetAnimOverlay( m_pLayerOrderPreset[i], USE_ANIMLAYER_RAW_INDEX );
  1651. if ( pLayer )
  1652. {
  1653. pLayer->SetOrder( i );
  1654. // purge dispatch info too
  1655. pLayer->m_pDispatchedStudioHdr = NULL;
  1656. pLayer->m_nDispatchedSrc = ACT_INVALID;
  1657. pLayer->m_nDispatchedDst = ACT_INVALID;
  1658. }
  1659. }
  1660. }
  1661. void CCSGOPlayerAnimState::UpdateLayerOrderPreset( animstate_layer_t nLayerIndex, int nSequence )
  1662. {
  1663. if ( !m_pPlayer || nLayerIndex != ANIMATION_LAYER_WEAPON_ACTION )
  1664. return;
  1665. MDLCACHE_CRITICAL_SECTION();
  1666. if ( m_pPlayer->GetAnySequenceAnimTag( nSequence, ANIMTAG_WEAPON_POSTLAYER, 0 ) != 0 )
  1667. {
  1668. ApplyLayerOrderPreset( get_animlayerpreset( WeaponPost ) );
  1669. }
  1670. else
  1671. {
  1672. ApplyLayerOrderPreset( get_animlayerpreset( Default ) );
  1673. }
  1674. }
  1675. bool CCSGOPlayerAnimState::LayerSequenceHasActMod( animstate_layer_t nLayerIndex, const char* szActMod )
  1676. {
  1677. CAnimationLayer *pLayer = m_pPlayer->GetAnimOverlay( nLayerIndex, USE_ANIMLAYER_RAW_INDEX );
  1678. if ( !pLayer )
  1679. return false;
  1680. //CUtlSymbol sym = g_ActivityModifiersTable.Find( szActMod );
  1681. //if ( sym.IsValid() )
  1682. //{
  1683. mstudioseqdesc_t &seqdesc = m_pPlayer->GetModelPtr()->pSeqdesc( pLayer->GetSequence() );
  1684. for ( int i=0; i<seqdesc.numactivitymodifiers; i++ )
  1685. {
  1686. mstudioactivitymodifier_t *mod = seqdesc.pActivityModifier(i);
  1687. if ( !V_strcmp( mod->pszName(), szActMod ) )
  1688. return true;
  1689. }
  1690. //}
  1691. return false;
  1692. }
  1693. #define CSGO_ANIM_SPEED_TO_CHANGE_AIM_MATRIX 0.8f
  1694. #define CSGO_ANIM_SPEED_TO_CHANGE_AIM_MATRIX_SCOPED 4.2f
  1695. void CCSGOPlayerAnimState::SetUpAimMatrix( void )
  1696. {
  1697. MDLCACHE_CRITICAL_SECTION();
  1698. if ( m_flAnimDuckAmount <= 0 || m_flAnimDuckAmount >= 1 ) // only transition aim pose when fully ducked or fully standing
  1699. {
  1700. bool bPlayerIsWalking = ( m_pPlayer && m_pPlayer->m_bIsWalking );
  1701. bool bPlayerIsScoped = ( m_pPlayer && m_pPlayer->m_bIsScoped );
  1702. float flTransitionSpeed = m_flLastUpdateIncrement * ( bPlayerIsScoped ? CSGO_ANIM_SPEED_TO_CHANGE_AIM_MATRIX_SCOPED : CSGO_ANIM_SPEED_TO_CHANGE_AIM_MATRIX );
  1703. if ( bPlayerIsScoped ) // hacky: just tell all the transitions they've been invalid too long so all transitions clear as soon as the player starts scoping
  1704. {
  1705. m_tStandWalkAim.m_flDurationStateHasBeenInValid = m_tStandWalkAim.m_flHowLongToWaitUntilTransitionCanBlendOut;
  1706. m_tStandRunAim.m_flDurationStateHasBeenInValid = m_tStandRunAim.m_flHowLongToWaitUntilTransitionCanBlendOut;
  1707. m_tCrouchWalkAim.m_flDurationStateHasBeenInValid = m_tCrouchWalkAim.m_flHowLongToWaitUntilTransitionCanBlendOut;
  1708. }
  1709. m_tStandWalkAim.UpdateTransitionState( bPlayerIsWalking && !bPlayerIsScoped && m_flSpeedAsPortionOfWalkTopSpeed > 0.7f && m_flSpeedAsPortionOfRunTopSpeed < 0.7,
  1710. m_flLastUpdateIncrement, flTransitionSpeed );
  1711. m_tStandRunAim.UpdateTransitionState( !bPlayerIsScoped && m_flSpeedAsPortionOfRunTopSpeed >= 0.7,
  1712. m_flLastUpdateIncrement, flTransitionSpeed );
  1713. m_tCrouchWalkAim.UpdateTransitionState( !bPlayerIsScoped && m_flSpeedAsPortionOfCrouchTopSpeed >= 0.5,
  1714. m_flLastUpdateIncrement, flTransitionSpeed );
  1715. }
  1716. // Set aims to zero weight if they're underneath aims with 100% weight, for animation perf optimization.
  1717. // Also set aims to full weight if their overlapping aims aren't enough to cover them, because cross-fades don't sum to 100% weight.
  1718. float flStandIdleWeight = 1;
  1719. float flStandWalkWeight = m_tStandWalkAim.m_flBlendValue;
  1720. float flStandRunWeight = m_tStandRunAim.m_flBlendValue;
  1721. float flCrouchIdleWeight = 1;
  1722. float flCrouchWalkWeight = m_tCrouchWalkAim.m_flBlendValue;
  1723. if ( flStandWalkWeight >= 1 )
  1724. flStandIdleWeight = 0;
  1725. if ( flStandRunWeight >= 1 )
  1726. {
  1727. flStandIdleWeight = 0;
  1728. flStandWalkWeight = 0;
  1729. }
  1730. if ( flCrouchWalkWeight >= 1 )
  1731. flCrouchIdleWeight = 0;
  1732. if ( m_flAnimDuckAmount >= 1 )
  1733. {
  1734. flStandIdleWeight = 0;
  1735. flStandWalkWeight = 0;
  1736. flStandRunWeight = 0;
  1737. }
  1738. else if ( m_flAnimDuckAmount <= 0 )
  1739. {
  1740. flCrouchIdleWeight = 0;
  1741. flCrouchWalkWeight = 0;
  1742. }
  1743. float flOneMinusDuckAmount = 1.0f - m_flAnimDuckAmount;
  1744. flCrouchIdleWeight *= m_flAnimDuckAmount;
  1745. flCrouchWalkWeight *= m_flAnimDuckAmount;
  1746. flStandWalkWeight *= flOneMinusDuckAmount;
  1747. flStandRunWeight *= flOneMinusDuckAmount;
  1748. // make sure idle is present underneath cross-fades
  1749. if ( flCrouchIdleWeight < 1 && flCrouchWalkWeight < 1 && flStandWalkWeight < 1 && flStandRunWeight < 1 )
  1750. flStandIdleWeight = 1;
  1751. m_tPoseParamMappings[ PLAYER_POSE_PARAM_AIM_BLEND_STAND_IDLE ].SetValue( m_pPlayer, flStandIdleWeight );
  1752. m_tPoseParamMappings[ PLAYER_POSE_PARAM_AIM_BLEND_STAND_WALK ].SetValue( m_pPlayer, flStandWalkWeight );
  1753. m_tPoseParamMappings[ PLAYER_POSE_PARAM_AIM_BLEND_STAND_RUN ].SetValue( m_pPlayer, flStandRunWeight );
  1754. m_tPoseParamMappings[ PLAYER_POSE_PARAM_AIM_BLEND_CROUCH_IDLE ].SetValue( m_pPlayer, flCrouchIdleWeight );
  1755. m_tPoseParamMappings[ PLAYER_POSE_PARAM_AIM_BLEND_CROUCH_WALK ].SetValue( m_pPlayer, flCrouchWalkWeight );
  1756. char szTransitionStandAimMatrix[MAX_ANIMSTATE_ANIMNAME_CHARS];
  1757. V_sprintf_safe( szTransitionStandAimMatrix, "%s_aim", GetWeaponPrefix() );
  1758. int nSeqStand = m_pPlayer->LookupSequence( szTransitionStandAimMatrix );
  1759. {
  1760. // use data-driven aim matrix limits
  1761. CAnimationLayer *pAimLayer = m_pPlayer->GetAnimOverlay( ANIMATION_LAYER_AIMMATRIX, USE_ANIMLAYER_RAW_INDEX );
  1762. if ( pAimLayer && m_pWeapon )
  1763. {
  1764. MDLCACHE_CRITICAL_SECTION();
  1765. CBaseAnimating *pAimMatrixHolder = m_pPlayer;
  1766. int nSeq = nSeqStand;
  1767. CBaseWeaponWorldModel *pWeaponWorldModel = m_pWeapon->m_hWeaponWorldModel.Get();
  1768. if ( pWeaponWorldModel && pAimLayer->m_nDispatchedDst != ACT_INVALID )
  1769. {
  1770. pAimMatrixHolder = pWeaponWorldModel;
  1771. nSeq = pAimLayer->m_nDispatchedDst;
  1772. }
  1773. if ( nSeq > 0 )
  1774. {
  1775. float flYawIdleMin = pAimMatrixHolder->GetAnySequenceAnimTag( nSeq, ANIMTAG_AIMLIMIT_YAWMIN_IDLE, CSGO_ANIM_AIMMATRIX_DEFAULT_YAW_MIN );
  1776. float flYawIdleMax = pAimMatrixHolder->GetAnySequenceAnimTag( nSeq, ANIMTAG_AIMLIMIT_YAWMAX_IDLE, CSGO_ANIM_AIMMATRIX_DEFAULT_YAW_MAX );
  1777. float flYawWalkMin = pAimMatrixHolder->GetAnySequenceAnimTag( nSeq, ANIMTAG_AIMLIMIT_YAWMIN_WALK, flYawIdleMin );
  1778. float flYawWalkMax = pAimMatrixHolder->GetAnySequenceAnimTag( nSeq, ANIMTAG_AIMLIMIT_YAWMAX_WALK, flYawIdleMax );
  1779. float flYawRunMin = pAimMatrixHolder->GetAnySequenceAnimTag( nSeq, ANIMTAG_AIMLIMIT_YAWMIN_RUN, flYawWalkMin );
  1780. float flYawRunMax = pAimMatrixHolder->GetAnySequenceAnimTag( nSeq, ANIMTAG_AIMLIMIT_YAWMAX_RUN, flYawWalkMax );
  1781. float flYawCrouchIdleMin = pAimMatrixHolder->GetAnySequenceAnimTag( nSeq, ANIMTAG_AIMLIMIT_YAWMIN_CROUCHIDLE, CSGO_ANIM_AIMMATRIX_DEFAULT_YAW_MIN );
  1782. float flYawCrouchIdleMax = pAimMatrixHolder->GetAnySequenceAnimTag( nSeq, ANIMTAG_AIMLIMIT_YAWMAX_CROUCHIDLE, CSGO_ANIM_AIMMATRIX_DEFAULT_YAW_MAX );
  1783. float flYawCrouchWalkMin = pAimMatrixHolder->GetAnySequenceAnimTag( nSeq, ANIMTAG_AIMLIMIT_YAWMIN_CROUCHWALK, flYawCrouchIdleMin );
  1784. float flYawCrouchWalkMax = pAimMatrixHolder->GetAnySequenceAnimTag( nSeq, ANIMTAG_AIMLIMIT_YAWMAX_CROUCHWALK, flYawCrouchIdleMax );
  1785. float flWalkAmt = m_tPoseParamMappings[ PLAYER_POSE_PARAM_AIM_BLEND_STAND_WALK ].GetValue( m_pPlayer );
  1786. float flRunAmt = m_tPoseParamMappings[ PLAYER_POSE_PARAM_AIM_BLEND_STAND_RUN ].GetValue( m_pPlayer );
  1787. float flCrouchWalkAmt = m_tPoseParamMappings[ PLAYER_POSE_PARAM_AIM_BLEND_CROUCH_WALK ].GetValue( m_pPlayer );
  1788. m_flAimYawMin = Lerp( m_flAnimDuckAmount,
  1789. Lerp( flRunAmt, Lerp( flWalkAmt, flYawIdleMin, flYawWalkMin ), flYawRunMin ),
  1790. Lerp( flCrouchWalkAmt, flYawCrouchIdleMin, flYawCrouchWalkMin ) );
  1791. m_flAimYawMax = Lerp( m_flAnimDuckAmount,
  1792. Lerp( flRunAmt, Lerp( flWalkAmt, flYawIdleMax, flYawWalkMax ), flYawRunMax ),
  1793. Lerp( flCrouchWalkAmt, flYawCrouchIdleMax, flYawCrouchWalkMax ) );
  1794. float flPitchIdleMin = pAimMatrixHolder->GetAnySequenceAnimTag( nSeq, ANIMTAG_AIMLIMIT_PITCHMIN_IDLE, CSGO_ANIM_AIMMATRIX_DEFAULT_PITCH_MIN );
  1795. float flPitchIdleMax = pAimMatrixHolder->GetAnySequenceAnimTag( nSeq, ANIMTAG_AIMLIMIT_PITCHMAX_IDLE, CSGO_ANIM_AIMMATRIX_DEFAULT_PITCH_MAX );
  1796. float flPitchWalkRunMin = pAimMatrixHolder->GetAnySequenceAnimTag( nSeq, ANIMTAG_AIMLIMIT_PITCHMIN_WALKRUN, flPitchIdleMin );
  1797. float flPitchWalkRunMax = pAimMatrixHolder->GetAnySequenceAnimTag( nSeq, ANIMTAG_AIMLIMIT_PITCHMAX_WALKRUN, flPitchIdleMax );
  1798. float flPitchCrouchMin = pAimMatrixHolder->GetAnySequenceAnimTag( nSeq, ANIMTAG_AIMLIMIT_PITCHMIN_CROUCH, CSGO_ANIM_AIMMATRIX_DEFAULT_PITCH_MIN );
  1799. float flPitchCrouchMax = pAimMatrixHolder->GetAnySequenceAnimTag( nSeq, ANIMTAG_AIMLIMIT_PITCHMAX_CROUCH, CSGO_ANIM_AIMMATRIX_DEFAULT_PITCH_MAX );
  1800. float flPitchCrouchWalkMin = pAimMatrixHolder->GetAnySequenceAnimTag( nSeq, ANIMTAG_AIMLIMIT_PITCHMIN_CROUCHWALK, flPitchCrouchMin );
  1801. float flPitchCrouchWalkMax = pAimMatrixHolder->GetAnySequenceAnimTag( nSeq, ANIMTAG_AIMLIMIT_PITCHMAX_CROUCHWALK, flPitchCrouchMax );
  1802. m_flAimPitchMin = Lerp( m_flAnimDuckAmount, Lerp( flWalkAmt, flPitchIdleMin, flPitchWalkRunMin ), Lerp( flCrouchWalkAmt, flPitchCrouchMin, flPitchCrouchWalkMin ) );
  1803. m_flAimPitchMax = Lerp( m_flAnimDuckAmount, Lerp( flWalkAmt, flPitchIdleMax, flPitchWalkRunMax ), Lerp( flCrouchWalkAmt, flPitchCrouchMax, flPitchCrouchWalkMax ) );
  1804. }
  1805. }
  1806. }
  1807. UpdateAnimLayer( ANIMATION_LAYER_AIMMATRIX, nSeqStand, 0, 1, 0 );
  1808. }
  1809. #define CSGO_ANIM_LOWER_CATCHUP_IDLE 100.0f
  1810. #define CSGO_ANIM_AIM_NARROW_WALK 0.8f
  1811. #define CSGO_ANIM_AIM_NARROW_RUN 0.5f
  1812. #define CSGO_ANIM_AIM_NARROW_CROUCHMOVING 0.5f
  1813. #define CSGO_ANIM_LOWER_CATCHUP_WITHIN 3.0f
  1814. #define CSGO_ANIM_LOWER_REALIGN_DELAY 1.1f
  1815. #define CSGO_ANIM_READJUST_THRESHOLD 120.0f
  1816. #define EIGHT_WAY_WIDTH 22.5f
  1817. void CCSGOPlayerAnimState::SetUpVelocity( void )
  1818. {
  1819. MDLCACHE_CRITICAL_SECTION();
  1820. // update the local velocity variables so we don't recalculate them unnecessarily
  1821. #ifndef CLIENT_DLL
  1822. Vector vecAbsVelocity = m_pPlayer->GetAbsVelocity();
  1823. #else
  1824. Vector vecAbsVelocity = m_vecVelocity;
  1825. if ( engine->IsHLTV() || engine->IsPlayingDemo() )
  1826. {
  1827. // Estimating velocity when playing demos is prone to fail, especially in POVs. Fall back to GetAbsVelocity.
  1828. vecAbsVelocity = m_pPlayer->GetAbsVelocity();
  1829. }
  1830. else
  1831. {
  1832. m_pPlayer->EstimateAbsVelocity( vecAbsVelocity ); // Using this accessor if the client is starved of information,
  1833. // the player doesn't run on the spot. Note this is unreliable
  1834. // and could fail to populate the value if prediction fails.
  1835. }
  1836. // prevent the client input velocity vector from exceeding a reasonable magnitude
  1837. #define CSGO_ANIM_MAX_VEL_LIMIT 1.2f
  1838. if ( vecAbsVelocity.LengthSqr() > Sqr( CS_PLAYER_SPEED_RUN * CSGO_ANIM_MAX_VEL_LIMIT ) )
  1839. vecAbsVelocity = vecAbsVelocity.Normalized() * (CS_PLAYER_SPEED_RUN * CSGO_ANIM_MAX_VEL_LIMIT);
  1840. #endif
  1841. // save vertical velocity component
  1842. m_flVelocityLengthZ = vecAbsVelocity.z;
  1843. // discard z component
  1844. vecAbsVelocity.z = 0;
  1845. // remember if the player is accelerating.
  1846. m_bPlayerIsAccelerating = ( m_vecVelocityLast.LengthSqr() < vecAbsVelocity.LengthSqr() );
  1847. // rapidly approach ideal velocity instead of instantly adopt it. This helps smooth out instant velocity changes, like
  1848. // when the player runs headlong into a wall and their velocity instantly becomes zero.
  1849. m_vecVelocity = Approach( vecAbsVelocity, m_vecVelocity, m_flLastUpdateIncrement * 2000 );
  1850. m_vecVelocityNormalized = m_vecVelocity.Normalized();
  1851. // save horizontal velocity length
  1852. m_flVelocityLengthXY = MIN( m_vecVelocity.Length(), CS_PLAYER_SPEED_RUN );
  1853. if ( m_flVelocityLengthXY > 0 )
  1854. {
  1855. m_vecVelocityNormalizedNonZero = m_vecVelocityNormalized;
  1856. }
  1857. //compute speed in various normalized forms
  1858. float flMaxSpeedRun = m_pWeapon ? MAX( m_pWeapon->GetMaxSpeed(), 0.001f ) : CS_PLAYER_SPEED_RUN;
  1859. Assert( flMaxSpeedRun > 0 );
  1860. m_flSpeedAsPortionOfRunTopSpeed = clamp( m_flVelocityLengthXY / flMaxSpeedRun, 0, 1 );
  1861. m_flSpeedAsPortionOfWalkTopSpeed = m_flVelocityLengthXY / (flMaxSpeedRun * CS_PLAYER_SPEED_WALK_MODIFIER);
  1862. m_flSpeedAsPortionOfCrouchTopSpeed = m_flVelocityLengthXY / (flMaxSpeedRun * CS_PLAYER_SPEED_DUCK_MODIFIER);
  1863. if ( m_flSpeedAsPortionOfWalkTopSpeed >= 1 )
  1864. {
  1865. m_flStaticApproachSpeed = m_flVelocityLengthXY;
  1866. }
  1867. else if ( m_flSpeedAsPortionOfWalkTopSpeed < 0.5f )
  1868. {
  1869. m_flStaticApproachSpeed = Approach( 80, m_flStaticApproachSpeed, m_flLastUpdateIncrement * 60 );
  1870. }
  1871. bool bStartedMovingThisFrame = false;
  1872. bool bStoppedMovingThisFrame = false;
  1873. if ( m_flVelocityLengthXY > 0 )
  1874. {
  1875. bStartedMovingThisFrame = ( m_flDurationMoving <= 0 );
  1876. m_flDurationStill = 0;
  1877. m_flDurationMoving += m_flLastUpdateIncrement;
  1878. }
  1879. else
  1880. {
  1881. bStoppedMovingThisFrame = ( m_flDurationStill <= 0 );
  1882. m_flDurationMoving = 0;
  1883. m_flDurationStill += m_flLastUpdateIncrement;
  1884. }
  1885. #ifndef CLIENT_DLL
  1886. if ( !m_bAdjustStarted && bStoppedMovingThisFrame && m_bOnGround && !m_bOnLadder && !m_bLanding && m_flStutterStep < 50 )
  1887. {
  1888. SetLayerSequence( ANIMATION_LAYER_ADJUST, SelectSequenceFromActMods( ACT_CSGO_IDLE_ADJUST_STOPPEDMOVING ) );
  1889. m_bAdjustStarted = true;
  1890. }
  1891. if ( GetLayerActivity( ANIMATION_LAYER_ADJUST ) == ACT_CSGO_IDLE_ADJUST_STOPPEDMOVING ||
  1892. GetLayerActivity( ANIMATION_LAYER_ADJUST ) == ACT_CSGO_IDLE_TURN_BALANCEADJUST )
  1893. {
  1894. if ( m_bAdjustStarted && m_flSpeedAsPortionOfCrouchTopSpeed <= 0.25f )
  1895. {
  1896. IncrementLayerCycleWeightRateGeneric( ANIMATION_LAYER_ADJUST );
  1897. m_bAdjustStarted = !( IsLayerSequenceCompleted( ANIMATION_LAYER_ADJUST ) );
  1898. }
  1899. else
  1900. {
  1901. m_bAdjustStarted = false;
  1902. float flWeight = GetLayerWeight( ANIMATION_LAYER_ADJUST );
  1903. SetLayerWeight( ANIMATION_LAYER_ADJUST, Approach( 0, flWeight, m_flLastUpdateIncrement * 5 ) );
  1904. SetLayerWeightRate( ANIMATION_LAYER_ADJUST, flWeight );
  1905. }
  1906. }
  1907. #endif
  1908. // if the player is looking far enough to either side, turn the feet to keep them within the extent of the aim matrix
  1909. m_flFootYawLast = m_flFootYaw;
  1910. m_flFootYaw = clamp( m_flFootYaw, -360, 360 );
  1911. float flEyeFootDelta = AngleDiff(m_flEyeYaw, m_flFootYaw);
  1912. // narrow the available aim matrix width as speed increases
  1913. float flAimMatrixWidthRange = Lerp( clamp(m_flSpeedAsPortionOfWalkTopSpeed,0,1), 1.0f, Lerp( m_flWalkToRunTransition, CSGO_ANIM_AIM_NARROW_WALK, CSGO_ANIM_AIM_NARROW_RUN ) );
  1914. if ( m_flAnimDuckAmount > 0 )
  1915. {
  1916. flAimMatrixWidthRange = Lerp( m_flAnimDuckAmount * clamp( m_flSpeedAsPortionOfCrouchTopSpeed, 0, 1 ), flAimMatrixWidthRange, CSGO_ANIM_AIM_NARROW_CROUCHMOVING );
  1917. }
  1918. float flTempYawMax = m_flAimYawMax * flAimMatrixWidthRange;
  1919. float flTempYawMin = m_flAimYawMin * flAimMatrixWidthRange;
  1920. if ( flEyeFootDelta > flTempYawMax )
  1921. {
  1922. m_flFootYaw = m_flEyeYaw - abs(flTempYawMax);
  1923. }
  1924. else if ( flEyeFootDelta < flTempYawMin )
  1925. {
  1926. m_flFootYaw = m_flEyeYaw + abs(flTempYawMin);
  1927. }
  1928. m_flFootYaw = AngleNormalize( m_flFootYaw );
  1929. // pull the lower body direction towards the eye direction, but only when the player is moving
  1930. if ( m_bOnGround )
  1931. {
  1932. if ( m_flVelocityLengthXY > 0.1f )
  1933. {
  1934. m_flFootYaw = ApproachAngle( m_flEyeYaw, m_flFootYaw, m_flLastUpdateIncrement * (30.0f + 20.0f * m_flWalkToRunTransition) );
  1935. #ifndef CLIENT_DLL
  1936. m_flLowerBodyRealignTimer = gpGlobals->curtime + ( CSGO_ANIM_LOWER_REALIGN_DELAY * 0.2f );
  1937. m_pPlayer->m_flLowerBodyYawTarget.Set( m_flEyeYaw );
  1938. #endif
  1939. }
  1940. else
  1941. {
  1942. m_flFootYaw = ApproachAngle( m_pPlayer->m_flLowerBodyYawTarget.Get(), m_flFootYaw, m_flLastUpdateIncrement * CSGO_ANIM_LOWER_CATCHUP_IDLE );
  1943. #ifndef CLIENT_DLL
  1944. if ( gpGlobals->curtime > m_flLowerBodyRealignTimer && abs( AngleDiff( m_flFootYaw, m_flEyeYaw ) ) > 35.0f )
  1945. {
  1946. m_flLowerBodyRealignTimer = gpGlobals->curtime + CSGO_ANIM_LOWER_REALIGN_DELAY;
  1947. m_pPlayer->m_flLowerBodyYawTarget.Set( m_flEyeYaw );
  1948. }
  1949. #endif
  1950. }
  1951. }
  1952. #ifndef CLIENT_DLL
  1953. if ( m_flVelocityLengthXY <= CS_PLAYER_SPEED_STOPPED && m_bOnGround && !m_bOnLadder && !m_bLanding && m_flLastUpdateIncrement > 0 && abs( AngleDiff( m_flFootYawLast, m_flFootYaw ) / m_flLastUpdateIncrement > CSGO_ANIM_READJUST_THRESHOLD ) )
  1954. {
  1955. SetLayerSequence( ANIMATION_LAYER_ADJUST, SelectSequenceFromActMods( ACT_CSGO_IDLE_TURN_BALANCEADJUST ) );
  1956. m_bAdjustStarted = true;
  1957. }
  1958. #endif
  1959. #ifdef CLIENT_DLL
  1960. if ( GetLayerWeight( ANIMATION_LAYER_ADJUST ) > 0 )
  1961. {
  1962. IncrementLayerCycle( ANIMATION_LAYER_ADJUST, false );
  1963. IncrementLayerWeight( ANIMATION_LAYER_ADJUST );
  1964. }
  1965. #endif
  1966. // the final model render yaw is aligned to the foot yaw
  1967. if ( m_flVelocityLengthXY > 0 && m_bOnGround )
  1968. {
  1969. // convert horizontal velocity vec to angular yaw
  1970. float flRawYawIdeal = (atan2(-m_vecVelocity[1], -m_vecVelocity[0]) * 180 / M_PI);
  1971. if (flRawYawIdeal < 0)
  1972. flRawYawIdeal += 360;
  1973. m_flMoveYawIdeal = AngleNormalize( AngleDiff( flRawYawIdeal, m_flFootYaw ) );
  1974. }
  1975. // delta between current yaw and ideal velocity derived target (possibly negative!)
  1976. m_flMoveYawCurrentToIdeal = AngleNormalize( AngleDiff( m_flMoveYawIdeal, m_flMoveYaw ) );
  1977. if ( bStartedMovingThisFrame && m_flMoveWeight <= 0 )
  1978. {
  1979. m_flMoveYaw = m_flMoveYawIdeal;
  1980. // select a special starting cycle that's set by the animator in content
  1981. int nMoveSeq = GetLayerSequence( ANIMATION_LAYER_MOVEMENT_MOVE );
  1982. if ( nMoveSeq != -1 )
  1983. {
  1984. mstudioseqdesc_t &seqdesc = m_pPlayer->GetModelPtr()->pSeqdesc( nMoveSeq );
  1985. if ( seqdesc.numanimtags > 0 )
  1986. {
  1987. if ( abs( AngleDiff( m_flMoveYaw, 180 ) ) <= EIGHT_WAY_WIDTH ) //N
  1988. {
  1989. m_flPrimaryCycle = m_pPlayer->GetFirstSequenceAnimTag( nMoveSeq, ANIMTAG_STARTCYCLE_N, 0, 1 );
  1990. }
  1991. else if ( abs( AngleDiff( m_flMoveYaw, 135 ) ) <= EIGHT_WAY_WIDTH ) //NE
  1992. {
  1993. m_flPrimaryCycle = m_pPlayer->GetFirstSequenceAnimTag( nMoveSeq, ANIMTAG_STARTCYCLE_NE, 0, 1 );
  1994. }
  1995. else if ( abs( AngleDiff( m_flMoveYaw, 90 ) ) <= EIGHT_WAY_WIDTH ) //E
  1996. {
  1997. m_flPrimaryCycle = m_pPlayer->GetFirstSequenceAnimTag( nMoveSeq, ANIMTAG_STARTCYCLE_E, 0, 1 );
  1998. }
  1999. else if ( abs( AngleDiff( m_flMoveYaw, 45 ) ) <= EIGHT_WAY_WIDTH ) //SE
  2000. {
  2001. m_flPrimaryCycle = m_pPlayer->GetFirstSequenceAnimTag( nMoveSeq, ANIMTAG_STARTCYCLE_SE, 0, 1 );
  2002. }
  2003. else if ( abs( AngleDiff( m_flMoveYaw, 0 ) ) <= EIGHT_WAY_WIDTH ) //S
  2004. {
  2005. m_flPrimaryCycle = m_pPlayer->GetFirstSequenceAnimTag( nMoveSeq, ANIMTAG_STARTCYCLE_S, 0, 1 );
  2006. }
  2007. else if ( abs( AngleDiff( m_flMoveYaw, -45 ) ) <= EIGHT_WAY_WIDTH ) //SW
  2008. {
  2009. m_flPrimaryCycle = m_pPlayer->GetFirstSequenceAnimTag( nMoveSeq, ANIMTAG_STARTCYCLE_SW, 0, 1 );
  2010. }
  2011. else if ( abs( AngleDiff( m_flMoveYaw, -90 ) ) <= EIGHT_WAY_WIDTH ) //W
  2012. {
  2013. m_flPrimaryCycle = m_pPlayer->GetFirstSequenceAnimTag( nMoveSeq, ANIMTAG_STARTCYCLE_W, 0, 1 );
  2014. }
  2015. else if ( abs( AngleDiff( m_flMoveYaw, -135 ) ) <= EIGHT_WAY_WIDTH ) //NW
  2016. {
  2017. m_flPrimaryCycle = m_pPlayer->GetFirstSequenceAnimTag( nMoveSeq, ANIMTAG_STARTCYCLE_NW, 0, 1 );
  2018. }
  2019. }
  2020. }
  2021. #ifdef CLIENT_DLL
  2022. if ( m_flInAirSmoothValue >= 1 && !m_bFirstRunSinceInit && abs(m_flMoveYawCurrentToIdeal) > 45 && m_bOnGround && m_pPlayer->m_boneSnapshots[BONESNAPSHOT_ENTIRE_BODY].GetCurrentWeight() <= 0 )
  2023. {
  2024. m_pPlayer->m_boneSnapshots[BONESNAPSHOT_ENTIRE_BODY].SetShouldCapture( bonesnapshot_get( cl_bonesnapshot_speed_movebegin ) );
  2025. }
  2026. #endif
  2027. }
  2028. else
  2029. {
  2030. if ( GetLayerWeight( ANIMATION_LAYER_MOVEMENT_STRAFECHANGE ) >= 1 )
  2031. {
  2032. m_flMoveYaw = m_flMoveYawIdeal;
  2033. }
  2034. else
  2035. {
  2036. #ifdef CLIENT_DLL
  2037. if ( m_flInAirSmoothValue >= 1 && !m_bFirstRunSinceInit && abs(m_flMoveYawCurrentToIdeal) > 100 && m_bOnGround && m_pPlayer->m_boneSnapshots[BONESNAPSHOT_ENTIRE_BODY].GetCurrentWeight() <= 0 )
  2038. {
  2039. m_pPlayer->m_boneSnapshots[BONESNAPSHOT_ENTIRE_BODY].SetShouldCapture( bonesnapshot_get( cl_bonesnapshot_speed_movebegin ) );
  2040. }
  2041. #endif
  2042. float flMoveWeight = Lerp( m_flAnimDuckAmount, clamp(m_flSpeedAsPortionOfWalkTopSpeed, 0, 1), clamp(m_flSpeedAsPortionOfCrouchTopSpeed, 0, 1) );
  2043. float flRatio = Bias( flMoveWeight, 0.18f ) + 0.1f;
  2044. m_flMoveYaw = AngleNormalize( m_flMoveYaw + ( m_flMoveYawCurrentToIdeal * flRatio ) );
  2045. }
  2046. }
  2047. m_tPoseParamMappings[ PLAYER_POSE_PARAM_MOVE_YAW ].SetValue( m_pPlayer, m_flMoveYaw );
  2048. float flAimYaw = AngleDiff( m_flEyeYaw, m_flFootYaw );
  2049. if ( flAimYaw >= 0 && m_flAimYawMax != 0 )
  2050. {
  2051. flAimYaw = (flAimYaw / m_flAimYawMax) * 60.0f;
  2052. }
  2053. else if ( m_flAimYawMin != 0 )
  2054. {
  2055. flAimYaw = (flAimYaw / m_flAimYawMin) * -60.0f;
  2056. }
  2057. m_tPoseParamMappings[ PLAYER_POSE_PARAM_BODY_YAW ].SetValue( m_pPlayer, flAimYaw );
  2058. // we need non-symmetrical arbitrary min/max bounds for vertical aim (pitch) too
  2059. float flPitch = AngleDiff( m_flEyePitch, 0 );
  2060. if ( flPitch > 0 )
  2061. {
  2062. flPitch = (flPitch / m_flAimPitchMax) * CSGO_ANIM_AIMMATRIX_DEFAULT_PITCH_MAX;
  2063. }
  2064. else
  2065. {
  2066. flPitch = (flPitch / m_flAimPitchMin) * CSGO_ANIM_AIMMATRIX_DEFAULT_PITCH_MIN;
  2067. }
  2068. m_tPoseParamMappings[ PLAYER_POSE_PARAM_BODY_PITCH ].SetValue( m_pPlayer, flPitch );
  2069. m_tPoseParamMappings[ PLAYER_POSE_PARAM_SPEED ].SetValue( m_pPlayer, m_flSpeedAsPortionOfWalkTopSpeed );
  2070. m_tPoseParamMappings[ PLAYER_POSE_PARAM_STAND ].SetValue( m_pPlayer, 1.0f - (m_flAnimDuckAmount*m_flInAirSmoothValue) );
  2071. }
  2072. #ifndef CLIENT_DLL
  2073. int CCSGOPlayerAnimState::SelectSequenceFromActMods( Activity iAct )
  2074. {
  2075. MDLCACHE_CRITICAL_SECTION();
  2076. Assert( m_pPlayer );
  2077. int nSelectedActivity = m_pPlayer->SelectWeightedSequenceFromModifiers( iAct, m_ActivityModifiers.Base(), m_ActivityModifiers.Count() );
  2078. Assert( nSelectedActivity != ACT_INVALID );
  2079. return nSelectedActivity;
  2080. }
  2081. void CCSGOPlayerAnimState::DoAnimationEvent( PlayerAnimEvent_t animEvent, int nData )
  2082. {
  2083. UpdateActivityModifiers();
  2084. switch (animEvent) {
  2085. case PLAYERANIMEVENT_THROW_GRENADE_UNDERHAND:
  2086. {
  2087. AddActivityModifier( "underhand" );
  2088. }
  2089. case PLAYERANIMEVENT_FIRE_GUN_PRIMARY:
  2090. case PLAYERANIMEVENT_THROW_GRENADE:
  2091. {
  2092. if ( m_pWeapon && animEvent == PLAYERANIMEVENT_FIRE_GUN_PRIMARY && m_pWeapon->IsA( WEAPON_C4 ) )
  2093. {
  2094. SetLayerSequence( ANIMATION_LAYER_WHOLE_BODY, SelectSequenceFromActMods( ACT_CSGO_PLANT_BOMB ) );
  2095. m_bPlantAnimStarted = true;
  2096. }
  2097. //else if ( m_pWeapon->GetWeaponType() == WEAPONTYPE_KNIFE )
  2098. //{
  2099. // // HACK: knives keep previous firing weight, if any
  2100. // float flSavedWeight = GetLayerWeight( ANIMATION_LAYER_WEAPON_ACTION );
  2101. // SetLayerSequence( ANIMATION_LAYER_WEAPON_ACTION, SelectSequenceFromActMods( ACT_CSGO_FIRE_PRIMARY ) );
  2102. // SetLayerWeight( ANIMATION_LAYER_WEAPON_ACTION, flSavedWeight );
  2103. //}
  2104. else
  2105. {
  2106. SetLayerSequence( ANIMATION_LAYER_WEAPON_ACTION, SelectSequenceFromActMods( ACT_CSGO_FIRE_PRIMARY ) );
  2107. }
  2108. break;
  2109. }
  2110. case PLAYERANIMEVENT_FIRE_GUN_PRIMARY_OPT:
  2111. {
  2112. //if ( m_pWeapon->GetWeaponType() == WEAPONTYPE_KNIFE )
  2113. //{
  2114. // // HACK: knives keep previous firing weight, if any
  2115. // float flSavedWeight = GetLayerWeight( ANIMATION_LAYER_WEAPON_ACTION );
  2116. // SetLayerSequence( ANIMATION_LAYER_WEAPON_ACTION, SelectSequenceFromActMods( ACT_CSGO_FIRE_PRIMARY_OPT_1 ) );
  2117. // SetLayerWeight( ANIMATION_LAYER_WEAPON_ACTION, flSavedWeight );
  2118. //}
  2119. //else
  2120. {
  2121. SetLayerSequence( ANIMATION_LAYER_WEAPON_ACTION, SelectSequenceFromActMods( ACT_CSGO_FIRE_PRIMARY_OPT_1 ) );
  2122. }
  2123. break;
  2124. }
  2125. case PLAYERANIMEVENT_FIRE_GUN_PRIMARY_SPECIAL1:
  2126. case PLAYERANIMEVENT_FIRE_GUN_PRIMARY_OPT_SPECIAL1:
  2127. {
  2128. SetLayerSequence( ANIMATION_LAYER_WEAPON_ACTION, SelectSequenceFromActMods( ACT_CSGO_FIRE_PRIMARY_OPT_2 ) );
  2129. break;
  2130. }
  2131. case PLAYERANIMEVENT_FIRE_GUN_SECONDARY:
  2132. {
  2133. if ( m_pWeapon->GetWeaponType() == WEAPONTYPE_SNIPER_RIFLE )
  2134. {
  2135. // hack: sniper rifles use primary fire anim when 'alt' firing, meaning scoped.
  2136. SetLayerSequence( ANIMATION_LAYER_WEAPON_ACTION, SelectSequenceFromActMods( ACT_CSGO_FIRE_PRIMARY ) );
  2137. }
  2138. else
  2139. {
  2140. SetLayerSequence( ANIMATION_LAYER_WEAPON_ACTION, SelectSequenceFromActMods( ACT_CSGO_FIRE_SECONDARY ) );
  2141. }
  2142. break;
  2143. }
  2144. case PLAYERANIMEVENT_FIRE_GUN_SECONDARY_SPECIAL1:
  2145. {
  2146. SetLayerSequence( ANIMATION_LAYER_WEAPON_ACTION, SelectSequenceFromActMods( ACT_CSGO_FIRE_SECONDARY_OPT_1 ) );
  2147. break;
  2148. }
  2149. case PLAYERANIMEVENT_GRENADE_PULL_PIN:
  2150. {
  2151. SetLayerSequence( ANIMATION_LAYER_WEAPON_ACTION, SelectSequenceFromActMods( ACT_CSGO_OPERATE ) );
  2152. break;
  2153. }
  2154. case PLAYERANIMEVENT_SILENCER_ATTACH:
  2155. {
  2156. SetLayerSequence( ANIMATION_LAYER_WEAPON_ACTION, SelectSequenceFromActMods( ACT_CSGO_SILENCER_ATTACH ) );
  2157. break;
  2158. }
  2159. case PLAYERANIMEVENT_SILENCER_DETACH:
  2160. {
  2161. SetLayerSequence( ANIMATION_LAYER_WEAPON_ACTION, SelectSequenceFromActMods( ACT_CSGO_SILENCER_DETACH ) );
  2162. break;
  2163. }
  2164. case PLAYERANIMEVENT_RELOAD:
  2165. {
  2166. if ( m_pWeapon && m_pWeapon->GetWeaponType() == WEAPONTYPE_SHOTGUN && m_pWeapon->GetCSWeaponID() != WEAPON_MAG7 )
  2167. break;
  2168. SetLayerSequence( ANIMATION_LAYER_WEAPON_ACTION, SelectSequenceFromActMods( ACT_CSGO_RELOAD ) );
  2169. break;
  2170. }
  2171. case PLAYERANIMEVENT_RELOAD_START:
  2172. {
  2173. SetLayerSequence( ANIMATION_LAYER_WEAPON_ACTION, SelectSequenceFromActMods( ACT_CSGO_RELOAD_START ) );
  2174. break;
  2175. }
  2176. case PLAYERANIMEVENT_RELOAD_LOOP:
  2177. {
  2178. SetLayerSequence( ANIMATION_LAYER_WEAPON_ACTION, SelectSequenceFromActMods( ACT_CSGO_RELOAD_LOOP ) );
  2179. break;
  2180. }
  2181. case PLAYERANIMEVENT_RELOAD_END:
  2182. {
  2183. SetLayerSequence( ANIMATION_LAYER_WEAPON_ACTION, SelectSequenceFromActMods( ACT_CSGO_RELOAD_END ) );
  2184. break;
  2185. }
  2186. case PLAYERANIMEVENT_CATCH_WEAPON:
  2187. {
  2188. SetLayerSequence( ANIMATION_LAYER_WEAPON_ACTION, SelectSequenceFromActMods( ACT_CSGO_CATCH ) );
  2189. break;
  2190. }
  2191. case PLAYERANIMEVENT_CLEAR_FIRING:
  2192. {
  2193. m_bPlantAnimStarted = false;
  2194. break;
  2195. }
  2196. //case PLAYERANIMEVENT_TAUNT:
  2197. //{
  2198. // //not implemented yet
  2199. // break;
  2200. //}
  2201. case PLAYERANIMEVENT_DEPLOY:
  2202. {
  2203. if ( m_pWeapon && GetLayerActivity( ANIMATION_LAYER_WEAPON_ACTION ) == ACT_CSGO_DEPLOY &&
  2204. GetLayerCycle( ANIMATION_LAYER_WEAPON_ACTION ) < CSGO_ANIM_DEPLOY_RATELIMIT )
  2205. {
  2206. // we're already deploying
  2207. m_bDeployRateLimiting = true;
  2208. }
  2209. else
  2210. {
  2211. SetLayerSequence( ANIMATION_LAYER_WEAPON_ACTION, SelectSequenceFromActMods( ACT_CSGO_DEPLOY ) );
  2212. }
  2213. break;
  2214. }
  2215. case PLAYERANIMEVENT_JUMP:
  2216. {
  2217. // note: this event means a jump is definitely happening, not just that a jump is desired
  2218. m_bJumping = true;
  2219. SetLayerSequence( ANIMATION_LAYER_MOVEMENT_JUMP_OR_FALL, SelectSequenceFromActMods( ACT_CSGO_JUMP ) );
  2220. break;
  2221. }
  2222. default:
  2223. {
  2224. break;
  2225. }
  2226. }
  2227. }
  2228. void CCSGOPlayerAnimState::AddActivityModifier( const char *szName )
  2229. {
  2230. if ( szName == NULL )
  2231. {
  2232. Assert(0);
  2233. return;
  2234. }
  2235. char szLookup[32];
  2236. V_strcpy_safe( szLookup, szName );
  2237. CUtlSymbol sym = g_ActivityModifiersTable.Find( szLookup );
  2238. if ( !sym.IsValid() )
  2239. {
  2240. sym = g_ActivityModifiersTable.AddString( szLookup );
  2241. }
  2242. m_ActivityModifiers.AddToTail( sym );
  2243. }
  2244. void CCSGOPlayerAnimState::UpdateActivityModifiers( void )
  2245. {
  2246. m_ActivityModifiers.Purge();
  2247. AddActivityModifier( GetWeaponPrefix() );
  2248. if ( m_flSpeedAsPortionOfWalkTopSpeed > 0.25f )
  2249. {
  2250. AddActivityModifier( "moving" );
  2251. }
  2252. if ( m_flAnimDuckAmount > 0.55f )
  2253. {
  2254. AddActivityModifier( "crouch" );
  2255. }
  2256. }
  2257. void CCSGOPlayerAnimState::SelectDeathPose( const CTakeDamageInfo &info, int hitgroup, Activity& activity, float& yaw )
  2258. {
  2259. activity = ACT_INVALID;
  2260. yaw = 0;
  2261. if ( !m_pPlayer )
  2262. return;
  2263. if ( hitgroup == HITGROUP_HEAD )
  2264. {
  2265. activity = ( m_flAnimDuckAmount > 0.5f ) ? ACT_DIE_CROUCH_HEADSHOT : ACT_DIE_STAND_HEADSHOT;
  2266. }
  2267. else
  2268. {
  2269. activity = ( m_flAnimDuckAmount > 0.5f ) ? ACT_DIE_CROUCH : ACT_DIE_STAND;
  2270. }
  2271. Vector vecDamageDir = info.GetDamageForce();
  2272. VectorNormalize( vecDamageDir );
  2273. Vector vecDamagePlusPlayerVel = vecDamageDir + ( m_vecVelocity.Normalized() * MIN(m_vecVelocity.Length() / CS_PLAYER_SPEED_RUN, 1) );
  2274. VectorNormalize( vecDamagePlusPlayerVel );
  2275. QAngle angDamageAnglePlusCurrentMoveVelocity;
  2276. VectorAngles( vecDamageDir, Vector(0,0,1), angDamageAnglePlusCurrentMoveVelocity );
  2277. float flPlayerRelativeDamageAngle = AngleDiff( angDamageAnglePlusCurrentMoveVelocity[YAW], m_flFootYaw );
  2278. m_tPoseParamMappings[ PLAYER_POSE_PARAM_DEATH_YAW ].SetValue( m_pPlayer, clamp( flPlayerRelativeDamageAngle, -180, 180 ) );
  2279. yaw = flPlayerRelativeDamageAngle;
  2280. ////float flBaseSize = 10;
  2281. ////float flHeight = 80;
  2282. ////Vector vBasePos = m_pPlayer->GetAbsOrigin() + Vector( 0, 0, 3 );
  2283. ////Vector vForward, vRight, vUp;
  2284. ////AngleVectors( angDamageAnglePlusCurrentMoveVelocity, &vForward, &vRight, &vUp );
  2285. ////debugoverlay->AddTriangleOverlay( vBasePos+vRight*flBaseSize/2, vBasePos-vRight*flBaseSize/2, vBasePos+vForward*flHeight, 255, 0, 0, 255, false, 10 );
  2286. }
  2287. #endif
  2288. const char* CCSGOPlayerAnimState::GetWeaponPrefix( void )
  2289. {
  2290. int nWeaponType = 0; // knife
  2291. m_pWeapon = m_pPlayer->GetActiveCSWeapon();
  2292. if ( m_pWeapon )
  2293. {
  2294. nWeaponType = (int)m_pWeapon->GetWeaponType();
  2295. int nWeaponID = m_pWeapon->GetCSWeaponID();
  2296. if ( nWeaponID == WEAPON_MAG7 )
  2297. {
  2298. nWeaponType = WEAPONTYPE_RIFLE;
  2299. }
  2300. else if ( nWeaponID == WEAPON_TASER )
  2301. {
  2302. nWeaponType = WEAPONTYPE_PISTOL;
  2303. }
  2304. if ( nWeaponType == WEAPONTYPE_STACKABLEITEM )
  2305. {
  2306. nWeaponType = WEAPONTYPE_GRENADE; // redirect healthshot, adrenaline, etc to the grenade archetype
  2307. }
  2308. }
  2309. return g_szWeaponPrefixLookupTable[clamp( nWeaponType, 0, 9 )];
  2310. }
  2311. void CCSGOPlayerAnimState::WriteAnimstateDebugBuffer( char *pDest )
  2312. {
  2313. }
  2314. bool CCSGOPlayerAnimState::CacheSequences( void )
  2315. {
  2316. if ( !m_pPlayer )
  2317. return false;
  2318. if ( m_cachedModelIndex != m_pPlayer->GetModelIndex() )
  2319. {
  2320. // read animset version from keyvalues
  2321. m_nAnimstateModelVersion = 0;
  2322. CUtlBuffer buf( 1024, 0, CUtlBuffer::TEXT_BUFFER );
  2323. buf.PutString( "keyvalues {\n" ); // trick the kv loader into thinking this is one big block
  2324. if ( modelinfo->GetModelKeyValue( m_pPlayer->GetModel(), buf ) )
  2325. {
  2326. buf.PutString( "\n}\0" ); // end trickery
  2327. KeyValues *modelKeyValues = new KeyValues("");
  2328. KeyValues::AutoDelete autodelete_key( modelKeyValues );
  2329. if ( modelKeyValues->LoadFromBuffer( modelinfo->GetModelName( m_pPlayer->GetModel() ), buf ) )
  2330. {
  2331. FOR_EACH_SUBKEY( modelKeyValues, pSubKey )
  2332. {
  2333. //KeyValuesDumpAsDevMsg( pSubKey );
  2334. if ( pSubKey->FindKey( "animset_version" ) )
  2335. {
  2336. m_nAnimstateModelVersion = pSubKey->GetInt( "animset_version", CURRENT_ANIMSTATE_VERSION );
  2337. break;
  2338. }
  2339. }
  2340. }
  2341. }
  2342. AssertMsgOnce( m_nAnimstateModelVersion == CURRENT_ANIMSTATE_VERSION, "Animset version is out of date!" );
  2343. // cache pose param indices
  2344. m_tPoseParamMappings[ PLAYER_POSE_PARAM_LEAN_YAW ].Init( m_pPlayer, "lean_yaw" );
  2345. m_tPoseParamMappings[ PLAYER_POSE_PARAM_SPEED ].Init( m_pPlayer, "speed" );
  2346. m_tPoseParamMappings[ PLAYER_POSE_PARAM_LADDER_SPEED ].Init( m_pPlayer, "ladder_speed" );
  2347. m_tPoseParamMappings[ PLAYER_POSE_PARAM_LADDER_YAW ].Init( m_pPlayer, "ladder_yaw" );
  2348. m_tPoseParamMappings[ PLAYER_POSE_PARAM_MOVE_YAW ].Init( m_pPlayer, "move_yaw" );
  2349. if ( m_nAnimstateModelVersion < 2 )
  2350. m_tPoseParamMappings[ PLAYER_POSE_PARAM_RUN ].Init( m_pPlayer, "run" );
  2351. m_tPoseParamMappings[ PLAYER_POSE_PARAM_BODY_YAW ].Init( m_pPlayer, "body_yaw" );
  2352. m_tPoseParamMappings[ PLAYER_POSE_PARAM_BODY_PITCH ].Init( m_pPlayer, "body_pitch" );
  2353. m_tPoseParamMappings[ PLAYER_POSE_PARAM_DEATH_YAW ].Init( m_pPlayer, "death_yaw" );
  2354. m_tPoseParamMappings[ PLAYER_POSE_PARAM_STAND ].Init( m_pPlayer, "stand" );
  2355. m_tPoseParamMappings[ PLAYER_POSE_PARAM_JUMP_FALL ].Init( m_pPlayer, "jump_fall" );
  2356. m_tPoseParamMappings[ PLAYER_POSE_PARAM_AIM_BLEND_STAND_IDLE ].Init( m_pPlayer, "aim_blend_stand_idle" );
  2357. m_tPoseParamMappings[ PLAYER_POSE_PARAM_AIM_BLEND_CROUCH_IDLE ].Init( m_pPlayer, "aim_blend_crouch_idle" );
  2358. m_tPoseParamMappings[ PLAYER_POSE_PARAM_STRAFE_DIR ].Init( m_pPlayer, "strafe_yaw" );
  2359. m_tPoseParamMappings[ PLAYER_POSE_PARAM_AIM_BLEND_STAND_WALK ].Init( m_pPlayer, "aim_blend_stand_walk" );
  2360. m_tPoseParamMappings[ PLAYER_POSE_PARAM_AIM_BLEND_STAND_RUN ].Init( m_pPlayer, "aim_blend_stand_run" );
  2361. m_tPoseParamMappings[ PLAYER_POSE_PARAM_AIM_BLEND_CROUCH_WALK ].Init( m_pPlayer, "aim_blend_crouch_walk" );
  2362. if ( m_nAnimstateModelVersion > 0 )
  2363. {
  2364. m_tPoseParamMappings[ PLAYER_POSE_PARAM_MOVE_BLEND_WALK ].Init( m_pPlayer, "move_blend_walk" );
  2365. m_tPoseParamMappings[ PLAYER_POSE_PARAM_MOVE_BLEND_RUN ].Init( m_pPlayer, "move_blend_run" );
  2366. m_tPoseParamMappings[ PLAYER_POSE_PARAM_MOVE_BLEND_CROUCH_WALK ].Init( m_pPlayer, "move_blend_crouch" );
  2367. }
  2368. m_cachedModelIndex = m_pPlayer->GetModelIndex();
  2369. //// precache the sequences we'll be using for movement
  2370. //if ( m_cachedModelIndex > 0 && m_pPlayer->GetModelPtr() )
  2371. //{
  2372. // bool bSuccess = true;
  2373. // bSuccess = bSuccess && PopulateSequenceCache( "move", ANIMCACHE_MOVE );
  2374. // bSuccess = bSuccess && PopulateSequenceCache( "additive_posebreaker", ANIMCACHE_ALIVELOOP );
  2375. // bSuccess = bSuccess && PopulateSequenceCache( "jump", ANIMCACHE_JUMP );
  2376. // bSuccess = bSuccess && PopulateSequenceCache( "jump_moving", ANIMCACHE_JUMP_MOVING );
  2377. // bSuccess = bSuccess && PopulateSequenceCache( "fall", ANIMCACHE_FALL );
  2378. // bSuccess = bSuccess && PopulateSequenceCache( "land_light", ANIMCACHE_LANDLIGHT );
  2379. // bSuccess = bSuccess && PopulateSequenceCache( "land_heavy", ANIMCACHE_LANDHEAVY );
  2380. // bSuccess = bSuccess && PopulateSequenceCache( "land_light_crouched", ANIMCACHE_LANDLIGHT_CROUCHED );
  2381. // bSuccess = bSuccess && PopulateSequenceCache( "land_heavy_crouched", ANIMCACHE_LANDHEAVY_CROUCHED );
  2382. // bSuccess = bSuccess && PopulateSequenceCache( "ladder_climb", ANIMCACHE_LADDERCLIMB );
  2383. // bSuccess = bSuccess && PopulateSequenceCache( "lean", ANIMCACHE_LEAN );
  2384. // return bSuccess;
  2385. //}
  2386. }
  2387. return m_cachedModelIndex > 0;
  2388. }
  2389. //----------------------------------------------------------------------------------
  2390. int animstate_pose_param_cache_t::GetIndex( void )
  2391. {
  2392. Assert( m_bInitialized );
  2393. return m_nIndex;
  2394. }
  2395. float animstate_pose_param_cache_t::GetValue( CCSPlayer* pPlayer )
  2396. {
  2397. if ( !m_bInitialized )
  2398. {
  2399. Init( pPlayer, m_szName );
  2400. }
  2401. if ( m_bInitialized && pPlayer )
  2402. {
  2403. return pPlayer->GetPoseParameter( m_nIndex );
  2404. }
  2405. return 0;
  2406. }
  2407. void animstate_pose_param_cache_t::SetValue( CCSPlayer* pPlayer, float flValue )
  2408. {
  2409. if ( !m_bInitialized )
  2410. {
  2411. Init( pPlayer, m_szName );
  2412. }
  2413. if ( m_bInitialized && pPlayer )
  2414. {
  2415. MDLCACHE_CRITICAL_SECTION();
  2416. pPlayer->SetPoseParameter( m_nIndex, flValue );
  2417. }
  2418. }
  2419. bool animstate_pose_param_cache_t::Init( CCSPlayer* pPlayer, const char* szPoseParamName )
  2420. {
  2421. MDLCACHE_CRITICAL_SECTION();
  2422. m_szName = szPoseParamName;
  2423. m_nIndex = pPlayer->LookupPoseParameter( szPoseParamName );
  2424. if ( m_nIndex != -1 )
  2425. {
  2426. m_bInitialized = true;
  2427. }
  2428. return m_bInitialized;
  2429. }
  2430. //----------------------------------------------------------------------------------