D:\cygwin\wf_fusion_src_r8\WeaponsFactory\w_stinger.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_stinger.c -- Stinger Rocket Launcher
    With the special addition of SideWinder for alt.

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

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

void Stinger_Explode (edict_t *ent)
{
    int     i;  
    vec3_t  org;    
    float   spd;
    vec3_t  origin;
    float   shraps;
    
    shraps = random();

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

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

    WF_T_RadiusDamage (ent, ent->r.owner, ent->radius_dmg, NULL, ent->dmg_radius, ent->mod);

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

    G_TurnEntityIntoEvent ( ent, EV_EXPLOSION2, 0 );

    spd = 15.0 * ent->dmg / 200;

    for (i = 0; i < 4; i++)
    {
        org[0] = ent->s.origin[0] + crandom() * ent->r.size[0];
        org[1] = ent->s.origin[1] + crandom() * ent->r.size[1];
        org[2] = ent->s.origin[2] + crandom() * ent->r.size[2];
        ThrowShrapnel4 (ent, "models/objects/glowingdebris2.md3", spd, org, random());
    }

}
void Stinger_Alt_Explode (edict_t *ent)
{
    int     i;  
    vec3_t  org;    
    float   spd;
    vec3_t  origin;
    float   shraps;
    
    shraps = random();

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

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

    WF_T_Radius2Damage(ent, ent->r.owner, ent->radius_dmg, NULL, ent->dmg_radius, (ent->dmg * shraps), ent->mod);

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

    G_TurnEntityIntoEvent ( ent, EV_EXPLOSION2, 0 );

    spd = 15.0 * ent->dmg / 200;

    for (i = 0; i < ((shraps * 10) / 2); i++)
    {
        org[0] = ent->s.origin[0] + crandom() * ent->r.size[0];
        org[1] = ent->s.origin[1] + crandom() * ent->r.size[1];
        org[2] = ent->s.origin[2] + crandom() * ent->r.size[2];
        ThrowShrapnel4 (ent, "models/objects/glowingdebris2.md3", spd, org, random());
    }
}

