Dynamic NPC Footsteps
Similar to Half-Life, Half-Life 2 contained no dynamic footsteps for NPCs; dynamic footsteps meaning that they change when different surfaces are walked on.
Note:This overrides all NPC footsteps; this means the Combine will not sound like they used to when they walk. An extra addition would need to be taken regarding another
EmitSound
to still include the original sound.Contents
src\client\c_baseanimating.h
Includes
- vphysics_interface.h
Private Prototypes
virtual void UpdateStepSound( surfacedata_t *psurface, const Vector &vecOrigin, const Vector &vecVelocity, bool left ); virtual void PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool left ); virtual surfacedata_t *GetGroundSurface();
src\client\c_baseanimating.cpp
Includes
- decals.h
- soundemittersystem/isoundemittersystembase.h
Player Cloned Functions
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
extern ConVar sv_footsteps;
void C_BaseAnimating::UpdateStepSound( surfacedata_t *psurface, const Vector &vecOrigin, const Vector &vecVelocity, bool left )
{
int fWalking;
float fvol;
Vector knee;
Vector feet;
float height;
if ( GetFlags() & (FL_FROZEN|FL_ATCONTROLS))
return;
if ( !sv_footsteps.GetFloat() )
return;
float groundspeed = vecVelocity.Length2DSqr();
bool movingalongground = ( groundspeed > 0.0f );
// To hear step sounds you must be either on a ladder or moving along the ground AND
// You must be moving fast enough
if ( !movingalongground )
return;
fWalking = groundspeed < RUN_SPEED_ESTIMATE_SQR;
VectorCopy( vecOrigin, knee );
VectorCopy( vecOrigin, feet );
height = GetCollideable()->OBBMaxs()[ 2 ] - GetCollideable()->OBBMins()[ 2 ];
knee[2] = vecOrigin[2] + 0.2 * height;
// find out what we're stepping in or on...
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" ) );
fvol = 0.65;
}
else if ( enginetrace->GetPointContents( feet ) & MASK_WATER )
{
psurface = physprops->GetSurfaceData( physprops->GetSurfaceIndex( "water" ) );
fvol = fWalking ? 0.2 : 0.5;
}
else
{
if ( !psurface )
return;
switch ( psurface->game.material )
{
default:
case CHAR_TEX_CONCRETE:
fvol = fWalking ? 0.2 : 0.5;
break;
case CHAR_TEX_METAL:
fvol = fWalking ? 0.2 : 0.5;
break;
case CHAR_TEX_DIRT:
fvol = fWalking ? 0.25 : 0.55;
break;
case CHAR_TEX_VENT:
fvol = fWalking ? 0.4 : 0.7;
break;
case CHAR_TEX_GRATE:
fvol = fWalking ? 0.2 : 0.5;
break;
case CHAR_TEX_TILE:
fvol = fWalking ? 0.2 : 0.5;
break;
case CHAR_TEX_SLOSH:
fvol = fWalking ? 0.2 : 0.5;
break;
}
}
// play the sound
// 65% volume if ducking
if ( GetFlags() & FL_DUCKING )
{
fvol *= 0.65;
}
PlayStepSound( feet, psurface, fvol, left );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_BaseAnimating::PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool left )
{
if ( gpGlobals->maxClients > 1 && !sv_footsteps.GetFloat() )
return;
if ( !psurface )
return;
unsigned short stepSoundName = left ? psurface->sounds.stepleft : psurface->sounds.stepright;
if ( !stepSoundName )
return;
const char *pSoundName = physprops->GetString( stepSoundName );
CSoundParameters params;
if ( !CBaseEntity::GetParametersForSound( pSoundName, params, NULL ) )
return;
CPASFilter filter(vecOrigin);
EmitSound_t ep;
ep.m_nChannel = CHAN_BODY;
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 );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
surfacedata_t *C_BaseAnimating::GetGroundSurface()
{
//
// Find the name of the material that lies beneath the player.
//
Vector start, end;
VectorCopy( GetAbsOrigin(), start );
VectorCopy( start, end );
// Straight down
end.z -= 64;
// Fill in default values, just in case.
Ray_t ray;
ray.Init( start, end, GetCollideable()->OBBMins(), GetCollideable()->OBBMaxs() );
trace_t trace;
UTIL_TraceRay( ray, MASK_NPCSOLID, this, COLLISION_GROUP_NPC, &trace );
if ( trace.fraction == 1.0f )
return NULL; // no ground
return physprops->GetSurfaceData( trace.surface.surfaceProps );
}
Left Foot
#ifndef HL2MP
char pSoundName[256];
if ( !options || !options[0] )
{
options = "NPC_CombineS";
}
Vector vel;
EstimateAbsVelocity( vel );
// If he's moving fast enough, play the run sound
if ( vel.Length2DSqr() > RUN_SPEED_ESTIMATE_SQR )
{
Q_snprintf( pSoundName, 256, "%s.RunFootstepLeft", options );
}
else
{
Q_snprintf( pSoundName, 256, "%s.FootstepLeft", options );
}
EmitSound( pSoundName );
#endif
if ( IsNPC() )
{
Vector vel;
EstimateAbsVelocity( vel );
UpdateStepSound( GetGroundSurface(), GetAbsOrigin(), vel, true );
}
Right Foot
#ifndef HL2MP
char pSoundName[256];
if ( !options || !options[0] )
{
options = "NPC_CombineS";
}
Vector vel;
EstimateAbsVelocity( vel );
// If he's moving fast enough, play the run sound
if ( vel.Length2DSqr() > RUN_SPEED_ESTIMATE_SQR )
{
Q_snprintf( pSoundName, 256, "%s.RunFootstepRight", options );
}
else
{
Q_snprintf( pSoundName, 256, "%s.FootstepRight", options );
}
EmitSound( pSoundName );
#endif
if ( IsNPC() )
{
Vector vel;
EstimateAbsVelocity( vel );
UpdateStepSound( GetGroundSurface(), GetAbsOrigin(), vel, false );
}