
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, |