Quake DeveLS - Cluster grenades

Author: SumFuka
Difficulty: Medium


Shower, anyone ?

Cluster grenades ! Mmmmmmmm. Let's modify our grenade launcher so that when we fire a grenade, it splits into 4 new grenades. How do we do this ?

Well, thanks to Levvy for helping out with this one... he mostly wrote the code I'm presenting today. Thanks again, mate !

Let's talk entities

Entities in the quake2 world (edict_t objects) can be timed to do certain things. For example, a grenade explodes 1.2 seconds after you fire it. How does the quake2 engine know how to 'handle' a grenade ? Well, every entity has a nextthink data member. This defines the next time (in server frames, or 1/10th's of a second) the entity should do something. What should it do ? Well the think data member points to a function that is 'woken up' at this time. This function can be a standard one (for example, to 'remove self', a blaster bolt removes itself after 10 seconds), or we can write one. The think function must be of the form :

void My_think_function (edict_t *ent);

.. it takes only one parameter, the object in question. Let's find what the think data member for a grenade is set to... open up g_weapon.c and go to line 447, change this :
grenade->think = Grenade_Explode;

to this :
grenade->think = Cluster_Explode;

Now go up to the Grenade_Explode function on line 362. Add a new function below it (starting on line 394) that looks like this :
static void Cluster_Explode (edict_t *ent)

{
	vec3_t		origin;

	//Sean added these 4 vectors

	vec3_t   grenade1;
	vec3_t   grenade2;
	vec3_t   grenade3;
	vec3_t   grenade4;

	if (ent->owner->client)
		PlayerNoise(ent->owner, ent->s.origin, PNOISE_IMPACT);

	//FIXME: if we are onground then raise our Z just a bit since we are a point?
	T_RadiusDamage(ent, ent->owner, ent->dmg, NULL, ent->dmg_radius);

	VectorMA (ent->s.origin, -0.02, ent->velocity, origin);
	gi.WriteByte (svc_temp_entity);
	if (ent->waterlevel)
	{
		if (ent->groundentity)
			gi.WriteByte (TE_GRENADE_EXPLOSION_WATER);
		else
			gi.WriteByte (TE_ROCKET_EXPLOSION_WATER);
	}
	else
	{
		if (ent->groundentity)
			gi.WriteByte (TE_GRENADE_EXPLOSION);
		else
			gi.WriteByte (TE_ROCKET_EXPLOSION);
	}
	gi.WritePosition (origin);
	gi.multicast (ent->s.origin, MULTICAST_PVS);

	// SumFuka did this bit : give grenades up/outwards velocities
	VectorSet(grenade1,20,20,40);
	VectorSet(grenade2,20,-20,40);
	VectorSet(grenade3,-20,20,40);
	VectorSet(grenade4,-20,-20,40);

	// Sean : explode the four grenades outwards
	fire_grenade2(ent, origin, grenade1, 120, 10, 1.0, 120);
	fire_grenade2(ent, origin, grenade2, 120, 10, 1.0, 120);
	fire_grenade2(ent, origin, grenade3, 120, 10, 1.0, 120);
	fire_grenade2(ent, origin, grenade4, 120, 10, 1.0, 120);

	G_FreeEdict (ent);
}
All we have done is to create 4 new velocity vectors for the new grenades, and to call the fire_grenade2 function to fire them. These new grenades last 1 second, and do 120 points of damage (you could modify those parameters quite easily though !)

Inifinite Grenades ?

Notice that we used the fire_grenade2 function, not fire_grenade ! We are actually fire the hand grenade, but if we fired 4 normal grenades, they would have cluster exploded too, creating a chain reaction of 4 grenades, 16 grenades, 64 grenades, 256 grenades, then 1024 grenades.

Quake2 has a maximum number of entities in the world of 1024. So we have filled the entire world with grenades in just 5 seconds ! (And you might crash quake2, too ... I did). Moral of the story, be careful not to cause a chain reaction !


Oops !

(Imagine if you threw up on someone, they started throwing up, a chain reaction of sorts... yecht.)

Tutorial by SumFuka


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