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.

406 lines
9.6 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "c_sdk_player.h"
  8. #include "weapon_sdkbase.h"
  9. #include "c_basetempentity.h"
  10. #if defined( CSDKPlayer )
  11. #undef CSDKPlayer
  12. #endif
  13. // -------------------------------------------------------------------------------- //
  14. // Player animation event. Sent to the client when a player fires, jumps, reloads, etc..
  15. // -------------------------------------------------------------------------------- //
  16. class C_TEPlayerAnimEvent : public C_BaseTempEntity
  17. {
  18. public:
  19. DECLARE_CLASS( C_TEPlayerAnimEvent, C_BaseTempEntity );
  20. DECLARE_CLIENTCLASS();
  21. virtual void PostDataUpdate( DataUpdateType_t updateType )
  22. {
  23. // Create the effect.
  24. C_SDKPlayer *pPlayer = dynamic_cast< C_SDKPlayer* >( m_hPlayer.Get() );
  25. if ( pPlayer && !pPlayer->IsDormant() )
  26. {
  27. pPlayer->DoAnimationEvent( (PlayerAnimEvent_t)m_iEvent.Get(), m_nData );
  28. }
  29. }
  30. public:
  31. CNetworkHandle( CBasePlayer, m_hPlayer );
  32. CNetworkVar( int, m_iEvent );
  33. CNetworkVar( int, m_nData );
  34. };
  35. IMPLEMENT_CLIENTCLASS_EVENT( C_TEPlayerAnimEvent, DT_TEPlayerAnimEvent, CTEPlayerAnimEvent );
  36. BEGIN_RECV_TABLE_NOBASE( C_TEPlayerAnimEvent, DT_TEPlayerAnimEvent )
  37. RecvPropEHandle( RECVINFO( m_hPlayer ) ),
  38. RecvPropInt( RECVINFO( m_iEvent ) ),
  39. RecvPropInt( RECVINFO( m_nData ) )
  40. END_RECV_TABLE()
  41. BEGIN_RECV_TABLE_NOBASE( C_SDKPlayer, DT_SDKLocalPlayerExclusive )
  42. RecvPropInt( RECVINFO( m_iShotsFired ) ),
  43. END_RECV_TABLE()
  44. IMPLEMENT_CLIENTCLASS_DT( C_SDKPlayer, DT_SDKPlayer, CSDKPlayer )
  45. RecvPropDataTable( "sdklocaldata", 0, 0, &REFERENCE_RECV_TABLE(DT_SDKLocalPlayerExclusive) ),
  46. RecvPropFloat( RECVINFO( m_angEyeAngles[0] ) ),
  47. RecvPropFloat( RECVINFO( m_angEyeAngles[1] ) ),
  48. RecvPropInt( RECVINFO( m_iThrowGrenadeCounter ) ),
  49. RecvPropEHandle( RECVINFO( m_hRagdoll ) ),
  50. END_RECV_TABLE()
  51. BEGIN_PREDICTION_DATA( C_SDKPlayer )
  52. DEFINE_PRED_FIELD( m_flCycle, FIELD_FLOAT, FTYPEDESC_OVERRIDE | FTYPEDESC_PRIVATE | FTYPEDESC_NOERRORCHECK ),
  53. DEFINE_PRED_FIELD( m_iShotsFired, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  54. END_PREDICTION_DATA()
  55. class C_SDKRagdoll : public C_BaseAnimatingOverlay
  56. {
  57. public:
  58. DECLARE_CLASS( C_SDKRagdoll, C_BaseAnimatingOverlay );
  59. DECLARE_CLIENTCLASS();
  60. C_SDKRagdoll();
  61. ~C_SDKRagdoll();
  62. virtual void OnDataChanged( DataUpdateType_t type );
  63. int GetPlayerEntIndex() const;
  64. IRagdoll* GetIRagdoll() const;
  65. void ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName );
  66. private:
  67. C_SDKRagdoll( const C_SDKRagdoll & ) {}
  68. void Interp_Copy( C_BaseAnimatingOverlay *pSourceEntity );
  69. void CreateRagdoll();
  70. private:
  71. EHANDLE m_hPlayer;
  72. CNetworkVector( m_vecRagdollVelocity );
  73. CNetworkVector( m_vecRagdollOrigin );
  74. };
  75. IMPLEMENT_CLIENTCLASS_DT_NOBASE( C_SDKRagdoll, DT_SDKRagdoll, CSDKRagdoll )
  76. RecvPropVector( RECVINFO(m_vecRagdollOrigin) ),
  77. RecvPropEHandle( RECVINFO( m_hPlayer ) ),
  78. RecvPropInt( RECVINFO( m_nModelIndex ) ),
  79. RecvPropInt( RECVINFO(m_nForceBone) ),
  80. RecvPropVector( RECVINFO(m_vecForce) ),
  81. RecvPropVector( RECVINFO( m_vecRagdollVelocity ) )
  82. END_RECV_TABLE()
  83. C_SDKRagdoll::C_SDKRagdoll()
  84. {
  85. }
  86. C_SDKRagdoll::~C_SDKRagdoll()
  87. {
  88. PhysCleanupFrictionSounds( this );
  89. }
  90. void C_SDKRagdoll::Interp_Copy( C_BaseAnimatingOverlay *pSourceEntity )
  91. {
  92. if ( !pSourceEntity )
  93. return;
  94. VarMapping_t *pSrc = pSourceEntity->GetVarMapping();
  95. VarMapping_t *pDest = GetVarMapping();
  96. // Find all the VarMapEntry_t's that represent the same variable.
  97. for ( int i = 0; i < pDest->m_Entries.Count(); i++ )
  98. {
  99. VarMapEntry_t *pDestEntry = &pDest->m_Entries[i];
  100. for ( int j=0; j < pSrc->m_Entries.Count(); j++ )
  101. {
  102. VarMapEntry_t *pSrcEntry = &pSrc->m_Entries[j];
  103. if ( !Q_strcmp( pSrcEntry->watcher->GetDebugName(),
  104. pDestEntry->watcher->GetDebugName() ) )
  105. {
  106. pDestEntry->watcher->Copy( pSrcEntry->watcher );
  107. break;
  108. }
  109. }
  110. }
  111. }
  112. void C_SDKRagdoll::ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName )
  113. {
  114. IPhysicsObject *pPhysicsObject = VPhysicsGetObject();
  115. if( !pPhysicsObject )
  116. return;
  117. Vector dir = pTrace->endpos - pTrace->startpos;
  118. if ( iDamageType == DMG_BLAST )
  119. {
  120. dir *= 4000; // adjust impact strenght
  121. // apply force at object mass center
  122. pPhysicsObject->ApplyForceCenter( dir );
  123. }
  124. else
  125. {
  126. Vector hitpos;
  127. VectorMA( pTrace->startpos, pTrace->fraction, dir, hitpos );
  128. VectorNormalize( dir );
  129. dir *= 4000; // adjust impact strenght
  130. // apply force where we hit it
  131. pPhysicsObject->ApplyForceOffset( dir, hitpos );
  132. }
  133. m_pRagdoll->ResetRagdollSleepAfterTime();
  134. }
  135. void C_SDKRagdoll::CreateRagdoll()
  136. {
  137. // First, initialize all our data. If we have the player's entity on our client,
  138. // then we can make ourselves start out exactly where the player is.
  139. C_SDKPlayer *pPlayer = dynamic_cast< C_SDKPlayer* >( m_hPlayer.Get() );
  140. if ( pPlayer && !pPlayer->IsDormant() )
  141. {
  142. // move my current model instance to the ragdoll's so decals are preserved.
  143. pPlayer->SnatchModelInstance( this );
  144. VarMapping_t *varMap = GetVarMapping();
  145. // Copy all the interpolated vars from the player entity.
  146. // The entity uses the interpolated history to get bone velocity.
  147. bool bRemotePlayer = (pPlayer != C_BasePlayer::GetLocalPlayer());
  148. if ( bRemotePlayer )
  149. {
  150. Interp_Copy( pPlayer );
  151. SetAbsAngles( pPlayer->GetRenderAngles() );
  152. GetRotationInterpolator().Reset();
  153. m_flAnimTime = pPlayer->m_flAnimTime;
  154. SetSequence( pPlayer->GetSequence() );
  155. m_flPlaybackRate = pPlayer->GetPlaybackRate();
  156. }
  157. else
  158. {
  159. // This is the local player, so set them in a default
  160. // pose and slam their velocity, angles and origin
  161. SetAbsOrigin( m_vecRagdollOrigin );
  162. SetAbsAngles( pPlayer->GetRenderAngles() );
  163. SetAbsVelocity( m_vecRagdollVelocity );
  164. int iSeq = LookupSequence( "walk_lower" );
  165. if ( iSeq == -1 )
  166. {
  167. Assert( false ); // missing walk_lower?
  168. iSeq = 0;
  169. }
  170. SetSequence( iSeq ); // walk_lower, basic pose
  171. SetCycle( 0.0 );
  172. Interp_Reset( varMap );
  173. }
  174. }
  175. else
  176. {
  177. // overwrite network origin so later interpolation will
  178. // use this position
  179. SetNetworkOrigin( m_vecRagdollOrigin );
  180. SetAbsOrigin( m_vecRagdollOrigin );
  181. SetAbsVelocity( m_vecRagdollVelocity );
  182. Interp_Reset( GetVarMapping() );
  183. }
  184. SetModelIndex( m_nModelIndex );
  185. // Make us a ragdoll..
  186. m_nRenderFX = kRenderFxRagdoll;
  187. matrix3x4_t boneDelta0[MAXSTUDIOBONES];
  188. matrix3x4_t boneDelta1[MAXSTUDIOBONES];
  189. matrix3x4_t currentBones[MAXSTUDIOBONES];
  190. const float boneDt = 0.05f;
  191. if ( pPlayer && !pPlayer->IsDormant() )
  192. {
  193. pPlayer->GetRagdollInitBoneArrays( boneDelta0, boneDelta1, currentBones, boneDt );
  194. }
  195. else
  196. {
  197. GetRagdollInitBoneArrays( boneDelta0, boneDelta1, currentBones, boneDt );
  198. }
  199. InitAsClientRagdoll( boneDelta0, boneDelta1, currentBones, boneDt );
  200. }
  201. void C_SDKRagdoll::OnDataChanged( DataUpdateType_t type )
  202. {
  203. BaseClass::OnDataChanged( type );
  204. if ( type == DATA_UPDATE_CREATED )
  205. {
  206. CreateRagdoll();
  207. }
  208. }
  209. IRagdoll* C_SDKRagdoll::GetIRagdoll() const
  210. {
  211. return m_pRagdoll;
  212. }
  213. C_BaseAnimating * C_SDKPlayer::BecomeRagdollOnClient()
  214. {
  215. // Let the C_CSRagdoll entity do this.
  216. // m_builtRagdoll = true;
  217. return NULL;
  218. }
  219. IRagdoll* C_SDKPlayer::GetRepresentativeRagdoll() const
  220. {
  221. if ( m_hRagdoll.Get() )
  222. {
  223. C_SDKRagdoll *pRagdoll = (C_SDKRagdoll*)m_hRagdoll.Get();
  224. return pRagdoll->GetIRagdoll();
  225. }
  226. else
  227. {
  228. return NULL;
  229. }
  230. }
  231. C_SDKPlayer::C_SDKPlayer() :
  232. m_iv_angEyeAngles( "C_SDKPlayer::m_iv_angEyeAngles" )
  233. {
  234. m_PlayerAnimState = CreatePlayerAnimState( this, this, LEGANIM_9WAY, true );
  235. m_angEyeAngles.Init();
  236. AddVar( &m_angEyeAngles, &m_iv_angEyeAngles, LATCH_SIMULATION_VAR );
  237. }
  238. C_SDKPlayer::~C_SDKPlayer()
  239. {
  240. m_PlayerAnimState->Release();
  241. }
  242. C_SDKPlayer* C_SDKPlayer::GetLocalSDKPlayer()
  243. {
  244. return ToSDKPlayer( C_BasePlayer::GetLocalPlayer() );
  245. }
  246. const QAngle& C_SDKPlayer::GetRenderAngles()
  247. {
  248. if ( IsRagdoll() )
  249. {
  250. return vec3_angle;
  251. }
  252. else
  253. {
  254. return m_PlayerAnimState->GetRenderAngles();
  255. }
  256. }
  257. void C_SDKPlayer::UpdateClientSideAnimation()
  258. {
  259. // Update the animation data. It does the local check here so this works when using
  260. // a third-person camera (and we don't have valid player angles).
  261. if ( this == C_SDKPlayer::GetLocalSDKPlayer() )
  262. m_PlayerAnimState->Update( EyeAngles()[YAW], m_angEyeAngles[PITCH] );
  263. else
  264. m_PlayerAnimState->Update( m_angEyeAngles[YAW], m_angEyeAngles[PITCH] );
  265. BaseClass::UpdateClientSideAnimation();
  266. }
  267. void C_SDKPlayer::PostDataUpdate( DataUpdateType_t updateType )
  268. {
  269. // C_BaseEntity assumes we're networking the entity's angles, so pretend that it
  270. // networked the same value we already have.
  271. SetNetworkAngles( GetLocalAngles() );
  272. BaseClass::PostDataUpdate( updateType );
  273. }
  274. void C_SDKPlayer::OnDataChanged( DataUpdateType_t type )
  275. {
  276. BaseClass::OnDataChanged( type );
  277. if ( type == DATA_UPDATE_CREATED )
  278. {
  279. SetNextClientThink( CLIENT_THINK_ALWAYS );
  280. }
  281. UpdateVisibility();
  282. }
  283. void C_SDKPlayer::DoAnimationEvent( PlayerAnimEvent_t event, int nData )
  284. {
  285. if ( event == PLAYERANIMEVENT_THROW_GRENADE )
  286. {
  287. // Let the server handle this event. It will update m_iThrowGrenadeCounter and the client will
  288. // pick up the event in CCSPlayerAnimState.
  289. }
  290. else
  291. {
  292. m_PlayerAnimState->DoAnimationEvent( event, nData );
  293. }
  294. }
  295. bool C_SDKPlayer::ShouldDraw( void )
  296. {
  297. // If we're dead, our ragdoll will be drawn for us instead.
  298. if ( !IsAlive() )
  299. return false;
  300. if( GetTeamNumber() == TEAM_SPECTATOR )
  301. return false;
  302. if( IsLocalPlayer() && IsRagdoll() )
  303. return true;
  304. return BaseClass::ShouldDraw();
  305. }
  306. CWeaponSDKBase* C_SDKPlayer::GetActiveSDKWeapon() const
  307. {
  308. return dynamic_cast< CWeaponSDKBase* >( GetActiveWeapon() );
  309. }