Annotation of quake2/game/p_weapon.c, revision 1.1.1.2

1.1.1.2 ! root        1: /*
        !             2: Copyright (C) 1997-2001 Id Software, Inc.
        !             3: 
        !             4: This program is free software; you can redistribute it and/or
        !             5: modify it under the terms of the GNU General Public License
        !             6: as published by the Free Software Foundation; either version 2
        !             7: of the License, or (at your option) any later version.
        !             8: 
        !             9: This program is distributed in the hope that it will be useful,
        !            10: but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            11: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
        !            12: 
        !            13: See the GNU General Public License for more details.
        !            14: 
        !            15: You should have received a copy of the GNU General Public License
        !            16: along with this program; if not, write to the Free Software
        !            17: Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
        !            18: 
        !            19: */
1.1       root       20: // g_weapon.c
                     21: 
                     22: #include "g_local.h"
                     23: #include "m_player.h"
                     24: 
                     25: 
                     26: static qboolean        is_quad;
                     27: static byte            is_silenced;
                     28: 
                     29: 
                     30: void weapon_grenade_fire (edict_t *ent, qboolean held);
                     31: 
                     32: 
                     33: static void P_ProjectSource (gclient_t *client, vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result)
                     34: {
                     35:        vec3_t  _distance;
                     36: 
                     37:        VectorCopy (distance, _distance);
                     38:        if (client->pers.hand == LEFT_HANDED)
                     39:                _distance[1] *= -1;
                     40:        else if (client->pers.hand == CENTER_HANDED)
                     41:                _distance[1] = 0;
                     42:        G_ProjectSource (point, _distance, forward, right, result);
                     43: }
                     44: 
                     45: 
                     46: /*
                     47: ===============
                     48: PlayerNoise
                     49: 
                     50: Each player can have two noise objects associated with it:
                     51: a personal noise (jumping, pain, weapon firing), and a weapon
                     52: target noise (bullet wall impacts)
                     53: 
                     54: Monsters that don't directly see the player can move
                     55: to a noise in hopes of seeing the player from there.
                     56: ===============
                     57: */
                     58: void PlayerNoise(edict_t *who, vec3_t where, int type)
                     59: {
                     60:        edict_t         *noise;
                     61: 
                     62:        if (type == PNOISE_WEAPON)
                     63:        {
                     64:                if (who->client->silencer_shots)
                     65:                {
                     66:                        who->client->silencer_shots--;
                     67:                        return;
                     68:                }
                     69:        }
                     70: 
                     71:        if (deathmatch->value)
                     72:                return;
                     73: 
                     74:        if (who->flags & FL_NOTARGET)
                     75:                return;
                     76: 
                     77: 
                     78:        if (!who->mynoise)
                     79:        {
                     80:                noise = G_Spawn();
                     81:                noise->classname = "player_noise";
                     82:                VectorSet (noise->mins, -8, -8, -8);
                     83:                VectorSet (noise->maxs, 8, 8, 8);
                     84:                noise->owner = who;
                     85:                noise->svflags = SVF_NOCLIENT;
                     86:                who->mynoise = noise;
                     87: 
                     88:                noise = G_Spawn();
                     89:                noise->classname = "player_noise";
                     90:                VectorSet (noise->mins, -8, -8, -8);
                     91:                VectorSet (noise->maxs, 8, 8, 8);
                     92:                noise->owner = who;
                     93:                noise->svflags = SVF_NOCLIENT;
                     94:                who->mynoise2 = noise;
                     95:        }
                     96: 
                     97:        if (type == PNOISE_SELF || type == PNOISE_WEAPON)
                     98:        {
                     99:                noise = who->mynoise;
                    100:                level.sound_entity = noise;
                    101:                level.sound_entity_framenum = level.framenum;
                    102:        }
                    103:        else // type == PNOISE_IMPACT
                    104:        {
                    105:                noise = who->mynoise2;
                    106:                level.sound2_entity = noise;
                    107:                level.sound2_entity_framenum = level.framenum;
                    108:        }
                    109: 
                    110:        VectorCopy (where, noise->s.origin);
                    111:        VectorSubtract (where, noise->maxs, noise->absmin);
                    112:        VectorAdd (where, noise->maxs, noise->absmax);
                    113:        noise->teleport_time = level.time;
                    114:        gi.linkentity (noise);
                    115: }
                    116: 
                    117: 
                    118: qboolean Pickup_Weapon (edict_t *ent, edict_t *other)
                    119: {
                    120:        int                     index;
                    121:        gitem_t         *ammo;
                    122: 
                    123:        index = ITEM_INDEX(ent->item);
                    124: 
                    125:        if ( ( ((int)(dmflags->value) & DF_WEAPONS_STAY) || coop->value) 
                    126:                && other->client->pers.inventory[index])
                    127:        {
                    128:                if (!(ent->spawnflags & (DROPPED_ITEM | DROPPED_PLAYER_ITEM) ) )
                    129:                        return false;   // leave the weapon for others to pickup
                    130:        }
                    131: 
                    132:        other->client->pers.inventory[index]++;
                    133: 
                    134:        if (!(ent->spawnflags & DROPPED_ITEM) )
                    135:        {
                    136:                // give them some ammo with it
                    137:                ammo = FindItem (ent->item->ammo);
                    138:                if ( (int)dmflags->value & DF_INFINITE_AMMO )
                    139:                        Add_Ammo (other, ammo, 1000);
                    140:                else
                    141:                        Add_Ammo (other, ammo, ammo->quantity);
                    142: 
                    143:                if (! (ent->spawnflags & DROPPED_PLAYER_ITEM) )
                    144:                {
                    145:                        if (deathmatch->value)
                    146:                        {
                    147:                                if ((int)(dmflags->value) & DF_WEAPONS_STAY)
                    148:                                        ent->flags |= FL_RESPAWN;
                    149:                                else
                    150:                                        SetRespawn (ent, 30);
                    151:                        }
                    152:                        if (coop->value)
                    153:                                ent->flags |= FL_RESPAWN;
                    154:                }
                    155:        }
                    156: 
                    157:        if (other->client->pers.weapon != ent->item && 
                    158:                (other->client->pers.inventory[index] == 1) &&
                    159:                ( !deathmatch->value || other->client->pers.weapon == FindItem("blaster") ) )
                    160:                other->client->newweapon = ent->item;
                    161: 
                    162:        return true;
                    163: }
                    164: 
                    165: 
                    166: /*
                    167: ===============
                    168: ChangeWeapon
                    169: 
                    170: The old weapon has been dropped all the way, so make the new one
                    171: current
                    172: ===============
                    173: */
                    174: void ChangeWeapon (edict_t *ent)
                    175: {
                    176:        int i;
                    177: 
                    178:        if (ent->client->grenade_time)
                    179:        {
                    180:                ent->client->grenade_time = level.time;
                    181:                ent->client->weapon_sound = 0;
                    182:                weapon_grenade_fire (ent, false);
                    183:                ent->client->grenade_time = 0;
                    184:        }
                    185: 
                    186:        ent->client->pers.lastweapon = ent->client->pers.weapon;
                    187:        ent->client->pers.weapon = ent->client->newweapon;
                    188:        ent->client->newweapon = NULL;
                    189:        ent->client->machinegun_shots = 0;
                    190: 
                    191:        // set visible model
                    192:        if (ent->s.modelindex == 255) {
                    193:                if (ent->client->pers.weapon)
                    194:                        i = ((ent->client->pers.weapon->weapmodel & 0xff) << 8);
                    195:                else
                    196:                        i = 0;
                    197:                ent->s.skinnum = (ent - g_edicts - 1) | i;
                    198:        }
                    199: 
                    200:        if (ent->client->pers.weapon && ent->client->pers.weapon->ammo)
                    201:                ent->client->ammo_index = ITEM_INDEX(FindItem(ent->client->pers.weapon->ammo));
                    202:        else
                    203:                ent->client->ammo_index = 0;
                    204: 
                    205:        if (!ent->client->pers.weapon)
                    206:        {       // dead
                    207:                ent->client->ps.gunindex = 0;
                    208:                return;
                    209:        }
                    210: 
                    211:        ent->client->weaponstate = WEAPON_ACTIVATING;
                    212:        ent->client->ps.gunframe = 0;
                    213:        ent->client->ps.gunindex = gi.modelindex(ent->client->pers.weapon->view_model);
                    214: 
                    215:        ent->client->anim_priority = ANIM_PAIN;
                    216:        if(ent->client->ps.pmove.pm_flags & PMF_DUCKED)
                    217:        {
                    218:                        ent->s.frame = FRAME_crpain1;
                    219:                        ent->client->anim_end = FRAME_crpain4;
                    220:        }
                    221:        else
                    222:        {
                    223:                        ent->s.frame = FRAME_pain301;
                    224:                        ent->client->anim_end = FRAME_pain304;
                    225:                        
                    226:        }
                    227: }
                    228: 
                    229: /*
                    230: =================
                    231: NoAmmoWeaponChange
                    232: =================
                    233: */
                    234: void NoAmmoWeaponChange (edict_t *ent)
                    235: {
                    236:        if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("slugs"))]
                    237:                &&  ent->client->pers.inventory[ITEM_INDEX(FindItem("railgun"))] )
                    238:        {
                    239:                ent->client->newweapon = FindItem ("railgun");
                    240:                return;
                    241:        }
                    242:        if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("cells"))]
                    243:                &&  ent->client->pers.inventory[ITEM_INDEX(FindItem("hyperblaster"))] )
                    244:        {
                    245:                ent->client->newweapon = FindItem ("hyperblaster");
                    246:                return;
                    247:        }
                    248:        if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("bullets"))]
                    249:                &&  ent->client->pers.inventory[ITEM_INDEX(FindItem("chaingun"))] )
                    250:        {
                    251:                ent->client->newweapon = FindItem ("chaingun");
                    252:                return;
                    253:        }
                    254:        if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("bullets"))]
                    255:                &&  ent->client->pers.inventory[ITEM_INDEX(FindItem("machinegun"))] )
                    256:        {
                    257:                ent->client->newweapon = FindItem ("machinegun");
                    258:                return;
                    259:        }
                    260:        if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("shells"))] > 1
                    261:                &&  ent->client->pers.inventory[ITEM_INDEX(FindItem("super shotgun"))] )
                    262:        {
                    263:                ent->client->newweapon = FindItem ("super shotgun");
                    264:                return;
                    265:        }
                    266:        if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("shells"))]
                    267:                &&  ent->client->pers.inventory[ITEM_INDEX(FindItem("shotgun"))] )
                    268:        {
                    269:                ent->client->newweapon = FindItem ("shotgun");
                    270:                return;
                    271:        }
                    272:        ent->client->newweapon = FindItem ("blaster");
                    273: }
                    274: 
                    275: /*
                    276: =================
                    277: Think_Weapon
                    278: 
                    279: Called by ClientBeginServerFrame and ClientThink
                    280: =================
                    281: */
                    282: void Think_Weapon (edict_t *ent)
                    283: {
                    284:        // if just died, put the weapon away
                    285:        if (ent->health < 1)
                    286:        {
                    287:                ent->client->newweapon = NULL;
                    288:                ChangeWeapon (ent);
                    289:        }
                    290: 
                    291:        // call active weapon think routine
                    292:        if (ent->client->pers.weapon && ent->client->pers.weapon->weaponthink)
                    293:        {
                    294:                is_quad = (ent->client->quad_framenum > level.framenum);
                    295:                if (ent->client->silencer_shots)
                    296:                        is_silenced = MZ_SILENCED;
                    297:                else
                    298:                        is_silenced = 0;
                    299:                ent->client->pers.weapon->weaponthink (ent);
                    300:        }
                    301: }
                    302: 
                    303: 
                    304: /*
                    305: ================
                    306: Use_Weapon
                    307: 
                    308: Make the weapon ready if there is ammo
                    309: ================
                    310: */
                    311: void Use_Weapon (edict_t *ent, gitem_t *item)
                    312: {
                    313:        int                     ammo_index;
                    314:        gitem_t         *ammo_item;
                    315: 
                    316:        // see if we're already using it
                    317:        if (item == ent->client->pers.weapon)
                    318:                return;
                    319: 
                    320:        if (item->ammo && !g_select_empty->value && !(item->flags & IT_AMMO))
                    321:        {
                    322:                ammo_item = FindItem(item->ammo);
                    323:                ammo_index = ITEM_INDEX(ammo_item);
                    324: 
                    325:                if (!ent->client->pers.inventory[ammo_index])
                    326:                {
                    327:                        gi.cprintf (ent, PRINT_HIGH, "No %s for %s.\n", ammo_item->pickup_name, item->pickup_name);
                    328:                        return;
                    329:                }
                    330: 
                    331:                if (ent->client->pers.inventory[ammo_index] < item->quantity)
                    332:                {
                    333:                        gi.cprintf (ent, PRINT_HIGH, "Not enough %s for %s.\n", ammo_item->pickup_name, item->pickup_name);
                    334:                        return;
                    335:                }
                    336:        }
                    337: 
                    338:        // change to this weapon when down
                    339:        ent->client->newweapon = item;
                    340: }
                    341: 
                    342: 
                    343: 
                    344: /*
                    345: ================
                    346: Drop_Weapon
                    347: ================
                    348: */
                    349: void Drop_Weapon (edict_t *ent, gitem_t *item)
                    350: {
                    351:        int             index;
                    352: 
                    353:        if ((int)(dmflags->value) & DF_WEAPONS_STAY)
                    354:                return;
                    355: 
                    356:        index = ITEM_INDEX(item);
                    357:        // see if we're already using it
                    358:        if ( ((item == ent->client->pers.weapon) || (item == ent->client->newweapon))&& (ent->client->pers.inventory[index] == 1) )
                    359:        {
                    360:                gi.cprintf (ent, PRINT_HIGH, "Can't drop current weapon\n");
                    361:                return;
                    362:        }
                    363: 
                    364:        Drop_Item (ent, item);
                    365:        ent->client->pers.inventory[index]--;
                    366: }
                    367: 
                    368: 
                    369: /*
                    370: ================
                    371: Weapon_Generic
                    372: 
                    373: A generic function to handle the basics of weapon thinking
                    374: ================
                    375: */
                    376: #define FRAME_FIRE_FIRST               (FRAME_ACTIVATE_LAST + 1)
                    377: #define FRAME_IDLE_FIRST               (FRAME_FIRE_LAST + 1)
                    378: #define FRAME_DEACTIVATE_FIRST (FRAME_IDLE_LAST + 1)
                    379: 
                    380: void Weapon_Generic (edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST, int FRAME_IDLE_LAST, int FRAME_DEACTIVATE_LAST, int *pause_frames, int *fire_frames, void (*fire)(edict_t *ent))
                    381: {
                    382:        int             n;
                    383: 
                    384:        if(ent->deadflag || ent->s.modelindex != 255) // VWep animations screw up corpses
                    385:        {
                    386:                return;
                    387:        }
                    388: 
                    389:        if (ent->client->weaponstate == WEAPON_DROPPING)
                    390:        {
                    391:                if (ent->client->ps.gunframe == FRAME_DEACTIVATE_LAST)
                    392:                {
                    393:                        ChangeWeapon (ent);
                    394:                        return;
                    395:                }
                    396:                else if ((FRAME_DEACTIVATE_LAST - ent->client->ps.gunframe) == 4)
                    397:                {
                    398:                        ent->client->anim_priority = ANIM_REVERSE;
                    399:                        if(ent->client->ps.pmove.pm_flags & PMF_DUCKED)
                    400:                        {
                    401:                                ent->s.frame = FRAME_crpain4+1;
                    402:                                ent->client->anim_end = FRAME_crpain1;
                    403:                        }
                    404:                        else
                    405:                        {
                    406:                                ent->s.frame = FRAME_pain304+1;
                    407:                                ent->client->anim_end = FRAME_pain301;
                    408:                                
                    409:                        }
                    410:                }
                    411: 
                    412:                ent->client->ps.gunframe++;
                    413:                return;
                    414:        }
                    415: 
                    416:        if (ent->client->weaponstate == WEAPON_ACTIVATING)
                    417:        {
                    418:                if (ent->client->ps.gunframe == FRAME_ACTIVATE_LAST)
                    419:                {
                    420:                        ent->client->weaponstate = WEAPON_READY;
                    421:                        ent->client->ps.gunframe = FRAME_IDLE_FIRST;
                    422:                        return;
                    423:                }
                    424: 
                    425:                ent->client->ps.gunframe++;
                    426:                return;
                    427:        }
                    428: 
                    429:        if ((ent->client->newweapon) && (ent->client->weaponstate != WEAPON_FIRING))
                    430:        {
                    431:                ent->client->weaponstate = WEAPON_DROPPING;
                    432:                ent->client->ps.gunframe = FRAME_DEACTIVATE_FIRST;
                    433: 
                    434:                if ((FRAME_DEACTIVATE_LAST - FRAME_DEACTIVATE_FIRST) < 4)
                    435:                {
                    436:                        ent->client->anim_priority = ANIM_REVERSE;
                    437:                        if(ent->client->ps.pmove.pm_flags & PMF_DUCKED)
                    438:                        {
                    439:                                ent->s.frame = FRAME_crpain4+1;
                    440:                                ent->client->anim_end = FRAME_crpain1;
                    441:                        }
                    442:                        else
                    443:                        {
                    444:                                ent->s.frame = FRAME_pain304+1;
                    445:                                ent->client->anim_end = FRAME_pain301;
                    446:                                
                    447:                        }
                    448:                }
                    449:                return;
                    450:        }
                    451: 
                    452:        if (ent->client->weaponstate == WEAPON_READY)
                    453:        {
                    454:                if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
                    455:                {
                    456:                        ent->client->latched_buttons &= ~BUTTON_ATTACK;
                    457:                        if ((!ent->client->ammo_index) || 
                    458:                                ( ent->client->pers.inventory[ent->client->ammo_index] >= ent->client->pers.weapon->quantity))
                    459:                        {
                    460:                                ent->client->ps.gunframe = FRAME_FIRE_FIRST;
                    461:                                ent->client->weaponstate = WEAPON_FIRING;
                    462: 
                    463:                                // start the animation
                    464:                                ent->client->anim_priority = ANIM_ATTACK;
                    465:                                if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
                    466:                                {
                    467:                                        ent->s.frame = FRAME_crattak1-1;
                    468:                                        ent->client->anim_end = FRAME_crattak9;
                    469:                                }
                    470:                                else
                    471:                                {
                    472:                                        ent->s.frame = FRAME_attack1-1;
                    473:                                        ent->client->anim_end = FRAME_attack8;
                    474:                                }
                    475:                        }
                    476:                        else
                    477:                        {
                    478:                                if (level.time >= ent->pain_debounce_time)
                    479:                                {
                    480:                                        gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
                    481:                                        ent->pain_debounce_time = level.time + 1;
                    482:                                }
                    483:                                NoAmmoWeaponChange (ent);
                    484:                        }
                    485:                }
                    486:                else
                    487:                {
                    488:                        if (ent->client->ps.gunframe == FRAME_IDLE_LAST)
                    489:                        {
                    490:                                ent->client->ps.gunframe = FRAME_IDLE_FIRST;
                    491:                                return;
                    492:                        }
                    493: 
                    494:                        if (pause_frames)
                    495:                        {
                    496:                                for (n = 0; pause_frames[n]; n++)
                    497:                                {
                    498:                                        if (ent->client->ps.gunframe == pause_frames[n])
                    499:                                        {
                    500:                                                if (rand()&15)
                    501:                                                        return;
                    502:                                        }
                    503:                                }
                    504:                        }
                    505: 
                    506:                        ent->client->ps.gunframe++;
                    507:                        return;
                    508:                }
                    509:        }
                    510: 
                    511:        if (ent->client->weaponstate == WEAPON_FIRING)
                    512:        {
                    513:                for (n = 0; fire_frames[n]; n++)
                    514:                {
                    515:                        if (ent->client->ps.gunframe == fire_frames[n])
                    516:                        {
                    517:                                if (ent->client->quad_framenum > level.framenum)
                    518:                                        gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage3.wav"), 1, ATTN_NORM, 0);
                    519: 
                    520:                                fire (ent);
                    521:                                break;
                    522:                        }
                    523:                }
                    524: 
                    525:                if (!fire_frames[n])
                    526:                        ent->client->ps.gunframe++;
                    527: 
                    528:                if (ent->client->ps.gunframe == FRAME_IDLE_FIRST+1)
                    529:                        ent->client->weaponstate = WEAPON_READY;
                    530:        }
                    531: }
                    532: 
                    533: 
                    534: /*
                    535: ======================================================================
                    536: 
                    537: GRENADE
                    538: 
                    539: ======================================================================
                    540: */
                    541: 
                    542: #define GRENADE_TIMER          3.0
                    543: #define GRENADE_MINSPEED       400
                    544: #define GRENADE_MAXSPEED       800
                    545: 
                    546: void weapon_grenade_fire (edict_t *ent, qboolean held)
                    547: {
                    548:        vec3_t  offset;
                    549:        vec3_t  forward, right;
                    550:        vec3_t  start;
                    551:        int             damage = 125;
                    552:        float   timer;
                    553:        int             speed;
                    554:        float   radius;
                    555: 
                    556:        radius = damage+40;
                    557:        if (is_quad)
                    558:                damage *= 4;
                    559: 
                    560:        VectorSet(offset, 8, 8, ent->viewheight-8);
                    561:        AngleVectors (ent->client->v_angle, forward, right, NULL);
                    562:        P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
                    563: 
                    564:        timer = ent->client->grenade_time - level.time;
                    565:        speed = GRENADE_MINSPEED + (GRENADE_TIMER - timer) * ((GRENADE_MAXSPEED - GRENADE_MINSPEED) / GRENADE_TIMER);
                    566:        fire_grenade2 (ent, start, forward, damage, speed, timer, radius, held);
                    567: 
                    568:        if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                    569:                ent->client->pers.inventory[ent->client->ammo_index]--;
                    570: 
                    571:        ent->client->grenade_time = level.time + 1.0;
                    572: 
                    573:        if(ent->deadflag || ent->s.modelindex != 255) // VWep animations screw up corpses
                    574:        {
                    575:                return;
                    576:        }
                    577: 
                    578:        if (ent->health <= 0)
                    579:                return;
                    580: 
                    581:        if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
                    582:        {
                    583:                ent->client->anim_priority = ANIM_ATTACK;
                    584:                ent->s.frame = FRAME_crattak1-1;
                    585:                ent->client->anim_end = FRAME_crattak3;
                    586:        }
                    587:        else
                    588:        {
                    589:                ent->client->anim_priority = ANIM_REVERSE;
                    590:                ent->s.frame = FRAME_wave08;
                    591:                ent->client->anim_end = FRAME_wave01;
                    592:        }
                    593: }
                    594: 
                    595: void Weapon_Grenade (edict_t *ent)
                    596: {
                    597:        if ((ent->client->newweapon) && (ent->client->weaponstate == WEAPON_READY))
                    598:        {
                    599:                ChangeWeapon (ent);
                    600:                return;
                    601:        }
                    602: 
                    603:        if (ent->client->weaponstate == WEAPON_ACTIVATING)
                    604:        {
                    605:                ent->client->weaponstate = WEAPON_READY;
                    606:                ent->client->ps.gunframe = 16;
                    607:                return;
                    608:        }
                    609: 
                    610:        if (ent->client->weaponstate == WEAPON_READY)
                    611:        {
                    612:                if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
                    613:                {
                    614:                        ent->client->latched_buttons &= ~BUTTON_ATTACK;
                    615:                        if (ent->client->pers.inventory[ent->client->ammo_index])
                    616:                        {
                    617:                                ent->client->ps.gunframe = 1;
                    618:                                ent->client->weaponstate = WEAPON_FIRING;
                    619:                                ent->client->grenade_time = 0;
                    620:                        }
                    621:                        else
                    622:                        {
                    623:                                if (level.time >= ent->pain_debounce_time)
                    624:                                {
                    625:                                        gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
                    626:                                        ent->pain_debounce_time = level.time + 1;
                    627:                                }
                    628:                                NoAmmoWeaponChange (ent);
                    629:                        }
                    630:                        return;
                    631:                }
                    632: 
                    633:                if ((ent->client->ps.gunframe == 29) || (ent->client->ps.gunframe == 34) || (ent->client->ps.gunframe == 39) || (ent->client->ps.gunframe == 48))
                    634:                {
                    635:                        if (rand()&15)
                    636:                                return;
                    637:                }
                    638: 
                    639:                if (++ent->client->ps.gunframe > 48)
                    640:                        ent->client->ps.gunframe = 16;
                    641:                return;
                    642:        }
                    643: 
                    644:        if (ent->client->weaponstate == WEAPON_FIRING)
                    645:        {
                    646:                if (ent->client->ps.gunframe == 5)
                    647:                        gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/hgrena1b.wav"), 1, ATTN_NORM, 0);
                    648: 
                    649:                if (ent->client->ps.gunframe == 11)
                    650:                {
                    651:                        if (!ent->client->grenade_time)
                    652:                        {
                    653:                                ent->client->grenade_time = level.time + GRENADE_TIMER + 0.2;
                    654:                                ent->client->weapon_sound = gi.soundindex("weapons/hgrenc1b.wav");
                    655:                        }
                    656: 
                    657:                        // they waited too long, detonate it in their hand
                    658:                        if (!ent->client->grenade_blew_up && level.time >= ent->client->grenade_time)
                    659:                        {
                    660:                                ent->client->weapon_sound = 0;
                    661:                                weapon_grenade_fire (ent, true);
                    662:                                ent->client->grenade_blew_up = true;
                    663:                        }
                    664: 
                    665:                        if (ent->client->buttons & BUTTON_ATTACK)
                    666:                                return;
                    667: 
                    668:                        if (ent->client->grenade_blew_up)
                    669:                        {
                    670:                                if (level.time >= ent->client->grenade_time)
                    671:                                {
                    672:                                        ent->client->ps.gunframe = 15;
                    673:                                        ent->client->grenade_blew_up = false;
                    674:                                }
                    675:                                else
                    676:                                {
                    677:                                        return;
                    678:                                }
                    679:                        }
                    680:                }
                    681: 
                    682:                if (ent->client->ps.gunframe == 12)
                    683:                {
                    684:                        ent->client->weapon_sound = 0;
                    685:                        weapon_grenade_fire (ent, false);
                    686:                }
                    687: 
                    688:                if ((ent->client->ps.gunframe == 15) && (level.time < ent->client->grenade_time))
                    689:                        return;
                    690: 
                    691:                ent->client->ps.gunframe++;
                    692: 
                    693:                if (ent->client->ps.gunframe == 16)
                    694:                {
                    695:                        ent->client->grenade_time = 0;
                    696:                        ent->client->weaponstate = WEAPON_READY;
                    697:                }
                    698:        }
                    699: }
                    700: 
                    701: /*
                    702: ======================================================================
                    703: 
                    704: GRENADE LAUNCHER
                    705: 
                    706: ======================================================================
                    707: */
                    708: 
                    709: void weapon_grenadelauncher_fire (edict_t *ent)
                    710: {
                    711:        vec3_t  offset;
                    712:        vec3_t  forward, right;
                    713:        vec3_t  start;
                    714:        int             damage = 120;
                    715:        float   radius;
                    716: 
                    717:        radius = damage+40;
                    718:        if (is_quad)
                    719:                damage *= 4;
                    720: 
                    721:        VectorSet(offset, 8, 8, ent->viewheight-8);
                    722:        AngleVectors (ent->client->v_angle, forward, right, NULL);
                    723:        P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
                    724: 
                    725:        VectorScale (forward, -2, ent->client->kick_origin);
                    726:        ent->client->kick_angles[0] = -1;
                    727: 
                    728:        fire_grenade (ent, start, forward, damage, 600, 2.5, radius);
                    729: 
                    730:        gi.WriteByte (svc_muzzleflash);
                    731:        gi.WriteShort (ent-g_edicts);
                    732:        gi.WriteByte (MZ_GRENADE | is_silenced);
                    733:        gi.multicast (ent->s.origin, MULTICAST_PVS);
                    734: 
                    735:        ent->client->ps.gunframe++;
                    736: 
                    737:        PlayerNoise(ent, start, PNOISE_WEAPON);
                    738: 
                    739:        if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                    740:                ent->client->pers.inventory[ent->client->ammo_index]--;
                    741: }
                    742: 
                    743: void Weapon_GrenadeLauncher (edict_t *ent)
                    744: {
                    745:        static int      pause_frames[]  = {34, 51, 59, 0};
                    746:        static int      fire_frames[]   = {6, 0};
                    747: 
                    748:        Weapon_Generic (ent, 5, 16, 59, 64, pause_frames, fire_frames, weapon_grenadelauncher_fire);
                    749: }
                    750: 
                    751: /*
                    752: ======================================================================
                    753: 
                    754: ROCKET
                    755: 
                    756: ======================================================================
                    757: */
                    758: 
                    759: void Weapon_RocketLauncher_Fire (edict_t *ent)
                    760: {
                    761:        vec3_t  offset, start;
                    762:        vec3_t  forward, right;
                    763:        int             damage;
                    764:        float   damage_radius;
                    765:        int             radius_damage;
                    766: 
                    767:        damage = 100 + (int)(random() * 20.0);
                    768:        radius_damage = 120;
                    769:        damage_radius = 120;
                    770:        if (is_quad)
                    771:        {
                    772:                damage *= 4;
                    773:                radius_damage *= 4;
                    774:        }
                    775: 
                    776:        AngleVectors (ent->client->v_angle, forward, right, NULL);
                    777: 
                    778:        VectorScale (forward, -2, ent->client->kick_origin);
                    779:        ent->client->kick_angles[0] = -1;
                    780: 
                    781:        VectorSet(offset, 8, 8, ent->viewheight-8);
                    782:        P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
                    783:        fire_rocket (ent, start, forward, damage, 650, damage_radius, radius_damage);
                    784: 
                    785:        // send muzzle flash
                    786:        gi.WriteByte (svc_muzzleflash);
                    787:        gi.WriteShort (ent-g_edicts);
                    788:        gi.WriteByte (MZ_ROCKET | is_silenced);
                    789:        gi.multicast (ent->s.origin, MULTICAST_PVS);
                    790: 
                    791:        ent->client->ps.gunframe++;
                    792: 
                    793:        PlayerNoise(ent, start, PNOISE_WEAPON);
                    794: 
                    795:        if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                    796:                ent->client->pers.inventory[ent->client->ammo_index]--;
                    797: }
                    798: 
                    799: void Weapon_RocketLauncher (edict_t *ent)
                    800: {
                    801:        static int      pause_frames[]  = {25, 33, 42, 50, 0};
                    802:        static int      fire_frames[]   = {5, 0};
                    803: 
                    804:        Weapon_Generic (ent, 4, 12, 50, 54, pause_frames, fire_frames, Weapon_RocketLauncher_Fire);
                    805: }
                    806: 
                    807: 
                    808: /*
                    809: ======================================================================
                    810: 
                    811: BLASTER / HYPERBLASTER
                    812: 
                    813: ======================================================================
                    814: */
                    815: 
                    816: void Blaster_Fire (edict_t *ent, vec3_t g_offset, int damage, qboolean hyper, int effect)
                    817: {
                    818:        vec3_t  forward, right;
                    819:        vec3_t  start;
                    820:        vec3_t  offset;
                    821: 
                    822:        if (is_quad)
                    823:                damage *= 4;
                    824:        AngleVectors (ent->client->v_angle, forward, right, NULL);
                    825:        VectorSet(offset, 24, 8, ent->viewheight-8);
                    826:        VectorAdd (offset, g_offset, offset);
                    827:        P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
                    828: 
                    829:        VectorScale (forward, -2, ent->client->kick_origin);
                    830:        ent->client->kick_angles[0] = -1;
                    831: 
                    832:        fire_blaster (ent, start, forward, damage, 1000, effect, hyper);
                    833: 
                    834:        // send muzzle flash
                    835:        gi.WriteByte (svc_muzzleflash);
                    836:        gi.WriteShort (ent-g_edicts);
                    837:        if (hyper)
                    838:                gi.WriteByte (MZ_HYPERBLASTER | is_silenced);
                    839:        else
                    840:                gi.WriteByte (MZ_BLASTER | is_silenced);
                    841:        gi.multicast (ent->s.origin, MULTICAST_PVS);
                    842: 
                    843:        PlayerNoise(ent, start, PNOISE_WEAPON);
                    844: }
                    845: 
                    846: 
                    847: void Weapon_Blaster_Fire (edict_t *ent)
                    848: {
                    849:        int             damage;
                    850: 
                    851:        if (deathmatch->value)
                    852:                damage = 15;
                    853:        else
                    854:                damage = 10;
                    855:        Blaster_Fire (ent, vec3_origin, damage, false, EF_BLASTER);
                    856:        ent->client->ps.gunframe++;
                    857: }
                    858: 
                    859: void Weapon_Blaster (edict_t *ent)
                    860: {
                    861:        static int      pause_frames[]  = {19, 32, 0};
                    862:        static int      fire_frames[]   = {5, 0};
                    863: 
                    864:        Weapon_Generic (ent, 4, 8, 52, 55, pause_frames, fire_frames, Weapon_Blaster_Fire);
                    865: }
                    866: 
                    867: 
                    868: void Weapon_HyperBlaster_Fire (edict_t *ent)
                    869: {
                    870:        float   rotation;
                    871:        vec3_t  offset;
                    872:        int             effect;
                    873:        int             damage;
                    874: 
                    875:        ent->client->weapon_sound = gi.soundindex("weapons/hyprbl1a.wav");
                    876: 
                    877:        if (!(ent->client->buttons & BUTTON_ATTACK))
                    878:        {
                    879:                ent->client->ps.gunframe++;
                    880:        }
                    881:        else
                    882:        {
                    883:                if (! ent->client->pers.inventory[ent->client->ammo_index] )
                    884:                {
                    885:                        if (level.time >= ent->pain_debounce_time)
                    886:                        {
                    887:                                gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
                    888:                                ent->pain_debounce_time = level.time + 1;
                    889:                        }
                    890:                        NoAmmoWeaponChange (ent);
                    891:                }
                    892:                else
                    893:                {
                    894:                        rotation = (ent->client->ps.gunframe - 5) * 2*M_PI/6;
                    895:                        offset[0] = -4 * sin(rotation);
                    896:                        offset[1] = 0;
                    897:                        offset[2] = 4 * cos(rotation);
                    898: 
                    899:                        if ((ent->client->ps.gunframe == 6) || (ent->client->ps.gunframe == 9))
                    900:                                effect = EF_HYPERBLASTER;
                    901:                        else
                    902:                                effect = 0;
                    903:                        if (deathmatch->value)
                    904:                                damage = 15;
                    905:                        else
                    906:                                damage = 20;
                    907:                        Blaster_Fire (ent, offset, damage, true, effect);
                    908:                        if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                    909:                                ent->client->pers.inventory[ent->client->ammo_index]--;
                    910: 
                    911:                        ent->client->anim_priority = ANIM_ATTACK;
                    912:                        if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
                    913:                        {
                    914:                                ent->s.frame = FRAME_crattak1 - 1;
                    915:                                ent->client->anim_end = FRAME_crattak9;
                    916:                        }
                    917:                        else
                    918:                        {
                    919:                                ent->s.frame = FRAME_attack1 - 1;
                    920:                                ent->client->anim_end = FRAME_attack8;
                    921:                        }
                    922:                }
                    923: 
                    924:                ent->client->ps.gunframe++;
                    925:                if (ent->client->ps.gunframe == 12 && ent->client->pers.inventory[ent->client->ammo_index])
                    926:                        ent->client->ps.gunframe = 6;
                    927:        }
                    928: 
                    929:        if (ent->client->ps.gunframe == 12)
                    930:        {
                    931:                gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/hyprbd1a.wav"), 1, ATTN_NORM, 0);
                    932:                ent->client->weapon_sound = 0;
                    933:        }
                    934: 
                    935: }
                    936: 
                    937: void Weapon_HyperBlaster (edict_t *ent)
                    938: {
                    939:        static int      pause_frames[]  = {0};
                    940:        static int      fire_frames[]   = {6, 7, 8, 9, 10, 11, 0};
                    941: 
                    942:        Weapon_Generic (ent, 5, 20, 49, 53, pause_frames, fire_frames, Weapon_HyperBlaster_Fire);
                    943: }
                    944: 
                    945: /*
                    946: ======================================================================
                    947: 
                    948: MACHINEGUN / CHAINGUN
                    949: 
                    950: ======================================================================
                    951: */
                    952: 
                    953: void Machinegun_Fire (edict_t *ent)
                    954: {
                    955:        int     i;
                    956:        vec3_t          start;
                    957:        vec3_t          forward, right;
                    958:        vec3_t          angles;
                    959:        int                     damage = 8;
                    960:        int                     kick = 2;
                    961:        vec3_t          offset;
                    962: 
                    963:        if (!(ent->client->buttons & BUTTON_ATTACK))
                    964:        {
                    965:                ent->client->machinegun_shots = 0;
                    966:                ent->client->ps.gunframe++;
                    967:                return;
                    968:        }
                    969: 
                    970:        if (ent->client->ps.gunframe == 5)
                    971:                ent->client->ps.gunframe = 4;
                    972:        else
                    973:                ent->client->ps.gunframe = 5;
                    974: 
                    975:        if (ent->client->pers.inventory[ent->client->ammo_index] < 1)
                    976:        {
                    977:                ent->client->ps.gunframe = 6;
                    978:                if (level.time >= ent->pain_debounce_time)
                    979:                {
                    980:                        gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
                    981:                        ent->pain_debounce_time = level.time + 1;
                    982:                }
                    983:                NoAmmoWeaponChange (ent);
                    984:                return;
                    985:        }
                    986: 
                    987:        if (is_quad)
                    988:        {
                    989:                damage *= 4;
                    990:                kick *= 4;
                    991:        }
                    992: 
                    993:        for (i=1 ; i<3 ; i++)
                    994:        {
                    995:                ent->client->kick_origin[i] = crandom() * 0.35;
                    996:                ent->client->kick_angles[i] = crandom() * 0.7;
                    997:        }
                    998:        ent->client->kick_origin[0] = crandom() * 0.35;
                    999:        ent->client->kick_angles[0] = ent->client->machinegun_shots * -1.5;
                   1000: 
                   1001:        // raise the gun as it is firing
                   1002:        if (!deathmatch->value)
                   1003:        {
                   1004:                ent->client->machinegun_shots++;
                   1005:                if (ent->client->machinegun_shots > 9)
                   1006:                        ent->client->machinegun_shots = 9;
                   1007:        }
                   1008: 
                   1009:        // get start / end positions
                   1010:        VectorAdd (ent->client->v_angle, ent->client->kick_angles, angles);
                   1011:        AngleVectors (angles, forward, right, NULL);
                   1012:        VectorSet(offset, 0, 8, ent->viewheight-8);
                   1013:        P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
                   1014:        fire_bullet (ent, start, forward, damage, kick, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MOD_MACHINEGUN);
                   1015: 
                   1016:        gi.WriteByte (svc_muzzleflash);
                   1017:        gi.WriteShort (ent-g_edicts);
                   1018:        gi.WriteByte (MZ_MACHINEGUN | is_silenced);
                   1019:        gi.multicast (ent->s.origin, MULTICAST_PVS);
                   1020: 
                   1021:        PlayerNoise(ent, start, PNOISE_WEAPON);
                   1022: 
                   1023:        if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                   1024:                ent->client->pers.inventory[ent->client->ammo_index]--;
                   1025: 
                   1026:        ent->client->anim_priority = ANIM_ATTACK;
                   1027:        if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
                   1028:        {
                   1029:                ent->s.frame = FRAME_crattak1 - (int) (random()+0.25);
                   1030:                ent->client->anim_end = FRAME_crattak9;
                   1031:        }
                   1032:        else
                   1033:        {
                   1034:                ent->s.frame = FRAME_attack1 - (int) (random()+0.25);
                   1035:                ent->client->anim_end = FRAME_attack8;
                   1036:        }
                   1037: }
                   1038: 
                   1039: void Weapon_Machinegun (edict_t *ent)
                   1040: {
                   1041:        static int      pause_frames[]  = {23, 45, 0};
                   1042:        static int      fire_frames[]   = {4, 5, 0};
                   1043: 
                   1044:        Weapon_Generic (ent, 3, 5, 45, 49, pause_frames, fire_frames, Machinegun_Fire);
                   1045: }
                   1046: 
                   1047: void Chaingun_Fire (edict_t *ent)
                   1048: {
                   1049:        int                     i;
                   1050:        int                     shots;
                   1051:        vec3_t          start;
                   1052:        vec3_t          forward, right, up;
                   1053:        float           r, u;
                   1054:        vec3_t          offset;
                   1055:        int                     damage;
                   1056:        int                     kick = 2;
                   1057: 
                   1058:        if (deathmatch->value)
                   1059:                damage = 6;
                   1060:        else
                   1061:                damage = 8;
                   1062: 
                   1063:        if (ent->client->ps.gunframe == 5)
                   1064:                gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnu1a.wav"), 1, ATTN_IDLE, 0);
                   1065: 
                   1066:        if ((ent->client->ps.gunframe == 14) && !(ent->client->buttons & BUTTON_ATTACK))
                   1067:        {
                   1068:                ent->client->ps.gunframe = 32;
                   1069:                ent->client->weapon_sound = 0;
                   1070:                return;
                   1071:        }
                   1072:        else if ((ent->client->ps.gunframe == 21) && (ent->client->buttons & BUTTON_ATTACK)
                   1073:                && ent->client->pers.inventory[ent->client->ammo_index])
                   1074:        {
                   1075:                ent->client->ps.gunframe = 15;
                   1076:        }
                   1077:        else
                   1078:        {
                   1079:                ent->client->ps.gunframe++;
                   1080:        }
                   1081: 
                   1082:        if (ent->client->ps.gunframe == 22)
                   1083:        {
                   1084:                ent->client->weapon_sound = 0;
                   1085:                gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnd1a.wav"), 1, ATTN_IDLE, 0);
                   1086:        }
                   1087:        else
                   1088:        {
                   1089:                ent->client->weapon_sound = gi.soundindex("weapons/chngnl1a.wav");
                   1090:        }
                   1091: 
                   1092:        ent->client->anim_priority = ANIM_ATTACK;
                   1093:        if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
                   1094:        {
                   1095:                ent->s.frame = FRAME_crattak1 - (ent->client->ps.gunframe & 1);
                   1096:                ent->client->anim_end = FRAME_crattak9;
                   1097:        }
                   1098:        else
                   1099:        {
                   1100:                ent->s.frame = FRAME_attack1 - (ent->client->ps.gunframe & 1);
                   1101:                ent->client->anim_end = FRAME_attack8;
                   1102:        }
                   1103: 
                   1104:        if (ent->client->ps.gunframe <= 9)
                   1105:                shots = 1;
                   1106:        else if (ent->client->ps.gunframe <= 14)
                   1107:        {
                   1108:                if (ent->client->buttons & BUTTON_ATTACK)
                   1109:                        shots = 2;
                   1110:                else
                   1111:                        shots = 1;
                   1112:        }
                   1113:        else
                   1114:                shots = 3;
                   1115: 
                   1116:        if (ent->client->pers.inventory[ent->client->ammo_index] < shots)
                   1117:                shots = ent->client->pers.inventory[ent->client->ammo_index];
                   1118: 
                   1119:        if (!shots)
                   1120:        {
                   1121:                if (level.time >= ent->pain_debounce_time)
                   1122:                {
                   1123:                        gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
                   1124:                        ent->pain_debounce_time = level.time + 1;
                   1125:                }
                   1126:                NoAmmoWeaponChange (ent);
                   1127:                return;
                   1128:        }
                   1129: 
                   1130:        if (is_quad)
                   1131:        {
                   1132:                damage *= 4;
                   1133:                kick *= 4;
                   1134:        }
                   1135: 
                   1136:        for (i=0 ; i<3 ; i++)
                   1137:        {
                   1138:                ent->client->kick_origin[i] = crandom() * 0.35;
                   1139:                ent->client->kick_angles[i] = crandom() * 0.7;
                   1140:        }
                   1141: 
                   1142:        for (i=0 ; i<shots ; i++)
                   1143:        {
                   1144:                // get start / end positions
                   1145:                AngleVectors (ent->client->v_angle, forward, right, up);
                   1146:                r = 7 + crandom()*4;
                   1147:                u = crandom()*4;
                   1148:                VectorSet(offset, 0, r, u + ent->viewheight-8);
                   1149:                P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
                   1150: 
                   1151:                fire_bullet (ent, start, forward, damage, kick, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MOD_CHAINGUN);
                   1152:        }
                   1153: 
                   1154:        // send muzzle flash
                   1155:        gi.WriteByte (svc_muzzleflash);
                   1156:        gi.WriteShort (ent-g_edicts);
                   1157:        gi.WriteByte ((MZ_CHAINGUN1 + shots - 1) | is_silenced);
                   1158:        gi.multicast (ent->s.origin, MULTICAST_PVS);
                   1159: 
                   1160:        PlayerNoise(ent, start, PNOISE_WEAPON);
                   1161: 
                   1162:        if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                   1163:                ent->client->pers.inventory[ent->client->ammo_index] -= shots;
                   1164: }
                   1165: 
                   1166: 
                   1167: void Weapon_Chaingun (edict_t *ent)
                   1168: {
                   1169:        static int      pause_frames[]  = {38, 43, 51, 61, 0};
                   1170:        static int      fire_frames[]   = {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0};
                   1171: 
                   1172:        Weapon_Generic (ent, 4, 31, 61, 64, pause_frames, fire_frames, Chaingun_Fire);
                   1173: }
                   1174: 
                   1175: 
                   1176: /*
                   1177: ======================================================================
                   1178: 
                   1179: SHOTGUN / SUPERSHOTGUN
                   1180: 
                   1181: ======================================================================
                   1182: */
                   1183: 
                   1184: void weapon_shotgun_fire (edict_t *ent)
                   1185: {
                   1186:        vec3_t          start;
                   1187:        vec3_t          forward, right;
                   1188:        vec3_t          offset;
                   1189:        int                     damage = 4;
                   1190:        int                     kick = 8;
                   1191: 
                   1192:        if (ent->client->ps.gunframe == 9)
                   1193:        {
                   1194:                ent->client->ps.gunframe++;
                   1195:                return;
                   1196:        }
                   1197: 
                   1198:        AngleVectors (ent->client->v_angle, forward, right, NULL);
                   1199: 
                   1200:        VectorScale (forward, -2, ent->client->kick_origin);
                   1201:        ent->client->kick_angles[0] = -2;
                   1202: 
                   1203:        VectorSet(offset, 0, 8,  ent->viewheight-8);
                   1204:        P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
                   1205: 
                   1206:        if (is_quad)
                   1207:        {
                   1208:                damage *= 4;
                   1209:                kick *= 4;
                   1210:        }
                   1211: 
                   1212:        if (deathmatch->value)
                   1213:                fire_shotgun (ent, start, forward, damage, kick, 500, 500, DEFAULT_DEATHMATCH_SHOTGUN_COUNT, MOD_SHOTGUN);
                   1214:        else
                   1215:                fire_shotgun (ent, start, forward, damage, kick, 500, 500, DEFAULT_SHOTGUN_COUNT, MOD_SHOTGUN);
                   1216: 
                   1217:        // send muzzle flash
                   1218:        gi.WriteByte (svc_muzzleflash);
                   1219:        gi.WriteShort (ent-g_edicts);
                   1220:        gi.WriteByte (MZ_SHOTGUN | is_silenced);
                   1221:        gi.multicast (ent->s.origin, MULTICAST_PVS);
                   1222: 
                   1223:        ent->client->ps.gunframe++;
                   1224:        PlayerNoise(ent, start, PNOISE_WEAPON);
                   1225: 
                   1226:        if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                   1227:                ent->client->pers.inventory[ent->client->ammo_index]--;
                   1228: }
                   1229: 
                   1230: void Weapon_Shotgun (edict_t *ent)
                   1231: {
                   1232:        static int      pause_frames[]  = {22, 28, 34, 0};
                   1233:        static int      fire_frames[]   = {8, 9, 0};
                   1234: 
                   1235:        Weapon_Generic (ent, 7, 18, 36, 39, pause_frames, fire_frames, weapon_shotgun_fire);
                   1236: }
                   1237: 
                   1238: 
                   1239: void weapon_supershotgun_fire (edict_t *ent)
                   1240: {
                   1241:        vec3_t          start;
                   1242:        vec3_t          forward, right;
                   1243:        vec3_t          offset;
                   1244:        vec3_t          v;
                   1245:        int                     damage = 6;
                   1246:        int                     kick = 12;
                   1247: 
                   1248:        AngleVectors (ent->client->v_angle, forward, right, NULL);
                   1249: 
                   1250:        VectorScale (forward, -2, ent->client->kick_origin);
                   1251:        ent->client->kick_angles[0] = -2;
                   1252: 
                   1253:        VectorSet(offset, 0, 8,  ent->viewheight-8);
                   1254:        P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
                   1255: 
                   1256:        if (is_quad)
                   1257:        {
                   1258:                damage *= 4;
                   1259:                kick *= 4;
                   1260:        }
                   1261: 
                   1262:        v[PITCH] = ent->client->v_angle[PITCH];
                   1263:        v[YAW]   = ent->client->v_angle[YAW] - 5;
                   1264:        v[ROLL]  = ent->client->v_angle[ROLL];
                   1265:        AngleVectors (v, forward, NULL, NULL);
                   1266:        fire_shotgun (ent, start, forward, damage, kick, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT/2, MOD_SSHOTGUN);
                   1267:        v[YAW]   = ent->client->v_angle[YAW] + 5;
                   1268:        AngleVectors (v, forward, NULL, NULL);
                   1269:        fire_shotgun (ent, start, forward, damage, kick, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT/2, MOD_SSHOTGUN);
                   1270: 
                   1271:        // send muzzle flash
                   1272:        gi.WriteByte (svc_muzzleflash);
                   1273:        gi.WriteShort (ent-g_edicts);
                   1274:        gi.WriteByte (MZ_SSHOTGUN | is_silenced);
                   1275:        gi.multicast (ent->s.origin, MULTICAST_PVS);
                   1276: 
                   1277:        ent->client->ps.gunframe++;
                   1278:        PlayerNoise(ent, start, PNOISE_WEAPON);
                   1279: 
                   1280:        if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                   1281:                ent->client->pers.inventory[ent->client->ammo_index] -= 2;
                   1282: }
                   1283: 
                   1284: void Weapon_SuperShotgun (edict_t *ent)
                   1285: {
                   1286:        static int      pause_frames[]  = {29, 42, 57, 0};
                   1287:        static int      fire_frames[]   = {7, 0};
                   1288: 
                   1289:        Weapon_Generic (ent, 6, 17, 57, 61, pause_frames, fire_frames, weapon_supershotgun_fire);
                   1290: }
                   1291: 
                   1292: 
                   1293: 
                   1294: /*
                   1295: ======================================================================
                   1296: 
                   1297: RAILGUN
                   1298: 
                   1299: ======================================================================
                   1300: */
                   1301: 
                   1302: void weapon_railgun_fire (edict_t *ent)
                   1303: {
                   1304:        vec3_t          start;
                   1305:        vec3_t          forward, right;
                   1306:        vec3_t          offset;
                   1307:        int                     damage;
                   1308:        int                     kick;
                   1309: 
                   1310:        if (deathmatch->value)
                   1311:        {       // normal damage is too extreme in dm
                   1312:                damage = 100;
                   1313:                kick = 200;
                   1314:        }
                   1315:        else
                   1316:        {
                   1317:                damage = 150;
                   1318:                kick = 250;
                   1319:        }
                   1320: 
                   1321:        if (is_quad)
                   1322:        {
                   1323:                damage *= 4;
                   1324:                kick *= 4;
                   1325:        }
                   1326: 
                   1327:        AngleVectors (ent->client->v_angle, forward, right, NULL);
                   1328: 
                   1329:        VectorScale (forward, -3, ent->client->kick_origin);
                   1330:        ent->client->kick_angles[0] = -3;
                   1331: 
                   1332:        VectorSet(offset, 0, 7,  ent->viewheight-8);
                   1333:        P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
                   1334:        fire_rail (ent, start, forward, damage, kick);
                   1335: 
                   1336:        // send muzzle flash
                   1337:        gi.WriteByte (svc_muzzleflash);
                   1338:        gi.WriteShort (ent-g_edicts);
                   1339:        gi.WriteByte (MZ_RAILGUN | is_silenced);
                   1340:        gi.multicast (ent->s.origin, MULTICAST_PVS);
                   1341: 
                   1342:        ent->client->ps.gunframe++;
                   1343:        PlayerNoise(ent, start, PNOISE_WEAPON);
                   1344: 
                   1345:        if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                   1346:                ent->client->pers.inventory[ent->client->ammo_index]--;
                   1347: }
                   1348: 
                   1349: 
                   1350: void Weapon_Railgun (edict_t *ent)
                   1351: {
                   1352:        static int      pause_frames[]  = {56, 0};
                   1353:        static int      fire_frames[]   = {4, 0};
                   1354: 
                   1355:        Weapon_Generic (ent, 3, 18, 56, 61, pause_frames, fire_frames, weapon_railgun_fire);
                   1356: }
                   1357: 
                   1358: 
                   1359: /*
                   1360: ======================================================================
                   1361: 
                   1362: BFG10K
                   1363: 
                   1364: ======================================================================
                   1365: */
                   1366: 
                   1367: void weapon_bfg_fire (edict_t *ent)
                   1368: {
                   1369:        vec3_t  offset, start;
                   1370:        vec3_t  forward, right;
                   1371:        int             damage;
                   1372:        float   damage_radius = 1000;
                   1373: 
                   1374:        if (deathmatch->value)
                   1375:                damage = 200;
                   1376:        else
                   1377:                damage = 500;
                   1378: 
                   1379:        if (ent->client->ps.gunframe == 9)
                   1380:        {
                   1381:                // send muzzle flash
                   1382:                gi.WriteByte (svc_muzzleflash);
                   1383:                gi.WriteShort (ent-g_edicts);
                   1384:                gi.WriteByte (MZ_BFG | is_silenced);
                   1385:                gi.multicast (ent->s.origin, MULTICAST_PVS);
                   1386: 
                   1387:                ent->client->ps.gunframe++;
                   1388: 
                   1389:                PlayerNoise(ent, start, PNOISE_WEAPON);
                   1390:                return;
                   1391:        }
                   1392: 
                   1393:        // cells can go down during windup (from power armor hits), so
                   1394:        // check again and abort firing if we don't have enough now
                   1395:        if (ent->client->pers.inventory[ent->client->ammo_index] < 50)
                   1396:        {
                   1397:                ent->client->ps.gunframe++;
                   1398:                return;
                   1399:        }
                   1400: 
                   1401:        if (is_quad)
                   1402:                damage *= 4;
                   1403: 
                   1404:        AngleVectors (ent->client->v_angle, forward, right, NULL);
                   1405: 
                   1406:        VectorScale (forward, -2, ent->client->kick_origin);
                   1407: 
                   1408:        // make a big pitch kick with an inverse fall
                   1409:        ent->client->v_dmg_pitch = -40;
                   1410:        ent->client->v_dmg_roll = crandom()*8;
                   1411:        ent->client->v_dmg_time = level.time + DAMAGE_TIME;
                   1412: 
                   1413:        VectorSet(offset, 8, 8, ent->viewheight-8);
                   1414:        P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
                   1415:        fire_bfg (ent, start, forward, damage, 400, damage_radius);
                   1416: 
                   1417:        ent->client->ps.gunframe++;
                   1418: 
                   1419:        PlayerNoise(ent, start, PNOISE_WEAPON);
                   1420: 
                   1421:        if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                   1422:                ent->client->pers.inventory[ent->client->ammo_index] -= 50;
                   1423: }
                   1424: 
                   1425: void Weapon_BFG (edict_t *ent)
                   1426: {
                   1427:        static int      pause_frames[]  = {39, 45, 50, 55, 0};
                   1428:        static int      fire_frames[]   = {9, 17, 0};
                   1429: 
                   1430:        Weapon_Generic (ent, 8, 32, 55, 58, pause_frames, fire_frames, weapon_bfg_fire);
                   1431: }
                   1432: 
                   1433: 
                   1434: //======================================================================

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.