D:\cygwin\wf_fusion_src_r8\WeaponsFactory\w_magnotron.c

/*
==============================================================================
The Weapons Factory - 
  
Modified code by Keith Pase

Copyright (C) 1997-2003 Weapons Factory Software

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

  Original code by various

  w_magnotron.c -- The grenade that "sucks".
  

==============================================================================
*/

#include "..\game\g_local.h"

static void MagnoGrenade_Explode (edict_t *ent)
{
    vec3_t      origin;
    vec3_t offset;

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

    VectorSet(offset,0,0,0.5);
    VectorAdd(offset,ent->s.origin,offset);
    VectorCopy (offset, ent->s.origin);

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

    VectorMA (ent->s.origin, -.02, ent->velocity, origin);

    G_TurnEntityIntoEvent ( ent, ent->groundentity ? EV_GRENADE_EXPLOSION : EV_ROCKET_EXPLOSION, DirToByte (NULL) );

    T_ShockWave(ent, 255, 1024);
    // explode and destroy grenade
    BecomeNewExplosion (ent);
}


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

    ent = NULL;

    self->nextthink = level.time + 0.2;

    if (level.time > self->delay)
    {
        self->think = MagnoGrenade_Explode;
        return;
    }

    while ((ent = findradius(ent, self->s.origin, 512)) != NULL)
    {
        if (ent == self)
            continue;

        if (!ent->r.client)
            continue;

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

        if (!visible(self, ent))
             continue;

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

        if (!ent->takedamage)
            continue;

        if (!(ent->r.svflags & SVF_MONSTER) && (!ent->r.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);
    }

}

static void MagnoGrenade_Touch (edict_t *ent, edict_t *other, cplane_t *plane, int surfFlags)
{
    if (other == ent->r.owner)
        return;

    if (surfFlags & SURF_NOIMPACT)
    {
        G_FreeEdict (ent);
        return;
    }

    if (!other->takedamage)
    {
        if (ent->spawnflags & 1)
        {
            if (random() > 0.5)
                G_Sound (ent, CHAN_VOICE, trap_SoundIndex  ("sound/weapons/grenade/hgrenb1a.wav"), 1, ATTN_NORM);
            else
                G_Sound (ent, CHAN_VOICE, trap_SoundIndex  ("sound/weapons/grenade/hgrenb2a.wav"), 1, ATTN_NORM);
        }
        else
        {
            G_Sound (ent, CHAN_VOICE, trap_SoundIndex  ("sound/weapons2/grenades/grenlb1b.wav"), 1, ATTN_NORM);
        }
        return;
    }

}

void Magnogrenade_Die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
    self->takedamage = DAMAGE_NO;
    self->nextthink = level.time + .1;
    self->think = MagnoGrenade_Explode;
}

void fire_magnogrenade (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;

    ++self->r.client->pers.active_grenades[GRENADE_TYPE_MAGNOTRON];

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

    grenade = G_Spawn();

    if ((int)wfflags->value & WF_ANARCHY)
        grenade->wf_team = 0;   //fire at anybody
    else
        grenade->wf_team = self->wf_team;

    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->r.clipmask = MASK_SHOT;
    grenade->r.solid = SOLID_BBOX;
    grenade->grenade_index = GRENADE_TYPE_MAGNOTRON;

    VectorClear (grenade->r.mins);
    VectorClear (grenade->r.maxs);

    grenade->s.modelindex = trap_ModelIndex ("models/weapons2/wfgrenade/magnotron.md3");

    grenade->s.effects |= EF_GRENADE;

    grenade->r.owner = self;
    grenade->touch = MagnoGrenade_Touch; //Stuff for cluster grenades when they explode
    grenade->nextthink = level.time + 2.0;  //start sucking in 1 second
    grenade->delay = level.time + 3.5;  //explode in 3.5 seconds

if (wfdebug) grenade->delay = level.time + 20;  //for testing magno die

    grenade->think = MagnoGrenade_Timer; //stuff for cluster grenades exploding
    grenade->dmg = damage;
    grenade->dmg_radius = damage_radius;
    grenade->classname = "magnotron";
    VectorSet(grenade->r.mins, -5, -8, 0);
    VectorSet(grenade->r.maxs, 4, 8, 5);
    grenade->mass = 2;
    grenade->health = 30;
    grenade->die = Magnogrenade_Die;
    grenade->takedamage = DAMAGE_YES;
    grenade->monsterinfo.aiflags = AI_NOSTEP;

    trap_LinkEntity (grenade);
}

void weapon_magnogrenadelauncher_fire (edict_t *ent)
{
    vec3_t  offset;
    vec3_t  forward, right;
    vec3_t  start;
    int     damage = wf_game.grenade_damage[GRENADE_TYPE_MAGNOTRON];
    float   radius;

    radius = damage+40;
    if (is_quad)
        damage *= 4;

    VectorSet(offset, 8, 8, ent->viewheight-8);
    AngleVectors (ent->r.client->v_angle, forward, right, NULL);
    P_ProjectSource (ent->r.client, ent->s.origin, offset, forward, right, start);

    VectorScale (forward, -2, ent->r.client->kick_origin);
    ent->r.client->kick_angles[0] = -1;

    fire_magnogrenade (ent, start, forward, damage, 400, 2.5, radius);

    G_AddEvent (ent, EV_MUZZLEFLASH, is_silenced, qtrue);

    ent->r.client->ps.gunframe++;

    PlayerNoise(ent, start, PNOISE_WEAPON);

    if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
        ent->r.client->pers.inventory[ent->r.client->ammo_index] -= ent->r.client->pers.weapon->quantity;
}

void Weapon_MagnoGrenadeLauncher (edict_t *ent)
{
    static int  pause_frames[]  = {34, 51, 59, 0};
    static int  fire_frames[]   = {6, 0};

    Weapon_Generic (ent, 5, 16, 59, 64, pause_frames, fire_frames, weapon_magnogrenadelauncher_fire);
}