D:\cygwin\wf_fusion_src_r8\WeaponsFactory\w_hyperblaster.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 multiple authors

  w_hyperblaster.c -- Hyper Blaster
  

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

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

void fire_blaster_wf (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick)
{

    vec3_t      from;
    vec3_t      end;
    trace_t     tr;
    edict_t     *ignore, *event;
    int         mask;

    VectorMA (start, 8192, aimdir, end);
    VectorCopy (start, from);
    ignore = self;
    mask = MASK_SHOT;
    while (ignore)
    {
        trap_Trace (&tr, from, NULL, NULL, end, ignore, mask);

        ignore = NULL;


        if ( (game.edicts[tr.ent].takedamage))
            WF_T_Damage (&game.edicts[tr.ent], self, self, aimdir, tr.endpos, tr.plane.normal, damage, kick, 0, MOD_HYPERBLASTER);

        VectorCopy (tr.endpos, from);
    }

    if (self->wf_team == 1)
        event = G_SpawnEvent ( EV_REDHYPER, 0, start );
    else
        event = G_SpawnEvent ( EV_BLUEHYPER, 0, start );
    event->s.renderfx = RF_BEAM;
    VectorCopy ( tr.endpos, event->s.origin2 );

    if (self->r.client)
        PlayerNoise(self, tr.endpos, PNOISE_IMPACT);


}


void WF_Blaster_Fire (edict_t *ent, vec3_t g_offset, int damage, qboolean hyper, int effect)
{
    vec3_t  forward, right;
    vec3_t  start;
    vec3_t  offset;
    gclient_t *client = ent->r.client;

    if (is_quad)
        damage *= 4;
    AngleVectors (client->v_angle, forward, right, NULL);
    VectorSet(offset, 12, 8, ent->viewheight-8);
    VectorAdd (offset, g_offset, offset);
    P_ProjectSource (client, ent->s.origin, offset, forward, right, start);

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

    fire_blaster_wf (ent, start, forward, damage, 0);

    // send muzzle flash
    G_AddEvent (ent, EV_MUZZLEFLASH, is_silenced, qtrue);

    PlayerNoise(ent, start, PNOISE_WEAPON);
}


void Weapon_HyperBlaster_Fire_WF (edict_t *ent)
{
    float   rotation;
    vec3_t  offset;
    int     effect;
    int     damage;
    gclient_t *client = ent->r.client;

    ent->r.client->weapon_sound = trap_SoundIndex ("sound/weapons2/hyperblaster/hyprbl1a.wav");

    if (!(ent->r.client->buttons & BUTTON_ATTACK))
    {
        ent->r.client->ps.gunframe++;
    }
    else
    {
        if (! ent->r.client->pers.inventory[ent->r.client->ammo_index] )
        {
            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);
        }
        else
        {
            rotation = (ent->r.client->ps.gunframe - 5) * 2*M_PI/6;
            offset[0] = -4 * sin(rotation);
            offset[1] = 0;
            offset[2] = 4 * cos(rotation);

            if ((ent->r.client->ps.gunframe == 6) || (ent->r.client->ps.gunframe == 9))
                effect = EF_HYPERBLASTER;
            else
                effect = 0;
            damage = wf_game.weapon_damage[WEAPON_HYPERBLASTER];

            ent->ShotNumber++;
            if (ent->r.client->r.ping > g_pingfloor->value)
            {
                if (ent->ShotNumber>1)
                {
                    ent->ShotNumber = 0;
                    WF_Blaster_Fire (ent, offset, damage*2, qtrue, effect);
                }
            }
            else
            {
                ent->ShotNumber = 0;
                WF_Blaster_Fire (ent, offset, damage, qtrue, effect);
            }
            if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                client->pers.inventory[client->ammo_index]--;

        }

        client->ps.gunframe++;
        if (client->ps.gunframe == 12 && client->pers.inventory[client->ammo_index])
            client->ps.gunframe = 6;
    }

    if (client->ps.gunframe == 12)
    {
        G_Sound (ent, CHAN_AUTO, trap_SoundIndex("sound/weapons2/hyperblaster/hyprbd1a.wav"), 1, ATTN_NORM);
        client->weapon_sound = 0;
    }

}

