diff options
| author | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
|---|---|---|
| committer | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
| commit | 39ed87570bdb2f86969d4be821c94b722dc71179 (patch) | |
| tree | abc53757f75f40c80278e87650ea92808274aa59 /mp/src/game/client/hl2mp/c_hl2mp_player.cpp | |
| download | source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip | |
First version of the SOurce SDK 2013
Diffstat (limited to 'mp/src/game/client/hl2mp/c_hl2mp_player.cpp')
| -rw-r--r-- | mp/src/game/client/hl2mp/c_hl2mp_player.cpp | 985 |
1 files changed, 985 insertions, 0 deletions
diff --git a/mp/src/game/client/hl2mp/c_hl2mp_player.cpp b/mp/src/game/client/hl2mp/c_hl2mp_player.cpp new file mode 100644 index 00000000..d68c5215 --- /dev/null +++ b/mp/src/game/client/hl2mp/c_hl2mp_player.cpp @@ -0,0 +1,985 @@ +//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Player for HL2.
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "vcollide_parse.h"
+#include "c_hl2mp_player.h"
+#include "view.h"
+#include "takedamageinfo.h"
+#include "hl2mp_gamerules.h"
+#include "in_buttons.h"
+#include "iviewrender_beams.h" // flashlight beam
+#include "r_efx.h"
+#include "dlight.h"
+
+// Don't alias here
+#if defined( CHL2MP_Player )
+#undef CHL2MP_Player
+#endif
+
+LINK_ENTITY_TO_CLASS( player, C_HL2MP_Player );
+
+IMPLEMENT_CLIENTCLASS_DT(C_HL2MP_Player, DT_HL2MP_Player, CHL2MP_Player)
+ RecvPropFloat( RECVINFO( m_angEyeAngles[0] ) ),
+ RecvPropFloat( RECVINFO( m_angEyeAngles[1] ) ),
+ RecvPropEHandle( RECVINFO( m_hRagdoll ) ),
+ RecvPropInt( RECVINFO( m_iSpawnInterpCounter ) ),
+ RecvPropInt( RECVINFO( m_iPlayerSoundType) ),
+
+ RecvPropBool( RECVINFO( m_fIsWalking ) ),
+END_RECV_TABLE()
+
+BEGIN_PREDICTION_DATA( C_HL2MP_Player )
+ DEFINE_PRED_FIELD( m_fIsWalking, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
+END_PREDICTION_DATA()
+
+#define HL2_WALK_SPEED 150
+#define HL2_NORM_SPEED 190
+#define HL2_SPRINT_SPEED 320
+
+static ConVar cl_playermodel( "cl_playermodel", "none", FCVAR_USERINFO | FCVAR_ARCHIVE | FCVAR_SERVER_CAN_EXECUTE, "Default Player Model");
+static ConVar cl_defaultweapon( "cl_defaultweapon", "weapon_physcannon", FCVAR_USERINFO | FCVAR_ARCHIVE, "Default Spawn Weapon");
+
+void SpawnBlood (Vector vecSpot, const Vector &vecDir, int bloodColor, float flDamage);
+
+C_HL2MP_Player::C_HL2MP_Player() : m_PlayerAnimState( this ), m_iv_angEyeAngles( "C_HL2MP_Player::m_iv_angEyeAngles" )
+{
+ m_iIDEntIndex = 0;
+ m_iSpawnInterpCounterCache = 0;
+
+ m_angEyeAngles.Init();
+
+ AddVar( &m_angEyeAngles, &m_iv_angEyeAngles, LATCH_SIMULATION_VAR );
+
+ m_EntClientFlags |= ENTCLIENTFLAG_DONTUSEIK;
+ m_blinkTimer.Invalidate();
+
+ m_pFlashlightBeam = NULL;
+}
+
+C_HL2MP_Player::~C_HL2MP_Player( void )
+{
+ ReleaseFlashlight();
+}
+
+int C_HL2MP_Player::GetIDTarget() const
+{
+ return m_iIDEntIndex;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Update this client's target entity
+//-----------------------------------------------------------------------------
+void C_HL2MP_Player::UpdateIDTarget()
+{
+ if ( !IsLocalPlayer() )
+ return;
+
+ // Clear old target and find a new one
+ m_iIDEntIndex = 0;
+
+ // don't show IDs in chase spec mode
+ if ( GetObserverMode() == OBS_MODE_CHASE ||
+ GetObserverMode() == OBS_MODE_DEATHCAM )
+ return;
+
+ trace_t tr;
+ Vector vecStart, vecEnd;
+ VectorMA( MainViewOrigin(), 1500, MainViewForward(), vecEnd );
+ VectorMA( MainViewOrigin(), 10, MainViewForward(), vecStart );
+ UTIL_TraceLine( vecStart, vecEnd, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr );
+
+ if ( !tr.startsolid && tr.DidHitNonWorldEntity() )
+ {
+ C_BaseEntity *pEntity = tr.m_pEnt;
+
+ if ( pEntity && (pEntity != this) )
+ {
+ m_iIDEntIndex = pEntity->entindex();
+ }
+ }
+}
+
+void C_HL2MP_Player::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator )
+{
+ Vector vecOrigin = ptr->endpos - vecDir * 4;
+
+ float flDistance = 0.0f;
+
+ if ( info.GetAttacker() )
+ {
+ flDistance = (ptr->endpos - info.GetAttacker()->GetAbsOrigin()).Length();
+ }
+
+ if ( m_takedamage )
+ {
+ AddMultiDamage( info, this );
+
+ int blood = BloodColor();
+
+ CBaseEntity *pAttacker = info.GetAttacker();
+
+ if ( pAttacker )
+ {
+ if ( HL2MPRules()->IsTeamplay() && pAttacker->InSameTeam( this ) == true )
+ return;
+ }
+
+ if ( blood != DONT_BLEED )
+ {
+ SpawnBlood( vecOrigin, vecDir, blood, flDistance );// a little surface blood.
+ TraceBleed( flDistance, vecDir, ptr, info.GetDamageType() );
+ }
+ }
+}
+
+
+C_HL2MP_Player* C_HL2MP_Player::GetLocalHL2MPPlayer()
+{
+ return (C_HL2MP_Player*)C_BasePlayer::GetLocalPlayer();
+}
+
+void C_HL2MP_Player::Initialize( void )
+{
+ m_headYawPoseParam = LookupPoseParameter( "head_yaw" );
+ GetPoseParameterRange( m_headYawPoseParam, m_headYawMin, m_headYawMax );
+
+ m_headPitchPoseParam = LookupPoseParameter( "head_pitch" );
+ GetPoseParameterRange( m_headPitchPoseParam, m_headPitchMin, m_headPitchMax );
+
+ CStudioHdr *hdr = GetModelPtr();
+ for ( int i = 0; i < hdr->GetNumPoseParameters() ; i++ )
+ {
+ SetPoseParameter( hdr, i, 0.0 );
+ }
+}
+
+CStudioHdr *C_HL2MP_Player::OnNewModel( void )
+{
+ CStudioHdr *hdr = BaseClass::OnNewModel();
+
+ Initialize( );
+
+ return hdr;
+}
+
+//-----------------------------------------------------------------------------
+/**
+ * Orient head and eyes towards m_lookAt.
+ */
+void C_HL2MP_Player::UpdateLookAt( void )
+{
+ // head yaw
+ if (m_headYawPoseParam < 0 || m_headPitchPoseParam < 0)
+ return;
+
+ // orient eyes
+ m_viewtarget = m_vLookAtTarget;
+
+ // blinking
+ if (m_blinkTimer.IsElapsed())
+ {
+ m_blinktoggle = !m_blinktoggle;
+ m_blinkTimer.Start( RandomFloat( 1.5f, 4.0f ) );
+ }
+
+ // Figure out where we want to look in world space.
+ QAngle desiredAngles;
+ Vector to = m_vLookAtTarget - EyePosition();
+ VectorAngles( to, desiredAngles );
+
+ // Figure out where our body is facing in world space.
+ QAngle bodyAngles( 0, 0, 0 );
+ bodyAngles[YAW] = GetLocalAngles()[YAW];
+
+
+ float flBodyYawDiff = bodyAngles[YAW] - m_flLastBodyYaw;
+ m_flLastBodyYaw = bodyAngles[YAW];
+
+
+ // Set the head's yaw.
+ float desired = AngleNormalize( desiredAngles[YAW] - bodyAngles[YAW] );
+ desired = clamp( desired, m_headYawMin, m_headYawMax );
+ m_flCurrentHeadYaw = ApproachAngle( desired, m_flCurrentHeadYaw, 130 * gpGlobals->frametime );
+
+ // Counterrotate the head from the body rotation so it doesn't rotate past its target.
+ m_flCurrentHeadYaw = AngleNormalize( m_flCurrentHeadYaw - flBodyYawDiff );
+ desired = clamp( desired, m_headYawMin, m_headYawMax );
+
+ SetPoseParameter( m_headYawPoseParam, m_flCurrentHeadYaw );
+
+
+ // Set the head's yaw.
+ desired = AngleNormalize( desiredAngles[PITCH] );
+ desired = clamp( desired, m_headPitchMin, m_headPitchMax );
+
+ m_flCurrentHeadPitch = ApproachAngle( desired, m_flCurrentHeadPitch, 130 * gpGlobals->frametime );
+ m_flCurrentHeadPitch = AngleNormalize( m_flCurrentHeadPitch );
+ SetPoseParameter( m_headPitchPoseParam, m_flCurrentHeadPitch );
+}
+
+void C_HL2MP_Player::ClientThink( void )
+{
+ bool bFoundViewTarget = false;
+
+ Vector vForward;
+ AngleVectors( GetLocalAngles(), &vForward );
+
+ for( int iClient = 1; iClient <= gpGlobals->maxClients; ++iClient )
+ {
+ CBaseEntity *pEnt = UTIL_PlayerByIndex( iClient );
+ if(!pEnt || !pEnt->IsPlayer())
+ continue;
+
+ if ( pEnt->entindex() == entindex() )
+ continue;
+
+ Vector vTargetOrigin = pEnt->GetAbsOrigin();
+ Vector vMyOrigin = GetAbsOrigin();
+
+ Vector vDir = vTargetOrigin - vMyOrigin;
+
+ if ( vDir.Length() > 128 )
+ continue;
+
+ VectorNormalize( vDir );
+
+ if ( DotProduct( vForward, vDir ) < 0.0f )
+ continue;
+
+ m_vLookAtTarget = pEnt->EyePosition();
+ bFoundViewTarget = true;
+ break;
+ }
+
+ if ( bFoundViewTarget == false )
+ {
+ m_vLookAtTarget = GetAbsOrigin() + vForward * 512;
+ }
+
+ UpdateIDTarget();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int C_HL2MP_Player::DrawModel( int flags )
+{
+ if ( !m_bReadyToDraw )
+ return 0;
+
+ return BaseClass::DrawModel(flags);
+}
+
+//-----------------------------------------------------------------------------
+// Should this object receive shadows?
+//-----------------------------------------------------------------------------
+bool C_HL2MP_Player::ShouldReceiveProjectedTextures( int flags )
+{
+ Assert( flags & SHADOW_FLAGS_PROJECTED_TEXTURE_TYPE_MASK );
+
+ if ( IsEffectActive( EF_NODRAW ) )
+ return false;
+
+ if( flags & SHADOW_FLAGS_FLASHLIGHT )
+ {
+ return true;
+ }
+
+ return BaseClass::ShouldReceiveProjectedTextures( flags );
+}
+
+void C_HL2MP_Player::DoImpactEffect( trace_t &tr, int nDamageType )
+{
+ if ( GetActiveWeapon() )
+ {
+ GetActiveWeapon()->DoImpactEffect( tr, nDamageType );
+ return;
+ }
+
+ BaseClass::DoImpactEffect( tr, nDamageType );
+}
+
+void C_HL2MP_Player::PreThink( void )
+{
+ 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();
+
+ HandleSpeedChanges();
+
+ if ( m_HL2Local.m_flSuitPower <= 0.0f )
+ {
+ if( IsSprinting() )
+ {
+ StopSprinting();
+ }
+ }
+}
+
+const QAngle &C_HL2MP_Player::EyeAngles()
+{
+ if( IsLocalPlayer() )
+ {
+ return BaseClass::EyeAngles();
+ }
+ else
+ {
+ return m_angEyeAngles;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_HL2MP_Player::AddEntity( void )
+{
+ BaseClass::AddEntity();
+
+ QAngle vTempAngles = GetLocalAngles();
+ vTempAngles[PITCH] = m_angEyeAngles[PITCH];
+
+ SetLocalAngles( vTempAngles );
+
+ m_PlayerAnimState.Update();
+
+ // Zero out model pitch, blending takes care of all of it.
+ SetLocalAnglesDim( X_INDEX, 0 );
+
+ if( this != C_BasePlayer::GetLocalPlayer() )
+ {
+ if ( IsEffectActive( EF_DIMLIGHT ) )
+ {
+ int iAttachment = LookupAttachment( "anim_attachment_RH" );
+
+ if ( iAttachment < 0 )
+ return;
+
+ Vector vecOrigin;
+ QAngle eyeAngles = m_angEyeAngles;
+
+ GetAttachment( iAttachment, vecOrigin, eyeAngles );
+
+ Vector vForward;
+ AngleVectors( eyeAngles, &vForward );
+
+ trace_t tr;
+ UTIL_TraceLine( vecOrigin, vecOrigin + (vForward * 200), MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
+
+ if( !m_pFlashlightBeam )
+ {
+ BeamInfo_t beamInfo;
+ beamInfo.m_nType = TE_BEAMPOINTS;
+ beamInfo.m_vecStart = tr.startpos;
+ beamInfo.m_vecEnd = tr.endpos;
+ beamInfo.m_pszModelName = "sprites/glow01.vmt";
+ beamInfo.m_pszHaloName = "sprites/glow01.vmt";
+ beamInfo.m_flHaloScale = 3.0;
+ beamInfo.m_flWidth = 8.0f;
+ beamInfo.m_flEndWidth = 35.0f;
+ beamInfo.m_flFadeLength = 300.0f;
+ beamInfo.m_flAmplitude = 0;
+ beamInfo.m_flBrightness = 60.0;
+ beamInfo.m_flSpeed = 0.0f;
+ beamInfo.m_nStartFrame = 0.0;
+ beamInfo.m_flFrameRate = 0.0;
+ beamInfo.m_flRed = 255.0;
+ beamInfo.m_flGreen = 255.0;
+ beamInfo.m_flBlue = 255.0;
+ beamInfo.m_nSegments = 8;
+ beamInfo.m_bRenderable = true;
+ beamInfo.m_flLife = 0.5;
+ beamInfo.m_nFlags = FBEAM_FOREVER | FBEAM_ONLYNOISEONCE | FBEAM_NOTILE | FBEAM_HALOBEAM;
+
+ m_pFlashlightBeam = beams->CreateBeamPoints( beamInfo );
+ }
+
+ if( m_pFlashlightBeam )
+ {
+ BeamInfo_t beamInfo;
+ beamInfo.m_vecStart = tr.startpos;
+ beamInfo.m_vecEnd = tr.endpos;
+ beamInfo.m_flRed = 255.0;
+ beamInfo.m_flGreen = 255.0;
+ beamInfo.m_flBlue = 255.0;
+
+ beams->UpdateBeamInfo( m_pFlashlightBeam, beamInfo );
+
+ dlight_t *el = effects->CL_AllocDlight( 0 );
+ el->origin = tr.endpos;
+ el->radius = 50;
+ el->color.r = 200;
+ el->color.g = 200;
+ el->color.b = 200;
+ el->die = gpGlobals->curtime + 0.1;
+ }
+ }
+ else if ( m_pFlashlightBeam )
+ {
+ ReleaseFlashlight();
+ }
+ }
+}
+
+ShadowType_t C_HL2MP_Player::ShadowCastType( void )
+{
+ if ( !IsVisible() )
+ return SHADOWS_NONE;
+
+ return SHADOWS_RENDER_TO_TEXTURE_DYNAMIC;
+}
+
+
+const QAngle& C_HL2MP_Player::GetRenderAngles()
+{
+ if ( IsRagdoll() )
+ {
+ return vec3_angle;
+ }
+ else
+ {
+ return m_PlayerAnimState.GetRenderAngles();
+ }
+}
+
+bool C_HL2MP_Player::ShouldDraw( void )
+{
+ // If we're dead, our ragdoll will be drawn for us instead.
+ if ( !IsAlive() )
+ return false;
+
+// if( GetTeamNumber() == TEAM_SPECTATOR )
+// return false;
+
+ if( IsLocalPlayer() && IsRagdoll() )
+ return true;
+
+ if ( IsRagdoll() )
+ return false;
+
+ return BaseClass::ShouldDraw();
+}
+
+void C_HL2MP_Player::NotifyShouldTransmit( ShouldTransmitState_t state )
+{
+ if ( state == SHOULDTRANSMIT_END )
+ {
+ if( m_pFlashlightBeam != NULL )
+ {
+ ReleaseFlashlight();
+ }
+ }
+
+ BaseClass::NotifyShouldTransmit( state );
+}
+
+void C_HL2MP_Player::OnDataChanged( DataUpdateType_t type )
+{
+ BaseClass::OnDataChanged( type );
+
+ if ( type == DATA_UPDATE_CREATED )
+ {
+ SetNextClientThink( CLIENT_THINK_ALWAYS );
+ }
+
+ UpdateVisibility();
+}
+
+void C_HL2MP_Player::PostDataUpdate( DataUpdateType_t updateType )
+{
+ if ( m_iSpawnInterpCounter != m_iSpawnInterpCounterCache )
+ {
+ MoveToLastReceivedPosition( true );
+ ResetLatched();
+ m_iSpawnInterpCounterCache = m_iSpawnInterpCounter;
+ }
+
+ BaseClass::PostDataUpdate( updateType );
+}
+
+void C_HL2MP_Player::ReleaseFlashlight( void )
+{
+ if( m_pFlashlightBeam )
+ {
+ m_pFlashlightBeam->flags = 0;
+ m_pFlashlightBeam->die = gpGlobals->curtime - 1;
+
+ m_pFlashlightBeam = NULL;
+ }
+}
+
+float C_HL2MP_Player::GetFOV( void )
+{
+ //Find our FOV with offset zoom value
+ float flFOVOffset = C_BasePlayer::GetFOV() + GetZoom();
+
+ // Clamp FOV in MP
+ int min_fov = GetMinFOV();
+
+ // Don't let it go too low
+ flFOVOffset = MAX( min_fov, flFOVOffset );
+
+ return flFOVOffset;
+}
+
+//=========================================================
+// Autoaim
+// set crosshair position to point to enemey
+//=========================================================
+Vector C_HL2MP_Player::GetAutoaimVector( float flDelta )
+{
+ // Never autoaim a predicted weapon (for now)
+ Vector forward;
+ AngleVectors( EyeAngles() + m_Local.m_vecPunchAngle, &forward );
+ return forward;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns whether or not we are allowed to sprint now.
+//-----------------------------------------------------------------------------
+bool C_HL2MP_Player::CanSprint( void )
+{
+ return ( (!m_Local.m_bDucked && !m_Local.m_bDucking) && (GetWaterLevel() != 3) );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_HL2MP_Player::StartSprinting( void )
+{
+ if( m_HL2Local.m_flSuitPower < 10 )
+ {
+ // Don't sprint unless there's a reasonable
+ // amount of suit power.
+ CPASAttenuationFilter filter( this );
+ filter.UsePredictionRules();
+ EmitSound( filter, entindex(), "HL2Player.SprintNoPower" );
+ return;
+ }
+
+ CPASAttenuationFilter filter( this );
+ filter.UsePredictionRules();
+ EmitSound( filter, entindex(), "HL2Player.SprintStart" );
+
+ SetMaxSpeed( HL2_SPRINT_SPEED );
+ m_fIsSprinting = true;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_HL2MP_Player::StopSprinting( void )
+{
+ SetMaxSpeed( HL2_NORM_SPEED );
+ m_fIsSprinting = false;
+}
+
+void C_HL2MP_Player::HandleSpeedChanges( void )
+{
+ int buttonsChanged = m_afButtonPressed | m_afButtonReleased;
+
+ if( buttonsChanged & IN_SPEED )
+ {
+ // The state of the sprint/run button has changed.
+ if ( IsSuitEquipped() )
+ {
+ if ( !(m_afButtonPressed & IN_SPEED) && IsSprinting() )
+ {
+ StopSprinting();
+ }
+ else if ( (m_afButtonPressed & IN_SPEED) && !IsSprinting() )
+ {
+ if ( CanSprint() )
+ {
+ StartSprinting();
+ }
+ else
+ {
+ // Reset key, so it will be activated post whatever is suppressing it.
+ m_nButtons &= ~IN_SPEED;
+ }
+ }
+ }
+ }
+ else if( buttonsChanged & IN_WALK )
+ {
+ if ( IsSuitEquipped() )
+ {
+ // The state of the WALK button has changed.
+ if( IsWalking() && !(m_afButtonPressed & IN_WALK) )
+ {
+ StopWalking();
+ }
+ else if( !IsWalking() && !IsSprinting() && (m_afButtonPressed & IN_WALK) && !(m_nButtons & IN_DUCK) )
+ {
+ StartWalking();
+ }
+ }
+ }
+
+ if ( IsSuitEquipped() && m_fIsWalking && !(m_nButtons & IN_WALK) )
+ StopWalking();
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_HL2MP_Player::StartWalking( void )
+{
+ SetMaxSpeed( HL2_WALK_SPEED );
+ m_fIsWalking = true;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_HL2MP_Player::StopWalking( void )
+{
+ SetMaxSpeed( HL2_NORM_SPEED );
+ m_fIsWalking = false;
+}
+
+void C_HL2MP_Player::ItemPreFrame( void )
+{
+ if ( GetFlags() & FL_FROZEN )
+ return;
+
+ // Disallow shooting while zooming
+ if ( m_nButtons & IN_ZOOM )
+ {
+ //FIXME: Held weapons like the grenade get sad when this happens
+ m_nButtons &= ~(IN_ATTACK|IN_ATTACK2);
+ }
+
+ BaseClass::ItemPreFrame();
+
+}
+
+void C_HL2MP_Player::ItemPostFrame( void )
+{
+ if ( GetFlags() & FL_FROZEN )
+ return;
+
+ BaseClass::ItemPostFrame();
+}
+
+C_BaseAnimating *C_HL2MP_Player::BecomeRagdollOnClient()
+{
+ // Let the C_CSRagdoll entity do this.
+ // m_builtRagdoll = true;
+ return NULL;
+}
+
+void C_HL2MP_Player::CalcView( Vector &eyeOrigin, QAngle &eyeAngles, float &zNear, float &zFar, float &fov )
+{
+ if ( m_lifeState != LIFE_ALIVE && !IsObserver() )
+ {
+ 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_HL2MP_Player::GetRepresentativeRagdoll() const
+{
+ if ( m_hRagdoll.Get() )
+ {
+ C_HL2MPRagdoll *pRagdoll = (C_HL2MPRagdoll*)m_hRagdoll.Get();
+
+ return pRagdoll->GetIRagdoll();
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+//HL2MPRAGDOLL
+
+
+IMPLEMENT_CLIENTCLASS_DT_NOBASE( C_HL2MPRagdoll, DT_HL2MPRagdoll, CHL2MPRagdoll )
+ 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_HL2MPRagdoll::C_HL2MPRagdoll()
+{
+
+}
+
+C_HL2MPRagdoll::~C_HL2MPRagdoll()
+{
+ PhysCleanupFrictionSounds( this );
+
+ if ( m_hPlayer )
+ {
+ m_hPlayer->CreateModelInstance();
+ }
+}
+
+void C_HL2MPRagdoll::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_HL2MPRagdoll::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 );
+
+ // Blood spray!
+// FX_CS_BloodSpray( hitpos, dir, 10 );
+ }
+
+ m_pRagdoll->ResetRagdollSleepAfterTime();
+}
+
+
+void C_HL2MPRagdoll::CreateHL2MPRagdoll( 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_HL2MP_Player *pPlayer = dynamic_cast< C_HL2MP_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_HL2MPRagdoll::OnDataChanged( DataUpdateType_t type )
+{
+ BaseClass::OnDataChanged( type );
+
+ if ( type == DATA_UPDATE_CREATED )
+ {
+ CreateHL2MPRagdoll();
+ }
+}
+
+IRagdoll* C_HL2MPRagdoll::GetIRagdoll() const
+{
+ return m_pRagdoll;
+}
+
+void C_HL2MPRagdoll::UpdateOnRemove( void )
+{
+ VPhysicsSetObject( NULL );
+
+ BaseClass::UpdateOnRemove();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: clear out any face/eye values stored in the material system
+//-----------------------------------------------------------------------------
+void C_HL2MPRagdoll::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 );
+ }
+ }
+}
+
+void C_HL2MP_Player::PostThink( void )
+{
+ BaseClass::PostThink();
+
+ // Store the eye angles pitch so the client can compute its animation state correctly.
+ m_angEyeAngles = EyeAngles();
+}
\ No newline at end of file |