Team Fortress 2 Source Code as on 22/4/2020
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.

576 lines
14 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "cbase.h"
  9. #ifdef CLIENT_DLL
  10. #include "c_hl2mp_player.h"
  11. #include "prediction.h"
  12. #define CRecipientFilter C_RecipientFilter
  13. #else
  14. #include "hl2mp_player.h"
  15. #endif
  16. #include "engine/IEngineSound.h"
  17. #include "SoundEmitterSystem/isoundemittersystembase.h"
  18. extern ConVar sv_footsteps;
  19. const char *g_ppszPlayerSoundPrefixNames[PLAYER_SOUNDS_MAX] =
  20. {
  21. "NPC_Citizen",
  22. "NPC_CombineS",
  23. "NPC_MetroPolice",
  24. };
  25. const char *CHL2MP_Player::GetPlayerModelSoundPrefix( void )
  26. {
  27. return g_ppszPlayerSoundPrefixNames[m_iPlayerSoundType];
  28. }
  29. void CHL2MP_Player::PrecacheFootStepSounds( void )
  30. {
  31. int iFootstepSounds = ARRAYSIZE( g_ppszPlayerSoundPrefixNames );
  32. int i;
  33. for ( i = 0; i < iFootstepSounds; ++i )
  34. {
  35. char szFootStepName[128];
  36. Q_snprintf( szFootStepName, sizeof( szFootStepName ), "%s.RunFootstepLeft", g_ppszPlayerSoundPrefixNames[i] );
  37. PrecacheScriptSound( szFootStepName );
  38. Q_snprintf( szFootStepName, sizeof( szFootStepName ), "%s.RunFootstepRight", g_ppszPlayerSoundPrefixNames[i] );
  39. PrecacheScriptSound( szFootStepName );
  40. }
  41. }
  42. //-----------------------------------------------------------------------------
  43. // Consider the weapon's built-in accuracy, this character's proficiency with
  44. // the weapon, and the status of the target. Use this information to determine
  45. // how accurately to shoot at the target.
  46. //-----------------------------------------------------------------------------
  47. Vector CHL2MP_Player::GetAttackSpread( CBaseCombatWeapon *pWeapon, CBaseEntity *pTarget )
  48. {
  49. if ( pWeapon )
  50. return pWeapon->GetBulletSpread( WEAPON_PROFICIENCY_PERFECT );
  51. return VECTOR_CONE_15DEGREES;
  52. }
  53. //-----------------------------------------------------------------------------
  54. // Purpose:
  55. // Input : step -
  56. // fvol -
  57. // force - force sound to play
  58. //-----------------------------------------------------------------------------
  59. void CHL2MP_Player::PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool force )
  60. {
  61. if ( gpGlobals->maxClients > 1 && !sv_footsteps.GetFloat() )
  62. return;
  63. #if defined( CLIENT_DLL )
  64. // during prediction play footstep sounds only once
  65. if ( !prediction->IsFirstTimePredicted() )
  66. return;
  67. #endif
  68. if ( GetFlags() & FL_DUCKING )
  69. return;
  70. m_Local.m_nStepside = !m_Local.m_nStepside;
  71. char szStepSound[128];
  72. if ( m_Local.m_nStepside )
  73. {
  74. Q_snprintf( szStepSound, sizeof( szStepSound ), "%s.RunFootstepLeft", g_ppszPlayerSoundPrefixNames[m_iPlayerSoundType] );
  75. }
  76. else
  77. {
  78. Q_snprintf( szStepSound, sizeof( szStepSound ), "%s.RunFootstepRight", g_ppszPlayerSoundPrefixNames[m_iPlayerSoundType] );
  79. }
  80. CSoundParameters params;
  81. if ( GetParametersForSound( szStepSound, params, NULL ) == false )
  82. return;
  83. CRecipientFilter filter;
  84. filter.AddRecipientsByPAS( vecOrigin );
  85. #ifndef CLIENT_DLL
  86. // im MP, server removed all players in origins PVS, these players
  87. // generate the footsteps clientside
  88. if ( gpGlobals->maxClients > 1 )
  89. filter.RemoveRecipientsByPVS( vecOrigin );
  90. #endif
  91. EmitSound_t ep;
  92. ep.m_nChannel = CHAN_BODY;
  93. ep.m_pSoundName = params.soundname;
  94. ep.m_flVolume = fvol;
  95. ep.m_SoundLevel = params.soundlevel;
  96. ep.m_nFlags = 0;
  97. ep.m_nPitch = params.pitch;
  98. ep.m_pOrigin = &vecOrigin;
  99. EmitSound( filter, entindex(), ep );
  100. }
  101. //==========================
  102. // ANIMATION CODE
  103. //==========================
  104. // Below this many degrees, slow down turning rate linearly
  105. #define FADE_TURN_DEGREES 45.0f
  106. // After this, need to start turning feet
  107. #define MAX_TORSO_ANGLE 90.0f
  108. // Below this amount, don't play a turning animation/perform IK
  109. #define MIN_TURN_ANGLE_REQUIRING_TURN_ANIMATION 15.0f
  110. static ConVar tf2_feetyawrunscale( "tf2_feetyawrunscale", "2", FCVAR_REPLICATED, "Multiplier on tf2_feetyawrate to allow turning faster when running." );
  111. extern ConVar sv_backspeed;
  112. extern ConVar mp_feetyawrate;
  113. extern ConVar mp_facefronttime;
  114. extern ConVar mp_ik;
  115. CPlayerAnimState::CPlayerAnimState( CHL2MP_Player *outer )
  116. : m_pOuter( outer )
  117. {
  118. m_flGaitYaw = 0.0f;
  119. m_flGoalFeetYaw = 0.0f;
  120. m_flCurrentFeetYaw = 0.0f;
  121. m_flCurrentTorsoYaw = 0.0f;
  122. m_flLastYaw = 0.0f;
  123. m_flLastTurnTime = 0.0f;
  124. m_flTurnCorrectionTime = 0.0f;
  125. };
  126. //-----------------------------------------------------------------------------
  127. // Purpose:
  128. //-----------------------------------------------------------------------------
  129. void CPlayerAnimState::Update()
  130. {
  131. m_angRender = GetOuter()->GetLocalAngles();
  132. m_angRender[ PITCH ] = m_angRender[ ROLL ] = 0.0f;
  133. ComputePoseParam_BodyYaw();
  134. ComputePoseParam_BodyPitch(GetOuter()->GetModelPtr());
  135. ComputePoseParam_BodyLookYaw();
  136. ComputePlaybackRate();
  137. #ifdef CLIENT_DLL
  138. GetOuter()->UpdateLookAt();
  139. #endif
  140. }
  141. //-----------------------------------------------------------------------------
  142. // Purpose:
  143. //-----------------------------------------------------------------------------
  144. void CPlayerAnimState::ComputePlaybackRate()
  145. {
  146. // Determine ideal playback rate
  147. Vector vel;
  148. GetOuterAbsVelocity( vel );
  149. float speed = vel.Length2D();
  150. bool isMoving = ( speed > 0.5f ) ? true : false;
  151. float maxspeed = GetOuter()->GetSequenceGroundSpeed( GetOuter()->GetSequence() );
  152. if ( isMoving && ( maxspeed > 0.0f ) )
  153. {
  154. float flFactor = 1.0f;
  155. // Note this gets set back to 1.0 if sequence changes due to ResetSequenceInfo below
  156. GetOuter()->SetPlaybackRate( ( speed * flFactor ) / maxspeed );
  157. // BUG BUG:
  158. // This stuff really should be m_flPlaybackRate = speed / m_flGroundSpeed
  159. }
  160. else
  161. {
  162. GetOuter()->SetPlaybackRate( 1.0f );
  163. }
  164. }
  165. //-----------------------------------------------------------------------------
  166. // Purpose:
  167. // Output : CBasePlayer
  168. //-----------------------------------------------------------------------------
  169. CHL2MP_Player *CPlayerAnimState::GetOuter()
  170. {
  171. return m_pOuter;
  172. }
  173. //-----------------------------------------------------------------------------
  174. // Purpose:
  175. // Input : dt -
  176. //-----------------------------------------------------------------------------
  177. void CPlayerAnimState::EstimateYaw( void )
  178. {
  179. float dt = gpGlobals->frametime;
  180. if ( !dt )
  181. {
  182. return;
  183. }
  184. Vector est_velocity;
  185. QAngle angles;
  186. GetOuterAbsVelocity( est_velocity );
  187. angles = GetOuter()->GetLocalAngles();
  188. if ( est_velocity[1] == 0 && est_velocity[0] == 0 )
  189. {
  190. float flYawDiff = angles[YAW] - m_flGaitYaw;
  191. flYawDiff = flYawDiff - (int)(flYawDiff / 360) * 360;
  192. if (flYawDiff > 180)
  193. flYawDiff -= 360;
  194. if (flYawDiff < -180)
  195. flYawDiff += 360;
  196. if (dt < 0.25)
  197. flYawDiff *= dt * 4;
  198. else
  199. flYawDiff *= dt;
  200. m_flGaitYaw += flYawDiff;
  201. m_flGaitYaw = m_flGaitYaw - (int)(m_flGaitYaw / 360) * 360;
  202. }
  203. else
  204. {
  205. m_flGaitYaw = (atan2(est_velocity[1], est_velocity[0]) * 180 / M_PI);
  206. if (m_flGaitYaw > 180)
  207. m_flGaitYaw = 180;
  208. else if (m_flGaitYaw < -180)
  209. m_flGaitYaw = -180;
  210. }
  211. }
  212. //-----------------------------------------------------------------------------
  213. // Purpose: Override for backpeddling
  214. // Input : dt -
  215. //-----------------------------------------------------------------------------
  216. void CPlayerAnimState::ComputePoseParam_BodyYaw( void )
  217. {
  218. int iYaw = GetOuter()->LookupPoseParameter( "move_yaw" );
  219. if ( iYaw < 0 )
  220. return;
  221. // view direction relative to movement
  222. float flYaw;
  223. EstimateYaw();
  224. QAngle angles = GetOuter()->GetLocalAngles();
  225. float ang = angles[ YAW ];
  226. if ( ang > 180.0f )
  227. {
  228. ang -= 360.0f;
  229. }
  230. else if ( ang < -180.0f )
  231. {
  232. ang += 360.0f;
  233. }
  234. // calc side to side turning
  235. flYaw = ang - m_flGaitYaw;
  236. // Invert for mapping into 8way blend
  237. flYaw = -flYaw;
  238. flYaw = flYaw - (int)(flYaw / 360) * 360;
  239. if (flYaw < -180)
  240. {
  241. flYaw = flYaw + 360;
  242. }
  243. else if (flYaw > 180)
  244. {
  245. flYaw = flYaw - 360;
  246. }
  247. GetOuter()->SetPoseParameter( iYaw, flYaw );
  248. #ifndef CLIENT_DLL
  249. //Adrian: Make the model's angle match the legs so the hitboxes match on both sides.
  250. GetOuter()->SetLocalAngles( QAngle( GetOuter()->GetAnimEyeAngles().x, m_flCurrentFeetYaw, 0 ) );
  251. #endif
  252. }
  253. //-----------------------------------------------------------------------------
  254. // Purpose:
  255. //-----------------------------------------------------------------------------
  256. void CPlayerAnimState::ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr )
  257. {
  258. // Get pitch from v_angle
  259. float flPitch = GetOuter()->GetLocalAngles()[ PITCH ];
  260. if ( flPitch > 180.0f )
  261. {
  262. flPitch -= 360.0f;
  263. }
  264. flPitch = clamp( flPitch, -90, 90 );
  265. QAngle absangles = GetOuter()->GetAbsAngles();
  266. absangles.x = 0.0f;
  267. m_angRender = absangles;
  268. m_angRender[ PITCH ] = m_angRender[ ROLL ] = 0.0f;
  269. // See if we have a blender for pitch
  270. GetOuter()->SetPoseParameter( pStudioHdr, "aim_pitch", flPitch );
  271. }
  272. //-----------------------------------------------------------------------------
  273. // Purpose:
  274. // Input : goal -
  275. // maxrate -
  276. // dt -
  277. // current -
  278. // Output : int
  279. //-----------------------------------------------------------------------------
  280. int CPlayerAnimState::ConvergeAngles( float goal,float maxrate, float dt, float& current )
  281. {
  282. int direction = TURN_NONE;
  283. float anglediff = goal - current;
  284. float anglediffabs = fabs( anglediff );
  285. anglediff = AngleNormalize( anglediff );
  286. float scale = 1.0f;
  287. if ( anglediffabs <= FADE_TURN_DEGREES )
  288. {
  289. scale = anglediffabs / FADE_TURN_DEGREES;
  290. // Always do at least a bit of the turn ( 1% )
  291. scale = clamp( scale, 0.01f, 1.0f );
  292. }
  293. float maxmove = maxrate * dt * scale;
  294. if ( fabs( anglediff ) < maxmove )
  295. {
  296. current = goal;
  297. }
  298. else
  299. {
  300. if ( anglediff > 0 )
  301. {
  302. current += maxmove;
  303. direction = TURN_LEFT;
  304. }
  305. else
  306. {
  307. current -= maxmove;
  308. direction = TURN_RIGHT;
  309. }
  310. }
  311. current = AngleNormalize( current );
  312. return direction;
  313. }
  314. void CPlayerAnimState::ComputePoseParam_BodyLookYaw( void )
  315. {
  316. QAngle absangles = GetOuter()->GetAbsAngles();
  317. absangles.y = AngleNormalize( absangles.y );
  318. m_angRender = absangles;
  319. m_angRender[ PITCH ] = m_angRender[ ROLL ] = 0.0f;
  320. // See if we even have a blender for pitch
  321. int upper_body_yaw = GetOuter()->LookupPoseParameter( "aim_yaw" );
  322. if ( upper_body_yaw < 0 )
  323. {
  324. return;
  325. }
  326. // Assume upper and lower bodies are aligned and that we're not turning
  327. float flGoalTorsoYaw = 0.0f;
  328. int turning = TURN_NONE;
  329. float turnrate = 360.0f;
  330. Vector vel;
  331. GetOuterAbsVelocity( vel );
  332. bool isMoving = ( vel.Length() > 1.0f ) ? true : false;
  333. if ( !isMoving )
  334. {
  335. // Just stopped moving, try and clamp feet
  336. if ( m_flLastTurnTime <= 0.0f )
  337. {
  338. m_flLastTurnTime = gpGlobals->curtime;
  339. m_flLastYaw = GetOuter()->GetAnimEyeAngles().y;
  340. // Snap feet to be perfectly aligned with torso/eyes
  341. m_flGoalFeetYaw = GetOuter()->GetAnimEyeAngles().y;
  342. m_flCurrentFeetYaw = m_flGoalFeetYaw;
  343. m_nTurningInPlace = TURN_NONE;
  344. }
  345. // If rotating in place, update stasis timer
  346. if ( m_flLastYaw != GetOuter()->GetAnimEyeAngles().y )
  347. {
  348. m_flLastTurnTime = gpGlobals->curtime;
  349. m_flLastYaw = GetOuter()->GetAnimEyeAngles().y;
  350. }
  351. if ( m_flGoalFeetYaw != m_flCurrentFeetYaw )
  352. {
  353. m_flLastTurnTime = gpGlobals->curtime;
  354. }
  355. turning = ConvergeAngles( m_flGoalFeetYaw, turnrate, gpGlobals->frametime, m_flCurrentFeetYaw );
  356. QAngle eyeAngles = GetOuter()->GetAnimEyeAngles();
  357. QAngle vAngle = GetOuter()->GetLocalAngles();
  358. // See how far off current feetyaw is from true yaw
  359. float yawdelta = GetOuter()->GetAnimEyeAngles().y - m_flCurrentFeetYaw;
  360. yawdelta = AngleNormalize( yawdelta );
  361. bool rotated_too_far = false;
  362. float yawmagnitude = fabs( yawdelta );
  363. // If too far, then need to turn in place
  364. if ( yawmagnitude > 45 )
  365. {
  366. rotated_too_far = true;
  367. }
  368. // Standing still for a while, rotate feet around to face forward
  369. // Or rotated too far
  370. // FIXME: Play an in place turning animation
  371. if ( rotated_too_far ||
  372. ( gpGlobals->curtime > m_flLastTurnTime + mp_facefronttime.GetFloat() ) )
  373. {
  374. m_flGoalFeetYaw = GetOuter()->GetAnimEyeAngles().y;
  375. m_flLastTurnTime = gpGlobals->curtime;
  376. /* float yd = m_flCurrentFeetYaw - m_flGoalFeetYaw;
  377. if ( yd > 0 )
  378. {
  379. m_nTurningInPlace = TURN_RIGHT;
  380. }
  381. else if ( yd < 0 )
  382. {
  383. m_nTurningInPlace = TURN_LEFT;
  384. }
  385. else
  386. {
  387. m_nTurningInPlace = TURN_NONE;
  388. }
  389. turning = ConvergeAngles( m_flGoalFeetYaw, turnrate, gpGlobals->frametime, m_flCurrentFeetYaw );
  390. yawdelta = GetOuter()->GetAnimEyeAngles().y - m_flCurrentFeetYaw;*/
  391. }
  392. // Snap upper body into position since the delta is already smoothed for the feet
  393. flGoalTorsoYaw = yawdelta;
  394. m_flCurrentTorsoYaw = flGoalTorsoYaw;
  395. }
  396. else
  397. {
  398. m_flLastTurnTime = 0.0f;
  399. m_nTurningInPlace = TURN_NONE;
  400. m_flCurrentFeetYaw = m_flGoalFeetYaw = GetOuter()->GetAnimEyeAngles().y;
  401. flGoalTorsoYaw = 0.0f;
  402. m_flCurrentTorsoYaw = GetOuter()->GetAnimEyeAngles().y - m_flCurrentFeetYaw;
  403. }
  404. if ( turning == TURN_NONE )
  405. {
  406. m_nTurningInPlace = turning;
  407. }
  408. if ( m_nTurningInPlace != TURN_NONE )
  409. {
  410. // If we're close to finishing the turn, then turn off the turning animation
  411. if ( fabs( m_flCurrentFeetYaw - m_flGoalFeetYaw ) < MIN_TURN_ANGLE_REQUIRING_TURN_ANIMATION )
  412. {
  413. m_nTurningInPlace = TURN_NONE;
  414. }
  415. }
  416. // Rotate entire body into position
  417. absangles = GetOuter()->GetAbsAngles();
  418. absangles.y = m_flCurrentFeetYaw;
  419. m_angRender = absangles;
  420. m_angRender[ PITCH ] = m_angRender[ ROLL ] = 0.0f;
  421. GetOuter()->SetPoseParameter( upper_body_yaw, clamp( m_flCurrentTorsoYaw, -60.0f, 60.0f ) );
  422. /*
  423. // FIXME: Adrian, what is this?
  424. int body_yaw = GetOuter()->LookupPoseParameter( "body_yaw" );
  425. if ( body_yaw >= 0 )
  426. {
  427. GetOuter()->SetPoseParameter( body_yaw, 30 );
  428. }
  429. */
  430. }
  431. //-----------------------------------------------------------------------------
  432. // Purpose:
  433. // Input : activity -
  434. // Output : Activity
  435. //-----------------------------------------------------------------------------
  436. Activity CPlayerAnimState::BodyYawTranslateActivity( Activity activity )
  437. {
  438. // Not even standing still, sigh
  439. if ( activity != ACT_IDLE )
  440. return activity;
  441. // Not turning
  442. switch ( m_nTurningInPlace )
  443. {
  444. default:
  445. case TURN_NONE:
  446. return activity;
  447. /*
  448. case TURN_RIGHT:
  449. return ACT_TURNRIGHT45;
  450. case TURN_LEFT:
  451. return ACT_TURNLEFT45;
  452. */
  453. case TURN_RIGHT:
  454. case TURN_LEFT:
  455. return mp_ik.GetBool() ? ACT_TURN : activity;
  456. }
  457. Assert( 0 );
  458. return activity;
  459. }
  460. const QAngle& CPlayerAnimState::GetRenderAngles()
  461. {
  462. return m_angRender;
  463. }
  464. void CPlayerAnimState::GetOuterAbsVelocity( Vector& vel )
  465. {
  466. #if defined( CLIENT_DLL )
  467. GetOuter()->EstimateAbsVelocity( vel );
  468. #else
  469. vel = GetOuter()->GetAbsVelocity();
  470. #endif
  471. }