D:\cygwin\wf_fusion_src_r8\WeaponsFactory\w_megachaingun.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 Gregg Reno, Acrid, TeT, and JR

  w_megachaingun.c -- Weapon Mega Stupid Fucking Chaingun
  

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

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


void fire_chainlead (edict_t *self, vec3_t start, vec3_t aimdir, vec3_t axis[3], int damage, int kick, int hspread, int vspread, int *seed, int mod)
{
    trace_t     tr;
    vec3_t      dir;
    vec3_t      end;
    float       r;
    float       u;
    vec3_t      water_start;
    int         content_mask = MASK_SHOT | MASK_WATER;
    float       ran;

     trap_Trace (&tr, self->s.origin, NULL, NULL, start, self, MASK_SHOT);
    if (!(tr.fraction < 1.0))
    {
        r = Q_crandom (seed) * hspread;
        u = Q_crandom (seed) * vspread;
        VectorMA (start, 8192, axis[0], end);
        VectorMA (end, r, axis[1], end);
        VectorMA (end, u, axis[2], end);

        if (trap_PointContents (start) & MASK_WATER)
        {
            VectorCopy (start, water_start);
            content_mask &= ~MASK_WATER;
        }

        trap_Trace (&tr, start, NULL, NULL, end, self, content_mask);

        if (tr.contents & MASK_WATER)
        {
            VectorCopy (tr.endpos, water_start);

            if (!VectorCompare (start, tr.endpos))
            {
                vec3_t forward, right, up;
                VectorSubtract (end, start, dir);
                VecToAngles (dir, dir);
                AngleVectors (dir, forward, right, up);
                r = Q_crandom (seed) * hspread * 2;
                u = Q_crandom (seed) * vspread * 2;
                VectorMA (water_start, 8192, forward, end);
                VectorMA (end, r, right, end);
                VectorMA (end, u, up, end);
            }

            trap_Trace (&tr, water_start, NULL, NULL, end, self, MASK_SHOT);
        }
    }

    if (tr.fraction < 1.0)
    {
        if (game.edicts[tr.ent].takedamage)
        {
            T_Damage (&game.edicts[tr.ent], self, self, aimdir, tr.endpos, tr.plane.normal, damage, kick, DAMAGE_BULLET, mod);
        }
        else
        {
            ran = random();
            if(ran<0.2)
            {
                if ( !(tr.surfFlags & SURF_NOIMPACT) )
                {
                    if (self->r.client)
                        PlayerNoise (self, tr.endpos, PNOISE_IMPACT);
                }
            }
        }
    }
}

void fire_ChainBlast (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread)
{
    vec3_t      dir, axis[3];
    edict_t     *event;
    float       ran;
    int         seed = rand() & 255;

    VecToAngles ( aimdir, dir );
    AngleVectors ( dir, axis[0], axis[1], axis[2] );

    ran = random();
    if(ran<0.2)
    {
        event = G_SpawnEvent ( EV_FIRE_MEGA, seed, start );
        event->s.ownerNum = self - game.edicts;
        event->r.svflags = SVF_FORCEOLDORIGIN;
        VectorScale ( axis[0], 1024, event->s.origin2 );
    }

    fire_chainlead ( self, start, aimdir, axis, damage, kick, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, &seed, MOD_MEGACHAINGUN );
}


