Vortex Grenades

Suck, suck, suck, BLAM!

These grenades are alot of fun!  When you throw them, they suck players/monsters to the grenade, then it blows up when they are near!
The whole grenade code is in g_weapon.c, so open that up, and add in all the
blue code, taking out the pink code.
First we need to add three new functions to the grenade section.  Put all three just above the fire_grenade function, so it looks like this:

static void Vortex_Explode (edict_t *ent)
{
    vec3_t        origin;
    vec3_t offset;
    int        mod;

    if (ent->owner->client)   
    {
        PlayerNoise(ent->owner, ent->s.origin, PNOISE_IMPACT);
    }
    VectorSet(offset,0,0,0.5);
    VectorAdd(offset,ent->s.origin,offset);
    VectorCopy (offset, ent->s.origin);
    if (ent->spawnflags & 2)
        mod = MOD_HELD_GRENADE;
    else if (ent->spawnflags & 1)
        mod = MOD_HG_SPLASH;
    else
        mod = MOD_G_SPLASH;

    T_RadiusDamage(ent, ent->owner, ent->dmg, NULL, ent->dmg_radius, mod);

    VectorMA (ent->s.origin, -.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);
    G_FreeEdict (ent);   
}

static void Vortex_Timer (edict_t *self)
{
    edict_t *ent;
    vec3_t dir,start,end;

    ent = NULL;

    if (level.time > self->delay)
    {
        self->think = Vortex_Explode;
        self->nextthink = level.time + 0.2;
        return;
    }
    while ((ent = findradius(ent, self->s.origin, 512)) != NULL)
    {
        if (ent == self)
            continue;

        if (!ent->client)
            continue;

        if (ent == self->owner)
            continue;

        if (!ent->takedamage)
            continue;

        if (!(ent->svflags & SVF_MONSTER) && (!ent->client) && (strcmp(ent->classname, "misc_explobox") != 0))
            continue;

        VectorCopy(ent->s.origin, start);
        VectorCopy(self->s.origin, end);
        VectorSubtract(end, start, dir);
        VectorNormalize(dir);
        VectorScale(dir,500, ent->velocity);
        VectorCopy(dir, ent->movedir);
    }
    self->nextthink = level.time + 0.2;
}

static void Vortex_Touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
{
    if (other == ent->owner)
        return;

    if (surf && (surf->flags & SURF_SKY))
    {
        G_FreeEdict (ent);
        return;
    }

    if (!other->takedamage)
    {
        if (ent->spawnflags & 1)
        {
            if (random() > 0.5)
                gi.sound (ent, CHAN_VOICE, gi.soundindex ("weapons/hgrenb1a.wav"), 1, ATTN_NORM, 0);
            else
                gi.sound (ent, CHAN_VOICE, gi.soundindex ("weapons/hgrenb2a.wav"), 1, ATTN_NORM, 0);
        }
        else
        {
            gi.sound (ent, CHAN_VOICE, gi.soundindex ("weapons/grenlb1b.wav"), 1, ATTN_NORM, 0);
        }
        return;
    }
}

The vortex_explode is almost the same as the original grenade_explode.  The vortex_timer is the key to these grenades.  It uses a findradius function to look for players and monsters, and pulls them towards itself at a speed of 500 (someone know the quake units here?).  The touch function is similar to the original grenade_touch, only the grenades don't blow up on contact.

Next you need to edit the fire_grenade and/or fire_grenade2 function(s).  The fire_grenade is for the grenade launcher, while the fire_grenade2 is for regular handgrenades.  I'll show you both.  First, the fire_grenade function:

void fire_grenade (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius)
{
    edict_t    *grenade;
    vec3_t    dir;
    vec3_t    forward, right, up;

    vectoangles (aimdir, dir);
    AngleVectors (dir, forward, right, up);

    grenade = G_Spawn();
    VectorCopy (start, grenade->s.origin);
    VectorScale (aimdir, speed, grenade->velocity);
    VectorMA (grenade->velocity, 200 + crandom() * 10.0, up, grenade->velocity);
    VectorMA (grenade->velocity, crandom() * 10.0, right, grenade->velocity);
    VectorSet (grenade->avelocity, 300, 300, 300);
    grenade->movetype = MOVETYPE_BOUNCE;
    grenade->clipmask = MASK_SHOT;
    grenade->solid = SOLID_BBOX;
    grenade->s.effects |= EF_GRENADE;
    VectorClear (grenade->mins);
    VectorClear (grenade->maxs);
    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;

    grenade->dmg = damage;
    grenade->dmg_radius = damage_radius;
    grenade->classname = "grenade";

   
grenade->nextthink = level.time + 2.0;
    grenade->think = Vortex_Timer;
    grenade->delay = level.time + 3;   
    grenade->touch = Vortex_Touch;


    gi.linkentity (grenade);
}

And then the fire_grenade2 function:

void fire_grenade2 (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius, qboolean held)
{
    edict_t    *grenade;
    vec3_t    dir;
    vec3_t    forward, right, up;

    vectoangles (aimdir, dir);
    AngleVectors (dir, forward, right, up);

    grenade = G_Spawn();
    VectorCopy (start, grenade->s.origin);
    VectorScale (aimdir, speed, grenade->velocity);
    VectorMA (grenade->velocity, 200 + crandom() * 10.0, up, grenade->velocity);
    VectorMA (grenade->velocity, crandom() * 10.0, right, grenade->velocity);
    VectorSet (grenade->avelocity, 300, 300, 300);
    grenade->movetype = MOVETYPE_BOUNCE;
    grenade->clipmask = MASK_SHOT;
    grenade->solid = SOLID_BBOX;
    grenade->s.effects |= EF_GRENADE;
    VectorClear (grenade->mins);
    VectorClear (grenade->maxs);
    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;

    grenade->dmg = damage;
    grenade->dmg_radius = damage_radius;
    grenade->classname = "hgrenade";

   
grenade->nextthink = level.time + 2.0;
    grenade->think = Vortex_Timer;
    grenade->delay = level.time + 3;   
    grenade->touch = Vortex_Touch;


   if (held)
        grenade->spawnflags = 3;
    else
        grenade->spawnflags = 1;
    grenade->s.sound = gi.soundindex("weapons/hgrenc1b.wav");

    if (timer <= 0.0)
        Grenade_Explode (grenade);
    else
    {
        gi.sound (self, CHAN_WEAPON, gi.soundindex ("weapons/hgrent1a.wav"), 1, ATTN_NORM, 0);
        gi.linkentity (grenade);
    }
}

All that you did there was substitute in the new explode, timer, and think functions for the Vortex Grenades.
That's it!  Now your grenades will suck people or monsters into them, and blow up.   Do you think fragging could get any easier?

Tutorial by Willi
Quake Style - Tutorials