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.

649 lines
19 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "c_basehlplayer.h"
  9. #include "playerandobjectenumerator.h"
  10. #include "engine/ivdebugoverlay.h"
  11. #include "c_ai_basenpc.h"
  12. #include "in_buttons.h"
  13. #include "collisionutils.h"
  14. // memdbgon must be the last include file in a .cpp file!!!
  15. #include "tier0/memdbgon.h"
  16. // How fast to avoid collisions with center of other object, in units per second
  17. #define AVOID_SPEED 2000.0f
  18. extern ConVar cl_forwardspeed;
  19. extern ConVar cl_backspeed;
  20. extern ConVar cl_sidespeed;
  21. extern ConVar zoom_sensitivity_ratio;
  22. extern ConVar default_fov;
  23. extern ConVar sensitivity;
  24. ConVar cl_npc_speedmod_intime( "cl_npc_speedmod_intime", "0.25", FCVAR_CLIENTDLL | FCVAR_ARCHIVE );
  25. ConVar cl_npc_speedmod_outtime( "cl_npc_speedmod_outtime", "1.5", FCVAR_CLIENTDLL | FCVAR_ARCHIVE );
  26. IMPLEMENT_CLIENTCLASS_DT(C_BaseHLPlayer, DT_HL2_Player, CHL2_Player)
  27. RecvPropDataTable( RECVINFO_DT(m_HL2Local),0, &REFERENCE_RECV_TABLE(DT_HL2Local) ),
  28. RecvPropBool( RECVINFO( m_fIsSprinting ) ),
  29. END_RECV_TABLE()
  30. BEGIN_PREDICTION_DATA( C_BaseHLPlayer )
  31. DEFINE_PRED_TYPEDESCRIPTION( m_HL2Local, C_HL2PlayerLocalData ),
  32. DEFINE_PRED_FIELD( m_fIsSprinting, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
  33. END_PREDICTION_DATA()
  34. //-----------------------------------------------------------------------------
  35. // Purpose: Drops player's primary weapon
  36. //-----------------------------------------------------------------------------
  37. void CC_DropPrimary( void )
  38. {
  39. C_BasePlayer *pPlayer = (C_BasePlayer *) C_BasePlayer::GetLocalPlayer();
  40. if ( pPlayer == NULL )
  41. return;
  42. pPlayer->Weapon_DropPrimary();
  43. }
  44. static ConCommand dropprimary("dropprimary", CC_DropPrimary, "dropprimary: Drops the primary weapon of the player.");
  45. //-----------------------------------------------------------------------------
  46. // Constructor
  47. //-----------------------------------------------------------------------------
  48. C_BaseHLPlayer::C_BaseHLPlayer()
  49. {
  50. AddVar( &m_Local.m_vecPunchAngle, &m_Local.m_iv_vecPunchAngle, LATCH_SIMULATION_VAR );
  51. AddVar( &m_Local.m_vecPunchAngleVel, &m_Local.m_iv_vecPunchAngleVel, LATCH_SIMULATION_VAR );
  52. m_flZoomStart = 0.0f;
  53. m_flZoomEnd = 0.0f;
  54. m_flZoomRate = 0.0f;
  55. m_flZoomStartTime = 0.0f;
  56. m_flSpeedMod = cl_forwardspeed.GetFloat();
  57. }
  58. //-----------------------------------------------------------------------------
  59. // Purpose:
  60. // Input : updateType -
  61. //-----------------------------------------------------------------------------
  62. void C_BaseHLPlayer::OnDataChanged( DataUpdateType_t updateType )
  63. {
  64. // Make sure we're thinking
  65. if ( updateType == DATA_UPDATE_CREATED )
  66. {
  67. SetNextClientThink( CLIENT_THINK_ALWAYS );
  68. }
  69. BaseClass::OnDataChanged( updateType );
  70. }
  71. //-----------------------------------------------------------------------------
  72. // Purpose:
  73. //-----------------------------------------------------------------------------
  74. void C_BaseHLPlayer::Weapon_DropPrimary( void )
  75. {
  76. engine->ServerCmd( "DropPrimary" );
  77. }
  78. float C_BaseHLPlayer::GetFOV()
  79. {
  80. //Find our FOV with offset zoom value
  81. float flFOVOffset = BaseClass::GetFOV() + GetZoom();
  82. // Clamp FOV in MP
  83. int min_fov = ( gpGlobals->maxClients == 1 ) ? 5 : default_fov.GetInt();
  84. // Don't let it go too low
  85. flFOVOffset = MAX( min_fov, flFOVOffset );
  86. return flFOVOffset;
  87. }
  88. //-----------------------------------------------------------------------------
  89. // Purpose:
  90. // Output : float
  91. //-----------------------------------------------------------------------------
  92. float C_BaseHLPlayer::GetZoom( void )
  93. {
  94. float fFOV = m_flZoomEnd;
  95. //See if we need to lerp the values
  96. if ( ( m_flZoomStart != m_flZoomEnd ) && ( m_flZoomRate > 0.0f ) )
  97. {
  98. float deltaTime = (float)( gpGlobals->curtime - m_flZoomStartTime ) / m_flZoomRate;
  99. if ( deltaTime >= 1.0f )
  100. {
  101. //If we're past the zoom time, just take the new value and stop lerping
  102. fFOV = m_flZoomStart = m_flZoomEnd;
  103. }
  104. else
  105. {
  106. fFOV = SimpleSplineRemapVal( deltaTime, 0.0f, 1.0f, m_flZoomStart, m_flZoomEnd );
  107. }
  108. }
  109. return fFOV;
  110. }
  111. //-----------------------------------------------------------------------------
  112. // Purpose:
  113. // Input : FOVOffset -
  114. // time -
  115. //-----------------------------------------------------------------------------
  116. void C_BaseHLPlayer::Zoom( float FOVOffset, float time )
  117. {
  118. m_flZoomStart = GetZoom();
  119. m_flZoomEnd = FOVOffset;
  120. m_flZoomRate = time;
  121. m_flZoomStartTime = gpGlobals->curtime;
  122. }
  123. //-----------------------------------------------------------------------------
  124. // Purpose: Hack to zero out player's pitch, use value from poseparameter instead
  125. // Input : flags -
  126. // Output : int
  127. //-----------------------------------------------------------------------------
  128. int C_BaseHLPlayer::DrawModel( int flags )
  129. {
  130. // Not pitch for player
  131. QAngle saveAngles = GetLocalAngles();
  132. QAngle useAngles = saveAngles;
  133. useAngles[ PITCH ] = 0.0f;
  134. SetLocalAngles( useAngles );
  135. int iret = BaseClass::DrawModel( flags );
  136. SetLocalAngles( saveAngles );
  137. return iret;
  138. }
  139. //-----------------------------------------------------------------------------
  140. // Purpose: Helper to remove from ladder
  141. //-----------------------------------------------------------------------------
  142. void C_BaseHLPlayer::ExitLadder()
  143. {
  144. if ( MOVETYPE_LADDER != GetMoveType() )
  145. return;
  146. SetMoveType( MOVETYPE_WALK );
  147. SetMoveCollide( MOVECOLLIDE_DEFAULT );
  148. // Remove from ladder
  149. m_HL2Local.m_hLadder = NULL;
  150. }
  151. //-----------------------------------------------------------------------------
  152. // Purpose: Determines if a player can be safely moved towards a point
  153. // Input: pos - position to test move to, fVertDist - how far to trace downwards to see if the player would fall,
  154. // radius - how close the player can be to the object, objPos - position of the object to avoid,
  155. // objDir - direction the object is travelling
  156. //-----------------------------------------------------------------------------
  157. bool C_BaseHLPlayer::TestMove( const Vector &pos, float fVertDist, float radius, const Vector &objPos, const Vector &objDir )
  158. {
  159. trace_t trUp;
  160. trace_t trOver;
  161. trace_t trDown;
  162. float flHit1, flHit2;
  163. UTIL_TraceHull( GetAbsOrigin(), pos, GetPlayerMins(), GetPlayerMaxs(), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &trOver );
  164. if ( trOver.fraction < 1.0f )
  165. {
  166. // check if the endpos intersects with the direction the object is travelling. if it doesn't, this is a good direction to move.
  167. if ( objDir.IsZero() ||
  168. ( IntersectInfiniteRayWithSphere( objPos, objDir, trOver.endpos, radius, &flHit1, &flHit2 ) &&
  169. ( ( flHit1 >= 0.0f ) || ( flHit2 >= 0.0f ) ) )
  170. )
  171. {
  172. // our first trace failed, so see if we can go farther if we step up.
  173. // trace up to see if we have enough room.
  174. UTIL_TraceHull( GetAbsOrigin(), GetAbsOrigin() + Vector( 0, 0, m_Local.m_flStepSize ),
  175. GetPlayerMins(), GetPlayerMaxs(), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &trUp );
  176. // do a trace from the stepped up height
  177. UTIL_TraceHull( trUp.endpos, pos + Vector( 0, 0, trUp.endpos.z - trUp.startpos.z ),
  178. GetPlayerMins(), GetPlayerMaxs(), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &trOver );
  179. if ( trOver.fraction < 1.0f )
  180. {
  181. // check if the endpos intersects with the direction the object is travelling. if it doesn't, this is a good direction to move.
  182. if ( objDir.IsZero() ||
  183. ( IntersectInfiniteRayWithSphere( objPos, objDir, trOver.endpos, radius, &flHit1, &flHit2 ) && ( ( flHit1 >= 0.0f ) || ( flHit2 >= 0.0f ) ) ) )
  184. {
  185. return false;
  186. }
  187. }
  188. }
  189. }
  190. // trace down to see if this position is on the ground
  191. UTIL_TraceLine( trOver.endpos, trOver.endpos - Vector( 0, 0, fVertDist ),
  192. MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &trDown );
  193. if ( trDown.fraction == 1.0f )
  194. return false;
  195. return true;
  196. }
  197. //-----------------------------------------------------------------------------
  198. // Client-side obstacle avoidance
  199. //-----------------------------------------------------------------------------
  200. void C_BaseHLPlayer::PerformClientSideObstacleAvoidance( float flFrameTime, CUserCmd *pCmd )
  201. {
  202. // Don't avoid if noclipping or in movetype none
  203. switch ( GetMoveType() )
  204. {
  205. case MOVETYPE_NOCLIP:
  206. case MOVETYPE_NONE:
  207. case MOVETYPE_OBSERVER:
  208. return;
  209. default:
  210. break;
  211. }
  212. // Try to steer away from any objects/players we might interpenetrate
  213. Vector size = WorldAlignSize();
  214. float radius = 0.7f * sqrt( size.x * size.x + size.y * size.y );
  215. float curspeed = GetLocalVelocity().Length2D();
  216. //int slot = 1;
  217. //engine->Con_NPrintf( slot++, "speed %f\n", curspeed );
  218. //engine->Con_NPrintf( slot++, "radius %f\n", radius );
  219. // If running, use a larger radius
  220. float factor = 1.0f;
  221. if ( curspeed > 150.0f )
  222. {
  223. curspeed = MIN( 2048.0f, curspeed );
  224. factor = ( 1.0f + ( curspeed - 150.0f ) / 150.0f );
  225. //engine->Con_NPrintf( slot++, "scaleup (%f) to radius %f\n", factor, radius * factor );
  226. radius = radius * factor;
  227. }
  228. Vector currentdir;
  229. Vector rightdir;
  230. QAngle vAngles = pCmd->viewangles;
  231. vAngles.x = 0;
  232. AngleVectors( vAngles, &currentdir, &rightdir, NULL );
  233. bool istryingtomove = false;
  234. bool ismovingforward = false;
  235. if ( fabs( pCmd->forwardmove ) > 0.0f ||
  236. fabs( pCmd->sidemove ) > 0.0f )
  237. {
  238. istryingtomove = true;
  239. if ( pCmd->forwardmove > 1.0f )
  240. {
  241. ismovingforward = true;
  242. }
  243. }
  244. if ( istryingtomove == true )
  245. radius *= 1.3f;
  246. CPlayerAndObjectEnumerator avoid( radius );
  247. partition->EnumerateElementsInSphere( PARTITION_CLIENT_SOLID_EDICTS, GetAbsOrigin(), radius, false, &avoid );
  248. // Okay, decide how to avoid if there's anything close by
  249. int c = avoid.GetObjectCount();
  250. if ( c <= 0 )
  251. return;
  252. //engine->Con_NPrintf( slot++, "moving %s forward %s\n", istryingtomove ? "true" : "false", ismovingforward ? "true" : "false" );
  253. float adjustforwardmove = 0.0f;
  254. float adjustsidemove = 0.0f;
  255. for ( int i = 0; i < c; i++ )
  256. {
  257. C_AI_BaseNPC *obj = dynamic_cast< C_AI_BaseNPC *>(avoid.GetObject( i ));
  258. if( !obj )
  259. continue;
  260. Vector vecToObject = obj->GetAbsOrigin() - GetAbsOrigin();
  261. float flDist = vecToObject.Length2D();
  262. // Figure out a 2D radius for the object
  263. Vector vecWorldMins, vecWorldMaxs;
  264. obj->CollisionProp()->WorldSpaceAABB( &vecWorldMins, &vecWorldMaxs );
  265. Vector objSize = vecWorldMaxs - vecWorldMins;
  266. float objectradius = 0.5f * sqrt( objSize.x * objSize.x + objSize.y * objSize.y );
  267. //Don't run this code if the NPC is not moving UNLESS we are in stuck inside of them.
  268. if ( !obj->IsMoving() && flDist > objectradius )
  269. continue;
  270. if ( flDist > objectradius && obj->IsEffectActive( EF_NODRAW ) )
  271. {
  272. obj->RemoveEffects( EF_NODRAW );
  273. }
  274. Vector vecNPCVelocity;
  275. obj->EstimateAbsVelocity( vecNPCVelocity );
  276. float flNPCSpeed = VectorNormalize( vecNPCVelocity );
  277. Vector vPlayerVel = GetAbsVelocity();
  278. VectorNormalize( vPlayerVel );
  279. float flHit1, flHit2;
  280. Vector vRayDir = vecToObject;
  281. VectorNormalize( vRayDir );
  282. float flVelProduct = DotProduct( vecNPCVelocity, vPlayerVel );
  283. float flDirProduct = DotProduct( vRayDir, vPlayerVel );
  284. if ( !IntersectInfiniteRayWithSphere(
  285. GetAbsOrigin(),
  286. vRayDir,
  287. obj->GetAbsOrigin(),
  288. radius,
  289. &flHit1,
  290. &flHit2 ) )
  291. continue;
  292. Vector dirToObject = -vecToObject;
  293. VectorNormalize( dirToObject );
  294. float fwd = 0;
  295. float rt = 0;
  296. float sidescale = 2.0f;
  297. float forwardscale = 1.0f;
  298. bool foundResult = false;
  299. Vector vMoveDir = vecNPCVelocity;
  300. if ( flNPCSpeed > 0.001f )
  301. {
  302. // This NPC is moving. First try deflecting the player left or right relative to the NPC's velocity.
  303. // Start with whatever side they're on relative to the NPC's velocity.
  304. Vector vecNPCTrajectoryRight = CrossProduct( vecNPCVelocity, Vector( 0, 0, 1) );
  305. int iDirection = ( vecNPCTrajectoryRight.Dot( dirToObject ) > 0 ) ? 1 : -1;
  306. for ( int nTries = 0; nTries < 2; nTries++ )
  307. {
  308. Vector vecTryMove = vecNPCTrajectoryRight * iDirection;
  309. VectorNormalize( vecTryMove );
  310. Vector vTestPosition = GetAbsOrigin() + vecTryMove * radius * 2;
  311. if ( TestMove( vTestPosition, size.z * 2, radius * 2, obj->GetAbsOrigin(), vMoveDir ) )
  312. {
  313. fwd = currentdir.Dot( vecTryMove );
  314. rt = rightdir.Dot( vecTryMove );
  315. //Msg( "PUSH DEFLECT fwd=%f, rt=%f\n", fwd, rt );
  316. foundResult = true;
  317. break;
  318. }
  319. else
  320. {
  321. // Try the other direction.
  322. iDirection *= -1;
  323. }
  324. }
  325. }
  326. else
  327. {
  328. // the object isn't moving, so try moving opposite the way it's facing
  329. Vector vecNPCForward;
  330. obj->GetVectors( &vecNPCForward, NULL, NULL );
  331. Vector vTestPosition = GetAbsOrigin() - vecNPCForward * radius * 2;
  332. if ( TestMove( vTestPosition, size.z * 2, radius * 2, obj->GetAbsOrigin(), vMoveDir ) )
  333. {
  334. fwd = currentdir.Dot( -vecNPCForward );
  335. rt = rightdir.Dot( -vecNPCForward );
  336. if ( flDist < objectradius )
  337. {
  338. obj->AddEffects( EF_NODRAW );
  339. }
  340. //Msg( "PUSH AWAY FACE fwd=%f, rt=%f\n", fwd, rt );
  341. foundResult = true;
  342. }
  343. }
  344. if ( !foundResult )
  345. {
  346. // test if we can move in the direction the object is moving
  347. Vector vTestPosition = GetAbsOrigin() + vMoveDir * radius * 2;
  348. if ( TestMove( vTestPosition, size.z * 2, radius * 2, obj->GetAbsOrigin(), vMoveDir ) )
  349. {
  350. fwd = currentdir.Dot( vMoveDir );
  351. rt = rightdir.Dot( vMoveDir );
  352. if ( flDist < objectradius )
  353. {
  354. obj->AddEffects( EF_NODRAW );
  355. }
  356. //Msg( "PUSH ALONG fwd=%f, rt=%f\n", fwd, rt );
  357. foundResult = true;
  358. }
  359. else
  360. {
  361. // try moving directly away from the object
  362. Vector vTestPosition = GetAbsOrigin() - dirToObject * radius * 2;
  363. if ( TestMove( vTestPosition, size.z * 2, radius * 2, obj->GetAbsOrigin(), vMoveDir ) )
  364. {
  365. fwd = currentdir.Dot( -dirToObject );
  366. rt = rightdir.Dot( -dirToObject );
  367. foundResult = true;
  368. //Msg( "PUSH AWAY fwd=%f, rt=%f\n", fwd, rt );
  369. }
  370. }
  371. }
  372. if ( !foundResult )
  373. {
  374. // test if we can move through the object
  375. Vector vTestPosition = GetAbsOrigin() - vMoveDir * radius * 2;
  376. fwd = currentdir.Dot( -vMoveDir );
  377. rt = rightdir.Dot( -vMoveDir );
  378. if ( flDist < objectradius )
  379. {
  380. obj->AddEffects( EF_NODRAW );
  381. }
  382. //Msg( "PUSH THROUGH fwd=%f, rt=%f\n", fwd, rt );
  383. foundResult = true;
  384. }
  385. // If running, then do a lot more sideways veer since we're not going to do anything to
  386. // forward velocity
  387. if ( istryingtomove )
  388. {
  389. sidescale = 6.0f;
  390. }
  391. if ( flVelProduct > 0.0f && flDirProduct > 0.0f )
  392. {
  393. sidescale = 0.1f;
  394. }
  395. float force = 1.0f;
  396. float forward = forwardscale * fwd * force * AVOID_SPEED;
  397. float side = sidescale * rt * force * AVOID_SPEED;
  398. adjustforwardmove += forward;
  399. adjustsidemove += side;
  400. }
  401. pCmd->forwardmove += adjustforwardmove;
  402. pCmd->sidemove += adjustsidemove;
  403. // Clamp the move to within legal limits, preserving direction. This is a little
  404. // complicated because we have different limits for forward, back, and side
  405. //Msg( "PRECLAMP: forwardmove=%f, sidemove=%f\n", pCmd->forwardmove, pCmd->sidemove );
  406. float flForwardScale = 1.0f;
  407. if ( pCmd->forwardmove > fabs( cl_forwardspeed.GetFloat() ) )
  408. {
  409. flForwardScale = fabs( cl_forwardspeed.GetFloat() ) / pCmd->forwardmove;
  410. }
  411. else if ( pCmd->forwardmove < -fabs( cl_backspeed.GetFloat() ) )
  412. {
  413. flForwardScale = fabs( cl_backspeed.GetFloat() ) / fabs( pCmd->forwardmove );
  414. }
  415. float flSideScale = 1.0f;
  416. if ( fabs( pCmd->sidemove ) > fabs( cl_sidespeed.GetFloat() ) )
  417. {
  418. flSideScale = fabs( cl_sidespeed.GetFloat() ) / fabs( pCmd->sidemove );
  419. }
  420. float flScale = MIN( flForwardScale, flSideScale );
  421. pCmd->forwardmove *= flScale;
  422. pCmd->sidemove *= flScale;
  423. //Msg( "POSTCLAMP: forwardmove=%f, sidemove=%f\n", pCmd->forwardmove, pCmd->sidemove );
  424. }
  425. void C_BaseHLPlayer::PerformClientSideNPCSpeedModifiers( float flFrameTime, CUserCmd *pCmd )
  426. {
  427. if ( m_hClosestNPC == NULL )
  428. {
  429. if ( m_flSpeedMod != cl_forwardspeed.GetFloat() )
  430. {
  431. float flDeltaTime = (m_flSpeedModTime - gpGlobals->curtime);
  432. m_flSpeedMod = RemapValClamped( flDeltaTime, cl_npc_speedmod_outtime.GetFloat(), 0, m_flExitSpeedMod, cl_forwardspeed.GetFloat() );
  433. }
  434. }
  435. else
  436. {
  437. C_AI_BaseNPC *pNPC = dynamic_cast< C_AI_BaseNPC *>( m_hClosestNPC.Get() );
  438. if ( pNPC )
  439. {
  440. float flDist = (GetAbsOrigin() - pNPC->GetAbsOrigin()).LengthSqr();
  441. bool bShouldModSpeed = false;
  442. // Within range?
  443. if ( flDist < pNPC->GetSpeedModifyRadius() )
  444. {
  445. // Now, only slowdown if we're facing & running parallel to the target's movement
  446. // Facing check first (in 2D)
  447. Vector vecTargetOrigin = pNPC->GetAbsOrigin();
  448. Vector los = ( vecTargetOrigin - EyePosition() );
  449. los.z = 0;
  450. VectorNormalize( los );
  451. Vector facingDir;
  452. AngleVectors( GetAbsAngles(), &facingDir );
  453. float flDot = DotProduct( los, facingDir );
  454. if ( flDot > 0.8 )
  455. {
  456. /*
  457. // Velocity check (abort if the target isn't moving)
  458. Vector vecTargetVelocity;
  459. pNPC->EstimateAbsVelocity( vecTargetVelocity );
  460. float flSpeed = VectorNormalize(vecTargetVelocity);
  461. Vector vecMyVelocity = GetAbsVelocity();
  462. VectorNormalize(vecMyVelocity);
  463. if ( flSpeed > 1.0 )
  464. {
  465. // Velocity roughly parallel?
  466. if ( DotProduct(vecTargetVelocity,vecMyVelocity) > 0.4 )
  467. {
  468. bShouldModSpeed = true;
  469. }
  470. }
  471. else
  472. {
  473. // NPC's not moving, slow down if we're moving at him
  474. //Msg("Dot: %.2f\n", DotProduct( los, vecMyVelocity ) );
  475. if ( DotProduct( los, vecMyVelocity ) > 0.8 )
  476. {
  477. bShouldModSpeed = true;
  478. }
  479. }
  480. */
  481. bShouldModSpeed = true;
  482. }
  483. }
  484. if ( !bShouldModSpeed )
  485. {
  486. m_hClosestNPC = NULL;
  487. m_flSpeedModTime = gpGlobals->curtime + cl_npc_speedmod_outtime.GetFloat();
  488. m_flExitSpeedMod = m_flSpeedMod;
  489. return;
  490. }
  491. else
  492. {
  493. if ( m_flSpeedMod != pNPC->GetSpeedModifySpeed() )
  494. {
  495. float flDeltaTime = (m_flSpeedModTime - gpGlobals->curtime);
  496. m_flSpeedMod = RemapValClamped( flDeltaTime, cl_npc_speedmod_intime.GetFloat(), 0, cl_forwardspeed.GetFloat(), pNPC->GetSpeedModifySpeed() );
  497. }
  498. }
  499. }
  500. }
  501. if ( pCmd->forwardmove > 0.0f )
  502. {
  503. pCmd->forwardmove = clamp( pCmd->forwardmove, -m_flSpeedMod, m_flSpeedMod );
  504. }
  505. else
  506. {
  507. pCmd->forwardmove = clamp( pCmd->forwardmove, -m_flSpeedMod, m_flSpeedMod );
  508. }
  509. pCmd->sidemove = clamp( pCmd->sidemove, -m_flSpeedMod, m_flSpeedMod );
  510. //Msg( "fwd %f right %f\n", pCmd->forwardmove, pCmd->sidemove );
  511. }
  512. //-----------------------------------------------------------------------------
  513. // Purpose: Input handling
  514. //-----------------------------------------------------------------------------
  515. bool C_BaseHLPlayer::CreateMove( float flInputSampleTime, CUserCmd *pCmd )
  516. {
  517. bool bResult = BaseClass::CreateMove( flInputSampleTime, pCmd );
  518. if ( !IsInAVehicle() )
  519. {
  520. PerformClientSideObstacleAvoidance( TICK_INTERVAL, pCmd );
  521. PerformClientSideNPCSpeedModifiers( TICK_INTERVAL, pCmd );
  522. }
  523. return bResult;
  524. }
  525. //-----------------------------------------------------------------------------
  526. // Purpose: Input handling
  527. //-----------------------------------------------------------------------------
  528. void C_BaseHLPlayer::BuildTransformations( CStudioHdr *hdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed )
  529. {
  530. BaseClass::BuildTransformations( hdr, pos, q, cameraTransform, boneMask, boneComputed );
  531. BuildFirstPersonMeathookTransformations( hdr, pos, q, cameraTransform, boneMask, boneComputed, "ValveBiped.Bip01_Head1" );
  532. }