void MegaChaingun_Fire (edict_t *ent)
{
    int         i;
    int         shots;
    vec3_t      start;
    vec3_t      forward, right, up;
    float       r, u;
    vec3_t      offset;
    int         damage;
    int         kick = 20;

    if (!ent->groundentity && !ent->cantmove)
    {
        ent->r.client->ps.gunframe = 32;

        G_PrintMsg (ent, PRINT_HIGH, "Must be on the ground to fire. \n");
        ent->cantmove = 0;
        ent->r.client->weapon_sound = 0;
        return;
    }

    damage = wf_game.weapon_damage[WEAPON_MEGACHAINGUN];

    if (ent->r.client->ps.gunframe == 5)
    {
        G_Sound(ent, CHAN_AUTO, trap_SoundIndex ("sound/weapons/megachaingun/megaspinup.wav"), 1, ATTN_IDLE);
        VectorCopy(ent->s.origin,ent->LockedPosition);
        ent->cantmove |= WF_NO_X_MOVE | WF_NO_Y_MOVE;
    }

    if ((ent->r.client->ps.gunframe == 14) && !(ent->r.client->buttons & BUTTON_ATTACK))
    {
        ent->r.client->ps.gunframe = 32;
        ent->cantmove = 0;
        ent->r.client->weapon_sound = 0;
        return;
    }
    else if ((ent->r.client->ps.gunframe == 21) && (ent->r.client->buttons & BUTTON_ATTACK)
        && ent->r.client->pers.inventory[ent->r.client->ammo_index])
    {
        ent->r.client->ps.gunframe = 15;
    }
    else
    {
        ent->r.client->ps.gunframe++;
    }

    if (ent->r.client->ps.gunframe == 22)
    {
        ent->r.client->weapon_sound = 0;
        ent->cantmove = 0;
        G_Sound(ent, CHAN_AUTO, trap_SoundIndex ("sound/weapons/megachaingun/megaspindown.wav"), 1, ATTN_IDLE);
    }
    else
    {
        ent->r.client->weapon_sound = trap_SoundIndex ("sound/weapons/megachaingun/megafire.wav");
    }

    if (ent->r.client->ps.gunframe <= 9)
        shots = 1;
    else if (ent->r.client->ps.gunframe <= 14)
    {
        if (ent->r.client->buttons & BUTTON_ATTACK)
            shots = 1;
        else
            shots = 1;
    }
    else
        shots = 2;

    if (ent->r.client->pers.inventory[ent->r.client->ammo_index] < shots)
        shots = ent->r.client->pers.inventory[ent->r.client->ammo_index];

    if (!shots)
    {
        if (level.time >= ent->pain_debounce_time)
        {
            G_Sound(ent, CHAN_VOICE, trap_SoundIndex ("sound/weapons/noammo.wav"), 1, ATTN_NORM);
            ent->pain_debounce_time = level.time + 1;
        }
        NoAmmoWeaponChange (ent->r.client);
        return;
    }

    if (is_quad)
    {
        damage *= 4;
        kick *= 4;
    }

    for (i=0 ; i<3 ; i++)
    {
        ent->r.client->kick_origin[i] = crandom() * 0.35;
        ent->r.client->kick_angles[i] = crandom() * 0.7;
    }

    for (i=0 ; i<shots ; i++)
    {
        AngleVectors (ent->r.client->v_angle, forward, right, up);
        r = 7 + crandom()*4;
        u = crandom()*4;
        VectorSet(offset, 0, r, u + ent->viewheight-8);
        P_ProjectSource (ent->r.client, ent->s.origin, offset, forward, right, start);
 
        if (ent->r.client->r.ping > g_pingfloor->value)
        {
            fire_ChainBlast(ent, start, forward, damage*2, kick, 450, 450);
            fire_ChainBlast(ent, start, forward, damage*2, kick, 450, 450);
        }
        else
        {
            fire_ChainBlast(ent, start, forward, damage, kick, 500, 500);
            fire_ChainBlast(ent, start, forward, damage, kick, 500, 500);
            fire_ChainBlast(ent, start, forward, damage, kick, 500, 500);
            fire_ChainBlast(ent, start, forward, damage, kick, 500, 500);
        }
    }

    G_AddEvent (ent, EV_MUZZLEFLASH, (3-shots) | is_silenced, qtrue);

    PlayerNoise(ent, start, PNOISE_WEAPON);

    if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
    {
        ent->r.client->pers.inventory[ent->r.client->ammo_index] -= (int)(shots * 1.5);
    }

    if ((shots == 3) && (random() < .16)) 
    {
        fire_blaster (ent, start, forward, 0, 500, EF_HYPERBLASTER, qtrue);
    }
}


void Weapon_MegaChaingun (edict_t *ent)
{
    static int  pause_frames[]  = {38, 43, 51, 61, 0};
    static int  fire_frames[]   = {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0};

    Weapon_Generic (ent, 4, 31, 61, 64, pause_frames, fire_frames, MegaChaingun_Fire);
}