Difference between revisions of "Dynamic NPC Footsteps"

From Valve Developer Community
Jump to: navigation, search
m (recategorize)
m (Cleanup, syntax highlighting, cl_dll -> client)
 
Line 1: Line 1:
Similarly to [[Half-Life]], [[Half-Life 2]] contained no dynamic footsteps for NPCs; dynamic footsteps meaning that they change when different surfaces are walked on.
+
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 <code>EmitSound</code> to still include the original sound.}}
 
{{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 <code>EmitSound</code> to still include the original sound.}}
===src\cl_dll\c_baseanimating.h===
+
 
====Includes====
+
=== src\client\c_baseanimating.h ===
 +
 
 +
==== Includes ====
 
* vphysics_interface.h
 
* vphysics_interface.h
====Private Prototypes====
+
 
 +
==== Private Prototypes ====
 
  virtual void UpdateStepSound( surfacedata_t *psurface, const Vector &vecOrigin, const Vector &vecVelocity, bool left );
 
  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 void PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool left );
  virtual surfacedata_t* GetGroundSurface();
+
  virtual surfacedata_t *GetGroundSurface();
===src\cl_dll\c_baseanimating.cpp===
+
 
====Includes====
+
=== src\client\c_baseanimating.cpp ===
 +
 
 +
==== Includes ====
 
* decals.h
 
* decals.h
 
* soundemittersystem/isoundemittersystembase.h
 
* soundemittersystem/isoundemittersystembase.h
====Player Cloned Functions====
+
 
<pre style="margin:0px 0px 0px 0px;">extern ConVar sv_footsteps;
+
==== Player Cloned Functions ====
 +
<source lang=cpp>
 +
//-----------------------------------------------------------------------------
 +
// Purpose:  
 +
//-----------------------------------------------------------------------------
 +
extern ConVar sv_footsteps;
 +
 
 
void C_BaseAnimating::UpdateStepSound( surfacedata_t *psurface, const Vector &vecOrigin, const Vector &vecVelocity, bool left )
 
void C_BaseAnimating::UpdateStepSound( surfacedata_t *psurface, const Vector &vecOrigin, const Vector &vecVelocity, bool left )
 
{
 
{
int fWalking;
+
int fWalking;
 
float fvol;
 
float fvol;
 
Vector knee;
 
Vector knee;
Line 117: Line 129:
 
PlayStepSound( feet, psurface, fvol, left );
 
PlayStepSound( feet, psurface, fvol, left );
 
}
 
}
 +
 +
//-----------------------------------------------------------------------------
 +
// Purpose:
 +
//-----------------------------------------------------------------------------
 
void C_BaseAnimating::PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool left )
 
void C_BaseAnimating::PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool left )
 
{
 
{
Line 148: Line 164:
 
EmitSound( filter, entindex(), ep );
 
EmitSound( filter, entindex(), ep );
 
}
 
}
surfacedata_t* C_BaseAnimating::GetGroundSurface()
+
 
 +
//-----------------------------------------------------------------------------
 +
// Purpose:
 +
//-----------------------------------------------------------------------------
 +
surfacedata_t *C_BaseAnimating::GetGroundSurface()
 
{
 
{
 
//
 
//
Line 172: Line 192:
 
 
 
return physprops->GetSurfaceData( trace.surface.surfaceProps );
 
return physprops->GetSurfaceData( trace.surface.surfaceProps );
}</pre>
+
}
 +
</source>
 +
 
 +
==== Left Foot ====
  
====Left Foot====
+
<source lang=cpp>
{|style="background:transparent;"
+
#ifndef HL2MP
|<pre style="margin:0px 0px 0px 0px;">#ifndef HL2MP
 
 
char pSoundName[256];
 
char pSoundName[256];
 
if ( !options || !options[0] )
 
if ( !options || !options[0] )
Line 196: Line 218:
 
}
 
}
 
EmitSound( pSoundName );
 
EmitSound( pSoundName );
#endif</pre>
+
#endif
|-
+
</source>
|style="text-align:center;"|&darr;
+
 
|-
+
<center>&darr;</center>
|<pre style="margin:0px 0px 0px 0px;"> if(IsNPC())
+
 
 +
<source lang=cpp>
 +
if ( IsNPC() )
 
{
 
{
 
Vector vel;
 
Vector vel;
 
EstimateAbsVelocity( vel );
 
EstimateAbsVelocity( vel );
 
UpdateStepSound( GetGroundSurface(), GetAbsOrigin(), vel, true );
 
UpdateStepSound( GetGroundSurface(), GetAbsOrigin(), vel, true );
}</pre>
+
}
|}
+
</source>
====Right Foot====
+
 
{|style="background:transparent;"
+
==== Right Foot ====
|<pre style="margin:0px 0px 0px 0px;">#ifndef HL2MP
+
<source lang=cpp>
 +
#ifndef HL2MP
 
char pSoundName[256];
 
char pSoundName[256];
 
if ( !options || !options[0] )
 
if ( !options || !options[0] )
Line 228: Line 253:
 
}
 
}
 
EmitSound( pSoundName );
 
EmitSound( pSoundName );
 +
#endif
 +
</source>
  
#endif
+
<center>&darr;</center>
</pre>
+
 
|-
+
<source lang=cpp>
|style="text-align:center;"|&darr;
+
if ( IsNPC() )
|-
 
|<pre style="margin:0px 0px 0px 0px;"> if(IsNPC())
 
 
{
 
{
 
Vector vel;
 
Vector vel;
 
EstimateAbsVelocity( vel );
 
EstimateAbsVelocity( vel );
UpdateStepSound( GetGroundSurface(), GetAbsOrigin(), vel, false);
+
UpdateStepSound( GetGroundSurface(), GetAbsOrigin(), vel, false );
}</pre>
+
}
|}
+
</source>
 +
 
 
[[Category:AI Programming]]
 
[[Category:AI Programming]]

Latest revision as of 14:04, 17 July 2021

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.png 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.

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 );
			}