Annotation of quake2/ctf/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: 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: static void Weapon_Generic2 (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 || instantweap->value)
                    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:                if (instantweap->value) {
                    433:                        ChangeWeapon(ent);
                    434:                        return;
                    435:                } else
                    436:                        ent->client->ps.gunframe = FRAME_DEACTIVATE_FIRST;
                    437: 
                    438:                if ((FRAME_DEACTIVATE_LAST - FRAME_DEACTIVATE_FIRST) < 4)
                    439:                {
                    440:                        ent->client->anim_priority = ANIM_REVERSE;
                    441:                        if(ent->client->ps.pmove.pm_flags & PMF_DUCKED)
                    442:                        {
                    443:                                ent->s.frame = FRAME_crpain4+1;
                    444:                                ent->client->anim_end = FRAME_crpain1;
                    445:                        }
                    446:                        else
                    447:                        {
                    448:                                ent->s.frame = FRAME_pain304+1;
                    449:                                ent->client->anim_end = FRAME_pain301;
                    450:                                
                    451:                        }
                    452:                }
                    453:                return;
                    454:        }
                    455: 
                    456:        if (ent->client->weaponstate == WEAPON_READY)
                    457:        {
                    458:                if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
                    459:                {
                    460:                        ent->client->latched_buttons &= ~BUTTON_ATTACK;
                    461:                        if ((!ent->client->ammo_index) || 
                    462:                                ( ent->client->pers.inventory[ent->client->ammo_index] >= ent->client->pers.weapon->quantity))
                    463:                        {
                    464:                                ent->client->ps.gunframe = FRAME_FIRE_FIRST;
                    465:                                ent->client->weaponstate = WEAPON_FIRING;
                    466: 
                    467:                                // start the animation
                    468:                                ent->client->anim_priority = ANIM_ATTACK;
                    469:                                if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
                    470:                                {
                    471:                                        ent->s.frame = FRAME_crattak1-1;
                    472:                                        ent->client->anim_end = FRAME_crattak9;
                    473:                                }
                    474:                                else
                    475:                                {
                    476:                                        ent->s.frame = FRAME_attack1-1;
                    477:                                        ent->client->anim_end = FRAME_attack8;
                    478:                                }
                    479:                        }
                    480:                        else
                    481:                        {
                    482:                                if (level.time >= ent->pain_debounce_time)
                    483:                                {
                    484:                                        gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
                    485:                                        ent->pain_debounce_time = level.time + 1;
                    486:                                }
                    487:                                NoAmmoWeaponChange (ent);
                    488:                        }
                    489:                }
                    490:                else
                    491:                {
                    492:                        if (ent->client->ps.gunframe == FRAME_IDLE_LAST)
                    493:                        {
                    494:                                ent->client->ps.gunframe = FRAME_IDLE_FIRST;
                    495:                                return;
                    496:                        }
                    497: 
                    498:                        if (pause_frames)
                    499:                        {
                    500:                                for (n = 0; pause_frames[n]; n++)
                    501:                                {
                    502:                                        if (ent->client->ps.gunframe == pause_frames[n])
                    503:                                        {
                    504:                                                if (rand()&15)
                    505:                                                        return;
                    506:                                        }
                    507:                                }
                    508:                        }
                    509: 
                    510:                        ent->client->ps.gunframe++;
                    511:                        return;
                    512:                }
                    513:        }
                    514: 
                    515:        if (ent->client->weaponstate == WEAPON_FIRING)
                    516:        {
                    517:                for (n = 0; fire_frames[n]; n++)
                    518:                {
                    519:                        if (ent->client->ps.gunframe == fire_frames[n])
                    520:                        {
                    521: //ZOID
                    522:                                if (!CTFApplyStrengthSound(ent))
                    523: //ZOID
                    524:                                if (ent->client->quad_framenum > level.framenum)
                    525:                                        gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage3.wav"), 1, ATTN_NORM, 0);
                    526: //ZOID
                    527:                                CTFApplyHasteSound(ent);
                    528: //ZOID
                    529: 
                    530:                                fire (ent);
                    531:                                break;
                    532:                        }
                    533:                }
                    534: 
                    535:                if (!fire_frames[n])
                    536:                        ent->client->ps.gunframe++;
                    537: 
                    538:                if (ent->client->ps.gunframe == FRAME_IDLE_FIRST+1)
                    539:                        ent->client->weaponstate = WEAPON_READY;
                    540:        }
                    541: }
                    542: 
                    543: //ZOID
                    544: 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))
                    545: {
                    546:        int oldstate = ent->client->weaponstate;
                    547: 
                    548:        Weapon_Generic2 (ent, FRAME_ACTIVATE_LAST, FRAME_FIRE_LAST, 
                    549:                FRAME_IDLE_LAST, FRAME_DEACTIVATE_LAST, pause_frames, 
                    550:                fire_frames, fire);
                    551: 
                    552:        // run the weapon frame again if hasted
                    553:        if (stricmp(ent->client->pers.weapon->pickup_name, "Grapple") == 0 &&
                    554:                ent->client->weaponstate == WEAPON_FIRING)
                    555:                return;
                    556: 
                    557:        if ((CTFApplyHaste(ent) ||
                    558:                (Q_stricmp(ent->client->pers.weapon->pickup_name, "Grapple") == 0 &&
                    559:                ent->client->weaponstate != WEAPON_FIRING))
                    560:                && oldstate == ent->client->weaponstate) {
                    561:                Weapon_Generic2 (ent, FRAME_ACTIVATE_LAST, FRAME_FIRE_LAST, 
                    562:                        FRAME_IDLE_LAST, FRAME_DEACTIVATE_LAST, pause_frames, 
                    563:                        fire_frames, fire);
                    564:        }
                    565: }
                    566: //ZOID
                    567: 
                    568: /*
                    569: ======================================================================
                    570: 
                    571: GRENADE
                    572: 
                    573: ======================================================================
                    574: */
                    575: 
                    576: #define GRENADE_TIMER          3.0
                    577: #define GRENADE_MINSPEED       400
                    578: #define GRENADE_MAXSPEED       800
                    579: 
                    580: void weapon_grenade_fire (edict_t *ent, qboolean held)
                    581: {
                    582:        vec3_t  offset;
                    583:        vec3_t  forward, right;
                    584:        vec3_t  start;
                    585:        int             damage = 125;
                    586:        float   timer;
                    587:        int             speed;
                    588:        float   radius;
                    589: 
                    590:        radius = damage+40;
                    591:        if (is_quad)
                    592:                damage *= 4;
                    593: 
                    594:        VectorSet(offset, 8, 8, ent->viewheight-8);
                    595:        AngleVectors (ent->client->v_angle, forward, right, NULL);
                    596:        P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
                    597: 
                    598:        timer = ent->client->grenade_time - level.time;
                    599:        speed = GRENADE_MINSPEED + (GRENADE_TIMER - timer) * ((GRENADE_MAXSPEED - GRENADE_MINSPEED) / GRENADE_TIMER);
                    600:        fire_grenade2 (ent, start, forward, damage, speed, timer, radius, held);
                    601: 
                    602:        if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                    603:                ent->client->pers.inventory[ent->client->ammo_index]--;
                    604: 
                    605:        ent->client->grenade_time = level.time + 1.0;
                    606: 
                    607:        if(ent->deadflag || ent->s.modelindex != 255) // VWep animations screw up corpses
                    608:        {
                    609:                return;
                    610:        }
                    611: 
                    612:        if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
                    613:        {
                    614:                ent->client->anim_priority = ANIM_ATTACK;
                    615:                ent->s.frame = FRAME_crattak1-1;
                    616:                ent->client->anim_end = FRAME_crattak3;
                    617:        }
                    618:        else
                    619:        {
                    620:                ent->client->anim_priority = ANIM_REVERSE;
                    621:                ent->s.frame = FRAME_wave08;
                    622:                ent->client->anim_end = FRAME_wave01;
                    623:        }
                    624: }
                    625: 
                    626: void Weapon_Grenade (edict_t *ent)
                    627: {
                    628:        if ((ent->client->newweapon) && (ent->client->weaponstate == WEAPON_READY))
                    629:        {
                    630:                ChangeWeapon (ent);
                    631:                return;
                    632:        }
                    633: 
                    634:        if (ent->client->weaponstate == WEAPON_ACTIVATING)
                    635:        {
                    636:                ent->client->weaponstate = WEAPON_READY;
                    637:                ent->client->ps.gunframe = 16;
                    638:                return;
                    639:        }
                    640: 
                    641:        if (ent->client->weaponstate == WEAPON_READY)
                    642:        {
                    643:                if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
                    644:                {
                    645:                        ent->client->latched_buttons &= ~BUTTON_ATTACK;
                    646:                        if (ent->client->pers.inventory[ent->client->ammo_index])
                    647:                        {
                    648:                                ent->client->ps.gunframe = 1;
                    649:                                ent->client->weaponstate = WEAPON_FIRING;
                    650:                                ent->client->grenade_time = 0;
                    651:                        }
                    652:                        else
                    653:                        {
                    654:                                if (level.time >= ent->pain_debounce_time)
                    655:                                {
                    656:                                        gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
                    657:                                        ent->pain_debounce_time = level.time + 1;
                    658:                                }
                    659:                                NoAmmoWeaponChange (ent);
                    660:                        }
                    661:                        return;
                    662:                }
                    663: 
                    664:                if ((ent->client->ps.gunframe == 29) || (ent->client->ps.gunframe == 34) || (ent->client->ps.gunframe == 39) || (ent->client->ps.gunframe == 48))
                    665:                {
                    666:                        if (rand()&15)
                    667:                                return;
                    668:                }
                    669: 
                    670:                if (++ent->client->ps.gunframe > 48)
                    671:                        ent->client->ps.gunframe = 16;
                    672:                return;
                    673:        }
                    674: 
                    675:        if (ent->client->weaponstate == WEAPON_FIRING)
                    676:        {
                    677:                if (ent->client->ps.gunframe == 5)
                    678:                        gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/hgrena1b.wav"), 1, ATTN_NORM, 0);
                    679: 
                    680:                if (ent->client->ps.gunframe == 11)
                    681:                {
                    682:                        if (!ent->client->grenade_time)
                    683:                        {
                    684:                                ent->client->grenade_time = level.time + GRENADE_TIMER + 0.2;
                    685:                                ent->client->weapon_sound = gi.soundindex("weapons/hgrenc1b.wav");
                    686:                        }
                    687: 
                    688:                        // they waited too long, detonate it in their hand
                    689:                        if (!ent->client->grenade_blew_up && level.time >= ent->client->grenade_time)
                    690:                        {
                    691:                                ent->client->weapon_sound = 0;
                    692:                                weapon_grenade_fire (ent, true);
                    693:                                ent->client->grenade_blew_up = true;
                    694:                        }
                    695: 
                    696:                        if (ent->client->buttons & BUTTON_ATTACK)
                    697:                                return;
                    698: 
                    699:                        if (ent->client->grenade_blew_up)
                    700:                        {
                    701:                                if (level.time >= ent->client->grenade_time)
                    702:                                {
                    703:                                        ent->client->ps.gunframe = 15;
                    704:                                        ent->client->grenade_blew_up = false;
                    705:                                }
                    706:                                else
                    707:                                {
                    708:                                        return;
                    709:                                }
                    710:                        }
                    711:                }
                    712: 
                    713:                if (ent->client->ps.gunframe == 12)
                    714:                {
                    715:                        ent->client->weapon_sound = 0;
                    716:                        weapon_grenade_fire (ent, false);
                    717:                }
                    718: 
                    719:                if ((ent->client->ps.gunframe == 15) && (level.time < ent->client->grenade_time))
                    720:                        return;
                    721: 
                    722:                ent->client->ps.gunframe++;
                    723: 
                    724:                if (ent->client->ps.gunframe == 16)
                    725:                {
                    726:                        ent->client->grenade_time = 0;
                    727:                        ent->client->weaponstate = WEAPON_READY;
                    728:                }
                    729:        }
                    730: }
                    731: 
                    732: /*
                    733: ======================================================================
                    734: 
                    735: GRENADE LAUNCHER
                    736: 
                    737: ======================================================================
                    738: */
                    739: 
                    740: void weapon_grenadelauncher_fire (edict_t *ent)
                    741: {
                    742:        vec3_t  offset;
                    743:        vec3_t  forward, right;
                    744:        vec3_t  start;
                    745:        int             damage = 120;
                    746:        float   radius;
                    747: 
                    748:        radius = damage+40;
                    749:        if (is_quad)
                    750:                damage *= 4;
                    751: 
                    752:        VectorSet(offset, 8, 8, ent->viewheight-8);
                    753:        AngleVectors (ent->client->v_angle, forward, right, NULL);
                    754:        P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
                    755: 
                    756:        VectorScale (forward, -2, ent->client->kick_origin);
                    757:        ent->client->kick_angles[0] = -1;
                    758: 
                    759:        fire_grenade (ent, start, forward, damage, 600, 2.5, radius);
                    760: 
                    761:        gi.WriteByte (svc_muzzleflash);
                    762:        gi.WriteShort (ent-g_edicts);
                    763:        gi.WriteByte (MZ_GRENADE | is_silenced);
                    764:        gi.multicast (ent->s.origin, MULTICAST_PVS);
                    765: 
                    766:        ent->client->ps.gunframe++;
                    767: 
                    768:        PlayerNoise(ent, start, PNOISE_WEAPON);
                    769: 
                    770:        if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                    771:                ent->client->pers.inventory[ent->client->ammo_index]--;
                    772: }
                    773: 
                    774: void Weapon_GrenadeLauncher (edict_t *ent)
                    775: {
                    776:        static int      pause_frames[]  = {34, 51, 59, 0};
                    777:        static int      fire_frames[]   = {6, 0};
                    778: 
                    779:        Weapon_Generic (ent, 5, 16, 59, 64, pause_frames, fire_frames, weapon_grenadelauncher_fire);
                    780: }
                    781: 
                    782: /*
                    783: ======================================================================
                    784: 
                    785: ROCKET
                    786: 
                    787: ======================================================================
                    788: */
                    789: 
                    790: void Weapon_RocketLauncher_Fire (edict_t *ent)
                    791: {
                    792:        vec3_t  offset, start;
                    793:        vec3_t  forward, right;
                    794:        int             damage;
                    795:        float   damage_radius;
                    796:        int             radius_damage;
                    797: 
                    798:        damage = 100 + (int)(random() * 20.0);
                    799:        radius_damage = 120;
                    800:        damage_radius = 120;
                    801:        if (is_quad)
                    802:        {
                    803:                damage *= 4;
                    804:                radius_damage *= 4;
                    805:        }
                    806: 
                    807:        AngleVectors (ent->client->v_angle, forward, right, NULL);
                    808: 
                    809:        VectorScale (forward, -2, ent->client->kick_origin);
                    810:        ent->client->kick_angles[0] = -1;
                    811: 
                    812:        VectorSet(offset, 8, 8, ent->viewheight-8);
                    813:        P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
                    814:        fire_rocket (ent, start, forward, damage, 650, damage_radius, radius_damage);
                    815: 
                    816:        // send muzzle flash
                    817:        gi.WriteByte (svc_muzzleflash);
                    818:        gi.WriteShort (ent-g_edicts);
                    819:        gi.WriteByte (MZ_ROCKET | is_silenced);
                    820:        gi.multicast (ent->s.origin, MULTICAST_PVS);
                    821: 
                    822:        ent->client->ps.gunframe++;
                    823: 
                    824:        PlayerNoise(ent, start, PNOISE_WEAPON);
                    825: 
                    826:        if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                    827:                ent->client->pers.inventory[ent->client->ammo_index]--;
                    828: }
                    829: 
                    830: void Weapon_RocketLauncher (edict_t *ent)
                    831: {
                    832:        static int      pause_frames[]  = {25, 33, 42, 50, 0};
                    833:        static int      fire_frames[]   = {5, 0};
                    834: 
                    835:        Weapon_Generic (ent, 4, 12, 50, 54, pause_frames, fire_frames, Weapon_RocketLauncher_Fire);
                    836: }
                    837: 
                    838: 
                    839: /*
                    840: ======================================================================
                    841: 
                    842: BLASTER / HYPERBLASTER
                    843: 
                    844: ======================================================================
                    845: */
                    846: 
                    847: void Blaster_Fire (edict_t *ent, vec3_t g_offset, int damage, qboolean hyper, int effect)
                    848: {
                    849:        vec3_t  forward, right;
                    850:        vec3_t  start;
                    851:        vec3_t  offset;
                    852: 
                    853:        if (is_quad)
                    854:                damage *= 4;
                    855:        AngleVectors (ent->client->v_angle, forward, right, NULL);
                    856:        VectorSet(offset, 24, 8, ent->viewheight-8);
                    857:        VectorAdd (offset, g_offset, offset);
                    858:        P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
                    859: 
                    860:        VectorScale (forward, -2, ent->client->kick_origin);
                    861:        ent->client->kick_angles[0] = -1;
                    862: 
                    863:        fire_blaster (ent, start, forward, damage, 1000, effect, hyper);
                    864: 
                    865:        // send muzzle flash
                    866:        gi.WriteByte (svc_muzzleflash);
                    867:        gi.WriteShort (ent-g_edicts);
                    868:        if (hyper)
                    869:                gi.WriteByte (MZ_HYPERBLASTER | is_silenced);
                    870:        else
                    871:                gi.WriteByte (MZ_BLASTER | is_silenced);
                    872:        gi.multicast (ent->s.origin, MULTICAST_PVS);
                    873: 
                    874:        PlayerNoise(ent, start, PNOISE_WEAPON);
                    875: }
                    876: 
                    877: 
                    878: void Weapon_Blaster_Fire (edict_t *ent)
                    879: {
                    880:        int             damage;
                    881: 
                    882:        if (deathmatch->value)
                    883:                damage = 15;
                    884:        else
                    885:                damage = 10;
                    886:        Blaster_Fire (ent, vec3_origin, damage, false, EF_BLASTER);
                    887:        ent->client->ps.gunframe++;
                    888: }
                    889: 
                    890: void Weapon_Blaster (edict_t *ent)
                    891: {
                    892:        static int      pause_frames[]  = {19, 32, 0};
                    893:        static int      fire_frames[]   = {5, 0};
                    894: 
                    895:        Weapon_Generic (ent, 4, 8, 52, 55, pause_frames, fire_frames, Weapon_Blaster_Fire);
                    896: }
                    897: 
                    898: 
                    899: void Weapon_HyperBlaster_Fire (edict_t *ent)
                    900: {
                    901:        float   rotation;
                    902:        vec3_t  offset;
                    903:        int             effect;
                    904:        int             damage;
                    905: 
                    906:        ent->client->weapon_sound = gi.soundindex("weapons/hyprbl1a.wav");
                    907: 
                    908:        if (!(ent->client->buttons & BUTTON_ATTACK))
                    909:        {
                    910:                ent->client->ps.gunframe++;
                    911:        }
                    912:        else
                    913:        {
                    914:                if (! ent->client->pers.inventory[ent->client->ammo_index] )
                    915:                {
                    916:                        if (level.time >= ent->pain_debounce_time)
                    917:                        {
                    918:                                gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
                    919:                                ent->pain_debounce_time = level.time + 1;
                    920:                        }
                    921:                        NoAmmoWeaponChange (ent);
                    922:                }
                    923:                else
                    924:                {
                    925:                        rotation = (ent->client->ps.gunframe - 5) * 2*M_PI/6;
                    926:                        offset[0] = -4 * sin(rotation);
                    927:                        offset[1] = 0;
                    928:                        offset[2] = 4 * cos(rotation);
                    929: 
                    930:                        if ((ent->client->ps.gunframe == 6) || (ent->client->ps.gunframe == 9))
                    931:                                effect = EF_HYPERBLASTER;
                    932:                        else
                    933:                                effect = 0;
                    934:                        if (deathmatch->value)
                    935:                                damage = 15;
                    936:                        else
                    937:                                damage = 20;
                    938:                        Blaster_Fire (ent, offset, damage, true, effect);
                    939:                        if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                    940:                                ent->client->pers.inventory[ent->client->ammo_index]--;
                    941: 
                    942:                        ent->client->anim_priority = ANIM_ATTACK;
                    943:                        if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
                    944:                        {
                    945:                                ent->s.frame = FRAME_crattak1 - 1;
                    946:                                ent->client->anim_end = FRAME_crattak9;
                    947:                        }
                    948:                        else
                    949:                        {
                    950:                                ent->s.frame = FRAME_attack1 - 1;
                    951:                                ent->client->anim_end = FRAME_attack8;
                    952:                        }
                    953:                }
                    954: 
                    955:                ent->client->ps.gunframe++;
                    956:                if (ent->client->ps.gunframe == 12 && ent->client->pers.inventory[ent->client->ammo_index])
                    957:                        ent->client->ps.gunframe = 6;
                    958:        }
                    959: 
                    960:        if (ent->client->ps.gunframe == 12)
                    961:        {
                    962:                gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/hyprbd1a.wav"), 1, ATTN_NORM, 0);
                    963:                ent->client->weapon_sound = 0;
                    964:        }
                    965: 
                    966: }
                    967: 
                    968: void Weapon_HyperBlaster (edict_t *ent)
                    969: {
                    970:        static int      pause_frames[]  = {0};
                    971:        static int      fire_frames[]   = {6, 7, 8, 9, 10, 11, 0};
                    972: 
                    973:        Weapon_Generic (ent, 5, 20, 49, 53, pause_frames, fire_frames, Weapon_HyperBlaster_Fire);
                    974: }
                    975: 
                    976: /*
                    977: ======================================================================
                    978: 
                    979: MACHINEGUN / CHAINGUN
                    980: 
                    981: ======================================================================
                    982: */
                    983: 
                    984: void Machinegun_Fire (edict_t *ent)
                    985: {
                    986:        int     i;
                    987:        vec3_t          start;
                    988:        vec3_t          forward, right;
                    989:        vec3_t          angles;
                    990:        int                     damage = 8;
                    991:        int                     kick = 2;
                    992:        vec3_t          offset;
                    993: 
                    994:        if (!(ent->client->buttons & BUTTON_ATTACK))
                    995:        {
                    996:                ent->client->machinegun_shots = 0;
                    997:                ent->client->ps.gunframe++;
                    998:                return;
                    999:        }
                   1000: 
                   1001:        if (ent->client->ps.gunframe == 5)
                   1002:                ent->client->ps.gunframe = 4;
                   1003:        else
                   1004:                ent->client->ps.gunframe = 5;
                   1005: 
                   1006:        if (ent->client->pers.inventory[ent->client->ammo_index] < 1)
                   1007:        {
                   1008:                ent->client->ps.gunframe = 6;
                   1009:                if (level.time >= ent->pain_debounce_time)
                   1010:                {
                   1011:                        gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
                   1012:                        ent->pain_debounce_time = level.time + 1;
                   1013:                }
                   1014:                NoAmmoWeaponChange (ent);
                   1015:                return;
                   1016:        }
                   1017: 
                   1018:        if (is_quad)
                   1019:        {
                   1020:                damage *= 4;
                   1021:                kick *= 4;
                   1022:        }
                   1023: 
                   1024:        for (i=1 ; i<3 ; i++)
                   1025:        {
                   1026:                ent->client->kick_origin[i] = crandom() * 0.35;
                   1027:                ent->client->kick_angles[i] = crandom() * 0.7;
                   1028:        }
                   1029:        ent->client->kick_origin[0] = crandom() * 0.35;
                   1030:        ent->client->kick_angles[0] = ent->client->machinegun_shots * -1.5;
                   1031: 
                   1032:        // raise the gun as it is firing
                   1033:        if (!deathmatch->value)
                   1034:        {
                   1035:                ent->client->machinegun_shots++;
                   1036:                if (ent->client->machinegun_shots > 9)
                   1037:                        ent->client->machinegun_shots = 9;
                   1038:        }
                   1039: 
                   1040:        // get start / end positions
                   1041:        VectorAdd (ent->client->v_angle, ent->client->kick_angles, angles);
                   1042:        AngleVectors (angles, forward, right, NULL);
                   1043:        VectorSet(offset, 0, 8, ent->viewheight-8);
                   1044:        P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
                   1045:        fire_bullet (ent, start, forward, damage, kick, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MOD_MACHINEGUN);
                   1046: 
                   1047:        gi.WriteByte (svc_muzzleflash);
                   1048:        gi.WriteShort (ent-g_edicts);
                   1049:        gi.WriteByte (MZ_MACHINEGUN | is_silenced);
                   1050:        gi.multicast (ent->s.origin, MULTICAST_PVS);
                   1051: 
                   1052:        PlayerNoise(ent, start, PNOISE_WEAPON);
                   1053: 
                   1054:        if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                   1055:                ent->client->pers.inventory[ent->client->ammo_index]--;
                   1056: 
                   1057:        ent->client->anim_priority = ANIM_ATTACK;
                   1058:        if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
                   1059:        {
                   1060:                ent->s.frame = FRAME_crattak1 - (int) (random()+0.25);
                   1061:                ent->client->anim_end = FRAME_crattak9;
                   1062:        }
                   1063:        else
                   1064:        {
                   1065:                ent->s.frame = FRAME_attack1 - (int) (random()+0.25);
                   1066:                ent->client->anim_end = FRAME_attack8;
                   1067:        }
                   1068: }
                   1069: 
                   1070: void Weapon_Machinegun (edict_t *ent)
                   1071: {
                   1072:        static int      pause_frames[]  = {23, 45, 0};
                   1073:        static int      fire_frames[]   = {4, 5, 0};
                   1074: 
                   1075:        Weapon_Generic (ent, 3, 5, 45, 49, pause_frames, fire_frames, Machinegun_Fire);
                   1076: }
                   1077: 
                   1078: void Chaingun_Fire (edict_t *ent)
                   1079: {
                   1080:        int                     i;
                   1081:        int                     shots;
                   1082:        vec3_t          start;
                   1083:        vec3_t          forward, right, up;
                   1084:        float           r, u;
                   1085:        vec3_t          offset;
                   1086:        int                     damage;
                   1087:        int                     kick = 2;
                   1088: 
                   1089:        if (deathmatch->value)
                   1090:                damage = 6;
                   1091:        else
                   1092:                damage = 8;
                   1093: 
                   1094:        if (ent->client->ps.gunframe == 5)
                   1095:                gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnu1a.wav"), 1, ATTN_IDLE, 0);
                   1096: 
                   1097:        if ((ent->client->ps.gunframe == 14) && !(ent->client->buttons & BUTTON_ATTACK))
                   1098:        {
                   1099:                ent->client->ps.gunframe = 32;
                   1100:                ent->client->weapon_sound = 0;
                   1101:                return;
                   1102:        }
                   1103:        else if ((ent->client->ps.gunframe == 21) && (ent->client->buttons & BUTTON_ATTACK)
                   1104:                && ent->client->pers.inventory[ent->client->ammo_index])
                   1105:        {
                   1106:                ent->client->ps.gunframe = 15;
                   1107:        }
                   1108:        else
                   1109:        {
                   1110:                ent->client->ps.gunframe++;
                   1111:        }
                   1112: 
                   1113:        if (ent->client->ps.gunframe == 22)
                   1114:        {
                   1115:                ent->client->weapon_sound = 0;
                   1116:                gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnd1a.wav"), 1, ATTN_IDLE, 0);
                   1117:        }
                   1118:        else
                   1119:        {
                   1120:                ent->client->weapon_sound = gi.soundindex("weapons/chngnl1a.wav");
                   1121:        }
                   1122: 
                   1123:        ent->client->anim_priority = ANIM_ATTACK;
                   1124:        if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
                   1125:        {
                   1126:                ent->s.frame = FRAME_crattak1 - (ent->client->ps.gunframe & 1);
                   1127:                ent->client->anim_end = FRAME_crattak9;
                   1128:        }
                   1129:        else
                   1130:        {
                   1131:                ent->s.frame = FRAME_attack1 - (ent->client->ps.gunframe & 1);
                   1132:                ent->client->anim_end = FRAME_attack8;
                   1133:        }
                   1134: 
                   1135:        if (ent->client->ps.gunframe <= 9)
                   1136:                shots = 1;
                   1137:        else if (ent->client->ps.gunframe <= 14)
                   1138:        {
                   1139:                if (ent->client->buttons & BUTTON_ATTACK)
                   1140:                        shots = 2;
                   1141:                else
                   1142:                        shots = 1;
                   1143:        }
                   1144:        else
                   1145:                shots = 3;
                   1146: 
                   1147:        if (ent->client->pers.inventory[ent->client->ammo_index] < shots)
                   1148:                shots = ent->client->pers.inventory[ent->client->ammo_index];
                   1149: 
                   1150:        if (!shots)
                   1151:        {
                   1152:                if (level.time >= ent->pain_debounce_time)
                   1153:                {
                   1154:                        gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
                   1155:                        ent->pain_debounce_time = level.time + 1;
                   1156:                }
                   1157:                NoAmmoWeaponChange (ent);
                   1158:                return;
                   1159:        }
                   1160: 
                   1161:        if (is_quad)
                   1162:        {
                   1163:                damage *= 4;
                   1164:                kick *= 4;
                   1165:        }
                   1166: 
                   1167:        for (i=0 ; i<3 ; i++)
                   1168:        {
                   1169:                ent->client->kick_origin[i] = crandom() * 0.35;
                   1170:                ent->client->kick_angles[i] = crandom() * 0.7;
                   1171:        }
                   1172: 
                   1173:        for (i=0 ; i<shots ; i++)
                   1174:        {
                   1175:                // get start / end positions
                   1176:                AngleVectors (ent->client->v_angle, forward, right, up);
                   1177:                r = 7 + crandom()*4;
                   1178:                u = crandom()*4;
                   1179:                VectorSet(offset, 0, r, u + ent->viewheight-8);
                   1180:                P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
                   1181: 
                   1182:                fire_bullet (ent, start, forward, damage, kick, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MOD_CHAINGUN);
                   1183:        }
                   1184: 
                   1185:        // send muzzle flash
                   1186:        gi.WriteByte (svc_muzzleflash);
                   1187:        gi.WriteShort (ent-g_edicts);
                   1188:        gi.WriteByte ((MZ_CHAINGUN1 + shots - 1) | is_silenced);
                   1189:        gi.multicast (ent->s.origin, MULTICAST_PVS);
                   1190: 
                   1191:        PlayerNoise(ent, start, PNOISE_WEAPON);
                   1192: 
                   1193:        if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                   1194:                ent->client->pers.inventory[ent->client->ammo_index] -= shots;
                   1195: }
                   1196: 
                   1197: 
                   1198: void Weapon_Chaingun (edict_t *ent)
                   1199: {
                   1200:        static int      pause_frames[]  = {38, 43, 51, 61, 0};
                   1201:        static int      fire_frames[]   = {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0};
                   1202: 
                   1203:        Weapon_Generic (ent, 4, 31, 61, 64, pause_frames, fire_frames, Chaingun_Fire);
                   1204: }
                   1205: 
                   1206: 
                   1207: /*
                   1208: ======================================================================
                   1209: 
                   1210: SHOTGUN / SUPERSHOTGUN
                   1211: 
                   1212: ======================================================================
                   1213: */
                   1214: 
                   1215: void weapon_shotgun_fire (edict_t *ent)
                   1216: {
                   1217:        vec3_t          start;
                   1218:        vec3_t          forward, right;
                   1219:        vec3_t          offset;
                   1220:        int                     damage = 4;
                   1221:        int                     kick = 8;
                   1222: 
                   1223:        if (ent->client->ps.gunframe == 9)
                   1224:        {
                   1225:                ent->client->ps.gunframe++;
                   1226:                return;
                   1227:        }
                   1228: 
                   1229:        AngleVectors (ent->client->v_angle, forward, right, NULL);
                   1230: 
                   1231:        VectorScale (forward, -2, ent->client->kick_origin);
                   1232:        ent->client->kick_angles[0] = -2;
                   1233: 
                   1234:        VectorSet(offset, 0, 8,  ent->viewheight-8);
                   1235:        P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
                   1236: 
                   1237:        if (is_quad)
                   1238:        {
                   1239:                damage *= 4;
                   1240:                kick *= 4;
                   1241:        }
                   1242: 
                   1243:        if (deathmatch->value)
                   1244:                fire_shotgun (ent, start, forward, damage, kick, 500, 500, DEFAULT_DEATHMATCH_SHOTGUN_COUNT, MOD_SHOTGUN);
                   1245:        else
                   1246:                fire_shotgun (ent, start, forward, damage, kick, 500, 500, DEFAULT_SHOTGUN_COUNT, MOD_SHOTGUN);
                   1247: 
                   1248:        // send muzzle flash
                   1249:        gi.WriteByte (svc_muzzleflash);
                   1250:        gi.WriteShort (ent-g_edicts);
                   1251:        gi.WriteByte (MZ_SHOTGUN | is_silenced);
                   1252:        gi.multicast (ent->s.origin, MULTICAST_PVS);
                   1253: 
                   1254:        ent->client->ps.gunframe++;
                   1255:        PlayerNoise(ent, start, PNOISE_WEAPON);
                   1256: 
                   1257:        if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                   1258:                ent->client->pers.inventory[ent->client->ammo_index]--;
                   1259: }
                   1260: 
                   1261: void Weapon_Shotgun (edict_t *ent)
                   1262: {
                   1263:        static int      pause_frames[]  = {22, 28, 34, 0};
                   1264:        static int      fire_frames[]   = {8, 9, 0};
                   1265: 
                   1266:        Weapon_Generic (ent, 7, 18, 36, 39, pause_frames, fire_frames, weapon_shotgun_fire);
                   1267: }
                   1268: 
                   1269: 
                   1270: void weapon_supershotgun_fire (edict_t *ent)
                   1271: {
                   1272:        vec3_t          start;
                   1273:        vec3_t          forward, right;
                   1274:        vec3_t          offset;
                   1275:        vec3_t          v;
                   1276:        int                     damage = 6;
                   1277:        int                     kick = 12;
                   1278: 
                   1279:        AngleVectors (ent->client->v_angle, forward, right, NULL);
                   1280: 
                   1281:        VectorScale (forward, -2, ent->client->kick_origin);
                   1282:        ent->client->kick_angles[0] = -2;
                   1283: 
                   1284:        VectorSet(offset, 0, 8,  ent->viewheight-8);
                   1285:        P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
                   1286: 
                   1287:        if (is_quad)
                   1288:        {
                   1289:                damage *= 4;
                   1290:                kick *= 4;
                   1291:        }
                   1292: 
                   1293:        v[PITCH] = ent->client->v_angle[PITCH];
                   1294:        v[YAW]   = ent->client->v_angle[YAW] - 5;
                   1295:        v[ROLL]  = ent->client->v_angle[ROLL];
                   1296:        AngleVectors (v, forward, NULL, NULL);
                   1297:        fire_shotgun (ent, start, forward, damage, kick, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT/2, MOD_SSHOTGUN);
                   1298:        v[YAW]   = ent->client->v_angle[YAW] + 5;
                   1299:        AngleVectors (v, forward, NULL, NULL);
                   1300:        fire_shotgun (ent, start, forward, damage, kick, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT/2, MOD_SSHOTGUN);
                   1301: 
                   1302:        // send muzzle flash
                   1303:        gi.WriteByte (svc_muzzleflash);
                   1304:        gi.WriteShort (ent-g_edicts);
                   1305:        gi.WriteByte (MZ_SSHOTGUN | is_silenced);
                   1306:        gi.multicast (ent->s.origin, MULTICAST_PVS);
                   1307: 
                   1308:        ent->client->ps.gunframe++;
                   1309:        PlayerNoise(ent, start, PNOISE_WEAPON);
                   1310: 
                   1311:        if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                   1312:                ent->client->pers.inventory[ent->client->ammo_index] -= 2;
                   1313: }
                   1314: 
                   1315: void Weapon_SuperShotgun (edict_t *ent)
                   1316: {
                   1317:        static int      pause_frames[]  = {29, 42, 57, 0};
                   1318:        static int      fire_frames[]   = {7, 0};
                   1319: 
                   1320:        Weapon_Generic (ent, 6, 17, 57, 61, pause_frames, fire_frames, weapon_supershotgun_fire);
                   1321: }
                   1322: 
                   1323: 
                   1324: 
                   1325: /*
                   1326: ======================================================================
                   1327: 
                   1328: RAILGUN
                   1329: 
                   1330: ======================================================================
                   1331: */
                   1332: 
                   1333: void weapon_railgun_fire (edict_t *ent)
                   1334: {
                   1335:        vec3_t          start;
                   1336:        vec3_t          forward, right;
                   1337:        vec3_t          offset;
                   1338:        int                     damage;
                   1339:        int                     kick;
                   1340: 
                   1341:        if (deathmatch->value)
                   1342:        {       // normal damage is too extreme in dm
                   1343:                damage = 100;
                   1344:                kick = 200;
                   1345:        }
                   1346:        else
                   1347:        {
                   1348:                damage = 150;
                   1349:                kick = 250;
                   1350:        }
                   1351: 
                   1352:        if (is_quad)
                   1353:        {
                   1354:                damage *= 4;
                   1355:                kick *= 4;
                   1356:        }
                   1357: 
                   1358:        AngleVectors (ent->client->v_angle, forward, right, NULL);
                   1359: 
                   1360:        VectorScale (forward, -3, ent->client->kick_origin);
                   1361:        ent->client->kick_angles[0] = -3;
                   1362: 
                   1363:        VectorSet(offset, 0, 7,  ent->viewheight-8);
                   1364:        P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
                   1365:        fire_rail (ent, start, forward, damage, kick);
                   1366: 
                   1367:        // send muzzle flash
                   1368:        gi.WriteByte (svc_muzzleflash);
                   1369:        gi.WriteShort (ent-g_edicts);
                   1370:        gi.WriteByte (MZ_RAILGUN | is_silenced);
                   1371:        gi.multicast (ent->s.origin, MULTICAST_PVS);
                   1372: 
                   1373:        ent->client->ps.gunframe++;
                   1374:        PlayerNoise(ent, start, PNOISE_WEAPON);
                   1375: 
                   1376:        if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                   1377:                ent->client->pers.inventory[ent->client->ammo_index]--;
                   1378: }
                   1379: 
                   1380: 
                   1381: void Weapon_Railgun (edict_t *ent)
                   1382: {
                   1383:        static int      pause_frames[]  = {56, 0};
                   1384:        static int      fire_frames[]   = {4, 0};
                   1385: 
                   1386:        Weapon_Generic (ent, 3, 18, 56, 61, pause_frames, fire_frames, weapon_railgun_fire);
                   1387: }
                   1388: 
                   1389: 
                   1390: /*
                   1391: ======================================================================
                   1392: 
                   1393: BFG10K
                   1394: 
                   1395: ======================================================================
                   1396: */
                   1397: 
                   1398: void weapon_bfg_fire (edict_t *ent)
                   1399: {
                   1400:        vec3_t  offset, start;
                   1401:        vec3_t  forward, right;
                   1402:        int             damage;
                   1403:        float   damage_radius = 1000;
                   1404: 
                   1405:        if (deathmatch->value)
                   1406:                damage = 200;
                   1407:        else
                   1408:                damage = 500;
                   1409: 
                   1410:        if (ent->client->ps.gunframe == 9)
                   1411:        {
                   1412:                // send muzzle flash
                   1413:                gi.WriteByte (svc_muzzleflash);
                   1414:                gi.WriteShort (ent-g_edicts);
                   1415:                gi.WriteByte (MZ_BFG | is_silenced);
                   1416:                gi.multicast (ent->s.origin, MULTICAST_PVS);
                   1417: 
                   1418:                ent->client->ps.gunframe++;
                   1419: 
                   1420:                PlayerNoise(ent, start, PNOISE_WEAPON);
                   1421:                return;
                   1422:        }
                   1423: 
                   1424:        // cells can go down during windup (from power armor hits), so
                   1425:        // check again and abort firing if we don't have enough now
                   1426:        if (ent->client->pers.inventory[ent->client->ammo_index] < 50)
                   1427:        {
                   1428:                ent->client->ps.gunframe++;
                   1429:                return;
                   1430:        }
                   1431: 
                   1432:        if (is_quad)
                   1433:                damage *= 4;
                   1434: 
                   1435:        AngleVectors (ent->client->v_angle, forward, right, NULL);
                   1436: 
                   1437:        VectorScale (forward, -2, ent->client->kick_origin);
                   1438: 
                   1439:        // make a big pitch kick with an inverse fall
                   1440:        ent->client->v_dmg_pitch = -40;
                   1441:        ent->client->v_dmg_roll = crandom()*8;
                   1442:        ent->client->v_dmg_time = level.time + DAMAGE_TIME;
                   1443: 
                   1444:        VectorSet(offset, 8, 8, ent->viewheight-8);
                   1445:        P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
                   1446:        fire_bfg (ent, start, forward, damage, 400, damage_radius);
                   1447: 
                   1448:        ent->client->ps.gunframe++;
                   1449: 
                   1450:        PlayerNoise(ent, start, PNOISE_WEAPON);
                   1451: 
                   1452:        if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                   1453:                ent->client->pers.inventory[ent->client->ammo_index] -= 50;
                   1454: }
                   1455: 
                   1456: void Weapon_BFG (edict_t *ent)
                   1457: {
                   1458:        static int      pause_frames[]  = {39, 45, 50, 55, 0};
                   1459:        static int      fire_frames[]   = {9, 17, 0};
                   1460: 
                   1461:        Weapon_Generic (ent, 8, 32, 55, 58, pause_frames, fire_frames, weapon_bfg_fire);
                   1462: }
                   1463: 
                   1464: 
                   1465: //======================================================================

unix.superglobalmegacorp.com

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