diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/client/hl2mp/c_hl2mp_player.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'game/client/hl2mp/c_hl2mp_player.cpp')
| -rw-r--r-- | game/client/hl2mp/c_hl2mp_player.cpp | 985 |
1 files changed, 985 insertions, 0 deletions
diff --git a/game/client/hl2mp/c_hl2mp_player.cpp b/game/client/hl2mp/c_hl2mp_player.cpp new file mode 100644 index 0000000..49e55e2 --- /dev/null +++ b/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 |