|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "cbase.h"
#include "c_hl1mp_player.h"
#include "c_basetempentity.h"
#include "iinput.h"
// Don't alias here
#if defined( CHL1MP_Player )
#undef CHL1MP_Player
#endif
//////////////////////////////////////////////////////////////////////
class C_TEPlayerAnimEvent : public C_BaseTempEntity { public: DECLARE_CLASS( C_TEPlayerAnimEvent, C_BaseTempEntity ); DECLARE_CLIENTCLASS();
virtual void PostDataUpdate( DataUpdateType_t updateType ) { // Create the effect.
C_HL1MP_Player *pPlayer = dynamic_cast< C_HL1MP_Player* >( m_hPlayer.Get() ); if ( pPlayer && !pPlayer->IsDormant() ) { pPlayer->DoAnimationEvent( (PlayerAnimEvent_t)m_iEvent.Get(), m_nData ); } }
public: CNetworkHandle( CBasePlayer, m_hPlayer ); CNetworkVar( int, m_iEvent ); CNetworkVar( int, m_nData ); };
IMPLEMENT_CLIENTCLASS_EVENT( C_TEPlayerAnimEvent, DT_TEPlayerAnimEvent, CTEPlayerAnimEvent );
// ------------------------------------------------------------------------------------------ //
// Data tables and prediction tables.
// ------------------------------------------------------------------------------------------ //
BEGIN_RECV_TABLE_NOBASE( C_TEPlayerAnimEvent, DT_TEPlayerAnimEvent ) RecvPropEHandle( RECVINFO( m_hPlayer ) ), RecvPropInt( RECVINFO( m_iEvent ) ), RecvPropInt( RECVINFO( m_nData ) ) END_RECV_TABLE()
IMPLEMENT_CLIENTCLASS_DT( C_HL1MP_Player, DT_HL1MP_Player, CHL1MP_Player ) RecvPropFloat( RECVINFO( m_angEyeAngles[0] ) ), RecvPropFloat( RECVINFO( m_angEyeAngles[1] ) ), RecvPropEHandle( RECVINFO( m_hRagdoll ) ), RecvPropInt( RECVINFO( m_iSpawnInterpCounter ) ), RecvPropInt( RECVINFO( m_iRealSequence ) ), // RecvPropDataTable( RECVINFO_DT( m_Shared ), 0, &REFERENCE_RECV_TABLE( DT_TFCPlayerShared ) )
END_RECV_TABLE()
BEGIN_PREDICTION_DATA( C_HL1MP_Player ) END_PREDICTION_DATA()
/////////////////////////////////////////////////////////////////////
static ConVar cl_playermodel( "cl_playermodel", "none", FCVAR_USERINFO | FCVAR_ARCHIVE | FCVAR_SERVER_CAN_EXECUTE, "Default Player Model"); C_HL1MP_Player::C_HL1MP_Player( void ) : m_iv_angEyeAngles( "C_HL1MP_Player::m_iv_angEyeAngles" ) { m_PlayerAnimState = CreatePlayerAnimState( this ); m_angEyeAngles.Init();
m_fLastPredFreeze = -1;
// cant interpolate ... buggy? it keeps resetting the angle to 0,0,0
// AddVar( &m_angEyeAngles, &m_iv_angEyeAngles, LATCH_SIMULATION_VAR );
}
C_HL1MP_Player::~C_HL1MP_Player() { m_PlayerAnimState->Release(); }
const QAngle& C_HL1MP_Player::GetRenderAngles() { if ( IsRagdoll() ) { return vec3_angle; } else { return m_PlayerAnimState->GetRenderAngles(); } }
void C_HL1MP_Player::UpdateClientSideAnimation() { // Update the animation data. It does the local check here so this works when using
// a third-person camera (and we don't have valid player angles).
if ( this == C_BasePlayer::GetLocalPlayer() ) m_PlayerAnimState->Update( EyeAngles()[YAW], m_angEyeAngles[PITCH] ); else m_PlayerAnimState->Update( m_angEyeAngles[YAW], m_angEyeAngles[PITCH] );
BaseClass::UpdateClientSideAnimation(); }
void C_HL1MP_Player::DoAnimationEvent( PlayerAnimEvent_t event, int nData ) { m_PlayerAnimState->DoAnimationEvent( event, nData ); }
void C_HL1MP_Player::ProcessMuzzleFlashEvent() { #if 0
// Reenable when the weapons have muzzle flash attachments in the right spot.
if ( this != C_BasePlayer::GetLocalPlayer() ) { Vector vAttachment; QAngle dummyAngles; C_WeaponTFCBase *pWeapon = m_Shared.GetActiveTFCWeapon(); if ( pWeapon ) { int iAttachment = pWeapon->LookupAttachment( "muzzle_flash" ); if ( iAttachment > 0 ) { float flScale = 1; pWeapon->GetAttachment( iAttachment, vAttachment, dummyAngles ); // The way the models are setup, the up vector points along the barrel.
Vector vForward, vRight, vUp; AngleVectors( dummyAngles, &vForward, &vRight, &vUp ); VectorAngles( vUp, dummyAngles );
FX_MuzzleEffect( vAttachment, dummyAngles, flScale, 0, NULL, true ); } } }
Vector vAttachment; QAngle dummyAngles; bool bFoundAttachment = GetAttachment( 1, vAttachment, dummyAngles ); // If we have an attachment, then stick a light on it.
if ( bFoundAttachment ) { dlight_t *el = effects->CL_AllocDlight( LIGHT_INDEX_MUZZLEFLASH + index ); el->origin = vAttachment; el->radius = 24; el->decay = el->radius / 0.05f; el->die = gpGlobals->curtime + 0.05f; el->color.r = 255; el->color.g = 192; el->color.b = 64; el->color.exponent = 5; } #endif
}
void C_HL1MP_Player::Spawn( void ) { BaseClass::Spawn();
// SetModel( "models/player/mp/barney/barney.mdl" );
m_iSpawnInterpCounterCache = 0;
UpdateVisibility(); }
void C_HL1MP_Player::AddEntity( void ) { BaseClass::AddEntity();
//m_PlayerAnimState.Update();
// SetLocalAnglesDim( X_INDEX, 0 );
}
void C_HL1MP_Player::OnDataChanged( DataUpdateType_t type ) { BaseClass::OnDataChanged( type );
if ( type == DATA_UPDATE_CREATED ) { SetNextClientThink( CLIENT_THINK_ALWAYS ); }
UpdateVisibility(); }
C_BaseAnimating *C_HL1MP_Player::BecomeRagdollOnClient() { // Handled elsewhere
return NULL; }
void C_HL1MP_Player::PreThink( void ) { BaseClass::PreThink(); return;
QAngle vTempAngles = GetLocalAngles();
if ( GetLocalPlayer() == this ) { vTempAngles[PITCH] = EyeAngles()[PITCH]; } else { vTempAngles[PITCH] = m_angEyeAngles[PITCH]; }
if ( vTempAngles[YAW] < 0.0f ) { vTempAngles[YAW] += 360.0f; }
SetLocalAngles( vTempAngles );
BaseClass::PreThink(); #if 0
HandleSpeedChanges();
if ( m_HL2Local.m_flSuitPower <= 0.0f ) { if( IsSprinting() ) { StopSprinting(); } } #endif
}
void C_HL1MP_Player::PostDataUpdate( DataUpdateType_t updateType ) { // C_BaseEntity assumes we're networking the entity's angles, so pretend that it
// networked the same value we already have.
SetNetworkAngles( GetLocalAngles() ); BaseClass::PostDataUpdate( updateType ); }
void C_HL1MP_Player::ClientThink( void ) { BaseClass::ClientThink(); // m_PlayerAnimState.Update();
}
//HL1MPRAGDOLL
IMPLEMENT_CLIENTCLASS_DT_NOBASE( C_HL1MPRagdoll, DT_HL1MPRagdoll, CHL1MPRagdoll ) 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()
C_HL1MPRagdoll::C_HL1MPRagdoll() {
}
C_HL1MPRagdoll::~C_HL1MPRagdoll() { PhysCleanupFrictionSounds( this );
if ( m_hPlayer ) { m_hPlayer->CreateModelInstance(); } }
void C_HL1MPRagdoll::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_HL1MPRagdoll::ImpactTrace( trace_t *pTrace, int iDamageType, const 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_HL1MP_Player::CalcView( Vector &eyeOrigin, QAngle &eyeAngles, float &zNear, float &zFar, float &fov ) { if ( m_lifeState != LIFE_ALIVE ) { Vector origin = EyePosition();
IRagdoll *pRagdoll = GetRepresentativeRagdoll();
if ( pRagdoll ) { origin = pRagdoll->GetRagdollOrigin(); origin.z += VEC_DEAD_VIEWHEIGHT_SCALED( this ).z; // look over ragdoll, not through
}
BaseClass::CalcView( eyeOrigin, eyeAngles, zNear, zFar, fov );
eyeOrigin = origin;
Vector vForward; AngleVectors( eyeAngles, &vForward );
VectorNormalize( vForward ); VectorMA( origin, -CHASE_CAM_DISTANCE_MAX, vForward, eyeOrigin );
Vector WALL_MIN( -WALL_OFFSET, -WALL_OFFSET, -WALL_OFFSET ); Vector WALL_MAX( WALL_OFFSET, WALL_OFFSET, WALL_OFFSET );
trace_t trace; // clip against world
C_BaseEntity::PushEnableAbsRecomputations( false ); // HACK don't recompute positions while doing RayTrace
UTIL_TraceHull( origin, eyeOrigin, WALL_MIN, WALL_MAX, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &trace ); C_BaseEntity::PopEnableAbsRecomputations();
if (trace.fraction < 1.0) { eyeOrigin = trace.endpos; }
return; }
BaseClass::CalcView( eyeOrigin, eyeAngles, zNear, zFar, fov ); }
IRagdoll* C_HL1MP_Player::GetRepresentativeRagdoll() const { if ( m_hRagdoll.Get() ) { C_HL1MPRagdoll *pRagdoll = (C_HL1MPRagdoll*)m_hRagdoll.Get();
return pRagdoll->GetIRagdoll(); } else { return NULL; } }
void C_HL1MPRagdoll::CreateHL1MPRagdoll( 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_HL1MP_Player *pPlayer = dynamic_cast< C_HL1MP_Player* >( 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_HL1MPRagdoll::OnDataChanged( DataUpdateType_t type ) { BaseClass::OnDataChanged( type );
if ( type == DATA_UPDATE_CREATED ) { CreateHL1MPRagdoll(); } }
IRagdoll* C_HL1MPRagdoll::GetIRagdoll() const { return m_pRagdoll; }
void C_HL1MPRagdoll::UpdateOnRemove( void ) { VPhysicsSetObject( NULL );
BaseClass::UpdateOnRemove(); }
//-----------------------------------------------------------------------------
// Purpose: clear out any face/eye values stored in the material system
//-----------------------------------------------------------------------------
void C_HL1MPRagdoll::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 ); } } }
bool C_HL1MP_Player::ShouldDraw( void ) { if ( !IsAlive() ) return false;
if ( IsLocalPlayer() && IsRagdoll() ) return true;
if ( IsRagdoll() ) return false;
return BaseClass::ShouldDraw(); }
bool C_HL1MP_Player::ShouldPredict( void ) { // Do this before calling into baseclass so prediction data block gets allocated
if ( IsLocalPlayer() ) { #if 0
// Disable prediction when player hops onto a moving train or elevator :-/
if ( GetGroundEntity() && GetGroundEntity()->GetMoveType() == MOVETYPE_PUSH ) { Vector vel = GetGroundEntity()->GetLocalVelocity(); if ( vel.Length() > 0.002f ) { m_fLastPredFreeze = gpGlobals->curtime; } }
// disable prediction for 3 seconds after touching a moving entity
if ( ( gpGlobals->curtime - m_fLastPredFreeze ) < 3 ) { if ( GetPredictable() ) { QuickShutdownPredictable(); }
return false; }
if ( !GetPredictable() && IsIntermediateDataAllocated() ) { QuickInitPredictable(); } #endif
return true; }
return false; }
|