Engine Side Footsteps

Post tutorials on how to do certain tasks within game or engine code here.
r00k
Posts: 1111
Joined: Sat Nov 13, 2004 10:39 pm

Engine Side Footsteps

Post by r00k »

description: quick and dirty footstep sounds engine tutorial.
---------------------------------------------------------------------------------
purpose: adds footstep sounds to local gameplay.
---------------------------------------------------------------------------------
future expansion: different sounds for different surfaces and different speeds.
---------------------------------------------------------------------------------
First thing we need to do is precache the sound effects internally in the engine.

Open up cl_tent.c

near the top of the file look for the other sound effects precaches
and add these under sfx_t *cl_sfx_r_exp3,

Code: Select all

sfx_t		*cl_sfx_step1;
sfx_t		*cl_sfx_step2;
sfx_t		*cl_sfx_step3;
sfx_t		*cl_sfx_step4;
scroll down and find void CL_InitTEnts (void)
and add these precaches to be initialized.

Code: Select all

	cl_sfx_step1		= S_PrecacheSound ("misc/step1.wav");	
	cl_sfx_step2		= S_PrecacheSound ("misc/step2.wav");	
	cl_sfx_step3		= S_PrecacheSound ("misc/step3.wav");		
	cl_sfx_step4		= S_PrecacheSound ("misc/step4.wav");	
NOTE: you are going to have to find your own .wav files for the sounds and put them in quake/id1/sound/misc

okay now open up cl_main.c

near the top around all the other cvar_t definitions add,

Code: Select all

cvar_t	cl_footsteps		= {"cl_footsteps", "0", true};
now look for CL_Init and register the variable,

Code: Select all

     Cvar_RegisterVariable (&cl_footsteps);	
Scroll back to the top of the file in cl_main.c and add this code block prior to CL_RelinkEntities,

Code: Select all

void CL_Footsteps(entity_t	*ent, int frame)
{
	extern	sfx_t		*cl_sfx_step1;
	extern	sfx_t		*cl_sfx_step2;
	extern	sfx_t		*cl_sfx_step3;
	extern	sfx_t		*cl_sfx_step4;

	if (ent->steptime > cl.time)//Timer to sync with player animations
		return;

	if (ent != &cl_entities[cl.viewentity])//check if it's our player
		return; //only play our OWN footsteps! no multiplayer hax!
	
	if (TruePointContents(ent->origin) != CONTENTS_EMPTY)// if in water etc.. no sound
		return;

	if (frame == 2 || frame == 5 ||	frame == 7 || frame == 10)//check for run frames
	{
		vec3_t	dest, forward, right,up;
		trace_t	trace;
		float f;
		int	i,e;
		entity_t *p;

		AngleVectors (ent->angles, forward, right, up);
		
		VectorMA (ent->origin, -32, up, dest);//trace down 
			
		memset (&trace, 0, sizeof(trace_t));

		trace.fraction = 1;

		SV_RecursiveHullCheck(cl.worldmodel->hulls, 0, 0, 1, ent->origin, dest, &trace);

		if (trace.fraction == 1) //if we didnt hit anything solid  dont make a sound
		{			
        		ent->steptime = cl.time + 0.1;//since the player model animates at 10 frames per sec, no need to come back here until time + 1/10...
			return;
		}
		
		f = (rand()%4)+1;

		e = (int)cl.viewentity;//emit the sound at our location
		
		if (f == 1)
			S_StartSound(e, 0, cl_sfx_step1, ent->origin, 0.40f, 1.0f);
		else if (f == 2)
			S_StartSound(e, 0, cl_sfx_step2, ent->origin, 0.40f, 1.0f);
		else if (f == 3)
			S_StartSound(e, 0, cl_sfx_step3, ent->origin, 0.40f, 1.0f);
		else
			S_StartSound(e, 0, cl_sfx_step4, ent->origin, 0.40f, 1.0f);
		
		ent->steptime = cl.time + 0.3;
	}
}
now scroll down into CL_RelinkEntites and add this bit of code before ent->forcelink = true;

Code: Select all

		if (cl_footsteps.value)
			CL_Footsteps(ent,ent->frame);
one last thing we need to do is add a timer to make the sound, so open up render.h and find the entity_s definition and add
to the end, like this

Code: Select all

	double	steptime;
} entity_t;
Team Xlink
Posts: 368
Joined: Thu Jun 25, 2009 4:45 am
Location: Michigan

Post by Team Xlink »

This is a very good tutorial and has much use to avoid tricky qc code. It allows you to play have sounds for footsteps in all mods. Thank you.

I am still intrigued by your mention of the future expansion's different footsteps for different surfaces, this would be great.

For example your running in a shallow puddle of water so you want to hear the small splash sounds, then you come up to a middle surface it then plays the ting sounds, so on and so fourth.

EDIT: Does anyone have any good sound files for this? My sound files aren't that good.
Downsider
Posts: 621
Joined: Tue Sep 16, 2008 1:35 am

Post by Downsider »

