Quake DeveLS - Proximity mines

Author: Chris Hilton
Difficulty: Easy

Let's turn those boring old grenades into proximity mines. For the most part this just requires a new think function for the grenade that checks for passing targets and blows up appropriately. However, we also want the proximity grenades to have a limited life span. This is how we'll modify the fire_grenade() function in g_weapon.c ('+' signs indicate lines added, '-' signs indicate lines removed)

 	grenade->s.modelindex = gi.modelindex ("models/objects/grenade/tris.md2");
 	grenade->owner = self;
 	grenade->touch = Grenade_Touch;
-	grenade->nextthink = level.time + timer;
-	grenade->think = Grenade_Explode;
+
+	// CCH: use our proximity think instead
+	grenade->nextthink = level.time + .1;
+	grenade->think = proxim_think;
+	grenade->delay = level.time + 60;
+
 	grenade->dmg = damage;
 	grenade->dmg_radius = damage_radius;
 	grenade->classname = "grenade";

We've replaced the grenade's original think function to explode when the timer is reached to call a new function proxim_think() in .1 seconds. Also, we've set ent->delay to 60 seconds in the future to represent the end of the grenade's lifespan and we'll check that value in our proxim_think() function for when to explode the grenade. The delay field of the edict_t type is normally only used by monster ai functions, not by grenades, so it's okay to grab it for our usage here.

Also, we'll make similar changes to the fire_grenade2() function.

 	grenade->s.modelindex = gi.modelindex ("models/objects/grenade2/tris.md2");
 	grenade->owner = self;
 	grenade->touch = Grenade_Touch;
-	grenade->nextthink = level.time + timer;
-	grenade->think = Grenade_Explode;
+
+	// CCH: use our proximity think instead
+	grenade->nextthink = level.time + .1;
+	grenade->think = proxim_think;
+	grenade->delay = level.time + 60;
+
 	grenade->dmg = damage;
 	grenade->dmg_radius = damage_radius;
 	grenade->classname = "grenade";

Incidentally, fire_grenade() is called when firing the grenade launcher, fire_grenade2() is called when throwing a grenade by hand.

Now we just need the new think function, which I put before the fire_grenade functions in g_weapon.c

+// CCH: New think function for proximity grenades
+static void proxim_think (edict_t *ent)
+{
+	edict_t *blip = NULL;
+
+	if (level.time > ent->delay)
+	{
+		Grenade_Explode(ent);
+		return;
+	}
+	
+	ent->think = proxim_think;
+	while ((blip = findradius(blip, ent->s.origin, 100)) != NULL)
+	{
+		if (!(blip->svflags & SVF_MONSTER) && !blip->client)
+			continue;
+		if (blip == ent->owner)
+			continue;
+		if (!blip->takedamage)
+			continue;
+		if (blip->health <= 0)
+			continue;
+		if (!visible(ent, blip))
+			continue;
+		ent->think = Grenade_Explode;
+		break;
+	}
+
+	ent->nextthink = level.time + .1;
+}

First, we check the delay to see if we've reached the end of our lifespan and should blow up immediately. Then we check all edicts within 100 units and see if there is a valid target. If there is, we stop searching and set ourselves to explode next think. Valid targets are monsters and players (not our owner) that can take damage, have health to lose, and are visible to us.

That's it. Have fun with your new toy. Full source and patch file at http://www.jump.net/~dctank.

Tutorial by Chris Hilton


This site, and all content and graphics displayed on it,
are ©opyrighted to the Quake DeveLS team. All rights received.
Got a suggestion? Comment? Question? Hate mail? Send it to us!
Oh yeah, this site is best viewed in 16 Bit or higher, with the resolution on 800*600.
Thanks to Planet Quake for there great help and support with hosting.
Best viewed with Netscape 4 or IE 3