D:\cygwin\wf_fusion_src_r8\WeaponsFactory\w_grenadelauncher.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.


  w_grenadelauncher.c -- Grenade Launcher et furax canicula 
  

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


#include "..\game\g_local.h"
#include "..\game\m_player.h"
#include "..\game\gs_pmodels.h"//splitmodels


qboolean    is_quad;

static void WF_Grenade_Launcher_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)
    {
        G_AddEvent (ent, EV_GRENADE_BOUNCE, 0, qtrue);
        return;
    }
    ent->enemy = other;
    Grenade_Explode (ent);
}
static void WF_Grenade_Launcher_Alt_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;
    }

//  ent->enemy = other;
    Grenade_Explode (ent);
}
void fire_alt_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;

    gclient_t *client = self->r.client;

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

    grenade = G_Spawn();
    VectorCopy (start, grenade->s.origin);
    VectorScale (aimdir, speed, grenade->velocity);
    grenade->velocity[2] += 100 * up[2] + crandom() * 10.0;
    VectorMA (grenade->velocity, crandom() * 10.0, right, grenade->velocity);
    VectorSet (grenade->avelocity, 300, 300, 300);
    grenade->movetype = MOVETYPE_BOUNCEGRENADE;
    grenade->r.clipmask = MASK_SHOT;
    grenade->r.solid = SOLID_BBOX;
    grenade->s.effects |= EF_GRENADE;
    grenade->s.renderfx |= RF_NOSHADOW;
    grenade->gravity = .8;
    VectorClear (grenade->r.mins);
    VectorClear (grenade->r.maxs);
    grenade->s.modelindex = trap_ModelIndex ("models/ammo/grenade1.md3");
    grenade->r.owner = self;
    grenade->touch = WF_Grenade_Launcher_Alt_Touch;
    grenade->nextthink = level.time + timer;
    grenade->think = Grenade_Explode;
    grenade->use = NULL;
    grenade->dmg = damage;
    grenade->dmg_radius = damage_radius;
    grenade->classname = "grenade";

    trap_LinkEntity (grenade);
}
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;

    gclient_t *client = self->r.client;

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

    grenade = G_Spawn();
    VectorCopy (start, grenade->s.origin);
    VectorScale (aimdir, speed, grenade->velocity);
    grenade->velocity[2] += 200 * up[2] + crandom() * 10.0;
    VectorMA (grenade->velocity, crandom() * 10.0, right, grenade->velocity);
    VectorSet (grenade->avelocity, 300, 300, 300);
    grenade->movetype = MOVETYPE_BOUNCEGRENADE;
    grenade->r.clipmask = MASK_SHOT;
    grenade->r.solid = SOLID_BBOX;
    grenade->s.effects |= EF_GRENADE;
    grenade->s.renderfx |= RF_NOSHADOW;
    VectorClear (grenade->r.mins);
    VectorClear (grenade->r.maxs);
    grenade->s.modelindex = trap_ModelIndex ("models/ammo/grenade1.md3");
    grenade->r.owner = self;
    grenade->touch = WF_Grenade_Launcher_Touch;
    grenade->nextthink = level.time + timer;
    grenade->think = Grenade_Explode;
    grenade->use = NULL;
    grenade->dmg = damage;
    grenade->dmg_radius = damage_radius;
    grenade->classname = "grenade";

    trap_LinkEntity (grenade);
}

void weapon_grenadelauncher_alt_fire (edict_t *ent)
{
    vec3_t  offset;
    vec3_t  forward, right;
    vec3_t  start;
    int     damage = wf_game.weapon_damage[WEAPON_GRENADELAUNCHER] * 1.2;
    float   radius;
    gclient_t *client = ent->r.client;

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

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

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

    fire_alt_grenade (ent, start, forward, damage, wf_game.weapon_speed[WEAPON_GRENADELAUNCHER] * 1.75, 2.5, radius);

    G_AddEvent (ent, EV_MUZZLEFLASH, is_silenced, qtrue);

    client->ps.gunframe++;

    PlayerNoise(ent, start, PNOISE_WEAPON);

    if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
        client->pers.inventory[client->ammo_index]--;
}
void weapon_grenadelauncher_fire (edict_t *ent)
{
    vec3_t  offset;
    vec3_t  forward, right;
    vec3_t  start;
    int     damage = wf_game.weapon_damage[WEAPON_GRENADELAUNCHER];
    float   radius;
    gclient_t *client = ent->r.client;

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

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

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

    fire_grenade (ent, start, forward, damage * 1.2, wf_game.weapon_speed[WEAPON_GRENADELAUNCHER], 2.5, radius);

    G_AddEvent (ent, EV_MUZZLEFLASH, is_silenced, qtrue);

    client->ps.gunframe++;

    PlayerNoise(ent, start, PNOISE_WEAPON);

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

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

    if (ent->r.client && ent->r.client->pers.altered_state)
    {
        Weapon_Alternate (ent, 4, 20, 50, 54, pause_frames, fire_frames, weapon_grenadelauncher_alt_fire);
    }
    else 
        Weapon_Generic (ent, 4, 12, 50, 54, pause_frames, fire_frames, weapon_grenadelauncher_fire);
}