You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1397 lines
32 KiB
1397 lines
32 KiB
3 years ago
|
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||
|
//
|
||
|
// Purpose:
|
||
|
//
|
||
|
//=============================================================================//
|
||
|
|
||
|
#include "cbase.h"
|
||
|
#include "dod_gamerules.h"
|
||
|
#include "takedamageinfo.h"
|
||
|
#include "dod_shareddefs.h"
|
||
|
#include "effect_dispatch_data.h"
|
||
|
|
||
|
#include "weapon_dodbase.h"
|
||
|
#include "weapon_dodbipodgun.h"
|
||
|
#include "weapon_dodbaserpg.h"
|
||
|
#include "weapon_dodsniper.h"
|
||
|
|
||
|
#include "movevars_shared.h"
|
||
|
#include "engine/IEngineSound.h"
|
||
|
#include "SoundEmitterSystem/isoundemittersystembase.h"
|
||
|
#include "engine/ivdebugoverlay.h"
|
||
|
#include "obstacle_pushaway.h"
|
||
|
#include "props_shared.h"
|
||
|
|
||
|
#include "decals.h"
|
||
|
#include "util_shared.h"
|
||
|
|
||
|
#ifdef CLIENT_DLL
|
||
|
|
||
|
#include "c_dod_player.h"
|
||
|
#include "prediction.h"
|
||
|
#include "clientmode_dod.h"
|
||
|
#include "vgui_controls/AnimationController.h"
|
||
|
|
||
|
#define CRecipientFilter C_RecipientFilter
|
||
|
|
||
|
#else
|
||
|
|
||
|
#include "dod_player.h"
|
||
|
|
||
|
#endif
|
||
|
|
||
|
ConVar dod_bonusround( "dod_bonusround", "1", FCVAR_REPLICATED, "If true, the winners of the round can attack in the intermission." );
|
||
|
ConVar sv_showimpacts("sv_showimpacts", "0", FCVAR_REPLICATED | FCVAR_CHEAT, "Shows client (red) and server (blue) bullet impact point" );
|
||
|
|
||
|
void DispatchEffect( const char *pName, const CEffectData &data );
|
||
|
|
||
|
bool CDODPlayer::CanMove( void ) const
|
||
|
{
|
||
|
bool bValidMoveState = (State_Get() == STATE_ACTIVE || State_Get() == STATE_OBSERVER_MODE);
|
||
|
|
||
|
if ( !bValidMoveState )
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// BUG! This is not called on the client at respawn, only first spawn!
|
||
|
void CDODPlayer::SharedSpawn()
|
||
|
{
|
||
|
BaseClass::SharedSpawn();
|
||
|
|
||
|
// Reset the animation state or we will animate to standing
|
||
|
// when we spawn
|
||
|
|
||
|
m_Shared.SetJumping( false );
|
||
|
|
||
|
m_flMinNextStepSoundTime = gpGlobals->curtime;
|
||
|
|
||
|
m_bPlayingProneMoveSound = false;
|
||
|
}
|
||
|
|
||
|
float GetDensityFromMaterial( surfacedata_t *pSurfaceData )
|
||
|
{
|
||
|
float flMaterialMod = 1.0f;
|
||
|
|
||
|
Assert( pSurfaceData );
|
||
|
|
||
|
// material mod is how many points of damage it costs to go through
|
||
|
// 1 unit of the material
|
||
|
|
||
|
switch( pSurfaceData->game.material )
|
||
|
{
|
||
|
//super soft
|
||
|
// case CHAR_TEX_LEAVES:
|
||
|
// flMaterialMod = 1.2f;
|
||
|
// break;
|
||
|
|
||
|
case CHAR_TEX_FLESH:
|
||
|
flMaterialMod = 1.35f;
|
||
|
break;
|
||
|
|
||
|
//soft
|
||
|
// case CHAR_TEX_STUCCO:
|
||
|
// case CHAR_TEX_SNOW:
|
||
|
case CHAR_TEX_GLASS:
|
||
|
case CHAR_TEX_WOOD:
|
||
|
case CHAR_TEX_TILE:
|
||
|
flMaterialMod = 1.8f;
|
||
|
break;
|
||
|
|
||
|
//hard
|
||
|
// case CHAR_TEX_SKY:
|
||
|
// case CHAR_TEX_ROCK:
|
||
|
// case CHAR_TEX_SAND:
|
||
|
case CHAR_TEX_CONCRETE:
|
||
|
case CHAR_TEX_DIRT: // "sand"
|
||
|
flMaterialMod = 6.6f;
|
||
|
break;
|
||
|
|
||
|
//really hard
|
||
|
// case CHAR_TEX_HEAVYMETAL:
|
||
|
case CHAR_TEX_GRATE:
|
||
|
case CHAR_TEX_METAL:
|
||
|
flMaterialMod = 13.5f;
|
||
|
break;
|
||
|
|
||
|
case 'X': // invisible collision material
|
||
|
flMaterialMod = 0.1f;
|
||
|
break;
|
||
|
|
||
|
//medium
|
||
|
// case CHAR_TEX_BRICK:
|
||
|
// case CHAR_TEX_GRAVEL:
|
||
|
// case CHAR_TEX_GRASS:
|
||
|
default:
|
||
|
|
||
|
#ifndef CLIENT_DLL
|
||
|
AssertMsg( 0, UTIL_VarArgs( "Material has unknown materialmod - '%c' \n", pSurfaceData->game.material ) );
|
||
|
#endif
|
||
|
|
||
|
flMaterialMod = 5.0f;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
Assert( flMaterialMod > 0 );
|
||
|
|
||
|
return flMaterialMod;
|
||
|
}
|
||
|
|
||
|
static bool TraceToExit( const Vector &start,
|
||
|
const Vector &dir,
|
||
|
Vector &end,
|
||
|
const float flStepSize,
|
||
|
const float flMaxDistance )
|
||
|
{
|
||
|
float flDistance = 0;
|
||
|
Vector last = start;
|
||
|
|
||
|
while ( flDistance < flMaxDistance )
|
||
|
{
|
||
|
flDistance += flStepSize;
|
||
|
|
||
|
// no point in tracing past the max distance.
|
||
|
// if this check fails, we save ourselves a traceline later
|
||
|
if ( flDistance > flMaxDistance )
|
||
|
{
|
||
|
flDistance = flMaxDistance;
|
||
|
}
|
||
|
|
||
|
end = start + flDistance * dir;
|
||
|
|
||
|
// point contents fails to return proper contents inside a func_detail brush, eg the dod_flash
|
||
|
// stairs
|
||
|
|
||
|
//int contents = UTIL_PointContents( end );
|
||
|
|
||
|
trace_t tr;
|
||
|
UTIL_TraceLine( end, end, MASK_SOLID | CONTENTS_HITBOX, NULL, &tr );
|
||
|
|
||
|
//if ( (UTIL_PointContents ( end ) & MASK_SOLID) == 0 )
|
||
|
|
||
|
if ( !tr.startsolid )
|
||
|
{
|
||
|
// found first free point
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
#include "ammodef.h"
|
||
|
|
||
|
#define NEW_HITBOX_GROUP_CODE 1
|
||
|
#undef ARM_PENETRATION
|
||
|
|
||
|
#ifndef CLIENT_DLL
|
||
|
#include "ndebugoverlay.h"
|
||
|
#endif
|
||
|
void CDODPlayer::FireBullets( const FireBulletsInfo_t &info )
|
||
|
{
|
||
|
trace_t tr;
|
||
|
trace_t reverseTr; //Used to find exit points
|
||
|
static int iMaxPenetrations = 6;
|
||
|
int iPenetrations = 0;
|
||
|
float flDamage = info.m_flDamage; //Remaining damage in the bullet
|
||
|
Vector vecSrc = info.m_vecSrc;
|
||
|
Vector vecEnd = vecSrc + info.m_vecDirShooting * info.m_flDistance;
|
||
|
|
||
|
static int iTraceMask = ( ( MASK_SOLID | CONTENTS_DEBRIS | CONTENTS_HITBOX | CONTENTS_PRONE_HELPER ) & ~CONTENTS_GRATE );
|
||
|
|
||
|
CBaseEntity *pLastHitEntity = this; // start with us so we don't trace ourselves
|
||
|
|
||
|
int iDamageType = GetAmmoDef()->DamageType( info.m_iAmmoType );
|
||
|
int iCollisionGroup = COLLISION_GROUP_NONE;
|
||
|
|
||
|
#ifdef GAME_DLL
|
||
|
int iNumHeadshots = 0;
|
||
|
#endif
|
||
|
|
||
|
while ( flDamage > 0 && iPenetrations < iMaxPenetrations )
|
||
|
{
|
||
|
//DevMsg( 2, "penetration: %d, starting dmg: %.1f\n", iPenetrations, flDamage );
|
||
|
|
||
|
CBaseEntity *pPreviousHit = pLastHitEntity;
|
||
|
|
||
|
// skip the shooter always
|
||
|
CTraceFilterSkipTwoEntities ignoreShooterAndPrevious( this, pPreviousHit, iCollisionGroup );
|
||
|
UTIL_TraceLine( vecSrc, vecEnd, iTraceMask, &ignoreShooterAndPrevious, &tr );
|
||
|
|
||
|
const float rayExtension = 40.0f;
|
||
|
UTIL_ClipTraceToPlayers( vecSrc, vecEnd + info.m_vecDirShooting * rayExtension, iTraceMask, &ignoreShooterAndPrevious, &tr );
|
||
|
|
||
|
if ( tr.fraction == 1.0f )
|
||
|
break; // we didn't hit anything, stop tracing shoot
|
||
|
|
||
|
// New hitbox code that uses hitbox groups instead of trying to trace
|
||
|
// through the player
|
||
|
if ( tr.m_pEnt && tr.m_pEnt->IsPlayer() )
|
||
|
{
|
||
|
switch( tr.hitgroup )
|
||
|
{
|
||
|
#ifdef GAME_DLL
|
||
|
case HITGROUP_HEAD:
|
||
|
{
|
||
|
if ( tr.m_pEnt->GetTeamNumber() != GetTeamNumber() )
|
||
|
{
|
||
|
iNumHeadshots++;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
#endif
|
||
|
|
||
|
case HITGROUP_LEFTARM:
|
||
|
case HITGROUP_RIGHTARM:
|
||
|
{
|
||
|
//DevMsg( 2, "Hit arms, tracing against alt hitboxes.. \n" );
|
||
|
|
||
|
CDODPlayer *pPlayer = ToDODPlayer( tr.m_pEnt );
|
||
|
|
||
|
// set hitbox set to "dod_no_arms"
|
||
|
pPlayer->SetHitboxSet( 1 );
|
||
|
|
||
|
trace_t newTr;
|
||
|
|
||
|
// re-fire the trace
|
||
|
UTIL_TraceLine( vecSrc, vecEnd, iTraceMask, &ignoreShooterAndPrevious, &newTr );
|
||
|
|
||
|
// if we hit the same player in the chest
|
||
|
if ( tr.m_pEnt == newTr.m_pEnt )
|
||
|
{
|
||
|
//DevMsg( 2, ".. and we hit the chest.\n" );
|
||
|
|
||
|
Assert( tr.hitgroup != newTr.hitgroup ); // If we hit this, hitbox sets are broken
|
||
|
|
||
|
// use that damage instead
|
||
|
tr = newTr;
|
||
|
}
|
||
|
|
||
|
// set hitboxes back to "dod"
|
||
|
pPlayer->SetHitboxSet( 0 );
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pLastHitEntity = tr.m_pEnt;
|
||
|
|
||
|
if ( sv_showimpacts.GetBool() )
|
||
|
{
|
||
|
#ifdef CLIENT_DLL
|
||
|
// draw red client impact markers
|
||
|
debugoverlay->AddBoxOverlay( tr.endpos, Vector(-1,-1,-1), Vector(1,1,1), QAngle(0,0,0), 255, 0, 0, 127, 4 );
|
||
|
|
||
|
if ( tr.m_pEnt && tr.m_pEnt->IsPlayer() )
|
||
|
{
|
||
|
C_BasePlayer *player = ToBasePlayer( tr.m_pEnt );
|
||
|
player->DrawClientHitboxes( 4, true );
|
||
|
}
|
||
|
#else
|
||
|
// draw blue server impact markers
|
||
|
NDebugOverlay::Box( tr.endpos, Vector(-1,-1,-1), Vector(1,1,1), 0,0,255,127, 4 );
|
||
|
|
||
|
if ( tr.m_pEnt && tr.m_pEnt->IsPlayer() )
|
||
|
{
|
||
|
CBasePlayer *player = ToBasePlayer( tr.m_pEnt );
|
||
|
player->DrawServerHitboxes( 4, true );
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
#ifdef CLIENT_DLL
|
||
|
// See if the bullet ended up underwater + started out of the water
|
||
|
if ( enginetrace->GetPointContents( tr.endpos ) & (CONTENTS_WATER|CONTENTS_SLIME) )
|
||
|
{
|
||
|
trace_t waterTrace;
|
||
|
UTIL_TraceLine( vecSrc, tr.endpos, (MASK_SHOT|CONTENTS_WATER|CONTENTS_SLIME), this, iCollisionGroup, &waterTrace );
|
||
|
|
||
|
if( waterTrace.allsolid != 1 )
|
||
|
{
|
||
|
CEffectData data;
|
||
|
data.m_vOrigin = waterTrace.endpos;
|
||
|
data.m_vNormal = waterTrace.plane.normal;
|
||
|
data.m_flScale = random->RandomFloat( 8, 12 );
|
||
|
|
||
|
if ( waterTrace.contents & CONTENTS_SLIME )
|
||
|
{
|
||
|
data.m_fFlags |= FX_WATER_IN_SLIME;
|
||
|
}
|
||
|
|
||
|
DispatchEffect( "gunshotsplash", data );
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//Do Regular hit effects
|
||
|
|
||
|
// Don't decal nodraw surfaces
|
||
|
if ( !( tr.surface.flags & (SURF_SKY|SURF_NODRAW|SURF_HINT|SURF_SKIP) ) )
|
||
|
{
|
||
|
CBaseEntity *pEntity = tr.m_pEnt;
|
||
|
if ( !( !friendlyfire.GetBool() && pEntity && pEntity->GetTeamNumber() == GetTeamNumber() ) )
|
||
|
{
|
||
|
UTIL_ImpactTrace( &tr, iDamageType );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// Get surface where the bullet entered ( if it had different surfaces on enter and exit )
|
||
|
surfacedata_t *pSurfaceData = physprops->GetSurfaceData( tr.surface.surfaceProps );
|
||
|
Assert( pSurfaceData );
|
||
|
|
||
|
float flMaterialMod = GetDensityFromMaterial(pSurfaceData);
|
||
|
|
||
|
if ( iDamageType & DMG_MACHINEGUN )
|
||
|
{
|
||
|
flMaterialMod *= 0.65;
|
||
|
}
|
||
|
|
||
|
// try to penetrate object
|
||
|
Vector penetrationEnd;
|
||
|
float flMaxDistance = flDamage / flMaterialMod;
|
||
|
|
||
|
#ifndef CLIENT_DLL
|
||
|
ClearMultiDamage();
|
||
|
|
||
|
float flActualDamage = flDamage;
|
||
|
|
||
|
CTakeDamageInfo dmgInfo( info.m_pAttacker, info.m_pAttacker, flActualDamage, iDamageType );
|
||
|
CalculateBulletDamageForce( &dmgInfo, info.m_iAmmoType, info.m_vecDirShooting, tr.endpos );
|
||
|
tr.m_pEnt->DispatchTraceAttack( dmgInfo, info.m_vecDirShooting, &tr );
|
||
|
|
||
|
DevMsg( 2, "Giving damage ( %.1f ) to entity of type %s\n", flActualDamage, tr.m_pEnt->GetClassname() );
|
||
|
|
||
|
TraceAttackToTriggers( dmgInfo, tr.startpos, tr.endpos, info.m_vecDirShooting );
|
||
|
#endif
|
||
|
|
||
|
int stepsize = 16;
|
||
|
|
||
|
// displacement always stops the bullet
|
||
|
if ( tr.IsDispSurface() )
|
||
|
{
|
||
|
DevMsg( 2, "bullet was stopped by displacement\n" );
|
||
|
ApplyMultiDamage();
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// trace through the solid to find the exit point and how much material we went through
|
||
|
if ( !TraceToExit( tr.endpos, info.m_vecDirShooting, penetrationEnd, stepsize, flMaxDistance ) )
|
||
|
{
|
||
|
DevMsg( 2, "bullet was stopped\n" );
|
||
|
ApplyMultiDamage();
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// find exact penetration exit
|
||
|
CTraceFilterSimple ignoreShooter( this, iCollisionGroup );
|
||
|
UTIL_TraceLine( penetrationEnd, tr.endpos, iTraceMask, &ignoreShooter, &reverseTr );
|
||
|
|
||
|
// Now we can apply the damage, after we have traced the entity
|
||
|
// so it doesn't break or die before we have a change to test against it
|
||
|
#ifndef CLIENT_DLL
|
||
|
ApplyMultiDamage();
|
||
|
#endif
|
||
|
|
||
|
// Continue looking for the exit point
|
||
|
if( reverseTr.m_pEnt != tr.m_pEnt && reverseTr.m_pEnt != NULL )
|
||
|
{
|
||
|
// something was blocking, trace again
|
||
|
CTraceFilterSkipTwoEntities ignoreShooterAndBlocker( this, reverseTr.m_pEnt, iCollisionGroup );
|
||
|
UTIL_TraceLine( penetrationEnd, tr.endpos, iTraceMask, &ignoreShooterAndBlocker, &reverseTr );
|
||
|
}
|
||
|
|
||
|
if ( sv_showimpacts.GetBool() )
|
||
|
{
|
||
|
debugoverlay->AddLineOverlay( penetrationEnd, reverseTr.endpos, 255, 0, 0, true, 3.0 );
|
||
|
}
|
||
|
|
||
|
// penetration was successful
|
||
|
|
||
|
#ifdef CLIENT_DLL
|
||
|
// bullet did penetrate object, exit Decal
|
||
|
if ( !( reverseTr.surface.flags & (SURF_SKY|SURF_NODRAW|SURF_HINT|SURF_SKIP) ) )
|
||
|
{
|
||
|
CBaseEntity *pEntity = reverseTr.m_pEnt;
|
||
|
if ( !( !friendlyfire.GetBool() && pEntity && pEntity->GetTeamNumber() == GetTeamNumber() ) )
|
||
|
{
|
||
|
UTIL_ImpactTrace( &reverseTr, iDamageType );
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//setup new start end parameters for successive trace
|
||
|
|
||
|
// New start point is our last exit point
|
||
|
vecSrc = reverseTr.endpos + /* 1.0 * */ info.m_vecDirShooting;
|
||
|
|
||
|
// Reduce bullet damage by material and distanced travelled through that material
|
||
|
// if it is < 0 we won't go through the loop again
|
||
|
float flTraceDistance = VectorLength( reverseTr.endpos - tr.endpos );
|
||
|
|
||
|
flDamage -= flMaterialMod * flTraceDistance;
|
||
|
|
||
|
if( flDamage > 0 )
|
||
|
{
|
||
|
DevMsg( 2, "Completed penetration, new damage is %.1f\n", flDamage );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DevMsg( 2, "bullet was stopped\n" );
|
||
|
}
|
||
|
|
||
|
iPenetrations++;
|
||
|
}
|
||
|
|
||
|
#ifdef GAME_DLL
|
||
|
HandleHeadshotAchievement( iNumHeadshots );
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void CDODPlayer::SetSprinting( bool bIsSprinting )
|
||
|
{
|
||
|
m_Shared.SetSprinting( bIsSprinting );
|
||
|
}
|
||
|
|
||
|
bool CDODPlayer::IsSprinting( void )
|
||
|
{
|
||
|
float flVelSqr = GetAbsVelocity().LengthSqr();
|
||
|
|
||
|
return m_Shared.m_bIsSprinting && ( flVelSqr > 0.5f );
|
||
|
}
|
||
|
|
||
|
bool CDODPlayer::CanAttack( void )
|
||
|
{
|
||
|
if ( IsSprinting() )
|
||
|
return false;
|
||
|
|
||
|
if ( GetMoveType() == MOVETYPE_LADDER )
|
||
|
return false;
|
||
|
|
||
|
if ( m_Shared.IsJumping() )
|
||
|
return false;
|
||
|
|
||
|
if ( m_Shared.IsDefusing() )
|
||
|
return false;
|
||
|
|
||
|
// cannot attack while prone moving. except if you have a bazooka
|
||
|
if ( m_Shared.IsProne() && GetAbsVelocity().LengthSqr() > 1 )
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if( m_Shared.IsGoingProne() || m_Shared.IsGettingUpFromProne() )
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
CDODGameRules *rules = DODGameRules();
|
||
|
|
||
|
Assert( rules );
|
||
|
|
||
|
DODRoundState state = rules->State_Get();
|
||
|
|
||
|
if ( dod_bonusround.GetBool() )
|
||
|
{
|
||
|
if ( GetTeamNumber() == TEAM_ALLIES )
|
||
|
{
|
||
|
return ( state == STATE_RND_RUNNING || state == STATE_ALLIES_WIN );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return ( state == STATE_RND_RUNNING || state == STATE_AXIS_WIN );
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
return ( state == STATE_RND_RUNNING );
|
||
|
}
|
||
|
|
||
|
|
||
|
void CDODPlayer::SetAnimation( PLAYER_ANIM playerAnim )
|
||
|
{
|
||
|
// In DoD, its CPlayerAnimState object manages ALL the animation state.
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
// Input :
|
||
|
// Output : const Vector
|
||
|
//-----------------------------------------------------------------------------
|
||
|
const Vector CDODPlayer::GetPlayerMins( void ) const
|
||
|
{
|
||
|
if ( IsObserver() )
|
||
|
{
|
||
|
return VEC_OBS_HULL_MIN;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( GetFlags() & FL_DUCKING )
|
||
|
{
|
||
|
return VEC_DUCK_HULL_MIN;
|
||
|
}
|
||
|
else if ( m_Shared.IsProne() )
|
||
|
{
|
||
|
return VEC_PRONE_HULL_MIN;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return VEC_HULL_MIN;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
// Input :
|
||
|
// Output : const Vector
|
||
|
//-----------------------------------------------------------------------------
|
||
|
const Vector CDODPlayer::GetPlayerMaxs( void ) const
|
||
|
{
|
||
|
if ( IsObserver() )
|
||
|
{
|
||
|
return VEC_OBS_HULL_MAX_SCALED( this );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( GetFlags() & FL_DUCKING )
|
||
|
{
|
||
|
return VEC_DUCK_HULL_MAX_SCALED( this );
|
||
|
}
|
||
|
else if ( m_Shared.IsProne() )
|
||
|
{
|
||
|
return VEC_PRONE_HULL_MAX_SCALED( this );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return VEC_HULL_MAX_SCALED( this );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
// Input : collisionGroup -
|
||
|
// Output : Returns true on success, false on failure.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
bool CDODPlayer::ShouldCollide( int collisionGroup, int contentsMask ) const
|
||
|
{
|
||
|
if ( collisionGroup == COLLISION_GROUP_PLAYER_MOVEMENT || collisionGroup == COLLISION_GROUP_PROJECTILE )
|
||
|
{
|
||
|
switch( GetTeamNumber() )
|
||
|
{
|
||
|
case TEAM_ALLIES:
|
||
|
if ( !( contentsMask & CONTENTS_TEAM2 ) )
|
||
|
return false;
|
||
|
break;
|
||
|
|
||
|
case TEAM_AXIS:
|
||
|
if ( !( contentsMask & CONTENTS_TEAM1 ) )
|
||
|
return false;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return BaseClass::ShouldCollide( collisionGroup, contentsMask );
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------------------------------- //
|
||
|
// CDODPlayerShared implementation.
|
||
|
// --------------------------------------------------------------------------------------------------- //
|
||
|
|
||
|
CDODPlayerShared::CDODPlayerShared()
|
||
|
{
|
||
|
m_bProne = false;
|
||
|
m_bForceProneChange = false;
|
||
|
m_flNextProneCheck = 0;
|
||
|
|
||
|
m_flSlowedUntilTime = 0;
|
||
|
|
||
|
m_flUnProneTime = 0;
|
||
|
m_flGoProneTime = 0;
|
||
|
|
||
|
m_flDeployedHeight = STANDING_DEPLOY_HEIGHT;
|
||
|
m_flDeployChangeTime = gpGlobals->curtime;
|
||
|
|
||
|
SetDesiredPlayerClass( PLAYERCLASS_UNDEFINED );
|
||
|
|
||
|
m_flLastViewAnimationTime = gpGlobals->curtime;
|
||
|
|
||
|
m_pViewOffsetAnim = NULL;
|
||
|
}
|
||
|
|
||
|
CDODPlayerShared::~CDODPlayerShared()
|
||
|
{
|
||
|
if ( m_pViewOffsetAnim )
|
||
|
{
|
||
|
delete m_pViewOffsetAnim;
|
||
|
m_pViewOffsetAnim = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CDODPlayerShared::Init( CDODPlayer *pPlayer )
|
||
|
{
|
||
|
m_pOuter = pPlayer;
|
||
|
}
|
||
|
|
||
|
bool CDODPlayerShared::IsDucking( void ) const
|
||
|
{
|
||
|
return !!( m_pOuter->GetFlags() & FL_DUCKING );
|
||
|
}
|
||
|
|
||
|
bool CDODPlayerShared::IsProne() const
|
||
|
{
|
||
|
return m_bProne;
|
||
|
}
|
||
|
|
||
|
bool CDODPlayerShared::IsGettingUpFromProne() const
|
||
|
{
|
||
|
return ( m_flUnProneTime > 0 );
|
||
|
}
|
||
|
|
||
|
bool CDODPlayerShared::IsGoingProne() const
|
||
|
{
|
||
|
return ( m_flGoProneTime > 0 );
|
||
|
}
|
||
|
|
||
|
void CDODPlayerShared::SetSprinting( bool bSprinting )
|
||
|
{
|
||
|
if ( bSprinting && !m_bIsSprinting )
|
||
|
{
|
||
|
StartSprinting();
|
||
|
|
||
|
// only one penalty per key press
|
||
|
if ( m_bGaveSprintPenalty == false )
|
||
|
{
|
||
|
m_flStamina -= INITIAL_SPRINT_STAMINA_PENALTY;
|
||
|
m_bGaveSprintPenalty = true;
|
||
|
}
|
||
|
}
|
||
|
else if ( !bSprinting && m_bIsSprinting )
|
||
|
{
|
||
|
StopSprinting();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// this is reset when we let go of the sprint key
|
||
|
void CDODPlayerShared::ResetSprintPenalty( void )
|
||
|
{
|
||
|
m_bGaveSprintPenalty = false;
|
||
|
}
|
||
|
|
||
|
void CDODPlayerShared::StartSprinting( void )
|
||
|
{
|
||
|
m_bIsSprinting = true;
|
||
|
|
||
|
#ifndef CLIENT_DLL
|
||
|
m_pOuter->RemoveHintTimer( HINT_USE_SPRINT );
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void CDODPlayerShared::StopSprinting( void )
|
||
|
{
|
||
|
m_bIsSprinting = false;
|
||
|
}
|
||
|
|
||
|
void CDODPlayerShared::SetProne( bool bProne, bool bNoAnimation /* = false */ )
|
||
|
{
|
||
|
m_bProne = bProne;
|
||
|
|
||
|
if ( bNoAnimation )
|
||
|
{
|
||
|
m_flGoProneTime = 0;
|
||
|
m_flUnProneTime = 0;
|
||
|
|
||
|
// cancel the view animation!
|
||
|
m_bForceProneChange = true;
|
||
|
}
|
||
|
|
||
|
if ( !bProne /*&& IsSniperZoomed()*/ ) // forceunzoom for going prone is in StartGoingProne
|
||
|
{
|
||
|
ForceUnzoom();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CDODPlayerShared::SetJumping( bool bJumping )
|
||
|
{
|
||
|
m_bJumping = bJumping;
|
||
|
|
||
|
if ( IsSniperZoomed() )
|
||
|
{
|
||
|
ForceUnzoom();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CDODPlayerShared::ForceUnzoom( void )
|
||
|
{
|
||
|
CWeaponDODBase *pWeapon = GetActiveDODWeapon();
|
||
|
if( pWeapon && ( pWeapon->GetDODWpnData().m_WeaponType & WPN_MASK_GUN ) )
|
||
|
{
|
||
|
CDODSniperWeapon *pSniper = dynamic_cast<CDODSniperWeapon *>(pWeapon);
|
||
|
|
||
|
if ( pSniper )
|
||
|
{
|
||
|
pSniper->ZoomOut();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool CDODPlayerShared::IsBazookaDeployed( void ) const
|
||
|
{
|
||
|
CWeaponDODBase *pWeapon = GetActiveDODWeapon();
|
||
|
if( pWeapon && pWeapon->GetDODWpnData().m_WeaponType == WPN_TYPE_BAZOOKA )
|
||
|
{
|
||
|
CDODBaseRocketWeapon *pBazooka = (CDODBaseRocketWeapon *)pWeapon;
|
||
|
return pBazooka->IsDeployed() && !pBazooka->m_bInReload;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool CDODPlayerShared::IsBazookaOnlyDeployed( void ) const
|
||
|
{
|
||
|
CWeaponDODBase *pWeapon = GetActiveDODWeapon();
|
||
|
if( pWeapon && pWeapon->GetDODWpnData().m_WeaponType == WPN_TYPE_BAZOOKA )
|
||
|
{
|
||
|
CDODBaseRocketWeapon *pBazooka = (CDODBaseRocketWeapon *)pWeapon;
|
||
|
return pBazooka->IsDeployed();
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool CDODPlayerShared::IsSniperZoomed( void ) const
|
||
|
{
|
||
|
CWeaponDODBase *pWeapon = GetActiveDODWeapon();
|
||
|
if( pWeapon && ( pWeapon->GetDODWpnData().m_WeaponType & WPN_MASK_GUN ) )
|
||
|
{
|
||
|
CWeaponDODBaseGun *pGun = (CWeaponDODBaseGun *)pWeapon;
|
||
|
Assert( pGun );
|
||
|
return pGun->IsSniperZoomed();
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool CDODPlayerShared::IsInMGDeploy( void ) const
|
||
|
{
|
||
|
CWeaponDODBase *pWeapon = GetActiveDODWeapon();
|
||
|
if( pWeapon && pWeapon->GetDODWpnData().m_WeaponType == WPN_TYPE_MG )
|
||
|
{
|
||
|
CDODBipodWeapon *pMG = dynamic_cast<CDODBipodWeapon *>( pWeapon );
|
||
|
Assert( pMG );
|
||
|
return pMG->IsDeployed();
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool CDODPlayerShared::IsProneDeployed( void ) const
|
||
|
{
|
||
|
return ( IsProne() && IsInMGDeploy() );
|
||
|
}
|
||
|
|
||
|
bool CDODPlayerShared::IsSandbagDeployed( void ) const
|
||
|
{
|
||
|
return ( !IsProne() && IsInMGDeploy() );
|
||
|
}
|
||
|
|
||
|
void CDODPlayerShared::SetDesiredPlayerClass( int playerclass )
|
||
|
{
|
||
|
m_iDesiredPlayerClass = playerclass;
|
||
|
}
|
||
|
|
||
|
int CDODPlayerShared::DesiredPlayerClass( void )
|
||
|
{
|
||
|
return m_iDesiredPlayerClass;
|
||
|
}
|
||
|
|
||
|
void CDODPlayerShared::SetPlayerClass( int playerclass )
|
||
|
{
|
||
|
m_iPlayerClass = playerclass;
|
||
|
}
|
||
|
|
||
|
int CDODPlayerShared::PlayerClass( void )
|
||
|
{
|
||
|
return m_iPlayerClass;
|
||
|
}
|
||
|
|
||
|
void CDODPlayerShared::SetStamina( float flStamina )
|
||
|
{
|
||
|
m_flStamina = clamp( flStamina, 0, 100 );
|
||
|
}
|
||
|
|
||
|
CWeaponDODBase* CDODPlayerShared::GetActiveDODWeapon() const
|
||
|
{
|
||
|
CBaseCombatWeapon *pWeapon = m_pOuter->GetActiveWeapon();
|
||
|
if ( pWeapon )
|
||
|
{
|
||
|
Assert( dynamic_cast< CWeaponDODBase* >( pWeapon ) == static_cast< CWeaponDODBase* >( pWeapon ) );
|
||
|
return static_cast< CWeaponDODBase* >( pWeapon );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CDODPlayerShared::SetDeployed( bool bDeployed, float flHeight /* = -1 */ )
|
||
|
{
|
||
|
if( gpGlobals->curtime - m_flDeployChangeTime < 0.2 )
|
||
|
{
|
||
|
Assert(0);
|
||
|
}
|
||
|
|
||
|
m_flDeployChangeTime = gpGlobals->curtime;
|
||
|
m_vecDeployedAngles = m_pOuter->EyeAngles();
|
||
|
|
||
|
if( flHeight > 0 )
|
||
|
{
|
||
|
m_flDeployedHeight = flHeight;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_flDeployedHeight = m_pOuter->GetViewOffset()[2];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
QAngle CDODPlayerShared::GetDeployedAngles( void ) const
|
||
|
{
|
||
|
return m_vecDeployedAngles;
|
||
|
}
|
||
|
|
||
|
void CDODPlayerShared::SetDeployedYawLimits( float flLeftYaw, float flRightYaw )
|
||
|
{
|
||
|
m_flDeployedYawLimitLeft = flLeftYaw;
|
||
|
m_flDeployedYawLimitRight = -flRightYaw;
|
||
|
|
||
|
m_vecDeployedAngles = m_pOuter->EyeAngles();
|
||
|
}
|
||
|
|
||
|
void CDODPlayerShared::ClampDeployedAngles( QAngle *vecTestAngles )
|
||
|
{
|
||
|
Assert( vecTestAngles );
|
||
|
|
||
|
// Clamp Pitch
|
||
|
vecTestAngles->x = clamp( vecTestAngles->x, MAX_DEPLOY_PITCH, MIN_DEPLOY_PITCH );
|
||
|
|
||
|
// Clamp Yaw - do a bit more work as yaw will wrap around and cause problems
|
||
|
float flDeployedYawCenter = GetDeployedAngles().y;
|
||
|
|
||
|
float flDelta = AngleNormalize( vecTestAngles->y - flDeployedYawCenter );
|
||
|
|
||
|
if( flDelta < m_flDeployedYawLimitRight )
|
||
|
{
|
||
|
vecTestAngles->y = flDeployedYawCenter + m_flDeployedYawLimitRight;
|
||
|
}
|
||
|
else if( flDelta > m_flDeployedYawLimitLeft )
|
||
|
{
|
||
|
vecTestAngles->y = flDeployedYawCenter + m_flDeployedYawLimitLeft;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
Msg( "delta %.1f ( left %.1f, right %.1f ) ( %.1f -> %.1f )\n",
|
||
|
flDelta,
|
||
|
flDeployedYawCenter + m_flDeployedYawLimitLeft,
|
||
|
flDeployedYawCenter + m_flDeployedYawLimitRight,
|
||
|
before,
|
||
|
vecTestAngles->y );
|
||
|
*/
|
||
|
|
||
|
}
|
||
|
|
||
|
float CDODPlayerShared::GetDeployedHeight( void ) const
|
||
|
{
|
||
|
return m_flDeployedHeight;
|
||
|
}
|
||
|
|
||
|
float CDODPlayerShared::GetSlowedTime( void ) const
|
||
|
{
|
||
|
return m_flSlowedUntilTime;
|
||
|
}
|
||
|
|
||
|
void CDODPlayerShared::SetSlowedTime( float t )
|
||
|
{
|
||
|
m_flSlowedUntilTime = gpGlobals->curtime + t;
|
||
|
}
|
||
|
|
||
|
void CDODPlayerShared::StartGoingProne( void )
|
||
|
{
|
||
|
// make the prone sound
|
||
|
CPASFilter filter( m_pOuter->GetAbsOrigin() );
|
||
|
filter.UsePredictionRules();
|
||
|
m_pOuter->EmitSound( filter, m_pOuter->entindex(), "Player.GoProne" );
|
||
|
|
||
|
// slow to prone speed
|
||
|
m_flGoProneTime = gpGlobals->curtime + TIME_TO_PRONE;
|
||
|
|
||
|
m_flUnProneTime = 0.0f; //reset
|
||
|
|
||
|
if ( IsSniperZoomed() )
|
||
|
ForceUnzoom();
|
||
|
}
|
||
|
|
||
|
void CDODPlayerShared::StandUpFromProne( void )
|
||
|
{
|
||
|
// make the prone sound
|
||
|
CPASFilter filter( m_pOuter->GetAbsOrigin() );
|
||
|
filter.UsePredictionRules();
|
||
|
m_pOuter->EmitSound( filter, m_pOuter->entindex(), "Player.UnProne" );
|
||
|
|
||
|
// speed up to target speed
|
||
|
m_flUnProneTime = gpGlobals->curtime + TIME_TO_PRONE;
|
||
|
|
||
|
m_flGoProneTime = 0.0f; //reset
|
||
|
}
|
||
|
|
||
|
bool CDODPlayerShared::CanChangePosition( void )
|
||
|
{
|
||
|
if ( IsInMGDeploy() )
|
||
|
return false;
|
||
|
|
||
|
if ( IsGettingUpFromProne() )
|
||
|
return false;
|
||
|
|
||
|
if ( IsGoingProne() )
|
||
|
return false;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void CDODPlayer::UpdateStepSound( surfacedata_t *psurface, const Vector &vecOrigin, const Vector &vecVelocity )
|
||
|
{
|
||
|
Vector knee;
|
||
|
Vector feet;
|
||
|
float height;
|
||
|
int fLadder;
|
||
|
|
||
|
if ( m_flStepSoundTime > 0 )
|
||
|
{
|
||
|
m_flStepSoundTime -= 1000.0f * gpGlobals->frametime;
|
||
|
if ( m_flStepSoundTime < 0 )
|
||
|
{
|
||
|
m_flStepSoundTime = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( m_flStepSoundTime > 0 )
|
||
|
return;
|
||
|
|
||
|
if ( GetFlags() & (FL_FROZEN|FL_ATCONTROLS))
|
||
|
return;
|
||
|
|
||
|
if ( GetMoveType() == MOVETYPE_NOCLIP || GetMoveType() == MOVETYPE_OBSERVER )
|
||
|
return;
|
||
|
|
||
|
if ( !sv_footsteps.GetFloat() )
|
||
|
return;
|
||
|
|
||
|
float speed = VectorLength( vecVelocity );
|
||
|
float groundspeed = Vector2DLength( vecVelocity.AsVector2D() );
|
||
|
|
||
|
// determine if we are on a ladder
|
||
|
fLadder = ( GetMoveType() == MOVETYPE_LADDER );
|
||
|
|
||
|
float flDuck;
|
||
|
|
||
|
if ( ( GetFlags() & FL_DUCKING) || fLadder )
|
||
|
{
|
||
|
flDuck = 100;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
flDuck = 0;
|
||
|
}
|
||
|
|
||
|
static float flMinProneSpeed = 10.0f;
|
||
|
static float flMinSpeed = 70.0f;
|
||
|
static float flRunSpeed = 110.0f;
|
||
|
|
||
|
bool onground = ( GetFlags() & FL_ONGROUND );
|
||
|
bool movingalongground = ( groundspeed > 0.0f );
|
||
|
bool moving_fast_enough = ( speed >= flMinSpeed );
|
||
|
|
||
|
// always play a step sound if we are moving faster than
|
||
|
|
||
|
// To hear step sounds you must be either on a ladder or moving along the ground AND
|
||
|
// You must be moving fast enough
|
||
|
|
||
|
CheckProneMoveSound( groundspeed, onground );
|
||
|
|
||
|
if ( !moving_fast_enough || !(fLadder || ( onground && movingalongground )) )
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
bool bWalking = ( speed < flRunSpeed ); // or ducking!
|
||
|
|
||
|
VectorCopy( vecOrigin, knee );
|
||
|
VectorCopy( vecOrigin, feet );
|
||
|
|
||
|
height = GetPlayerMaxs()[ 2 ] - GetPlayerMins()[ 2 ];
|
||
|
|
||
|
knee[2] = vecOrigin[2] + 0.2 * height;
|
||
|
|
||
|
float flVol;
|
||
|
|
||
|
// find out what we're stepping in or on...
|
||
|
if ( fLadder )
|
||
|
{
|
||
|
psurface = physprops->GetSurfaceData( physprops->GetSurfaceIndex( "ladder" ) );
|
||
|
flVol = 1.0;
|
||
|
m_flStepSoundTime = 350;
|
||
|
}
|
||
|
else if ( enginetrace->GetPointContents( knee ) & MASK_WATER )
|
||
|
{
|
||
|
static int iSkipStep = 0;
|
||
|
|
||
|
if ( iSkipStep == 0 )
|
||
|
{
|
||
|
iSkipStep++;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( iSkipStep++ == 3 )
|
||
|
{
|
||
|
iSkipStep = 0;
|
||
|
}
|
||
|
psurface = physprops->GetSurfaceData( physprops->GetSurfaceIndex( "wade" ) );
|
||
|
flVol = 0.65;
|
||
|
m_flStepSoundTime = 600;
|
||
|
}
|
||
|
else if ( enginetrace->GetPointContents( feet ) & MASK_WATER )
|
||
|
{
|
||
|
psurface = physprops->GetSurfaceData( physprops->GetSurfaceIndex( "water" ) );
|
||
|
flVol = bWalking ? 0.2 : 0.5;
|
||
|
m_flStepSoundTime = bWalking ? 400 : 300;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( !psurface )
|
||
|
return;
|
||
|
|
||
|
if ( bWalking )
|
||
|
{
|
||
|
m_flStepSoundTime = 400;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( speed > 200 )
|
||
|
{
|
||
|
int speeddiff = PLAYER_SPEED_SPRINT - PLAYER_SPEED_RUN;
|
||
|
int diff = speed - PLAYER_SPEED_RUN;
|
||
|
|
||
|
float percent = (float)diff / (float)speeddiff;
|
||
|
|
||
|
m_flStepSoundTime = 300.0f - 30.0f * percent;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_flStepSoundTime = 400;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
switch ( psurface->game.material )
|
||
|
{
|
||
|
default:
|
||
|
case CHAR_TEX_CONCRETE:
|
||
|
flVol = bWalking ? 0.2 : 0.5;
|
||
|
break;
|
||
|
|
||
|
case CHAR_TEX_METAL:
|
||
|
flVol = bWalking ? 0.2 : 0.5;
|
||
|
break;
|
||
|
|
||
|
case CHAR_TEX_DIRT:
|
||
|
flVol = bWalking ? 0.25 : 0.55;
|
||
|
break;
|
||
|
|
||
|
case CHAR_TEX_VENT:
|
||
|
flVol = bWalking ? 0.4 : 0.7;
|
||
|
break;
|
||
|
|
||
|
case CHAR_TEX_GRATE:
|
||
|
flVol = bWalking ? 0.2 : 0.5;
|
||
|
break;
|
||
|
|
||
|
case CHAR_TEX_TILE:
|
||
|
flVol = bWalking ? 0.2 : 0.5;
|
||
|
break;
|
||
|
|
||
|
case CHAR_TEX_SLOSH:
|
||
|
flVol = bWalking ? 0.2 : 0.5;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
m_flStepSoundTime += flDuck; // slower step time if ducking
|
||
|
|
||
|
if ( GetFlags() & FL_DUCKING )
|
||
|
{
|
||
|
flVol *= 0.65;
|
||
|
}
|
||
|
|
||
|
// protect us from prediction errors a little bit
|
||
|
if ( m_flMinNextStepSoundTime > gpGlobals->curtime )
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
m_flMinNextStepSoundTime = gpGlobals->curtime + 0.1f;
|
||
|
|
||
|
PlayStepSound( feet, psurface, flVol, false );
|
||
|
}
|
||
|
|
||
|
void CDODPlayer::CheckProneMoveSound( int groundspeed, bool onground )
|
||
|
{
|
||
|
#ifdef CLIENT_DLL
|
||
|
bool bShouldPlay = (groundspeed > 10) && (onground == true) && m_Shared.IsProne() && IsAlive();
|
||
|
|
||
|
if ( m_bPlayingProneMoveSound && !bShouldPlay )
|
||
|
{
|
||
|
StopSound( "Player.MoveProne" );
|
||
|
m_bPlayingProneMoveSound= false;
|
||
|
}
|
||
|
else if ( !m_bPlayingProneMoveSound && bShouldPlay )
|
||
|
{
|
||
|
CRecipientFilter filter;
|
||
|
filter.AddRecipientsByPAS( WorldSpaceCenter() );
|
||
|
EmitSound( filter, entindex(), "Player.MoveProne" );
|
||
|
|
||
|
m_bPlayingProneMoveSound = true;
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
// Input : step -
|
||
|
// fvol -
|
||
|
// force - force sound to play
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CDODPlayer::PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool force )
|
||
|
{
|
||
|
if ( gpGlobals->maxClients > 1 && !sv_footsteps.GetFloat() )
|
||
|
return;
|
||
|
|
||
|
#if defined( CLIENT_DLL )
|
||
|
// during prediction play footstep sounds only once
|
||
|
if ( prediction->InPrediction() && !prediction->IsFirstTimePredicted() )
|
||
|
return;
|
||
|
#endif
|
||
|
|
||
|
if ( !psurface )
|
||
|
return;
|
||
|
|
||
|
unsigned short stepSoundName = m_Local.m_nStepside ? psurface->sounds.stepleft : psurface->sounds.stepright;
|
||
|
m_Local.m_nStepside = !m_Local.m_nStepside;
|
||
|
|
||
|
if ( !stepSoundName )
|
||
|
return;
|
||
|
|
||
|
IPhysicsSurfaceProps *physprops = MoveHelper( )->GetSurfaceProps();
|
||
|
const char *pSoundName = physprops->GetString( stepSoundName );
|
||
|
CSoundParameters params;
|
||
|
|
||
|
// we don't always know the model, so go by team
|
||
|
char *pModelNameForGender = DOD_PLAYERMODEL_AXIS_RIFLEMAN;
|
||
|
|
||
|
if( GetTeamNumber() == TEAM_ALLIES )
|
||
|
pModelNameForGender = DOD_PLAYERMODEL_US_RIFLEMAN;
|
||
|
|
||
|
if ( !CBaseEntity::GetParametersForSound( pSoundName, params, pModelNameForGender ) )
|
||
|
return;
|
||
|
|
||
|
CRecipientFilter filter;
|
||
|
filter.AddRecipientsByPAS( vecOrigin );
|
||
|
|
||
|
#ifndef CLIENT_DLL
|
||
|
// im MP, server removed all players in origins PVS, these players
|
||
|
// generate the footsteps clientside
|
||
|
if ( gpGlobals->maxClients > 1 )
|
||
|
filter.RemoveRecipientsByPVS( vecOrigin );
|
||
|
#endif
|
||
|
|
||
|
EmitSound_t ep;
|
||
|
ep.m_nChannel = params.channel;
|
||
|
ep.m_pSoundName = params.soundname;
|
||
|
ep.m_flVolume = fvol;
|
||
|
ep.m_SoundLevel = params.soundlevel;
|
||
|
ep.m_nFlags = 0;
|
||
|
ep.m_nPitch = params.pitch;
|
||
|
ep.m_pOrigin = &vecOrigin;
|
||
|
|
||
|
EmitSound( filter, entindex(), ep );
|
||
|
}
|
||
|
|
||
|
Activity CDODPlayer::TranslateActivity( Activity baseAct, bool *pRequired /* = NULL */ )
|
||
|
{
|
||
|
Activity translated = baseAct;
|
||
|
|
||
|
if ( GetActiveWeapon() )
|
||
|
{
|
||
|
translated = GetActiveWeapon()->ActivityOverride( baseAct, pRequired );
|
||
|
}
|
||
|
else if (pRequired)
|
||
|
{
|
||
|
*pRequired = false;
|
||
|
}
|
||
|
|
||
|
return translated;
|
||
|
}
|
||
|
|
||
|
void CDODPlayerShared::SetCPIndex( int index )
|
||
|
{
|
||
|
#ifdef CLIENT_DLL
|
||
|
|
||
|
if ( m_pOuter->IsLocalPlayer() )
|
||
|
{
|
||
|
if ( index == -1 )
|
||
|
{
|
||
|
// just left an area
|
||
|
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "ObjectiveIconShrink" );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "ObjectiveIconGrow" );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
m_iCPIndex = index;
|
||
|
}
|
||
|
|
||
|
void CDODPlayerShared::SetLastViewAnimTime( float flTime )
|
||
|
{
|
||
|
m_flLastViewAnimationTime = flTime;
|
||
|
}
|
||
|
|
||
|
float CDODPlayerShared::GetLastViewAnimTime( void )
|
||
|
{
|
||
|
return m_flLastViewAnimationTime;
|
||
|
}
|
||
|
|
||
|
void CDODPlayerShared::ResetViewOffsetAnimation( void )
|
||
|
{
|
||
|
if ( m_pViewOffsetAnim )
|
||
|
{
|
||
|
//cancel it!
|
||
|
m_pViewOffsetAnim->Reset();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CDODPlayerShared::ViewOffsetAnimation( Vector vecDest, float flTime, ViewAnimationType type )
|
||
|
{
|
||
|
if ( !m_pViewOffsetAnim )
|
||
|
{
|
||
|
m_pViewOffsetAnim = CViewOffsetAnimation::CreateViewOffsetAnim( m_pOuter );
|
||
|
}
|
||
|
|
||
|
Assert( m_pViewOffsetAnim );
|
||
|
|
||
|
if ( m_pViewOffsetAnim )
|
||
|
{
|
||
|
m_pViewOffsetAnim->StartAnimation( m_pOuter->GetViewOffset(), vecDest, flTime, type );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CDODPlayerShared::ViewAnimThink( void )
|
||
|
{
|
||
|
// Check for the flag that will reset our view animations
|
||
|
// when the player respawns
|
||
|
if ( m_bForceProneChange )
|
||
|
{
|
||
|
ResetViewOffsetAnimation();
|
||
|
|
||
|
m_pOuter->SetViewOffset( VEC_VIEW_SCALED( m_pOuter ) );
|
||
|
|
||
|
m_bForceProneChange = false;
|
||
|
}
|
||
|
|
||
|
if ( m_pViewOffsetAnim )
|
||
|
{
|
||
|
m_pViewOffsetAnim->Think();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CDODPlayerShared::ComputeWorldSpaceSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs )
|
||
|
{
|
||
|
Vector org = m_pOuter->GetAbsOrigin();
|
||
|
|
||
|
if ( IsProne() )
|
||
|
{
|
||
|
static Vector vecProneMin(-44, -44, 0 );
|
||
|
static Vector vecProneMax(44, 44, 24 );
|
||
|
|
||
|
VectorAdd( vecProneMin, org, *pVecWorldMins );
|
||
|
VectorAdd( vecProneMax, org, *pVecWorldMaxs );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
static Vector vecMin(-32, -32, 0 );
|
||
|
static Vector vecMax(32, 32, 72 );
|
||
|
|
||
|
VectorAdd( vecMin, org, *pVecWorldMins );
|
||
|
VectorAdd( vecMax, org, *pVecWorldMaxs );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: Sets whether this player is dominating the specified other player
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CDODPlayerShared::SetPlayerDominated( CDODPlayer *pPlayer, bool bDominated )
|
||
|
{
|
||
|
int iPlayerIndex = pPlayer->entindex();
|
||
|
m_bPlayerDominated.Set( iPlayerIndex, bDominated );
|
||
|
pPlayer->m_Shared.SetPlayerDominatingMe( m_pOuter, bDominated );
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: Sets whether this player is being dominated by the other player
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CDODPlayerShared::SetPlayerDominatingMe( CDODPlayer *pPlayer, bool bDominated )
|
||
|
{
|
||
|
int iPlayerIndex = pPlayer->entindex();
|
||
|
m_bPlayerDominatingMe.Set( iPlayerIndex, bDominated );
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: Returns whether this player is dominating the specified other player
|
||
|
//-----------------------------------------------------------------------------
|
||
|
bool CDODPlayerShared::IsPlayerDominated( int iPlayerIndex )
|
||
|
{
|
||
|
#ifdef CLIENT_DLL
|
||
|
// On the client, we only have data for the local player.
|
||
|
// As a result, it's only valid to ask for dominations related to the local player
|
||
|
C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer();
|
||
|
if ( !pLocalPlayer )
|
||
|
return false;
|
||
|
|
||
|
Assert( m_pOuter->IsLocalPlayer() || pLocalPlayer->entindex() == iPlayerIndex );
|
||
|
|
||
|
if ( m_pOuter->IsLocalPlayer() )
|
||
|
return m_bPlayerDominated.Get( iPlayerIndex );
|
||
|
|
||
|
return pLocalPlayer->m_Shared.IsPlayerDominatingMe( m_pOuter->entindex() );
|
||
|
#else
|
||
|
// Server has all the data.
|
||
|
return m_bPlayerDominated.Get( iPlayerIndex );
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
bool CDODPlayerShared::IsPlayerDominatingMe( int iPlayerIndex )
|
||
|
{
|
||
|
return m_bPlayerDominatingMe.Get( iPlayerIndex );
|
||
|
}
|