If you're a big, bad space marine, you ought to have a rangefinder in
your HUD, right? Here's a quick and easy patch to add one. Thanks to
Decker for the Statusbar tutorial that this patch borrows heavily from.

First, we'll define the rangefinder's entry in the stats array. Edit
q_shared.h and add the following at about line 803 (+'s indicate lines
added).

 #define	STAT_FRAGS				14
 #define	STAT_FLASHES			15		// cleared each frame, 1 = health, 2 = armor
 
+// CCH: rangefinder stat
+#define	STAT_RANGEFINDER		16
+
 #define	MAX_STATS				32
 
Now, we need to fill that stat entry with the information we want to
display, namely the range to whatever the crosshair is pointing at.
We'll do this by editing the G_SetStats() function in p_hud.c. At the
top of the function we'll add the following declarations for variables
that we'll be using later.

 	int			index, cells;
 	int			power_armor_type;
 
+	// CCH: local variables for rangefinder
+	vec3_t		start, forward, end;
+	trace_t		tr;
+
 	//
 	// health
 	//

Now for our range calculation. We'll find this by tracing a line from
our viewpoint to a point 8192 units ahead of us and seeing how far the
line traces. Add the following code to the end of G_SetStats().

 		ent->client->ps.stats[STAT_HELPICON] = gi.imageindex (ent->client->pers.weapon->icon);
 	else
 		ent->client->ps.stats[STAT_HELPICON] = 0;
+
+	//
+	// CCH: rangefinder
+	//
+	VectorCopy(ent->s.origin, start);
+	start[2] += ent->viewheight;
+	AngleVectors(ent->client->v_angle, forward, NULL, NULL);
+	VectorMA(start, 8192, forward, end);
+	tr = gi.trace(start, NULL, NULL, end, ent, MASK_SHOT|CONTENTS_SLIME|CONTENTS_LAVA);
+	// check for sky and max the range if found
+	if ( tr.surface && (tr.surface->flags & SURF_SKY) )
+		ent->client->ps.stats[STAT_RANGEFINDER] = 9999;
+	else
+		ent->client->ps.stats[STAT_RANGEFINDER] = (int)(tr.fraction * 8192);
 }
 
Now, how this works. First, we locate our start point by adding our
viewheight to our origin. Then we use AngleVectors() to give us our
forward viewing angle. We then use VectorMA() to multiply this forward
unit vector by 8192, add it to the start position, and store this
endpoint in end.

gi.trace() performs the trace for us, from start to end, returning the
information it finds in a trace_t struct. The two NULLs that are passed
to gi.trace() replace bounding box arguments; we don't want to trace a
bounding box through the world, just a straight line. ent is passed as
the entity to ignore collisions with (we don't need the range to
ourself!) and the final argument is the mask to indicate what surfaces
should stop the trace. In our case, we're stopping wherever a shot would
stop, plus stopping at slime and lava.

Finally, for some added realism, we're going to check if we're pointed
at the sky. Now, a sky surface might be only 100 units away from you in
the game, but that isn't how it should look in the rangefinder! We check
if there's a surface that was run into in the trace struct and then we
check if that surface has the sky flag set. If it does, max the range to
the 4-digit limit of 9999. Otherwise, use tr.fraction to calculate how
far along the trace we got before being stopped. In either case, this
range is kept in our STAT_RANGEFINDER entry in the player's ps.stats
array.

Okay, range is all calculated, just gotta put it on the screen now. Easy
enough, just modify the end of the statusbar string in g_spawn.c at
about line 672 like so.

 "	xv	148 "
 "	pic	11 "
 "endif "
+
+// CCH: rangefinder
+"if 16 "
+"   xv 210 "
+"	num 4	16 "
+"   xv 234 "
+"   yb -59 "
+"   string RANGE "
+"endif "
 ;
 
 char *dm_statusbar =

For deathmatch play, just add the same thing to the end of the
deathmatch statusbar at about line 735.

 "xr	-50 "
 "yt 2 "
 "num 3 14"
+
+// CCH: rangefinder
+"if 16 "
+"   xv 210 "
+"	num 4	16 "
+"   xv 234 "
+"   yb -59 "
+"   string RANGE "
+"endif "
 ;
 
That's it. Your HUD is now rangefinder enabled. Full source code, patch
file, and DLL at http://www.jump.net/~dctank.

Chris Hilton
chilton@scci-ad.com
 