I'm pretty sure that when you trace against a face in the engine you can grab its texture name directly from the information returned, which could easily be your solution to getting surface-specific sounds.
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: Engine Side Footsteps

Post by Baker »

Is there a way to query what texture a player is walking on (Surface flags) like in Half-Life?

For instance, to play a different wav if the texture begins with "stone_" or "metal_".
goldenboy
Posts: 924
Joined: Fri Sep 05, 2008 11:04 pm
Location: Kiel
Contact:

Post by goldenboy »

Some of the multiplayer types argue that footsteps are bad, or cheating.

Also, mods will want to use their own footstep sounds, plus monster footsteps, like RemakeQuake does.

It's not really hard to do in QC - I think this should be left to individual mods. See RMQ source.

I would get pissed if an engine "overwrote" my carefully selected and randomized footstep sounds.

Edit: It would be nice, however, if the engine provided surface detection which could then be used by the footstep QC code.
r00k
Posts: 1111
Joined: Sat Nov 13, 2004 10:39 pm

Post by r00k »

Actually this doesnt provide a hack for multiplayer at all because it only plays your own footsteps. Also this shouldnt piss off modders cause it doesnt change monsters footsteps and the player footstep sounds can be copied to /sounds/misc. I think i would map out areas based on the origin, like how .locs are used. have an .fsm (footstep materail) file defined. That way at runtime im just comparing location to array not traceline collision detection.

It can be expanded to have custom monster sounds. The only real benefit of this is adding footsteps to mods that dont have them.

I think you are in your right that if your mod supports footsteps there should be a SVC_ trigger or ruleset or atleast you can stuffcmd to the client "cl_footstep 0\n", that way it will use your media/code instead.
Last edited by r00k on Mon Jan 04, 2010 11:02 pm, edited 2 times in total.
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Re: Engine Side Footsteps

Post by mh »

Baker wrote:Is there a way to query what texture a player is walking on (Surface flags) like in Half-Life?

For instance, to play a different wav if the texture begins with "stone_" or "metal_".
R_LightPoint will give you it. :D

I'm in two minds though about doing this via QC in preference to the engine. A part of me wants to agree bigtime, but another part of me says that the engine has access to so much more info than QC does, and that doing it via the engine gives players the option to switch footsteps off by a cvar if they find them annoying. And players are the most important thing at the end of the day, aren't they?

I reckon the engine wins this one so far as I'm concerned. Perhaps a good meet-in-the-middle option might be to make this footstep code extensible via QC (it would need to move to server-side for that, but shouldn't need a new protocol as the standard server-side sound spawning should work fine).

Say let QC control the volume, the sounds used, etc. Provide some new builtins and we're done.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
goldenboy
Posts: 924
Joined: Fri Sep 05, 2008 11:04 pm
Location: Kiel
Contact:

Post by goldenboy »

Yes, QC / the mod needs to control the sounds used and how they are used. There can be default sounds that the engine would supply, but as soon as a mod brings its own sound files along, control should shift to the mod.

RMQ uses much more than 4 footstep sound files, too. So that would be a possible clash. Requiring mods to provide exactly n footstep sounds is problematic. The engine should only offer an interface to the mod.

An engine that played the crappy hipnotic footsteps instead of the RMQ ones would make me want to shoot somebody.

Finally, disabling footstep sounds should be done by the mod, too, possibly via an impulse.
Teiman
Posts: 311
Joined: Sun Jun 03, 2007 9:39 am

Post by Teiman »

Telejano has footsteps builtin, I even have different sounds for different mosters.

Is a nice feature, and really adds to the game.
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Post by mh »

goldenboy wrote:Finally, disabling footstep sounds should be done by the mod, too, possibly via an impulse.
So long as it doesn't override what the player wants I'd agree.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
drm_wayne
Posts: 232
Joined: Sat Feb 11, 2012 5:47 pm

Re: Engine Side Footsteps

Post by drm_wayne »

mh wrote:
Baker wrote:Is there a way to query what texture a player is walking on (Surface flags) like in Half-Life?

For instance, to play a different wav if the texture begins with "stone_" or "metal_".
R_LightPoint will give you it. :D

Sorry for bumping this, but i adapted it to my engine and i wonder how exactly "R_LightPoint" will work gettign the texture name??
Can somebody explain it?
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Re: Engine Side Footsteps

Post by mh »

drm_wayne wrote:
mh wrote:
Baker wrote:Is there a way to query what texture a player is walking on (Surface flags) like in Half-Life?

For instance, to play a different wav if the texture begins with "stone_" or "metal_".
R_LightPoint will give you it. :D

Sorry for bumping this, but i adapted it to my engine and i wonder how exactly "R_LightPoint" will work gettign the texture name??
Can somebody explain it?
R_LightPoint will get you the lighting for an object from the msurface_t under it. It also gets you the lightspot (a position in 3D space where the trace intersects the surface) and the plane, which are used for Quake's crap planar shadows. It's a small enough thing to also save out surf->texinfo->texture.

