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

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

unix.superglobalmegacorp.com

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