#include "cbase.h" #include "basenetworkedragdoll_cl.h" IMPLEMENT_CLIENTCLASS_DT_NOBASE( C_BaseNetworkedRagdoll, DT_BaseNetworkedRagdoll, CBaseNetworkedRagdoll ) RecvPropVector( RECVINFO(m_vecRagdollOrigin) ), RecvPropEHandle( RECVINFO( m_hPlayer ) ), RecvPropInt( RECVINFO( m_nModelIndex ) ), RecvPropInt( RECVINFO(m_nForceBone) ), RecvPropVector( RECVINFO(m_vecForce) ), RecvPropVector( RECVINFO( m_vecRagdollVelocity ) ) END_RECV_TABLE() LINK_ENTITY_TO_CLASS( networked_ragdoll, C_BaseNetworkedRagdoll ); C_BaseNetworkedRagdoll::~C_BaseNetworkedRagdoll() { PhysCleanupFrictionSounds( this ); if ( m_hPlayer ) m_hPlayer->CreateModelInstance(); } void C_BaseNetworkedRagdoll::Interp_Copy( C_BaseAnimatingOverlay* pSourceEntity ) { if ( !pSourceEntity ) return; VarMapping_t* pSrc = pSourceEntity->GetVarMapping(); VarMapping_t* pDest = GetVarMapping(); // Find all the VarMapEntry_t's that represent the same variable. for ( int i = 0; i < pDest->m_Entries.Count(); i++ ) { VarMapEntry_t* pDestEntry = &pDest->m_Entries[i]; const char* pszName = pDestEntry->watcher->GetDebugName(); for ( int j=0; j < pSrc->m_Entries.Count(); j++ ) { VarMapEntry_t* pSrcEntry = &pSrc->m_Entries[j]; if ( !Q_strcmp( pSrcEntry->watcher->GetDebugName(), pszName ) ) { pDestEntry->watcher->Copy( pSrcEntry->watcher ); break; } } } } void C_BaseNetworkedRagdoll::ImpactTrace( trace_t* pTrace, int iDamageType, char* pCustomImpactName ) { IPhysicsObject* pPhysicsObject = VPhysicsGetObject(); if( !pPhysicsObject ) return; Vector dir = pTrace->endpos - pTrace->startpos; if ( iDamageType == DMG_BLAST ) { dir *= 4000; // adjust impact strenght // apply force at object mass center pPhysicsObject->ApplyForceCenter( dir ); } else { Vector hitpos; VectorMA( pTrace->startpos, pTrace->fraction, dir, hitpos ); VectorNormalize( dir ); dir *= 4000; // adjust impact strenght // apply force where we hit it pPhysicsObject->ApplyForceOffset( dir, hitpos ); } m_pRagdoll->ResetRagdollSleepAfterTime(); } void C_BaseNetworkedRagdoll::CreateRagdoll( void ) { // First, initialize all our data. If we have the player's entity on our client, // then we can make ourselves start out exactly where the player is. C_BasePlayer* pPlayer = dynamic_cast( m_hPlayer.Get() ); if ( pPlayer && !pPlayer->IsDormant() ) { // move my current model instance to the ragdoll's so decals are preserved. pPlayer->SnatchModelInstance( this ); VarMapping_t* varMap = GetVarMapping(); // Copy all the interpolated vars from the player entity. // The entity uses the interpolated history to get bone velocity. bool bRemotePlayer = (pPlayer != C_BasePlayer::GetLocalPlayer()); if ( bRemotePlayer ) { Interp_Copy( pPlayer ); SetAbsAngles( pPlayer->GetRenderAngles() ); GetRotationInterpolator().Reset(); m_flAnimTime = pPlayer->m_flAnimTime; SetSequence( pPlayer->GetSequence() ); m_flPlaybackRate = pPlayer->GetPlaybackRate(); } else { // This is the local player, so set them in a default // pose and slam their velocity, angles and origin SetAbsOrigin( m_vecRagdollOrigin ); SetAbsAngles( pPlayer->GetRenderAngles() ); SetAbsVelocity( m_vecRagdollVelocity ); int iSeq = pPlayer->GetSequence(); if ( iSeq == -1 ) { Assert( false ); // missing walk_lower? iSeq = 0; } SetSequence( iSeq ); // walk_lower, basic pose SetCycle( 0.0 ); Interp_Reset( varMap ); } } else { // overwrite network origin so later interpolation will // use this position SetNetworkOrigin( m_vecRagdollOrigin ); SetAbsOrigin( m_vecRagdollOrigin ); SetAbsVelocity( m_vecRagdollVelocity ); Interp_Reset( GetVarMapping() ); } SetModelIndex( m_nModelIndex ); // Make us a ragdoll.. m_nRenderFX = kRenderFxRagdoll; matrix3x4_t boneDelta0[MAXSTUDIOBONES]; matrix3x4_t boneDelta1[MAXSTUDIOBONES]; matrix3x4_t currentBones[MAXSTUDIOBONES]; const float boneDt = 0.05f; if ( pPlayer && !pPlayer->IsDormant() ) pPlayer->GetRagdollInitBoneArrays( boneDelta0, boneDelta1, currentBones, boneDt ); else GetRagdollInitBoneArrays( boneDelta0, boneDelta1, currentBones, boneDt ); InitAsClientRagdoll( boneDelta0, boneDelta1, currentBones, boneDt ); } void C_BaseNetworkedRagdoll::OnDataChanged( DataUpdateType_t type ) { BaseClass::OnDataChanged( type ); if ( type == DATA_UPDATE_CREATED ) CreateRagdoll(); } IRagdoll* C_BaseNetworkedRagdoll::GetIRagdoll() const { return m_pRagdoll; } void C_BaseNetworkedRagdoll::UpdateOnRemove( void ) { VPhysicsSetObject( NULL ); BaseClass::UpdateOnRemove(); } //----------------------------------------------------------------------------- // Purpose: clear out any face/eye values stored in the material system //----------------------------------------------------------------------------- void C_BaseNetworkedRagdoll::SetupWeights( const matrix3x4_t* pBoneToWorld, int nFlexWeightCount, float* pFlexWeights, float* pFlexDelayedWeights ) { BaseClass::SetupWeights( pBoneToWorld, nFlexWeightCount, pFlexWeights, pFlexDelayedWeights ); static float destweight[128]; static bool bIsInited = false; CStudioHdr* hdr = GetModelPtr(); if ( !hdr ) return; int nFlexDescCount = hdr->numflexdesc(); if ( nFlexDescCount ) { Assert( !pFlexDelayedWeights ); memset( pFlexWeights, 0, nFlexWeightCount* sizeof(float) ); } if ( m_iEyeAttachment > 0 ) { matrix3x4_t attToWorld; if (GetAttachment( m_iEyeAttachment, attToWorld )) { Vector local, tmp; local.Init( 1000.0f, 0.0f, 0.0f ); VectorTransform( local, attToWorld, tmp ); modelrender->SetViewTarget( GetModelPtr(), GetBody(), tmp ); } } }