void blaster_bolt_touch (edict_t *self, edict_t *other, cplane_t *plane, int surfFlags)
{
    if (other == self->r.owner)
        return;
    if (surfFlags & SURF_NOIMPACT)
    {
        G_FreeEdict (self);
        return;
    }

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

    if (other->takedamage)
    {
        WF_T_Damage (other, self, self->r.owner, self->velocity, self->s.origin, plane->normal, self->dmg, 1, DAMAGE_ENERGY, self->style);
        G_FreeEdict (self);
    }
    else
    {
        // turn entity into event
        G_TurnEntityIntoEvent ( self, EV_BLASTER, DirToByte (plane ? plane->normal : NULL) );
        return;
    }

    G_FreeEdict (self);
}
void blaster_bolt_touch2 (edict_t *ent, edict_t *other, cplane_t *plane, int surfFlags)
{
    if (surfFlags & SURF_NOIMPACT)
    {
        G_FreeEdict (ent);
        return;
    }

    if (other->takedamage)
    {
        WF_T_Damage (other, ent, ent->r.owner, ent->velocity, ent->s.origin, plane->normal, ent->dmg, 1, DAMAGE_ENERGY, ent->style);
        G_FreeEdict (ent);
    }
    else
    {
        ent->s.sound = 0;
        ent->movetype = MOVETYPE_FLYRICOCHET;

        ent->touch = blaster_bolt_touch;
        ent->think = G_FreeEdict;

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

}
void blaster_bolt_touch1 (edict_t *ent, edict_t *other, cplane_t *plane, int surfFlags)
{
    if (surfFlags & SURF_NOIMPACT)
    {
        G_FreeEdict (ent);
        return;
    }

    if (other->takedamage)
    {
        WF_T_Damage (other, ent, ent->r.owner, ent->velocity, ent->s.origin, plane->normal, ent->dmg, 1, DAMAGE_ENERGY, ent->style);
        G_FreeEdict (ent);
    }
    else
    {
        ent->s.sound = 0;
        ent->movetype = MOVETYPE_FLYRICOCHET;

        if (random() < .33)
        {
            ent->touch = blaster_bolt_touch2;
        }
        else
        {
            ent->touch = blaster_bolt_touch;
            ent->think = G_FreeEdict;
        }

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

}
void fire_blaster_bolt (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int effect, int mod)
{
    edict_t *bolt;
    trace_t tr;

    VectorNormalize (dir);

    bolt = G_Spawn();
    bolt->r.svflags = 0;
    VectorCopy (start, bolt->s.origin);
    VectorCopy (start, bolt->s.old_origin);
    VecToAngles (dir, bolt->s.angles);
    VectorScale (dir, speed, bolt->velocity);
    bolt->movetype = MOVETYPE_FLYMISSILE;
    bolt->r.clipmask = MASK_SHOT;
    bolt->r.solid = SOLID_BBOX;
    bolt->s.effects |= effect;
    bolt->s.renderfx |= RF_NOSHADOW | RF_FLARE;
    VectorClear (bolt->r.mins);
    VectorClear (bolt->r.maxs);
    if (self->wf_team == 2)
    {
        bolt->s.renderfx |= RF_SHELL_BLUE;
        bolt->s.modelindex = trap_ModelIndex ("models/weapons2/blaster/newbolt2.md3");
    }
    else
    {
        bolt->s.renderfx |= RF_SHELL_RED;
        bolt->s.modelindex = trap_ModelIndex ("models/weapons2/blaster/newbolt.md3");
    }

    bolt->s.sound = trap_SoundIndex ("sound/weapons/plasma/lasfly.wav");
    bolt->r.owner = self;
    bolt->touch = blaster_bolt_touch1;
    bolt->nextthink = level.time + 8000;
    bolt->think = G_FreeEdict;
    bolt->dmg = damage;
    bolt->classname = "bolt";
    bolt->style = mod;
    trap_LinkEntity (bolt);

    if (self->r.client)
        check_dodge (self, bolt->s.origin, dir, speed);

    trap_Trace (&tr, self->s.origin, NULL, NULL, bolt->s.origin, bolt, MASK_SHOT);
    if (tr.fraction < 1.0)
    {
        VectorMA (bolt->s.origin, -10, dir, bolt->s.origin);
        bolt->touch (bolt, &game.edicts[tr.ent], NULL, 0);
    }
}   
void BoltBlaster_Fire (edict_t *ent, vec3_t g_offset, int damage, qboolean hyper, int effect)
{
    vec3_t  forward, right;
    vec3_t  start;
    vec3_t  offset;
    gclient_t *client = ent->r.client;

    if (is_quad)
        damage *= 4;
    AngleVectors (client->v_angle, forward, right, NULL);
    VectorSet(offset, 24, 8, ent->viewheight-8);
    VectorAdd (offset, g_offset, offset);
    P_ProjectSource (client, ent->s.origin, offset, forward, right, start);

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

    fire_blaster_bolt (ent, start, forward, damage, 1000, effect, hyper ? MOD_HYPERBLASTER : MOD_BLASTER);

    // send muzzle flash
    G_AddEvent (ent, EV_MUZZLEFLASH, is_silenced, qtrue);

    PlayerNoise(ent, start, PNOISE_WEAPON);

}

void Weapon_HyperBlasterBolt_Fire (edict_t *ent)
{
    float   rotation;
    vec3_t  offset;
    int     effect;
    int     damage;
    gclient_t *client = ent->r.client;

    if (!(client->buttons & BUTTON_ALTERNATE))
    {
        client->ps.gunframe++;
    }
    else
    {
        if (! client->pers.inventory[client->ammo_index] )
        {
            NoAmmoWeaponChange ( client );
        } 
        else 
        {
            rotation = (client->ps.gunframe - 5) * M_TWOPI/6;
            offset[0] = -4 * sin(rotation);
            offset[1] = 0;
            offset[2] = 4 * cos(rotation);

            if ((client->ps.gunframe == 6) || (client->ps.gunframe == 9))
                if (ent->wf_team == 2)
                    effect = EF_FLAG2;
                else
                    effect = EF_FLAG1;
            else
                effect = 0;
            if (deathmatch->value)
                damage = 15;
            else
                damage = 20;
            
            BoltBlaster_Fire (ent, offset, damage, qtrue, effect);
            if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                client->pers.inventory[client->ammo_index]--;

            //splitmodels (hyperblaster special): remove animation
        }

        client->ps.gunframe++;
        if (client->ps.gunframe == 12 && client->pers.inventory[client->ammo_index])
            client->ps.gunframe = 6;
    }

}

void Weapon_HyperBlaster (edict_t *ent)
{


    static int  pause_frames[]  = {0};
    static int  fire_frames[]   = {6, 7, 8, 9, 10, 11, 0};

    if (ent->r.client && ent->r.client->pers.altered_state)
    {
        Weapon_Alternate (ent, 5, 20, 49, 53, pause_frames, fire_frames, Weapon_HyperBlasterBolt_Fire);
    }
    else
        Weapon_Generic (ent, 5, 20, 49, 53, pause_frames, fire_frames, Weapon_HyperBlaster_Fire_WF);

}