The object may not be in direct contact with the surface but for the player you can then use cl.onground to determine if it is (you may also need cl.inwater, it's been a while). If you want footsteps on monsters you could put something together from the object's bounding box and the distance between the entity origin and the saved-out lightspot (monsters don't send SU_ONGROUND or SU_INWATER). Beware of MDL bounding boxes here: they need to be fixed in the engine to make this work too (if you do it server-side you'll get access to a lot more info, of course, but you'll need to implement a server-side version of R_LightPoint too). You'd also need to hack something up for if the object is standing on a brush model, and again for BSP models. It's up to you to decide at what point this crosses the line between "a technically interesting challenge" and "a gigantic pain in the ass".

Quake doesn't have surface flags so you need to hack something from the texture name if you want different sounds for metal, wood, grass, etc. That will break down if one of those wacky modders decides to use texture names like "dkfgjbakshdv" (and then pulls a fit of passive-agressive whining and "I can't understand why we can't do it if HL2 can" on you when you try to point this out). There's nothing you can do about that, so it's better to just accept that your chosen technology can't do what you want to do and use a sound that's tweaked to sound not-particularly-dreadful with everything. Or else choose a different technology that can.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
goldenboy
Posts: 924
Joined: Fri Sep 05, 2008 11:04 pm
Location: Kiel
Contact:

Re: Engine Side Footsteps

Post by goldenboy »

Hi mh :)

My evil hacky modder idea how to do surface dependant footsteps in a Quake mod has to do with simply placing triggers on top of every walkable surface.

A hack? Sure! Workable? Totally! Next problem!
r00k
Posts: 1111
Joined: Sat Nov 13, 2004 10:39 pm

Re: Engine Side Footsteps

Post by r00k »

i have already implemented this 90%...

Code: Select all


char *nodename = "                 ";

int RecursiveNodePoint (mnode_t *node, vec3_t start, vec3_t end)
{
	float	front, back, frac;
	vec3_t	mid;
	void DrawGLPolyHighlight(glpoly_t *p);
	
loc0:
	if (node->contents < 0)
		return false;		// didn't hit anything
	
// calculate mid point
	if (node->plane->type < 3)
	{
		front = start[node->plane->type] - node->plane->dist;
		back = end[node->plane->type] - node->plane->dist;
	}
	else
	{
		front = DotProduct(start, node->plane->normal) - node->plane->dist;
		back = DotProduct(end, node->plane->normal) - node->plane->dist;
	}

	// optimized recursion
	if ((back < 0) == (front < 0))
	{
		node = node->children[front < 0];
		goto loc0;
	}
	
	frac = front / (front-back);
	mid[0] = start[0] + (end[0] - start[0]) * frac;
	mid[1] = start[1] + (end[1] - start[1]) * frac;
	mid[2] = start[2] + (end[2] - start[2]) * frac;
	
// go down front side
	if (RecursiveNodePoint(node->children[front < 0], start, mid))
	{		
		return true;	// hit something
	}
	else
	{
		int		i, ds, dt;
		msurface_t	*surf;

		surf = cl.worldmodel->surfaces + node->firstsurface;
		for (i = 0 ; i < node->numsurfaces ; i++, surf++)
		{
			ds = (int)((float)DotProduct (mid, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]);
			dt = (int)((float)DotProduct (mid, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]);

			if (ds < surf->texturemins[0] || dt < surf->texturemins[1])
				continue;
			
			ds -= surf->texturemins[0];
			dt -= surf->texturemins[1];
			
			if (ds > surf->extents[0] || dt > surf->extents[1])
				continue;
	
			if (developer.value)
				DrawGLPolyHighlight(surf->polys);

			nodename = (surf->texinfo->texture->name);
			return true;
		}

	// go down back side		
		return RecursiveNodePoint (node->children[front >= 0], mid, end);
	}
}

void GetNodePoint (vec3_t p, vec3_t	end)
{
	RecursiveNodePoint (cl.worldmodel->nodes, p, end);	
	SCR_CenterPrint (nodename);	
}
and then i just call GetNodePoint in the footstep code to get the name of the texture im standing on. I havent completed this but it would just parse the texturename and point it to a precached sound file.
But as MH says, texturenames do not have any strict syntax. Then there is the issues with brush models.

BTW MH, compiling the Jan 2012 RMQ SDK renders missing polygons on world surfaces :(
qbism
Posts: 1236
Joined: Thu Nov 04, 2004 5:51 am
Contact:

Re: Engine Side Footsteps

Post by qbism »

goldenboy wrote:My evil hacky modder idea how to do surface dependant footsteps in a Quake mod has to do with simply placing triggers on top of every walkable surface.
Wasn't there a mod that used a brute-force texture list file (read with frikfile) to determine footstep sounds? If mostly new textures, could encode 'surface flags' in the texture names to be decoded by qc. However, much could be done with audio triggers... put them off ledges to play "whoosh" or "oh shizzle!!" when player falls.
Post Reply