summaryrefslogtreecommitdiff
path: root/game/shared/dod/dod_player_shared.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/shared/dod/dod_player_shared.cpp')
-rw-r--r--game/shared/dod/dod_player_shared.cpp1396
1 files changed, 1396 insertions, 0 deletions
diff --git a/game/shared/dod/dod_player_shared.cpp b/game/shared/dod/dod_player_shared.cpp
new file mode 100644
index 0000000..ec35acf
--- /dev/null
+++ b/game/shared/dod/dod_player_shared.cpp
@@ -0,0 +1,1396 @@
+//========= 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 );
+}