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.

602 lines
14 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "cbase.h"
  9. #include "c_hl1mp_player.h"
  10. #include "c_basetempentity.h"
  11. #include "iinput.h"
  12. // Don't alias here
  13. #if defined( CHL1MP_Player )
  14. #undef CHL1MP_Player
  15. #endif
  16. //////////////////////////////////////////////////////////////////////
  17. class C_TEPlayerAnimEvent : public C_BaseTempEntity
  18. {
  19. public:
  20. DECLARE_CLASS( C_TEPlayerAnimEvent, C_BaseTempEntity );
  21. DECLARE_CLIENTCLASS();
  22. virtual void PostDataUpdate( DataUpdateType_t updateType )
  23. {
  24. // Create the effect.
  25. C_HL1MP_Player *pPlayer = dynamic_cast< C_HL1MP_Player* >( m_hPlayer.Get() );
  26. if ( pPlayer && !pPlayer->IsDormant() )
  27. {
  28. pPlayer->DoAnimationEvent( (PlayerAnimEvent_t)m_iEvent.Get(), m_nData );
  29. }
  30. }
  31. public:
  32. CNetworkHandle( CBasePlayer, m_hPlayer );
  33. CNetworkVar( int, m_iEvent );
  34. CNetworkVar( int, m_nData );
  35. };
  36. IMPLEMENT_CLIENTCLASS_EVENT( C_TEPlayerAnimEvent, DT_TEPlayerAnimEvent, CTEPlayerAnimEvent );
  37. // ------------------------------------------------------------------------------------------ //
  38. // Data tables and prediction tables.
  39. // ------------------------------------------------------------------------------------------ //
  40. BEGIN_RECV_TABLE_NOBASE( C_TEPlayerAnimEvent, DT_TEPlayerAnimEvent )
  41. RecvPropEHandle( RECVINFO( m_hPlayer ) ),
  42. RecvPropInt( RECVINFO( m_iEvent ) ),
  43. RecvPropInt( RECVINFO( m_nData ) )
  44. END_RECV_TABLE()
  45. IMPLEMENT_CLIENTCLASS_DT( C_HL1MP_Player, DT_HL1MP_Player, CHL1MP_Player )
  46. RecvPropFloat( RECVINFO( m_angEyeAngles[0] ) ),
  47. RecvPropFloat( RECVINFO( m_angEyeAngles[1] ) ),
  48. RecvPropEHandle( RECVINFO( m_hRagdoll ) ),
  49. RecvPropInt( RECVINFO( m_iSpawnInterpCounter ) ),
  50. RecvPropInt( RECVINFO( m_iRealSequence ) ),
  51. // RecvPropDataTable( RECVINFO_DT( m_Shared ), 0, &REFERENCE_RECV_TABLE( DT_TFCPlayerShared ) )
  52. END_RECV_TABLE()
  53. BEGIN_PREDICTION_DATA( C_HL1MP_Player )
  54. END_PREDICTION_DATA()
  55. /////////////////////////////////////////////////////////////////////
  56. static ConVar cl_playermodel( "cl_playermodel", "none", FCVAR_USERINFO | FCVAR_ARCHIVE | FCVAR_SERVER_CAN_EXECUTE, "Default Player Model");
  57. C_HL1MP_Player::C_HL1MP_Player( void ) :
  58. m_iv_angEyeAngles( "C_HL1MP_Player::m_iv_angEyeAngles" )
  59. {
  60. m_PlayerAnimState = CreatePlayerAnimState( this );
  61. m_angEyeAngles.Init();
  62. m_fLastPredFreeze = -1;
  63. // cant interpolate ... buggy? it keeps resetting the angle to 0,0,0
  64. // AddVar( &m_angEyeAngles, &m_iv_angEyeAngles, LATCH_SIMULATION_VAR );
  65. }
  66. C_HL1MP_Player::~C_HL1MP_Player()
  67. {
  68. m_PlayerAnimState->Release();
  69. }
  70. const QAngle& C_HL1MP_Player::GetRenderAngles()
  71. {
  72. if ( IsRagdoll() )
  73. {
  74. return vec3_angle;
  75. }
  76. else
  77. {
  78. return m_PlayerAnimState->GetRenderAngles();
  79. }
  80. }
  81. void C_HL1MP_Player::UpdateClientSideAnimation()
  82. {
  83. // Update the animation data. It does the local check here so this works when using
  84. // a third-person camera (and we don't have valid player angles).
  85. if ( this == C_BasePlayer::GetLocalPlayer() )
  86. m_PlayerAnimState->Update( EyeAngles()[YAW], m_angEyeAngles[PITCH] );
  87. else
  88. m_PlayerAnimState->Update( m_angEyeAngles[YAW], m_angEyeAngles[PITCH] );
  89. BaseClass::UpdateClientSideAnimation();
  90. }
  91. void C_HL1MP_Player::DoAnimationEvent( PlayerAnimEvent_t event, int nData )
  92. {
  93. m_PlayerAnimState->DoAnimationEvent( event, nData );
  94. }
  95. void C_HL1MP_Player::ProcessMuzzleFlashEvent()
  96. {
  97. #if 0
  98. // Reenable when the weapons have muzzle flash attachments in the right spot.
  99. if ( this != C_BasePlayer::GetLocalPlayer() )
  100. {
  101. Vector vAttachment;
  102. QAngle dummyAngles;
  103. C_WeaponTFCBase *pWeapon = m_Shared.GetActiveTFCWeapon();
  104. if ( pWeapon )
  105. {
  106. int iAttachment = pWeapon->LookupAttachment( "muzzle_flash" );
  107. if ( iAttachment > 0 )
  108. {
  109. float flScale = 1;
  110. pWeapon->GetAttachment( iAttachment, vAttachment, dummyAngles );
  111. // The way the models are setup, the up vector points along the barrel.
  112. Vector vForward, vRight, vUp;
  113. AngleVectors( dummyAngles, &vForward, &vRight, &vUp );
  114. VectorAngles( vUp, dummyAngles );
  115. FX_MuzzleEffect( vAttachment, dummyAngles, flScale, 0, NULL, true );
  116. }
  117. }
  118. }
  119. Vector vAttachment;
  120. QAngle dummyAngles;
  121. bool bFoundAttachment = GetAttachment( 1, vAttachment, dummyAngles );
  122. // If we have an attachment, then stick a light on it.
  123. if ( bFoundAttachment )
  124. {
  125. dlight_t *el = effects->CL_AllocDlight( LIGHT_INDEX_MUZZLEFLASH + index );
  126. el->origin = vAttachment;
  127. el->radius = 24;
  128. el->decay = el->radius / 0.05f;
  129. el->die = gpGlobals->curtime + 0.05f;
  130. el->color.r = 255;
  131. el->color.g = 192;
  132. el->color.b = 64;
  133. el->color.exponent = 5;
  134. }
  135. #endif
  136. }
  137. void C_HL1MP_Player::Spawn( void )
  138. {
  139. BaseClass::Spawn();
  140. // SetModel( "models/player/mp/barney/barney.mdl" );
  141. m_iSpawnInterpCounterCache = 0;
  142. UpdateVisibility();
  143. }
  144. void C_HL1MP_Player::AddEntity( void )
  145. {
  146. BaseClass::AddEntity();
  147. //m_PlayerAnimState.Update();
  148. // SetLocalAnglesDim( X_INDEX, 0 );
  149. }
  150. void C_HL1MP_Player::OnDataChanged( DataUpdateType_t type )
  151. {
  152. BaseClass::OnDataChanged( type );
  153. if ( type == DATA_UPDATE_CREATED )
  154. {
  155. SetNextClientThink( CLIENT_THINK_ALWAYS );
  156. }
  157. UpdateVisibility();
  158. }
  159. C_BaseAnimating *C_HL1MP_Player::BecomeRagdollOnClient()
  160. {
  161. // Handled elsewhere
  162. return NULL;
  163. }
  164. void C_HL1MP_Player::PreThink( void )
  165. {
  166. BaseClass::PreThink();
  167. return;
  168. QAngle vTempAngles = GetLocalAngles();
  169. if ( GetLocalPlayer() == this )
  170. {
  171. vTempAngles[PITCH] = EyeAngles()[PITCH];
  172. }
  173. else
  174. {
  175. vTempAngles[PITCH] = m_angEyeAngles[PITCH];
  176. }
  177. if ( vTempAngles[YAW] < 0.0f )
  178. {
  179. vTempAngles[YAW] += 360.0f;
  180. }
  181. SetLocalAngles( vTempAngles );
  182. BaseClass::PreThink();
  183. #if 0
  184. HandleSpeedChanges();
  185. if ( m_HL2Local.m_flSuitPower <= 0.0f )
  186. {
  187. if( IsSprinting() )
  188. {
  189. StopSprinting();
  190. }
  191. }
  192. #endif
  193. }
  194. void C_HL1MP_Player::PostDataUpdate( DataUpdateType_t updateType )
  195. {
  196. // C_BaseEntity assumes we're networking the entity's angles, so pretend that it
  197. // networked the same value we already have.
  198. SetNetworkAngles( GetLocalAngles() );
  199. BaseClass::PostDataUpdate( updateType );
  200. }
  201. void C_HL1MP_Player::ClientThink( void )
  202. {
  203. BaseClass::ClientThink();
  204. // m_PlayerAnimState.Update();
  205. }
  206. //HL1MPRAGDOLL
  207. IMPLEMENT_CLIENTCLASS_DT_NOBASE( C_HL1MPRagdoll, DT_HL1MPRagdoll, CHL1MPRagdoll )
  208. RecvPropVector( RECVINFO(m_vecRagdollOrigin) ),
  209. RecvPropEHandle( RECVINFO( m_hPlayer ) ),
  210. RecvPropInt( RECVINFO( m_nModelIndex ) ),
  211. RecvPropInt( RECVINFO(m_nForceBone) ),
  212. RecvPropVector( RECVINFO(m_vecForce) ),
  213. RecvPropVector( RECVINFO( m_vecRagdollVelocity ) )
  214. END_RECV_TABLE()
  215. C_HL1MPRagdoll::C_HL1MPRagdoll()
  216. {
  217. }
  218. C_HL1MPRagdoll::~C_HL1MPRagdoll()
  219. {
  220. PhysCleanupFrictionSounds( this );
  221. if ( m_hPlayer )
  222. {
  223. m_hPlayer->CreateModelInstance();
  224. }
  225. }
  226. void C_HL1MPRagdoll::Interp_Copy( C_BaseAnimatingOverlay *pSourceEntity )
  227. {
  228. if ( !pSourceEntity )
  229. return;
  230. VarMapping_t *pSrc = pSourceEntity->GetVarMapping();
  231. VarMapping_t *pDest = GetVarMapping();
  232. // Find all the VarMapEntry_t's that represent the same variable.
  233. for ( int i = 0; i < pDest->m_Entries.Count(); i++ )
  234. {
  235. VarMapEntry_t *pDestEntry = &pDest->m_Entries[i];
  236. const char *pszName = pDestEntry->watcher->GetDebugName();
  237. for ( int j=0; j < pSrc->m_Entries.Count(); j++ )
  238. {
  239. VarMapEntry_t *pSrcEntry = &pSrc->m_Entries[j];
  240. if ( !Q_strcmp( pSrcEntry->watcher->GetDebugName(), pszName ) )
  241. {
  242. pDestEntry->watcher->Copy( pSrcEntry->watcher );
  243. break;
  244. }
  245. }
  246. }
  247. }
  248. void C_HL1MPRagdoll::ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName )
  249. {
  250. IPhysicsObject *pPhysicsObject = VPhysicsGetObject();
  251. if( !pPhysicsObject )
  252. return;
  253. Vector dir = pTrace->endpos - pTrace->startpos;
  254. if ( iDamageType == DMG_BLAST )
  255. {
  256. dir *= 4000; // adjust impact strenght
  257. // apply force at object mass center
  258. pPhysicsObject->ApplyForceCenter( dir );
  259. }
  260. else
  261. {
  262. Vector hitpos;
  263. VectorMA( pTrace->startpos, pTrace->fraction, dir, hitpos );
  264. VectorNormalize( dir );
  265. dir *= 4000; // adjust impact strenght
  266. // apply force where we hit it
  267. pPhysicsObject->ApplyForceOffset( dir, hitpos );
  268. }
  269. m_pRagdoll->ResetRagdollSleepAfterTime();
  270. }
  271. void C_HL1MP_Player::CalcView( Vector &eyeOrigin, QAngle &eyeAngles, float &zNear, float &zFar, float &fov )
  272. {
  273. if ( m_lifeState != LIFE_ALIVE )
  274. {
  275. Vector origin = EyePosition();
  276. IRagdoll *pRagdoll = GetRepresentativeRagdoll();
  277. if ( pRagdoll )
  278. {
  279. origin = pRagdoll->GetRagdollOrigin();
  280. origin.z += VEC_DEAD_VIEWHEIGHT_SCALED( this ).z; // look over ragdoll, not through
  281. }
  282. BaseClass::CalcView( eyeOrigin, eyeAngles, zNear, zFar, fov );
  283. eyeOrigin = origin;
  284. Vector vForward;
  285. AngleVectors( eyeAngles, &vForward );
  286. VectorNormalize( vForward );
  287. VectorMA( origin, -CHASE_CAM_DISTANCE_MAX, vForward, eyeOrigin );
  288. Vector WALL_MIN( -WALL_OFFSET, -WALL_OFFSET, -WALL_OFFSET );
  289. Vector WALL_MAX( WALL_OFFSET, WALL_OFFSET, WALL_OFFSET );
  290. trace_t trace; // clip against world
  291. C_BaseEntity::PushEnableAbsRecomputations( false ); // HACK don't recompute positions while doing RayTrace
  292. UTIL_TraceHull( origin, eyeOrigin, WALL_MIN, WALL_MAX, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &trace );
  293. C_BaseEntity::PopEnableAbsRecomputations();
  294. if (trace.fraction < 1.0)
  295. {
  296. eyeOrigin = trace.endpos;
  297. }
  298. return;
  299. }
  300. BaseClass::CalcView( eyeOrigin, eyeAngles, zNear, zFar, fov );
  301. }
  302. IRagdoll* C_HL1MP_Player::GetRepresentativeRagdoll() const
  303. {
  304. if ( m_hRagdoll.Get() )
  305. {
  306. C_HL1MPRagdoll *pRagdoll = (C_HL1MPRagdoll*)m_hRagdoll.Get();
  307. return pRagdoll->GetIRagdoll();
  308. }
  309. else
  310. {
  311. return NULL;
  312. }
  313. }
  314. void C_HL1MPRagdoll::CreateHL1MPRagdoll( void )
  315. {
  316. // First, initialize all our data. If we have the player's entity on our client,
  317. // then we can make ourselves start out exactly where the player is.
  318. C_HL1MP_Player *pPlayer = dynamic_cast< C_HL1MP_Player* >( m_hPlayer.Get() );
  319. if ( pPlayer && !pPlayer->IsDormant() )
  320. {
  321. // move my current model instance to the ragdoll's so decals are preserved.
  322. pPlayer->SnatchModelInstance( this );
  323. VarMapping_t *varMap = GetVarMapping();
  324. // Copy all the interpolated vars from the player entity.
  325. // The entity uses the interpolated history to get bone velocity.
  326. bool bRemotePlayer = (pPlayer != C_BasePlayer::GetLocalPlayer());
  327. if ( bRemotePlayer )
  328. {
  329. Interp_Copy( pPlayer );
  330. SetAbsAngles( pPlayer->GetRenderAngles() );
  331. GetRotationInterpolator().Reset();
  332. m_flAnimTime = pPlayer->m_flAnimTime;
  333. SetSequence( pPlayer->GetSequence() );
  334. m_flPlaybackRate = pPlayer->GetPlaybackRate();
  335. }
  336. else
  337. {
  338. // This is the local player, so set them in a default
  339. // pose and slam their velocity, angles and origin
  340. SetAbsOrigin( m_vecRagdollOrigin );
  341. SetAbsAngles( pPlayer->GetRenderAngles() );
  342. SetAbsVelocity( m_vecRagdollVelocity );
  343. int iSeq = pPlayer->GetSequence();
  344. if ( iSeq == -1 )
  345. {
  346. Assert( false ); // missing walk_lower?
  347. iSeq = 0;
  348. }
  349. SetSequence( iSeq ); // walk_lower, basic pose
  350. SetCycle( 0.0 );
  351. Interp_Reset( varMap );
  352. }
  353. }
  354. else
  355. {
  356. // overwrite network origin so later interpolation will
  357. // use this position
  358. SetNetworkOrigin( m_vecRagdollOrigin );
  359. SetAbsOrigin( m_vecRagdollOrigin );
  360. SetAbsVelocity( m_vecRagdollVelocity );
  361. Interp_Reset( GetVarMapping() );
  362. }
  363. SetModelIndex( m_nModelIndex );
  364. // Make us a ragdoll..
  365. m_nRenderFX = kRenderFxRagdoll;
  366. matrix3x4_t boneDelta0[MAXSTUDIOBONES];
  367. matrix3x4_t boneDelta1[MAXSTUDIOBONES];
  368. matrix3x4_t currentBones[MAXSTUDIOBONES];
  369. const float boneDt = 0.05f;
  370. if ( pPlayer && !pPlayer->IsDormant() )
  371. {
  372. pPlayer->GetRagdollInitBoneArrays( boneDelta0, boneDelta1, currentBones, boneDt );
  373. }
  374. else
  375. {
  376. GetRagdollInitBoneArrays( boneDelta0, boneDelta1, currentBones, boneDt );
  377. }
  378. InitAsClientRagdoll( boneDelta0, boneDelta1, currentBones, boneDt );
  379. }
  380. void C_HL1MPRagdoll::OnDataChanged( DataUpdateType_t type )
  381. {
  382. BaseClass::OnDataChanged( type );
  383. if ( type == DATA_UPDATE_CREATED )
  384. {
  385. CreateHL1MPRagdoll();
  386. }
  387. }
  388. IRagdoll* C_HL1MPRagdoll::GetIRagdoll() const
  389. {
  390. return m_pRagdoll;
  391. }
  392. void C_HL1MPRagdoll::UpdateOnRemove( void )
  393. {
  394. VPhysicsSetObject( NULL );
  395. BaseClass::UpdateOnRemove();
  396. }
  397. //-----------------------------------------------------------------------------
  398. // Purpose: clear out any face/eye values stored in the material system
  399. //-----------------------------------------------------------------------------
  400. void C_HL1MPRagdoll::SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights )
  401. {
  402. BaseClass::SetupWeights( pBoneToWorld, nFlexWeightCount, pFlexWeights, pFlexDelayedWeights );
  403. static float destweight[128];
  404. static bool bIsInited = false;
  405. CStudioHdr *hdr = GetModelPtr();
  406. if ( !hdr )
  407. return;
  408. int nFlexDescCount = hdr->numflexdesc();
  409. if ( nFlexDescCount )
  410. {
  411. Assert( !pFlexDelayedWeights );
  412. memset( pFlexWeights, 0, nFlexWeightCount * sizeof(float) );
  413. }
  414. if ( m_iEyeAttachment > 0 )
  415. {
  416. matrix3x4_t attToWorld;
  417. if (GetAttachment( m_iEyeAttachment, attToWorld ))
  418. {
  419. Vector local, tmp;
  420. local.Init( 1000.0f, 0.0f, 0.0f );
  421. VectorTransform( local, attToWorld, tmp );
  422. modelrender->SetViewTarget( GetModelPtr(), GetBody(), tmp );
  423. }
  424. }
  425. }
  426. bool C_HL1MP_Player::ShouldDraw( void )
  427. {
  428. if ( !IsAlive() )
  429. return false;
  430. if ( IsLocalPlayer() && IsRagdoll() )
  431. return true;
  432. if ( IsRagdoll() )
  433. return false;
  434. return BaseClass::ShouldDraw();
  435. }
  436. bool C_HL1MP_Player::ShouldPredict( void )
  437. {
  438. // Do this before calling into baseclass so prediction data block gets allocated
  439. if ( IsLocalPlayer() )
  440. {
  441. #if 0
  442. // Disable prediction when player hops onto a moving train or elevator :-/
  443. if ( GetGroundEntity() && GetGroundEntity()->GetMoveType() == MOVETYPE_PUSH )
  444. {
  445. Vector vel = GetGroundEntity()->GetLocalVelocity();
  446. if ( vel.Length() > 0.002f )
  447. {
  448. m_fLastPredFreeze = gpGlobals->curtime;
  449. }
  450. }
  451. // disable prediction for 3 seconds after touching a moving entity
  452. if ( ( gpGlobals->curtime - m_fLastPredFreeze ) < 3 )
  453. {
  454. if ( GetPredictable() )
  455. {
  456. QuickShutdownPredictable();
  457. }
  458. return false;
  459. }
  460. if ( !GetPredictable() && IsIntermediateDataAllocated() )
  461. {
  462. QuickInitPredictable();
  463. }
  464. #endif
  465. return true;
  466. }
  467. return false;
  468. }