|
|
//========= 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(); }
|