void Weapon_StingerLauncher_Fire (edict_t *ent)
{
    vec3_t  offset, start, end;
    vec3_t  forward, right;
    int     damage;
    float   damage_radius;
    int     radius_damage;
    trace_t tr;
    gclient_t *client = ent->r.client;

    damage = wf_game.weapon_damage[WEAPON_STINGER];
    radius_damage = 120;
    damage_radius = 120;
    if (is_quad)
    {
        damage *= 4;
        radius_damage *= 4;
    }

    AngleVectors (client->v_angle, forward, right, NULL);

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

    VectorSet(offset, 8, 8, ent->viewheight-8);
    P_ProjectSource (client, ent->s.origin, offset, forward, right, start);
    VectorMA (start, 14, forward, end);

    trap_Trace (&tr, start, vec3_origin, vec3_origin, end, ent, MASK_SOLID);

    fire_stinger (ent, tr.endpos, forward, damage,wf_game.weapon_speed[WEAPON_STINGER], damage_radius, radius_damage, MOD_SIDEWINDER);

    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_StingerLauncher_Alt_Fire (edict_t *ent)
{
    vec3_t  offset, start, end;
    vec3_t  forward, right;
    int     damage;
    float   damage_radius;
    int     radius_damage;
    trace_t tr;
    gclient_t *client = ent->r.client;

    damage = wf_game.weapon_damage[WEAPON_STINGER];
    radius_damage = 120;
    damage_radius = 120;
    if (is_quad)
    {
        damage *= 4;
        radius_damage *= 4;
    }
    AngleVectors (client->v_angle, forward, right, NULL);

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

    VectorSet(offset, 8, 8, ent->viewheight-8);
    P_ProjectSource (client, ent->s.origin, offset, forward, right, start);
    VectorMA (start, 14, forward, end);

    trap_Trace (&tr, start, vec3_origin, vec3_origin, end, ent, MASK_SOLID);

    fire_alt_stinger (ent, tr.endpos, forward, damage,wf_game.weapon_speed[WEAPON_STINGER], damage_radius, radius_damage, MOD_STINGER);

    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 stinger_think (edict_t *ent)
{
    edict_t *target = NULL;
    edict_t *blip = NULL;
    vec3_t  targetdir, blipdir;
    vec_t   speed;
    float   dist;

    if (level.time > ent->delay)
    {
        ent->nextthink = level.time + .1;
        ent->think = Stinger_Explode;
        return;
    }

    while ((blip = findradius(blip, ent->s.origin, 1000 * g_radius->value)) != NULL)
    {
        if (!blip->r.client)
            continue;
        if (blip == ent->creator)
            continue;
        if (blip->disguised)
            continue;
        if ((blip->wf_team == ent->wf_team) && (((int)wfflags->value & WF_ALLOW_FRIENDLY_FIRE)==0))
            continue;
        if (!blip->takedamage)
            continue;
        if (blip->health <= 0)
            continue;
        if (!visible(ent, blip))
            continue;
        if (!infront(ent, blip))
            continue;
        if ((!blip->r.client->thrusting) && (!blip->r.client->ctf_grapple))
            continue;

        VectorSubtract(blip->s.origin, ent->s.origin, blipdir);

        dist = VectorLength(blipdir);

        if (dist < (100 * g_radius->value) )
        {
            ent->nextthink = level.time + .1;
            ent->think = Stinger_Explode;
            return;
        }

        blipdir[2] += 16;

        if ((target == NULL) || (VectorLength(blipdir) < VectorLength(targetdir)))
        {
            target = blip;
            VectorCopy(blipdir, targetdir);
        }
    }
                    
    if (target != NULL)
    {
        ent->s.effects = EF_ROCKET;
        ent->s.renderfx |= RF_NOSHADOW | RF_FLARE | RF_SHELL_RED | RF_SHELL_GREEN;
        ent->s.modelindex = trap_ModelIndex ("models/ammo/rocket/rocket.md3");
        VectorNormalize(targetdir);
        VectorScale(targetdir, 0.28, targetdir);
        VectorAdd(targetdir, ent->movedir, targetdir);
        VectorNormalize(targetdir);
        VectorCopy(targetdir, ent->movedir);
        VecToAngles(targetdir, ent->s.angles);
        speed = VectorLength(ent->velocity);
        VectorScale(targetdir, speed, ent->velocity);

        if (ent->homing_lock == 0)
        {
            G_Sound (target, CHAN_AUTO, trap_SoundIndex  ("sound/specials/homing/homelock.wav"), 1, ATTN_NORM);
            ent->homing_lock = 1;
        }
    }
     
    ent->nextthink = level.time + .1;
}

void stinger_alt_think (edict_t *ent)
{
    edict_t *target = NULL;
    edict_t *blip = NULL;
    vec3_t  targetdir, blipdir;
    vec_t   speed;
    float   dist;

    if (level.time > ent->delay)
    {
        ent->nextthink = level.time + .1;
        ent->think = Stinger_Explode;
        return;
    }

    while ((blip = findradius(blip, ent->s.origin, 1000 * g_radius->value)) != NULL)
    {
        if (!blip->r.client)
            continue;
        if (blip == ent->creator)
            continue;
        if (blip->disguised)
            continue;
        if ((blip->wf_team == ent->wf_team) && (((int)wfflags->value & WF_ALLOW_FRIENDLY_FIRE)==0))
            continue;
        if (!blip->takedamage)
            continue;
        if (blip->health <= 0)
            continue;
        if (!visible(ent, blip))
            continue;
        if (!infront(ent, blip))
            continue;
        if ((!blip->r.client->thrusting) && (!blip->r.client->ctf_grapple))
            continue;

        VectorSubtract(blip->s.origin, ent->s.origin, blipdir);

        dist = VectorLength(blipdir);

        if (dist < (100 * g_radius->value) )
        {
            ent->nextthink = level.time + .1;
            ent->think = Stinger_Explode;
            return;
        }

        blipdir[2] += 16;

        if ((target == NULL) || (VectorLength(blipdir) < VectorLength(targetdir)))
        {
            target = blip;
            VectorCopy(blipdir, targetdir);
        }
    }
                    
    if (target != NULL)
    {
        ent->s.effects = EF_ROCKET;
        ent->s.renderfx |= RF_NOSHADOW | RF_FLARE | RF_SHELL_RED | RF_SHELL_GREEN;
        ent->s.modelindex = trap_ModelIndex ("models/ammo/rocket/rocket.md3");

        if (level.time > (ent->delay - 9.75))
        {
            
            targetdir[1] = targetdir[1] * (100/dist);

            VectorNormalize(targetdir);
            VectorScale(targetdir, (100/dist), targetdir);
            VectorAdd(targetdir, ent->movedir, targetdir);
            VectorNormalize(targetdir);
            VectorCopy(targetdir, ent->movedir);
            VecToAngles(targetdir, ent->s.angles);
            speed = VectorLength(ent->velocity);
            VectorScale(targetdir, speed, ent->velocity);

            if (ent->homing_lock == 0)
            {
                G_Sound (target, CHAN_AUTO, trap_SoundIndex  ("sound/specials/homing/homelock.wav"), 1, ATTN_NORM);
                ent->homing_lock = 1;
            }
        }
    }
     
    ent->nextthink = level.time + .1;
}

void stinger_touch (edict_t *ent, edict_t *other, cplane_t *plane, int surfFlags)
{
    if (surfFlags & SURF_NOIMPACT)
    {
        G_FreeEdict (ent);
        return;
    }
    
    ent->s.sound = 0;
    ent->movetype = MOVETYPE_FLYRICOCHET2;
    ent->s.effects = RF_NOSHADOW;
    ent->s.modelindex = trap_ModelIndex ("models/ammo/rocketbare.md3");
    ent->mass = 2;
    ent->think = Stinger_Explode;
    ent->nextthink = level.time + 3;

    G_AddEvent (ent, EV_TINK, 0, qtrue);
}


void fire_stinger (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius, int radius_damage, int mod)
{
    edict_t *rocket;

    rocket = G_Spawn();
    VectorCopy (start, rocket->s.origin);
    VectorCopy (dir, rocket->movedir);
    VecToAngles (dir, rocket->s.angles);
    VectorScale (dir, speed, rocket->velocity);
    rocket->movetype = MOVETYPE_FLYMISSILE;
    rocket->r.clipmask = MASK_SHOT;
    rocket->r.solid = SOLID_BBOX;
    rocket->s.effects |= EF_ROCKET;
    rocket->s.renderfx |= RF_NOSHADOW;
    VectorClear (rocket->r.mins);
    VectorClear (rocket->r.maxs);
    rocket->s.modelindex = trap_ModelIndex ("models/ammo/rocket/rocket.md3");
    rocket->r.owner = self;
    rocket->touch = stinger_touch;
    rocket->nextthink = level.time + .1;
    rocket->think = stinger_think;
    rocket->dmg = damage;
    rocket->radius_dmg = radius_damage;
    rocket->dmg_radius = damage_radius;
    rocket->s.sound = trap_SoundIndex ("sound/weapons/rocket/rockfly.wav");
    rocket->classname = "stinger";
    rocket->mod = mod;
    rocket->wf_team = self->wf_team;
    rocket->delay = level.time + 10;
    
    if (self->r.client)
        wf_check_dodge (self, rocket->s.origin, dir, speed);

    trap_LinkEntity (rocket);
}

void fire_alt_stinger (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius, int radius_damage, int mod)
{
    edict_t *rocket;

    rocket = G_Spawn();
    VectorCopy (start, rocket->s.origin);
    VectorCopy (dir, rocket->movedir);
    VecToAngles (dir, rocket->s.angles);
    VectorScale (dir, speed, rocket->velocity);
    rocket->movetype = MOVETYPE_FLYMISSILE;
    rocket->r.clipmask = MASK_SHOT;
    rocket->r.solid = SOLID_BBOX;
    rocket->s.effects |= EF_ROCKET;
    rocket->s.renderfx |= RF_NOSHADOW;
    VectorClear (rocket->r.mins);
    VectorClear (rocket->r.maxs);
    rocket->s.modelindex = trap_ModelIndex ("models/ammo/rocket/rocket.md3");
    rocket->r.owner = self;
    rocket->touch = stinger_touch;
    rocket->nextthink = level.time + .1;
    rocket->think = stinger_alt_think;
    rocket->dmg = damage;
    rocket->radius_dmg = radius_damage;
    rocket->dmg_radius = damage_radius;
    rocket->s.sound = trap_SoundIndex ("sound/weapons/rocket/rockfly.wav");
    rocket->classname = "stinger";
    rocket->mod = mod;
    rocket->wf_team = self->wf_team;
    rocket->delay = level.time + 10;
    
    if (self->r.client)
        wf_check_dodge (self, rocket->s.origin, dir, speed);

    trap_LinkEntity (rocket);
}
void Weapon_StingerLauncher (edict_t *ent)
{
    static int  pause_frames[]  = {25, 33, 42, 50, 0};
    static int  fire_frames[]   = {5, 0};

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