Annotation of quake2/rogue/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: //PGM
                     11: static byte            damage_multiplier;
                     12: //PGM
                     13: 
                     14: void weapon_grenade_fire (edict_t *ent, qboolean held);
                     15: 
                     16: //========
                     17: //ROGUE
                     18: byte P_DamageModifier(edict_t *ent)
                     19: {
                     20:        is_quad = 0;
                     21:        damage_multiplier = 1;
                     22: 
                     23:        if(ent->client->quad_framenum > level.framenum)
                     24:        {
                     25:                damage_multiplier *= 4;
                     26:                is_quad = 1;
                     27: 
                     28:                // if we're quad and DF_NO_STACK_DOUBLE is on, return now.
                     29:                if(((int)(dmflags->value) & DF_NO_STACK_DOUBLE))
                     30:                        return damage_multiplier;
                     31:        }
                     32:        if(ent->client->double_framenum > level.framenum)
                     33:        {
                     34:                if ((deathmatch->value) || (damage_multiplier == 1))
                     35:                {
                     36:                        damage_multiplier *= 2;
                     37:                        is_quad = 1;
                     38:                }
                     39:        }
                     40:        
                     41:        return damage_multiplier;
                     42: }
                     43: //ROGUE
                     44: //========
                     45: 
                     46: static void P_ProjectSource (gclient_t *client, vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result)
                     47: {
                     48:        vec3_t  _distance;
                     49: 
                     50:        VectorCopy (distance, _distance);
                     51:        if (client->pers.hand == LEFT_HANDED)
                     52:                _distance[1] *= -1;
                     53:        else if (client->pers.hand == CENTER_HANDED)
                     54:                _distance[1] = 0;
                     55:        G_ProjectSource (point, _distance, forward, right, result);
                     56: }
                     57: 
                     58: static void P_ProjectSource2 (gclient_t *client, vec3_t point, vec3_t distance, vec3_t forward, 
                     59:                                                          vec3_t right, vec3_t up, vec3_t result)
                     60: {
                     61:        vec3_t  _distance;
                     62: 
                     63:        VectorCopy (distance, _distance);
                     64:        if (client->pers.hand == LEFT_HANDED)
                     65:                _distance[1] *= -1;
                     66:        else if (client->pers.hand == CENTER_HANDED)
                     67:                _distance[1] = 0;
                     68:        G_ProjectSource2 (point, _distance, forward, right, up, result);
                     69: }
                     70: 
                     71: /*
                     72: ===============
                     73: PlayerNoise
                     74: 
                     75: Each player can have two noise objects associated with it:
                     76: a personal noise (jumping, pain, weapon firing), and a weapon
                     77: target noise (bullet wall impacts)
                     78: 
                     79: Monsters that don't directly see the player can move
                     80: to a noise in hopes of seeing the player from there.
                     81: ===============
                     82: */
                     83: void PlayerNoise(edict_t *who, vec3_t where, int type)
                     84: {
                     85:        edict_t         *noise;
                     86: 
                     87:        if (type == PNOISE_WEAPON)
                     88:        {
                     89:                if (who->client->silencer_shots)
                     90:                {
                     91:                        who->client->silencer_shots--;
                     92:                        return;
                     93:                }
                     94:        }
                     95: 
                     96:        if (deathmatch->value)
                     97:                return;
                     98: 
                     99:        if (who->flags & FL_NOTARGET)
                    100:                return;
                    101: 
                    102:        if (who->flags & FL_DISGUISED)
                    103:        {
                    104:                if (type == PNOISE_WEAPON)
                    105:                {
                    106:                        level.disguise_violator = who;
                    107:                        level.disguise_violation_framenum = level.framenum + 5;
                    108:                }
                    109:                else
                    110:                        return;
                    111:        }
                    112: 
                    113:        if (!who->mynoise)
                    114:        {
                    115:                noise = G_Spawn();
                    116:                noise->classname = "player_noise";
                    117:                VectorSet (noise->mins, -8, -8, -8);
                    118:                VectorSet (noise->maxs, 8, 8, 8);
                    119:                noise->owner = who;
                    120:                noise->svflags = SVF_NOCLIENT;
                    121:                who->mynoise = noise;
                    122: 
                    123:                noise = G_Spawn();
                    124:                noise->classname = "player_noise";
                    125:                VectorSet (noise->mins, -8, -8, -8);
                    126:                VectorSet (noise->maxs, 8, 8, 8);
                    127:                noise->owner = who;
                    128:                noise->svflags = SVF_NOCLIENT;
                    129:                who->mynoise2 = noise;
                    130:        }
                    131: 
                    132:        if (type == PNOISE_SELF || type == PNOISE_WEAPON)
                    133:        {
                    134:                noise = who->mynoise;
                    135:                level.sound_entity = noise;
                    136:                level.sound_entity_framenum = level.framenum;
                    137:        }
                    138:        else // type == PNOISE_IMPACT
                    139:        {
                    140:                noise = who->mynoise2;
                    141:                level.sound2_entity = noise;
                    142:                level.sound2_entity_framenum = level.framenum;
                    143:        }
                    144: 
                    145:        VectorCopy (where, noise->s.origin);
                    146:        VectorSubtract (where, noise->maxs, noise->absmin);
                    147:        VectorAdd (where, noise->maxs, noise->absmax);
                    148:        noise->teleport_time = level.time;
                    149:        gi.linkentity (noise);
                    150: }
                    151: 
                    152: 
                    153: qboolean Pickup_Weapon (edict_t *ent, edict_t *other)
                    154: {
                    155:        int                     index;
                    156:        gitem_t         *ammo;
                    157: 
                    158:        index = ITEM_INDEX(ent->item);
                    159: 
                    160:        if ( ( ((int)(dmflags->value) & DF_WEAPONS_STAY) || coop->value) 
                    161:                && other->client->pers.inventory[index])
                    162:        {
                    163:                if (!(ent->spawnflags & (DROPPED_ITEM | DROPPED_PLAYER_ITEM) ) )
                    164:                        return false;   // leave the weapon for others to pickup
                    165:        }
                    166: 
                    167:        other->client->pers.inventory[index]++;
                    168: 
                    169:        if (!(ent->spawnflags & DROPPED_ITEM) )
                    170:        {
                    171:                // give them some ammo with it
                    172:                // PGM -- IF APPROPRIATE!
                    173:                if(ent->item->ammo)                     //PGM
                    174:                {
                    175:                        ammo = FindItem (ent->item->ammo);
                    176:                        if ( (int)dmflags->value & DF_INFINITE_AMMO )
                    177:                                Add_Ammo (other, ammo, 1000);
                    178:                        else
                    179:                                Add_Ammo (other, ammo, ammo->quantity);
                    180:                }
                    181: 
                    182:                if (! (ent->spawnflags & DROPPED_PLAYER_ITEM) )
                    183:                {
                    184:                        if (deathmatch->value)
                    185:                        {
                    186:                                if ((int)(dmflags->value) & DF_WEAPONS_STAY)
                    187:                                        ent->flags |= FL_RESPAWN;
                    188:                                else
                    189:                                        SetRespawn (ent, 30);
                    190:                        }
                    191:                        if (coop->value)
                    192:                                ent->flags |= FL_RESPAWN;
                    193:                }
                    194:        }
                    195: 
                    196:        if (other->client->pers.weapon != ent->item && 
                    197:                (other->client->pers.inventory[index] == 1) &&
                    198:                ( !deathmatch->value || other->client->pers.weapon == FindItem("blaster") ) )
                    199:                other->client->newweapon = ent->item;
                    200: 
                    201:        return true;
                    202: }
                    203: 
                    204: 
                    205: /*
                    206: ===============
                    207: ChangeWeapon
                    208: 
                    209: The old weapon has been dropped all the way, so make the new one
                    210: current
                    211: ===============
                    212: */
                    213: void ChangeWeapon (edict_t *ent)
                    214: {
                    215:        int i;
                    216: 
                    217:        if (ent->client->grenade_time)
                    218:        {
                    219:                ent->client->grenade_time = level.time;
                    220:                ent->client->weapon_sound = 0;
                    221:                weapon_grenade_fire (ent, false);
                    222:                ent->client->grenade_time = 0;
                    223:        }
                    224: 
                    225:        ent->client->pers.lastweapon = ent->client->pers.weapon;
                    226:        ent->client->pers.weapon = ent->client->newweapon;
                    227:        ent->client->newweapon = NULL;
                    228:        ent->client->machinegun_shots = 0;
                    229: 
                    230:        // set visible model
                    231:        if (ent->s.modelindex == 255)
                    232:        {
                    233:                if (ent->client->pers.weapon)
                    234:                        i = ((ent->client->pers.weapon->weapmodel & 0xff) << 8);
                    235:                else
                    236:                        i = 0;
                    237:                ent->s.skinnum = (ent - g_edicts - 1) | i;
                    238:        }
                    239: 
                    240:        if (ent->client->pers.weapon && ent->client->pers.weapon->ammo)
                    241:                ent->client->ammo_index = ITEM_INDEX(FindItem(ent->client->pers.weapon->ammo));
                    242:        else
                    243:                ent->client->ammo_index = 0;
                    244: 
                    245:        if (!ent->client->pers.weapon)
                    246:        {       // dead
                    247:                ent->client->ps.gunindex = 0;
                    248:                return;
                    249:        }
                    250: 
                    251:        ent->client->weaponstate = WEAPON_ACTIVATING;
                    252:        ent->client->ps.gunframe = 0;
                    253:        ent->client->ps.gunindex = gi.modelindex(ent->client->pers.weapon->view_model);
                    254: 
                    255:        ent->client->anim_priority = ANIM_PAIN;
                    256:        if(ent->client->ps.pmove.pm_flags & PMF_DUCKED)
                    257:        {
                    258:                        ent->s.frame = FRAME_crpain1;
                    259:                        ent->client->anim_end = FRAME_crpain4;
                    260:        }
                    261:        else
                    262:        {
                    263:                        ent->s.frame = FRAME_pain301;
                    264:                        ent->client->anim_end = FRAME_pain304;
                    265:                        
                    266:        }
                    267: }
                    268: 
                    269: /*
                    270: =================
                    271: NoAmmoWeaponChange
                    272: =================
                    273: */
                    274: 
                    275: // PMM - added rogue weapons to the list
                    276: 
                    277: void NoAmmoWeaponChange (edict_t *ent)
                    278: {
                    279:        if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("slugs"))]
                    280:                &&  ent->client->pers.inventory[ITEM_INDEX(FindItem("railgun"))] )
                    281:        {
                    282:                ent->client->newweapon = FindItem ("railgun");
                    283:                return;
                    284:        }
                    285:        // ROGUE
                    286:        if ( (ent->client->pers.inventory[ITEM_INDEX(FindItem("cells"))] >= 2)
                    287:                &&  ent->client->pers.inventory[ITEM_INDEX(FindItem("Plasma Beam"))] )
                    288:        {
                    289:                ent->client->newweapon = FindItem ("Plasma Beam");
                    290:                return;
                    291:        }
                    292:        // -ROGUE
                    293:        /*
                    294:        if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("cells"))]
                    295:                &&  ent->client->pers.inventory[ITEM_INDEX(FindItem("hyperblaster"))] )
                    296:        {
                    297:                ent->client->newweapon = FindItem ("hyperblaster");
                    298:                return;
                    299:        }
                    300:        */
                    301:        // ROGUE
                    302:        if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("flechettes"))]
                    303:                &&  ent->client->pers.inventory[ITEM_INDEX(FindItem("etf rifle"))] )
                    304:        {
                    305:                ent->client->newweapon = FindItem ("etf rifle");
                    306:                return;
                    307:        }
                    308:        // -ROGUE
                    309:        if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("bullets"))]
                    310:                &&  ent->client->pers.inventory[ITEM_INDEX(FindItem("chaingun"))] )
                    311:        {
                    312:                ent->client->newweapon = FindItem ("chaingun");
                    313:                return;
                    314:        }
                    315:        if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("bullets"))]
                    316:                &&  ent->client->pers.inventory[ITEM_INDEX(FindItem("machinegun"))] )
                    317:        {
                    318:                ent->client->newweapon = FindItem ("machinegun");
                    319:                return;
                    320:        }
                    321:        if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("shells"))] > 1
                    322:                &&  ent->client->pers.inventory[ITEM_INDEX(FindItem("super shotgun"))] )
                    323:        {
                    324:                ent->client->newweapon = FindItem ("super shotgun");
                    325:                return;
                    326:        }
                    327:        if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("shells"))]
                    328:                &&  ent->client->pers.inventory[ITEM_INDEX(FindItem("shotgun"))] )
                    329:        {
                    330:                ent->client->newweapon = FindItem ("shotgun");
                    331:                return;
                    332:        }
                    333:        ent->client->newweapon = FindItem ("blaster");
                    334: }
                    335: 
                    336: /*
                    337: =================
                    338: Think_Weapon
                    339: 
                    340: Called by ClientBeginServerFrame and ClientThink
                    341: =================
                    342: */
                    343: void Think_Weapon (edict_t *ent)
                    344: {
                    345:        // if just died, put the weapon away
                    346:        if (ent->health < 1)
                    347:        {
                    348:                ent->client->newweapon = NULL;
                    349:                ChangeWeapon (ent);
                    350:        }
                    351: 
                    352:        // call active weapon think routine
                    353:        if (ent->client->pers.weapon && ent->client->pers.weapon->weaponthink)
                    354:        {
                    355: //PGM
                    356:                P_DamageModifier(ent);  
                    357: //             is_quad = (ent->client->quad_framenum > level.framenum);
                    358: //PGM
                    359:                if (ent->client->silencer_shots)
                    360:                        is_silenced = MZ_SILENCED;
                    361:                else
                    362:                        is_silenced = 0;
                    363:                ent->client->pers.weapon->weaponthink (ent);
                    364:        }
                    365: }
                    366: 
                    367: 
                    368: /*
                    369: ================
                    370: Use_Weapon
                    371: 
                    372: Make the weapon ready if there is ammo
                    373: ================
                    374: */
                    375: void Use_Weapon (edict_t *ent, gitem_t *item)
                    376: {
                    377:        int                     ammo_index;
                    378:        gitem_t         *ammo_item;
                    379: 
                    380:        // see if we're already using it
                    381:        if (item == ent->client->pers.weapon)
                    382:                return;
                    383: 
                    384:        if (item->ammo && !g_select_empty->value && !(item->flags & IT_AMMO))
                    385:        {
                    386:                ammo_item = FindItem(item->ammo);
                    387:                ammo_index = ITEM_INDEX(ammo_item);
                    388: 
                    389:                if (!ent->client->pers.inventory[ammo_index])
                    390:                {
                    391:                        gi.cprintf (ent, PRINT_HIGH, "No %s for %s.\n", ammo_item->pickup_name, item->pickup_name);
                    392:                        return;
                    393:                }
                    394: 
                    395:                if (ent->client->pers.inventory[ammo_index] < item->quantity)
                    396:                {
                    397:                        gi.cprintf (ent, PRINT_HIGH, "Not enough %s for %s.\n", ammo_item->pickup_name, item->pickup_name);
                    398:                        return;
                    399:                }
                    400:        }
                    401: 
                    402:        // change to this weapon when down
                    403:        ent->client->newweapon = item;
                    404: }
                    405: 
                    406: 
                    407: 
                    408: /*
                    409: ================
                    410: Drop_Weapon
                    411: ================
                    412: */
                    413: void Drop_Weapon (edict_t *ent, gitem_t *item)
                    414: {
                    415:        int             index;
                    416: 
                    417:        if ((int)(dmflags->value) & DF_WEAPONS_STAY)
                    418:                return;
                    419: 
                    420:        index = ITEM_INDEX(item);
                    421:        // see if we're already using it
                    422:        if ( ((item == ent->client->pers.weapon) || (item == ent->client->newweapon))&& (ent->client->pers.inventory[index] == 1) )
                    423:        {
                    424:                gi.cprintf (ent, PRINT_HIGH, "Can't drop current weapon\n");
                    425:                return;
                    426:        }
                    427: 
                    428:        Drop_Item (ent, item);
                    429:        ent->client->pers.inventory[index]--;
                    430: }
                    431: 
                    432: 
                    433: /*
                    434: ================
                    435: Weapon_Generic
                    436: 
                    437: A generic function to handle the basics of weapon thinking
                    438: ================
                    439: */
                    440: #define FRAME_FIRE_FIRST               (FRAME_ACTIVATE_LAST + 1)
                    441: #define FRAME_IDLE_FIRST               (FRAME_FIRE_LAST + 1)
                    442: #define FRAME_DEACTIVATE_FIRST (FRAME_IDLE_LAST + 1)
                    443: 
                    444: 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))
                    445: {
                    446:        int             n;
                    447: 
                    448:        if(ent->deadflag || ent->s.modelindex != 255) // VWep animations screw up corpses
                    449:        {
                    450:                return;
                    451:        }
                    452: 
                    453:        if (ent->client->weaponstate == WEAPON_DROPPING)
                    454:        {
                    455:                if (ent->client->ps.gunframe == FRAME_DEACTIVATE_LAST)
                    456:                {
                    457:                        ChangeWeapon (ent);
                    458:                        return;
                    459:                }
                    460:                else if ((FRAME_DEACTIVATE_LAST - ent->client->ps.gunframe) == 4)
                    461:                {
                    462:                        ent->client->anim_priority = ANIM_REVERSE;
                    463:                        if(ent->client->ps.pmove.pm_flags & PMF_DUCKED)
                    464:                        {
                    465:                                ent->s.frame = FRAME_crpain4+1;
                    466:                                ent->client->anim_end = FRAME_crpain1;
                    467:                        }
                    468:                        else
                    469:                        {
                    470:                                ent->s.frame = FRAME_pain304+1;
                    471:                                ent->client->anim_end = FRAME_pain301;
                    472:                                
                    473:                        }
                    474:                }
                    475: 
                    476:                ent->client->ps.gunframe++;
                    477:                return;
                    478:        }
                    479: 
                    480:        if (ent->client->weaponstate == WEAPON_ACTIVATING)
                    481:        {
                    482:                if (ent->client->ps.gunframe == FRAME_ACTIVATE_LAST)
                    483:                {
                    484:                        ent->client->weaponstate = WEAPON_READY;
                    485:                        ent->client->ps.gunframe = FRAME_IDLE_FIRST;
                    486:                        return;
                    487:                }
                    488: 
                    489:                ent->client->ps.gunframe++;
                    490:                return;
                    491:        }
                    492: 
                    493:        if ((ent->client->newweapon) && (ent->client->weaponstate != WEAPON_FIRING))
                    494:        {
                    495:                ent->client->weaponstate = WEAPON_DROPPING;
                    496:                ent->client->ps.gunframe = FRAME_DEACTIVATE_FIRST;
                    497: 
                    498:                if ((FRAME_DEACTIVATE_LAST - FRAME_DEACTIVATE_FIRST) < 4)
                    499:                {
                    500:                        ent->client->anim_priority = ANIM_REVERSE;
                    501:                        if(ent->client->ps.pmove.pm_flags & PMF_DUCKED)
                    502:                        {
                    503:                                ent->s.frame = FRAME_crpain4+1;
                    504:                                ent->client->anim_end = FRAME_crpain1;
                    505:                        }
                    506:                        else
                    507:                        {
                    508:                                ent->s.frame = FRAME_pain304+1;
                    509:                                ent->client->anim_end = FRAME_pain301;
                    510:                                
                    511:                        }
                    512:                }
                    513:                return;
                    514:        }
                    515: 
                    516:        if (ent->client->weaponstate == WEAPON_READY)
                    517:        {
                    518:                if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
                    519:                {
                    520:                        ent->client->latched_buttons &= ~BUTTON_ATTACK;
                    521:                        if ((!ent->client->ammo_index) || 
                    522:                                ( ent->client->pers.inventory[ent->client->ammo_index] >= ent->client->pers.weapon->quantity))
                    523:                        {
                    524:                                ent->client->ps.gunframe = FRAME_FIRE_FIRST;
                    525:                                ent->client->weaponstate = WEAPON_FIRING;
                    526: 
                    527:                                // start the animation
                    528:                                ent->client->anim_priority = ANIM_ATTACK;
                    529:                                if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
                    530:                                {
                    531:                                        ent->s.frame = FRAME_crattak1-1;
                    532:                                        ent->client->anim_end = FRAME_crattak9;
                    533:                                }
                    534:                                else
                    535:                                {
                    536:                                        ent->s.frame = FRAME_attack1-1;
                    537:                                        ent->client->anim_end = FRAME_attack8;
                    538:                                }
                    539:                        }
                    540:                        else
                    541:                        {
                    542:                                if (level.time >= ent->pain_debounce_time)
                    543:                                {
                    544:                                        gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
                    545:                                        ent->pain_debounce_time = level.time + 1;
                    546:                                }
                    547:                                NoAmmoWeaponChange (ent);
                    548:                        }
                    549:                }
                    550:                else
                    551:                {
                    552:                        if (ent->client->ps.gunframe == FRAME_IDLE_LAST)
                    553:                        {
                    554:                                ent->client->ps.gunframe = FRAME_IDLE_FIRST;
                    555:                                return;
                    556:                        }
                    557: 
                    558:                        if (pause_frames)
                    559:                        {
                    560:                                for (n = 0; pause_frames[n]; n++)
                    561:                                {
                    562:                                        if (ent->client->ps.gunframe == pause_frames[n])
                    563:                                        {
                    564:                                                if (rand()&15)
                    565:                                                        return;
                    566:                                        }
                    567:                                }
                    568:                        }
                    569: 
                    570:                        ent->client->ps.gunframe++;
                    571:                        return;
                    572:                }
                    573:        }
                    574: 
                    575:        if (ent->client->weaponstate == WEAPON_FIRING)
                    576:        {
                    577:                for (n = 0; fire_frames[n]; n++)
                    578:                {
                    579:                        if (ent->client->ps.gunframe == fire_frames[n])
                    580:                        {
                    581:                                // FIXME - double should use different sound
                    582:                                if ((ent->client->quad_framenum > level.framenum) || (ent->client->double_framenum > level.framenum))
                    583:                                        gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage3.wav"), 1, ATTN_NORM, 0);
                    584: 
                    585:                                fire (ent);
                    586:                                break;
                    587:                        }
                    588:                }
                    589: 
                    590:                if (!fire_frames[n])
                    591:                        ent->client->ps.gunframe++;
                    592: 
                    593:                if (ent->client->ps.gunframe == FRAME_IDLE_FIRST+1)
                    594:                        ent->client->weaponstate = WEAPON_READY;
                    595:        }
                    596: }
                    597: 
                    598: 
                    599: /*
                    600: ======================================================================
                    601: 
                    602: GRENADE
                    603: 
                    604: ======================================================================
                    605: */
                    606: 
                    607: #define GRENADE_TIMER          3.0
                    608: #define GRENADE_MINSPEED       400
                    609: #define GRENADE_MAXSPEED       800
                    610: 
                    611: void weapon_grenade_fire (edict_t *ent, qboolean held)
                    612: {
                    613:        vec3_t  offset;
                    614:        vec3_t  forward, right, up;
                    615:        vec3_t  start;
                    616:        int             damage = 125;
                    617:        float   timer;
                    618:        int             speed;
                    619:        float   radius;
                    620: 
                    621:        radius = damage+40;
                    622:        if (is_quad)
                    623: //             damage *= 4;
                    624:                damage *= damage_multiplier;            // PGM
                    625: 
                    626:        AngleVectors (ent->client->v_angle, forward, right, up);
                    627:        if (ent->client->pers.weapon->tag == AMMO_TESLA)
                    628:        {
                    629: //             VectorSet(offset, 0, -12, ent->viewheight-26);
                    630:                VectorSet(offset, 0, -4, ent->viewheight-22);
                    631:        }
                    632:        else
                    633:        {
                    634: //             VectorSet(offset, 8, 8, ent->viewheight-8);
                    635:                VectorSet(offset, 2, 6, ent->viewheight-14);
                    636:        }
                    637:        P_ProjectSource2 (ent->client, ent->s.origin, offset, forward, right, up, start);
                    638: 
                    639:        timer = ent->client->grenade_time - level.time;
                    640:        speed = GRENADE_MINSPEED + (GRENADE_TIMER - timer) * ((GRENADE_MAXSPEED - GRENADE_MINSPEED) / GRENADE_TIMER);
                    641:        if (speed > GRENADE_MAXSPEED)
                    642:                speed = GRENADE_MAXSPEED;
                    643: 
                    644: //     fire_grenade2 (ent, start, forward, damage, speed, timer, radius, held);
                    645: 
                    646: // ============
                    647: // PGM
                    648:        switch(ent->client->pers.weapon->tag)
                    649:        {
                    650:                case AMMO_GRENADES:
                    651:                        fire_grenade2 (ent, start, forward, damage, speed, timer, radius, held);
                    652:                        break;
                    653:                case AMMO_TESLA:
                    654:                        fire_tesla (ent, start, forward, damage_multiplier, speed);
                    655:                        break;
                    656:                default:
                    657:                        fire_prox (ent, start, forward, damage_multiplier, speed);
                    658:                        break;
                    659:        }
                    660: // PGM
                    661: // ============
                    662: 
                    663:        if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                    664:                ent->client->pers.inventory[ent->client->ammo_index]--;
                    665: 
                    666:        ent->client->grenade_time = level.time + 1.0;
                    667: 
                    668:        if(ent->deadflag || ent->s.modelindex != 255) // VWep animations screw up corpses
                    669:        {
                    670:                return;
                    671:        }
                    672: 
                    673:        if (ent->health <= 0)
                    674:                return;
                    675: 
                    676:        if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
                    677:        {
                    678:                ent->client->anim_priority = ANIM_ATTACK;
                    679:                ent->s.frame = FRAME_crattak1-1;
                    680:                ent->client->anim_end = FRAME_crattak3;
                    681:        }
                    682:        else
                    683:        {
                    684:                ent->client->anim_priority = ANIM_REVERSE;
                    685:                ent->s.frame = FRAME_wave08;
                    686:                ent->client->anim_end = FRAME_wave01;
                    687:        }
                    688: }
                    689: /*
                    690: void Weapon_Grenade (edict_t *ent)
                    691: {
                    692:        if ((ent->client->newweapon) && (ent->client->weaponstate == WEAPON_READY))
                    693:        {
                    694:                ChangeWeapon (ent);
                    695:                return;
                    696:        }
                    697: 
                    698:        if (ent->client->weaponstate == WEAPON_ACTIVATING)
                    699:        {
                    700:                ent->client->weaponstate = WEAPON_READY;
                    701:                ent->client->ps.gunframe = 16;
                    702:                return;
                    703:        }
                    704: 
                    705:        if (ent->client->weaponstate == WEAPON_READY)
                    706:        {
                    707:                if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
                    708:                {
                    709:                        ent->client->latched_buttons &= ~BUTTON_ATTACK;
                    710:                        if (ent->client->pers.inventory[ent->client->ammo_index])
                    711:                        {
                    712:                                ent->client->ps.gunframe = 1;
                    713:                                ent->client->weaponstate = WEAPON_FIRING;
                    714:                                ent->client->grenade_time = 0;
                    715:                        }
                    716:                        else
                    717:                        {
                    718:                                if (level.time >= ent->pain_debounce_time)
                    719:                                {
                    720:                                        gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
                    721:                                        ent->pain_debounce_time = level.time + 1;
                    722:                                }
                    723:                                NoAmmoWeaponChange (ent);
                    724:                        }
                    725:                        return;
                    726:                }
                    727: 
                    728:                if ((ent->client->ps.gunframe == 29) || (ent->client->ps.gunframe == 34) || (ent->client->ps.gunframe == 39) || (ent->client->ps.gunframe == 48))
                    729:                {
                    730:                        if (rand()&15)
                    731:                                return;
                    732:                }
                    733: 
                    734:                if (++ent->client->ps.gunframe > 48)
                    735:                        ent->client->ps.gunframe = 16;
                    736:                return;
                    737:        }
                    738: 
                    739:        if (ent->client->weaponstate == WEAPON_FIRING)
                    740:        {
                    741:                if (ent->client->ps.gunframe == 5)
                    742:                        gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/hgrena1b.wav"), 1, ATTN_NORM, 0);
                    743: 
                    744:                if (ent->client->ps.gunframe == 11)
                    745:                {
                    746:                        if (!ent->client->grenade_time)
                    747:                        {
                    748:                                ent->client->grenade_time = level.time + GRENADE_TIMER + 0.2;
                    749:                                ent->client->weapon_sound = gi.soundindex("weapons/hgrenc1b.wav");
                    750:                        }
                    751: 
                    752:                        // they waited too long, detonate it in their hand
                    753:                        if (!ent->client->grenade_blew_up && level.time >= ent->client->grenade_time)
                    754:                        {
                    755:                                ent->client->weapon_sound = 0;
                    756:                                weapon_grenade_fire (ent, true);
                    757:                                ent->client->grenade_blew_up = true;
                    758:                        }
                    759: 
                    760:                        if (ent->client->buttons & BUTTON_ATTACK)
                    761:                                return;
                    762: 
                    763:                        if (ent->client->grenade_blew_up)
                    764:                        {
                    765:                                if (level.time >= ent->client->grenade_time)
                    766:                                {
                    767:                                        ent->client->ps.gunframe = 15;
                    768:                                        ent->client->grenade_blew_up = false;
                    769:                                }
                    770:                                else
                    771:                                {
                    772:                                        return;
                    773:                                }
                    774:                        }
                    775:                }
                    776: 
                    777:                if (ent->client->ps.gunframe == 12)
                    778:                {
                    779:                        ent->client->weapon_sound = 0;
                    780:                        weapon_grenade_fire (ent, false);
                    781:                }
                    782: 
                    783:                if ((ent->client->ps.gunframe == 15) && (level.time < ent->client->grenade_time))
                    784:                        return;
                    785: 
                    786:                ent->client->ps.gunframe++;
                    787: 
                    788:                if (ent->client->ps.gunframe == 16)
                    789:                {
                    790:                        ent->client->grenade_time = 0;
                    791:                        ent->client->weaponstate = WEAPON_READY;
                    792:                }
                    793:        }
                    794: }
                    795: */
                    796: 
                    797: #define FRAME_IDLE_FIRST               (FRAME_FIRE_LAST + 1)
                    798: 
                    799: //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))
                    800: //                                                                     15                      48                                              5                                               11                                      12                              29,34,39,48
                    801: void Throw_Generic (edict_t *ent, int FRAME_FIRE_LAST, int FRAME_IDLE_LAST, int FRAME_THROW_SOUND,
                    802:                                        int FRAME_THROW_HOLD, int FRAME_THROW_FIRE, int *pause_frames, int EXPLODE,
                    803:                                        void (*fire)(edict_t *ent, qboolean held))
                    804: {
                    805:        int n;
                    806: 
                    807:        if ((ent->client->newweapon) && (ent->client->weaponstate == WEAPON_READY))
                    808:        {
                    809:                ChangeWeapon (ent);
                    810:                return;
                    811:        }
                    812: 
                    813:        if (ent->client->weaponstate == WEAPON_ACTIVATING)
                    814:        {
                    815:                ent->client->weaponstate = WEAPON_READY;
                    816:                ent->client->ps.gunframe = FRAME_IDLE_FIRST;
                    817:                return;
                    818:        }
                    819: 
                    820:        if (ent->client->weaponstate == WEAPON_READY)
                    821:        {
                    822:                if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
                    823:                {
                    824:                        ent->client->latched_buttons &= ~BUTTON_ATTACK;
                    825:                        if (ent->client->pers.inventory[ent->client->ammo_index])
                    826:                        {
                    827:                                ent->client->ps.gunframe = 1;
                    828:                                ent->client->weaponstate = WEAPON_FIRING;
                    829:                                ent->client->grenade_time = 0;
                    830:                        }
                    831:                        else
                    832:                        {
                    833:                                if (level.time >= ent->pain_debounce_time)
                    834:                                {
                    835:                                        gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
                    836:                                        ent->pain_debounce_time = level.time + 1;
                    837:                                }
                    838:                                NoAmmoWeaponChange (ent);
                    839:                        }
                    840:                        return;
                    841:                }
                    842: 
                    843:                if (ent->client->ps.gunframe == FRAME_IDLE_LAST)
                    844:                {
                    845:                        ent->client->ps.gunframe = FRAME_IDLE_FIRST;
                    846:                        return;
                    847:                }
                    848: 
                    849:                if (pause_frames)
                    850:                {
                    851:                        for (n = 0; pause_frames[n]; n++)
                    852:                        {
                    853:                                if (ent->client->ps.gunframe == pause_frames[n])
                    854:                                {
                    855:                                        if (rand()&15)
                    856:                                                return;
                    857:                                }
                    858:                        }
                    859:                }
                    860: 
                    861:                ent->client->ps.gunframe++;
                    862:                return;
                    863:        }
                    864: 
                    865:        if (ent->client->weaponstate == WEAPON_FIRING)
                    866:        {
                    867:                if (ent->client->ps.gunframe == FRAME_THROW_SOUND)
                    868:                        gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/hgrena1b.wav"), 1, ATTN_NORM, 0);
                    869: 
                    870:                if (ent->client->ps.gunframe == FRAME_THROW_HOLD)
                    871:                {
                    872:                        if (!ent->client->grenade_time)
                    873:                        {
                    874:                                ent->client->grenade_time = level.time + GRENADE_TIMER + 0.2;
                    875:                                switch(ent->client->pers.weapon->tag)
                    876:                                {
                    877:                                        case AMMO_GRENADES:
                    878:                                                ent->client->weapon_sound = gi.soundindex("weapons/hgrenc1b.wav");
                    879:                                                break;
                    880:                                }
                    881:                        }
                    882: 
                    883:                        // they waited too long, detonate it in their hand
                    884:                        if (EXPLODE && !ent->client->grenade_blew_up && level.time >= ent->client->grenade_time)
                    885:                        {
                    886:                                ent->client->weapon_sound = 0;
                    887:                                fire (ent, true);
                    888:                                ent->client->grenade_blew_up = true;
                    889:                        }
                    890: 
                    891:                        if (ent->client->buttons & BUTTON_ATTACK)
                    892:                                return;
                    893: 
                    894:                        if (ent->client->grenade_blew_up)
                    895:                        {
                    896:                                if (level.time >= ent->client->grenade_time)
                    897:                                {
                    898:                                        ent->client->ps.gunframe = FRAME_FIRE_LAST;
                    899:                                        ent->client->grenade_blew_up = false;
                    900:                                }
                    901:                                else
                    902:                                {
                    903:                                        return;
                    904:                                }
                    905:                        }
                    906:                }
                    907: 
                    908:                if (ent->client->ps.gunframe == FRAME_THROW_FIRE)
                    909:                {
                    910:                        ent->client->weapon_sound = 0;
                    911:                        fire (ent, true);
                    912:                }
                    913: 
                    914:                if ((ent->client->ps.gunframe == FRAME_FIRE_LAST) && (level.time < ent->client->grenade_time))
                    915:                        return;
                    916: 
                    917:                ent->client->ps.gunframe++;
                    918: 
                    919:                if (ent->client->ps.gunframe == FRAME_IDLE_FIRST)
                    920:                {
                    921:                        ent->client->grenade_time = 0;
                    922:                        ent->client->weaponstate = WEAPON_READY;
                    923:                }
                    924:        }
                    925: }
                    926: 
                    927: //void Throw_Generic (edict_t *ent, int FRAME_FIRE_LAST, int FRAME_IDLE_LAST, int FRAME_THROW_SOUND,
                    928: //                                             int FRAME_THROW_HOLD, int FRAME_THROW_FIRE, int *pause_frames, 
                    929: //                                             int EXPLOSION_TIME, void (*fire)(edict_t *ent))
                    930: 
                    931: void Weapon_Grenade (edict_t *ent)
                    932: {
                    933:        static int      pause_frames[]  = {29,34,39,48,0};
                    934: 
                    935:        Throw_Generic (ent, 15, 48, 5, 11, 12, pause_frames, GRENADE_TIMER, weapon_grenade_fire);
                    936: }
                    937: 
                    938: void Weapon_Prox (edict_t *ent)
                    939: {
                    940:        static int      pause_frames[]  = {22, 29, 0};
                    941: 
                    942:        Throw_Generic (ent, 7, 27, 99, 2, 4, pause_frames, 0, weapon_grenade_fire);
                    943: }
                    944: 
                    945: void Weapon_Tesla (edict_t *ent)
                    946: {
                    947:        static int      pause_frames[]  = {21, 0};
                    948: 
                    949:        if ((ent->client->ps.gunframe > 1) && (ent->client->ps.gunframe < 9))
                    950:        {
                    951:                ent->client->ps.gunindex = gi.modelindex  ("models/weapons/v_tesla2/tris.md2");
                    952:        }
                    953:        else
                    954:        {
                    955:                ent->client->ps.gunindex = gi.modelindex  ("models/weapons/v_tesla/tris.md2");
                    956:        }
                    957: 
                    958:        Throw_Generic (ent, 8, 32, 99, 1, 2, pause_frames, 0, weapon_grenade_fire);
                    959: }
                    960: 
                    961: 
                    962: 
                    963: /*
                    964: ======================================================================
                    965: 
                    966: GRENADE LAUNCHER
                    967: 
                    968: ======================================================================
                    969: */
                    970: 
                    971: void weapon_grenadelauncher_fire (edict_t *ent)
                    972: {
                    973:        vec3_t  offset;
                    974:        vec3_t  forward, right;
                    975:        vec3_t  start;
                    976: //     int             damage = 120;
                    977:        int             damage;                 // PGM
                    978:        float   radius;
                    979: 
                    980: // =====
                    981: // PGM
                    982:        switch(ent->client->pers.weapon->tag)
                    983:        {
                    984:                case AMMO_PROX:
                    985:                        damage = 90;
                    986:                        break;
                    987:                default:
                    988:                        damage = 120;
                    989:                        break;
                    990:        }
                    991: // PGM
                    992: // =====
                    993: 
                    994:        radius = damage+40;
                    995:        if (is_quad)
                    996: //             damage *= 4;
                    997:                damage *= damage_multiplier;            //pgm
                    998: 
                    999:        VectorSet(offset, 8, 8, ent->viewheight-8);
                   1000:        AngleVectors (ent->client->v_angle, forward, right, NULL);
                   1001:        P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
                   1002: 
                   1003:        VectorScale (forward, -2, ent->client->kick_origin);
                   1004:        ent->client->kick_angles[0] = -1;
                   1005: 
                   1006: //     fire_grenade (ent, start, forward, damage, 600, 2.5, radius);
                   1007: // =====
                   1008: // PGM
                   1009:        switch(ent->client->pers.weapon->tag)
                   1010:        {
                   1011:                case AMMO_PROX:
                   1012:                        fire_prox (ent, start, forward, damage_multiplier, 600);
                   1013:                        break;
                   1014:                default:
                   1015:                        fire_grenade (ent, start, forward, damage, 600, 2.5, radius);
                   1016:                        break;
                   1017:        }
                   1018: // PGM
                   1019: // =====
                   1020: 
                   1021:        gi.WriteByte (svc_muzzleflash);
                   1022:        gi.WriteShort (ent-g_edicts);
                   1023:        gi.WriteByte (MZ_GRENADE | is_silenced);
                   1024:        gi.multicast (ent->s.origin, MULTICAST_PVS);
                   1025: 
                   1026:        ent->client->ps.gunframe++;
                   1027: 
                   1028:        PlayerNoise(ent, start, PNOISE_WEAPON);
                   1029: 
                   1030:        if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                   1031:                ent->client->pers.inventory[ent->client->ammo_index]--;
                   1032: }
                   1033: 
                   1034: void Weapon_GrenadeLauncher (edict_t *ent)
                   1035: {
                   1036:        static int      pause_frames[]  = {34, 51, 59, 0};
                   1037:        static int      fire_frames[]   = {6, 0};
                   1038: 
                   1039:        Weapon_Generic (ent, 5, 16, 59, 64, pause_frames, fire_frames, weapon_grenadelauncher_fire);
                   1040: }
                   1041: 
                   1042: //==========
                   1043: //PGM
                   1044: void Weapon_ProxLauncher (edict_t *ent)
                   1045: {
                   1046:        static int      pause_frames[]  = {34, 51, 59, 0};
                   1047:        static int      fire_frames[]   = {6, 0};
                   1048: 
                   1049:        Weapon_Generic (ent, 5, 16, 59, 64, pause_frames, fire_frames, weapon_grenadelauncher_fire);
                   1050: }
                   1051: //PGM
                   1052: //==========
                   1053: 
                   1054: /*
                   1055: ======================================================================
                   1056: 
                   1057: ROCKET
                   1058: 
                   1059: ======================================================================
                   1060: */
                   1061: 
                   1062: void Weapon_RocketLauncher_Fire (edict_t *ent)
                   1063: {
                   1064:        vec3_t  offset, start;
                   1065:        vec3_t  forward, right;
                   1066:        int             damage;
                   1067:        float   damage_radius;
                   1068:        int             radius_damage;
                   1069: 
                   1070:        damage = 100 + (int)(random() * 20.0);
                   1071:        radius_damage = 120;
                   1072:        damage_radius = 120;
                   1073:        if (is_quad)
                   1074:        {
                   1075: //PGM
                   1076: //             damage *= 4;
                   1077:                damage *= damage_multiplier;
                   1078: //             radius_damage *= 4;
                   1079:                radius_damage *= damage_multiplier;
                   1080: //PGM
                   1081:        }
                   1082: 
                   1083:        AngleVectors (ent->client->v_angle, forward, right, NULL);
                   1084: 
                   1085:        VectorScale (forward, -2, ent->client->kick_origin);
                   1086:        ent->client->kick_angles[0] = -1;
                   1087: 
                   1088:        VectorSet(offset, 8, 8, ent->viewheight-8);
                   1089:        P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
                   1090:        fire_rocket (ent, start, forward, damage, 650, damage_radius, radius_damage);
                   1091: 
                   1092:        // send muzzle flash
                   1093:        gi.WriteByte (svc_muzzleflash);
                   1094:        gi.WriteShort (ent-g_edicts);
                   1095:        gi.WriteByte (MZ_ROCKET | is_silenced);
                   1096:        gi.multicast (ent->s.origin, MULTICAST_PVS);
                   1097: 
                   1098:        ent->client->ps.gunframe++;
                   1099: 
                   1100:        PlayerNoise(ent, start, PNOISE_WEAPON);
                   1101: 
                   1102:        if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                   1103:                ent->client->pers.inventory[ent->client->ammo_index]--;
                   1104: }
                   1105: 
                   1106: void Weapon_RocketLauncher (edict_t *ent)
                   1107: {
                   1108:        static int      pause_frames[]  = {25, 33, 42, 50, 0};
                   1109:        static int      fire_frames[]   = {5, 0};
                   1110: 
                   1111:        Weapon_Generic (ent, 4, 12, 50, 54, pause_frames, fire_frames, Weapon_RocketLauncher_Fire);
                   1112: }
                   1113: 
                   1114: 
                   1115: /*
                   1116: ======================================================================
                   1117: 
                   1118: BLASTER / HYPERBLASTER
                   1119: 
                   1120: ======================================================================
                   1121: */
                   1122: 
                   1123: void Blaster_Fire (edict_t *ent, vec3_t g_offset, int damage, qboolean hyper, int effect)
                   1124: {
                   1125:        vec3_t  forward, right;
                   1126:        vec3_t  start;
                   1127:        vec3_t  offset;
                   1128: 
                   1129:        if (is_quad)
                   1130: //             damage *= 4;            
                   1131:                damage *= damage_multiplier;            //pgm
                   1132: 
                   1133:        AngleVectors (ent->client->v_angle, forward, right, NULL);
                   1134:        VectorSet(offset, 24, 8, ent->viewheight-8);
                   1135:        VectorAdd (offset, g_offset, offset);
                   1136:        P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
                   1137: 
                   1138:        VectorScale (forward, -2, ent->client->kick_origin);
                   1139:        ent->client->kick_angles[0] = -1;
                   1140: 
                   1141:        fire_blaster (ent, start, forward, damage, 1000, effect, hyper);
                   1142: 
                   1143:        // send muzzle flash
                   1144:        gi.WriteByte (svc_muzzleflash);
                   1145:        gi.WriteShort (ent-g_edicts);
                   1146:        if (hyper)
                   1147:                gi.WriteByte (MZ_HYPERBLASTER | is_silenced);
                   1148:        else
                   1149:                gi.WriteByte (MZ_BLASTER | is_silenced);
                   1150:        gi.multicast (ent->s.origin, MULTICAST_PVS);
                   1151: 
                   1152:        PlayerNoise(ent, start, PNOISE_WEAPON);
                   1153: }
                   1154: 
                   1155: 
                   1156: void Weapon_Blaster_Fire (edict_t *ent)
                   1157: {
                   1158:        int             damage;
                   1159: 
                   1160:        if (deathmatch->value)
                   1161:                damage = 15;
                   1162:        else
                   1163:                damage = 10;
                   1164:        Blaster_Fire (ent, vec3_origin, damage, false, EF_BLASTER);
                   1165:        ent->client->ps.gunframe++;
                   1166: }
                   1167: 
                   1168: void Weapon_Blaster (edict_t *ent)
                   1169: {
                   1170:        static int      pause_frames[]  = {19, 32, 0};
                   1171:        static int      fire_frames[]   = {5, 0};
                   1172: 
                   1173:        Weapon_Generic (ent, 4, 8, 52, 55, pause_frames, fire_frames, Weapon_Blaster_Fire);
                   1174: }
                   1175: 
                   1176: 
                   1177: void Weapon_HyperBlaster_Fire (edict_t *ent)
                   1178: {
                   1179:        float   rotation;
                   1180:        vec3_t  offset;
                   1181:        int             effect;
                   1182:        int             damage;
                   1183: 
                   1184:        ent->client->weapon_sound = gi.soundindex("weapons/hyprbl1a.wav");
                   1185: 
                   1186:        if (!(ent->client->buttons & BUTTON_ATTACK))
                   1187:        {
                   1188:                ent->client->ps.gunframe++;
                   1189:        }
                   1190:        else
                   1191:        {
                   1192:                if (! ent->client->pers.inventory[ent->client->ammo_index] )
                   1193:                {
                   1194:                        if (level.time >= ent->pain_debounce_time)
                   1195:                        {
                   1196:                                gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
                   1197:                                ent->pain_debounce_time = level.time + 1;
                   1198:                        }
                   1199:                        NoAmmoWeaponChange (ent);
                   1200:                }
                   1201:                else
                   1202:                {
                   1203:                        rotation = (ent->client->ps.gunframe - 5) * 2*M_PI/6;
                   1204:                        offset[0] = -4 * sin(rotation);
                   1205:                        offset[1] = 0;
                   1206:                        offset[2] = 4 * cos(rotation);
                   1207: 
                   1208:                        if ((ent->client->ps.gunframe == 6) || (ent->client->ps.gunframe == 9))
                   1209:                                effect = EF_HYPERBLASTER;
                   1210:                        else
                   1211:                                effect = 0;
                   1212:                        if (deathmatch->value)
                   1213:                                damage = 15;
                   1214:                        else
                   1215:                                damage = 20;
                   1216:                        Blaster_Fire (ent, offset, damage, true, effect);
                   1217:                        if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                   1218:                                ent->client->pers.inventory[ent->client->ammo_index]--;
                   1219: 
                   1220:                        ent->client->anim_priority = ANIM_ATTACK;
                   1221:                        if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
                   1222:                        {
                   1223:                                ent->s.frame = FRAME_crattak1 - 1;
                   1224:                                ent->client->anim_end = FRAME_crattak9;
                   1225:                        }
                   1226:                        else
                   1227:                        {
                   1228:                                ent->s.frame = FRAME_attack1 - 1;
                   1229:                                ent->client->anim_end = FRAME_attack8;
                   1230:                        }
                   1231:                }
                   1232: 
                   1233:                ent->client->ps.gunframe++;
                   1234:                if (ent->client->ps.gunframe == 12 && ent->client->pers.inventory[ent->client->ammo_index])
                   1235:                        ent->client->ps.gunframe = 6;
                   1236:        }
                   1237: 
                   1238:        if (ent->client->ps.gunframe == 12)
                   1239:        {
                   1240:                gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/hyprbd1a.wav"), 1, ATTN_NORM, 0);
                   1241:                ent->client->weapon_sound = 0;
                   1242:        }
                   1243: 
                   1244: }
                   1245: 
                   1246: void Weapon_HyperBlaster (edict_t *ent)
                   1247: {
                   1248:        static int      pause_frames[]  = {0};
                   1249:        static int      fire_frames[]   = {6, 7, 8, 9, 10, 11, 0};
                   1250: 
                   1251:        Weapon_Generic (ent, 5, 20, 49, 53, pause_frames, fire_frames, Weapon_HyperBlaster_Fire);
                   1252: }
                   1253: 
                   1254: /*
                   1255: ======================================================================
                   1256: 
                   1257: MACHINEGUN / CHAINGUN
                   1258: 
                   1259: ======================================================================
                   1260: */
                   1261: 
                   1262: void Machinegun_Fire (edict_t *ent)
                   1263: {
                   1264:        int     i;
                   1265:        vec3_t          start;
                   1266:        vec3_t          forward, right;
                   1267:        vec3_t          angles;
                   1268:        int                     damage = 8;
                   1269:        int                     kick = 2;
                   1270:        vec3_t          offset;
                   1271: 
                   1272:        if (!(ent->client->buttons & BUTTON_ATTACK))
                   1273:        {
                   1274:                ent->client->machinegun_shots = 0;
                   1275:                ent->client->ps.gunframe++;
                   1276:                return;
                   1277:        }
                   1278: 
                   1279:        if (ent->client->ps.gunframe == 5)
                   1280:                ent->client->ps.gunframe = 4;
                   1281:        else
                   1282:                ent->client->ps.gunframe = 5;
                   1283: 
                   1284:        if (ent->client->pers.inventory[ent->client->ammo_index] < 1)
                   1285:        {
                   1286:                ent->client->ps.gunframe = 6;
                   1287:                if (level.time >= ent->pain_debounce_time)
                   1288:                {
                   1289:                        gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
                   1290:                        ent->pain_debounce_time = level.time + 1;
                   1291:                }
                   1292:                NoAmmoWeaponChange (ent);
                   1293:                return;
                   1294:        }
                   1295: 
                   1296:        if (is_quad)
                   1297:        {
                   1298: //PGM
                   1299: //             damage *= 4;
                   1300:                damage *= damage_multiplier;
                   1301: //             kick *= 4;
                   1302:                kick *= damage_multiplier;
                   1303: //PGM
                   1304:        }
                   1305: 
                   1306:        for (i=1 ; i<3 ; i++)
                   1307:        {
                   1308:                ent->client->kick_origin[i] = crandom() * 0.35;
                   1309:                ent->client->kick_angles[i] = crandom() * 0.7;
                   1310:        }
                   1311:        ent->client->kick_origin[0] = crandom() * 0.35;
                   1312:        ent->client->kick_angles[0] = ent->client->machinegun_shots * -1.5;
                   1313: 
                   1314:        // raise the gun as it is firing
                   1315:        if (!deathmatch->value)
                   1316:        {
                   1317:                ent->client->machinegun_shots++;
                   1318:                if (ent->client->machinegun_shots > 9)
                   1319:                        ent->client->machinegun_shots = 9;
                   1320:        }
                   1321: 
                   1322:        // get start / end positions
                   1323:        VectorAdd (ent->client->v_angle, ent->client->kick_angles, angles);
                   1324:        AngleVectors (angles, forward, right, NULL);
                   1325:        VectorSet(offset, 0, 8, ent->viewheight-8);
                   1326:        P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
                   1327:        fire_bullet (ent, start, forward, damage, kick, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MOD_MACHINEGUN);
                   1328: 
                   1329:        gi.WriteByte (svc_muzzleflash);
                   1330:        gi.WriteShort (ent-g_edicts);
                   1331:        gi.WriteByte (MZ_MACHINEGUN | is_silenced);
                   1332:        gi.multicast (ent->s.origin, MULTICAST_PVS);
                   1333: 
                   1334:        PlayerNoise(ent, start, PNOISE_WEAPON);
                   1335: 
                   1336:        if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                   1337:                ent->client->pers.inventory[ent->client->ammo_index]--;
                   1338: 
                   1339:        ent->client->anim_priority = ANIM_ATTACK;
                   1340:        if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
                   1341:        {
                   1342:                ent->s.frame = FRAME_crattak1 - (int) (random()+0.25);
                   1343:                ent->client->anim_end = FRAME_crattak9;
                   1344:        }
                   1345:        else
                   1346:        {
                   1347:                ent->s.frame = FRAME_attack1 - (int) (random()+0.25);
                   1348:                ent->client->anim_end = FRAME_attack8;
                   1349:        }
                   1350: }
                   1351: 
                   1352: void Weapon_Machinegun (edict_t *ent)
                   1353: {
                   1354:        static int      pause_frames[]  = {23, 45, 0};
                   1355:        static int      fire_frames[]   = {4, 5, 0};
                   1356: 
                   1357:        Weapon_Generic (ent, 3, 5, 45, 49, pause_frames, fire_frames, Machinegun_Fire);
                   1358: }
                   1359: 
                   1360: void Chaingun_Fire (edict_t *ent)
                   1361: {
                   1362:        int                     i;
                   1363:        int                     shots;
                   1364:        vec3_t          start;
                   1365:        vec3_t          forward, right, up;
                   1366:        float           r, u;
                   1367:        vec3_t          offset;
                   1368:        int                     damage;
                   1369:        int                     kick = 2;
                   1370: 
                   1371:        if (deathmatch->value)
                   1372:                damage = 6;
                   1373:        else
                   1374:                damage = 8;
                   1375: 
                   1376:        if (ent->client->ps.gunframe == 5)
                   1377:                gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnu1a.wav"), 1, ATTN_IDLE, 0);
                   1378: 
                   1379:        if ((ent->client->ps.gunframe == 14) && !(ent->client->buttons & BUTTON_ATTACK))
                   1380:        {
                   1381:                ent->client->ps.gunframe = 32;
                   1382:                ent->client->weapon_sound = 0;
                   1383:                return;
                   1384:        }
                   1385:        else if ((ent->client->ps.gunframe == 21) && (ent->client->buttons & BUTTON_ATTACK)
                   1386:                && ent->client->pers.inventory[ent->client->ammo_index])
                   1387:        {
                   1388:                ent->client->ps.gunframe = 15;
                   1389:        }
                   1390:        else
                   1391:        {
                   1392:                ent->client->ps.gunframe++;
                   1393:        }
                   1394: 
                   1395:        if (ent->client->ps.gunframe == 22)
                   1396:        {
                   1397:                ent->client->weapon_sound = 0;
                   1398:                gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnd1a.wav"), 1, ATTN_IDLE, 0);
                   1399:        }
                   1400:        else
                   1401:        {
                   1402:                ent->client->weapon_sound = gi.soundindex("weapons/chngnl1a.wav");
                   1403:        }
                   1404: 
                   1405:        ent->client->anim_priority = ANIM_ATTACK;
                   1406:        if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
                   1407:        {
                   1408:                ent->s.frame = FRAME_crattak1 - (ent->client->ps.gunframe & 1);
                   1409:                ent->client->anim_end = FRAME_crattak9;
                   1410:        }
                   1411:        else
                   1412:        {
                   1413:                ent->s.frame = FRAME_attack1 - (ent->client->ps.gunframe & 1);
                   1414:                ent->client->anim_end = FRAME_attack8;
                   1415:        }
                   1416: 
                   1417:        if (ent->client->ps.gunframe <= 9)
                   1418:                shots = 1;
                   1419:        else if (ent->client->ps.gunframe <= 14)
                   1420:        {
                   1421:                if (ent->client->buttons & BUTTON_ATTACK)
                   1422:                        shots = 2;
                   1423:                else
                   1424:                        shots = 1;
                   1425:        }
                   1426:        else
                   1427:                shots = 3;
                   1428: 
                   1429:        if (ent->client->pers.inventory[ent->client->ammo_index] < shots)
                   1430:                shots = ent->client->pers.inventory[ent->client->ammo_index];
                   1431: 
                   1432:        if (!shots)
                   1433:        {
                   1434:                if (level.time >= ent->pain_debounce_time)
                   1435:                {
                   1436:                        gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
                   1437:                        ent->pain_debounce_time = level.time + 1;
                   1438:                }
                   1439:                NoAmmoWeaponChange (ent);
                   1440:                return;
                   1441:        }
                   1442: 
                   1443:        if (is_quad)
                   1444:        {
                   1445: //PGM
                   1446: //             damage *= 4;
                   1447:                damage *= damage_multiplier;
                   1448: //             kick *= 4;
                   1449:                kick *= damage_multiplier;
                   1450: //PGM
                   1451:        }
                   1452: 
                   1453:        for (i=0 ; i<3 ; i++)
                   1454:        {
                   1455:                ent->client->kick_origin[i] = crandom() * 0.35;
                   1456:                ent->client->kick_angles[i] = crandom() * 0.7;
                   1457:        }
                   1458: 
                   1459:        for (i=0 ; i<shots ; i++)
                   1460:        {
                   1461:                // get start / end positions
                   1462:                AngleVectors (ent->client->v_angle, forward, right, up);
                   1463:                r = 7 + crandom()*4;
                   1464:                u = crandom()*4;
                   1465:                VectorSet(offset, 0, r, u + ent->viewheight-8);
                   1466:                P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
                   1467: 
                   1468:                fire_bullet (ent, start, forward, damage, kick, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MOD_CHAINGUN);
                   1469:        }
                   1470: 
                   1471:        // send muzzle flash
                   1472:        gi.WriteByte (svc_muzzleflash);
                   1473:        gi.WriteShort (ent-g_edicts);
                   1474:        gi.WriteByte ((MZ_CHAINGUN1 + shots - 1) | is_silenced);
                   1475:        gi.multicast (ent->s.origin, MULTICAST_PVS);
                   1476: 
                   1477:        PlayerNoise(ent, start, PNOISE_WEAPON);
                   1478: 
                   1479:        if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                   1480:                ent->client->pers.inventory[ent->client->ammo_index] -= shots;
                   1481: }
                   1482: 
                   1483: 
                   1484: void Weapon_Chaingun (edict_t *ent)
                   1485: {
                   1486:        static int      pause_frames[]  = {38, 43, 51, 61, 0};
                   1487:        static int      fire_frames[]   = {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0};
                   1488: 
                   1489:        Weapon_Generic (ent, 4, 31, 61, 64, pause_frames, fire_frames, Chaingun_Fire);
                   1490: }
                   1491: 
                   1492: 
                   1493: /*
                   1494: ======================================================================
                   1495: 
                   1496: SHOTGUN / SUPERSHOTGUN
                   1497: 
                   1498: ======================================================================
                   1499: */
                   1500: 
                   1501: void weapon_shotgun_fire (edict_t *ent)
                   1502: {
                   1503:        vec3_t          start;
                   1504:        vec3_t          forward, right;
                   1505:        vec3_t          offset;
                   1506:        int                     damage = 4;
                   1507:        int                     kick = 8;
                   1508: 
                   1509:        if (ent->client->ps.gunframe == 9)
                   1510:        {
                   1511:                ent->client->ps.gunframe++;
                   1512:                return;
                   1513:        }
                   1514: 
                   1515:        AngleVectors (ent->client->v_angle, forward, right, NULL);
                   1516: 
                   1517:        VectorScale (forward, -2, ent->client->kick_origin);
                   1518:        ent->client->kick_angles[0] = -2;
                   1519: 
                   1520:        VectorSet(offset, 0, 8,  ent->viewheight-8);
                   1521:        P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
                   1522: 
                   1523:        if (is_quad)
                   1524:        {
                   1525: //PGM
                   1526: //             damage *= 4;
                   1527:                damage *= damage_multiplier;
                   1528: //             kick *= 4;
                   1529:                kick *= damage_multiplier;
                   1530: //PGM
                   1531:        }
                   1532: 
                   1533:        if (deathmatch->value)
                   1534:                fire_shotgun (ent, start, forward, damage, kick, 500, 500, DEFAULT_DEATHMATCH_SHOTGUN_COUNT, MOD_SHOTGUN);
                   1535:        else
                   1536:                fire_shotgun (ent, start, forward, damage, kick, 500, 500, DEFAULT_SHOTGUN_COUNT, MOD_SHOTGUN);
                   1537: 
                   1538:        // send muzzle flash
                   1539:        gi.WriteByte (svc_muzzleflash);
                   1540:        gi.WriteShort (ent-g_edicts);
                   1541:        gi.WriteByte (MZ_SHOTGUN | is_silenced);
                   1542:        gi.multicast (ent->s.origin, MULTICAST_PVS);
                   1543: 
                   1544:        ent->client->ps.gunframe++;
                   1545:        PlayerNoise(ent, start, PNOISE_WEAPON);
                   1546: 
                   1547:        if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                   1548:                ent->client->pers.inventory[ent->client->ammo_index]--;
                   1549: }
                   1550: 
                   1551: void Weapon_Shotgun (edict_t *ent)
                   1552: {
                   1553:        static int      pause_frames[]  = {22, 28, 34, 0};
                   1554:        static int      fire_frames[]   = {8, 9, 0};
                   1555: 
                   1556:        Weapon_Generic (ent, 7, 18, 36, 39, pause_frames, fire_frames, weapon_shotgun_fire);
                   1557: }
                   1558: 
                   1559: 
                   1560: void weapon_supershotgun_fire (edict_t *ent)
                   1561: {
                   1562:        vec3_t          start;
                   1563:        vec3_t          forward, right;
                   1564:        vec3_t          offset;
                   1565:        vec3_t          v;
                   1566:        int                     damage = 6;
                   1567:        int                     kick = 12;
                   1568: 
                   1569:        AngleVectors (ent->client->v_angle, forward, right, NULL);
                   1570: 
                   1571:        VectorScale (forward, -2, ent->client->kick_origin);
                   1572:        ent->client->kick_angles[0] = -2;
                   1573: 
                   1574:        VectorSet(offset, 0, 8,  ent->viewheight-8);
                   1575:        P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
                   1576: 
                   1577:        if (is_quad)
                   1578:        {
                   1579: //PGM
                   1580: //             damage *= 4;
                   1581:                damage *= damage_multiplier;
                   1582: //             kick *= 4;
                   1583:                kick *= damage_multiplier;
                   1584: //PGM
                   1585:        }
                   1586: 
                   1587:        v[PITCH] = ent->client->v_angle[PITCH];
                   1588:        v[YAW]   = ent->client->v_angle[YAW] - 5;
                   1589:        v[ROLL]  = ent->client->v_angle[ROLL];
                   1590:        AngleVectors (v, forward, NULL, NULL);
                   1591:        fire_shotgun (ent, start, forward, damage, kick, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT/2, MOD_SSHOTGUN);
                   1592:        v[YAW]   = ent->client->v_angle[YAW] + 5;
                   1593:        AngleVectors (v, forward, NULL, NULL);
                   1594:        fire_shotgun (ent, start, forward, damage, kick, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT/2, MOD_SSHOTGUN);
                   1595: 
                   1596:        // send muzzle flash
                   1597:        gi.WriteByte (svc_muzzleflash);
                   1598:        gi.WriteShort (ent-g_edicts);
                   1599:        gi.WriteByte (MZ_SSHOTGUN | is_silenced);
                   1600:        gi.multicast (ent->s.origin, MULTICAST_PVS);
                   1601: 
                   1602:        ent->client->ps.gunframe++;
                   1603:        PlayerNoise(ent, start, PNOISE_WEAPON);
                   1604: 
                   1605:        if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                   1606:                ent->client->pers.inventory[ent->client->ammo_index] -= 2;
                   1607: }
                   1608: 
                   1609: void Weapon_SuperShotgun (edict_t *ent)
                   1610: {
                   1611:        static int      pause_frames[]  = {29, 42, 57, 0};
                   1612:        static int      fire_frames[]   = {7, 0};
                   1613: 
                   1614:        Weapon_Generic (ent, 6, 17, 57, 61, pause_frames, fire_frames, weapon_supershotgun_fire);
                   1615: }
                   1616: 
                   1617: 
                   1618: 
                   1619: /*
                   1620: ======================================================================
                   1621: 
                   1622: RAILGUN
                   1623: 
                   1624: ======================================================================
                   1625: */
                   1626: 
                   1627: void weapon_railgun_fire (edict_t *ent)
                   1628: {
                   1629:        vec3_t          start;
                   1630:        vec3_t          forward, right;
                   1631:        vec3_t          offset;
                   1632:        int                     damage;
                   1633:        int                     kick;
                   1634: 
                   1635:        if (deathmatch->value)
                   1636:        {       // normal damage is too extreme in dm
                   1637:                damage = 100;
                   1638:                kick = 200;
                   1639:        }
                   1640:        else
                   1641:        {
                   1642:                damage = 150;
                   1643:                kick = 250;
                   1644:        }
                   1645: 
                   1646:        if (is_quad)
                   1647:        {
                   1648: //PGM
                   1649: //             damage *= 4;
                   1650:                damage *= damage_multiplier;
                   1651: //             kick *= 4;
                   1652:                kick *= damage_multiplier;
                   1653: //PGM
                   1654:        }
                   1655: 
                   1656:        AngleVectors (ent->client->v_angle, forward, right, NULL);
                   1657: 
                   1658:        VectorScale (forward, -3, ent->client->kick_origin);
                   1659:        ent->client->kick_angles[0] = -3;
                   1660: 
                   1661:        VectorSet(offset, 0, 7,  ent->viewheight-8);
                   1662:        P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
                   1663:        fire_rail (ent, start, forward, damage, kick);
                   1664: 
                   1665:        // send muzzle flash
                   1666:        gi.WriteByte (svc_muzzleflash);
                   1667:        gi.WriteShort (ent-g_edicts);
                   1668:        gi.WriteByte (MZ_RAILGUN | is_silenced);
                   1669:        gi.multicast (ent->s.origin, MULTICAST_PVS);
                   1670: 
                   1671:        ent->client->ps.gunframe++;
                   1672:        PlayerNoise(ent, start, PNOISE_WEAPON);
                   1673: 
                   1674:        if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                   1675:                ent->client->pers.inventory[ent->client->ammo_index]--;
                   1676: }
                   1677: 
                   1678: 
                   1679: void Weapon_Railgun (edict_t *ent)
                   1680: {
                   1681:        static int      pause_frames[]  = {56, 0};
                   1682:        static int      fire_frames[]   = {4, 0};
                   1683: 
                   1684:        Weapon_Generic (ent, 3, 18, 56, 61, pause_frames, fire_frames, weapon_railgun_fire);
                   1685: }
                   1686: 
                   1687: 
                   1688: /*
                   1689: ======================================================================
                   1690: 
                   1691: BFG10K
                   1692: 
                   1693: ======================================================================
                   1694: */
                   1695: 
                   1696: void weapon_bfg_fire (edict_t *ent)
                   1697: {
                   1698:        vec3_t  offset, start;
                   1699:        vec3_t  forward, right;
                   1700:        int             damage;
                   1701:        float   damage_radius = 1000;
                   1702: 
                   1703:        if (deathmatch->value)
                   1704:                damage = 200;
                   1705:        else
                   1706:                damage = 500;
                   1707: 
                   1708:        if (ent->client->ps.gunframe == 9)
                   1709:        {
                   1710:                // send muzzle flash
                   1711:                gi.WriteByte (svc_muzzleflash);
                   1712:                gi.WriteShort (ent-g_edicts);
                   1713:                gi.WriteByte (MZ_BFG | is_silenced);
                   1714:                gi.multicast (ent->s.origin, MULTICAST_PVS);
                   1715: 
                   1716:                ent->client->ps.gunframe++;
                   1717: 
                   1718:                PlayerNoise(ent, start, PNOISE_WEAPON);
                   1719:                return;
                   1720:        }
                   1721: 
                   1722:        // cells can go down during windup (from power armor hits), so
                   1723:        // check again and abort firing if we don't have enough now
                   1724:        if (ent->client->pers.inventory[ent->client->ammo_index] < 50)
                   1725:        {
                   1726:                ent->client->ps.gunframe++;
                   1727:                return;
                   1728:        }
                   1729: 
                   1730:        if (is_quad)
                   1731: //PGM
                   1732: //             damage *= 4;
                   1733:                damage *= damage_multiplier;
                   1734: //PGM
                   1735: 
                   1736:        AngleVectors (ent->client->v_angle, forward, right, NULL);
                   1737: 
                   1738:        VectorScale (forward, -2, ent->client->kick_origin);
                   1739: 
                   1740:        // make a big pitch kick with an inverse fall
                   1741:        ent->client->v_dmg_pitch = -40;
                   1742:        ent->client->v_dmg_roll = crandom()*8;
                   1743:        ent->client->v_dmg_time = level.time + DAMAGE_TIME;
                   1744: 
                   1745:        VectorSet(offset, 8, 8, ent->viewheight-8);
                   1746:        P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
                   1747:        fire_bfg (ent, start, forward, damage, 400, damage_radius);
                   1748: 
                   1749:        ent->client->ps.gunframe++;
                   1750: 
                   1751:        PlayerNoise(ent, start, PNOISE_WEAPON);
                   1752: 
                   1753:        if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                   1754:                ent->client->pers.inventory[ent->client->ammo_index] -= 50;
                   1755: }
                   1756: 
                   1757: void Weapon_BFG (edict_t *ent)
                   1758: {
                   1759:        static int      pause_frames[]  = {39, 45, 50, 55, 0};
                   1760:        static int      fire_frames[]   = {9, 17, 0};
                   1761: 
                   1762:        Weapon_Generic (ent, 8, 32, 55, 58, pause_frames, fire_frames, weapon_bfg_fire);
                   1763: }
                   1764: 
                   1765: 
                   1766: //======================================================================
                   1767: // ROGUE MODS BELOW
                   1768: //======================================================================
                   1769: 
                   1770: 
                   1771: //
                   1772: // CHAINFIST
                   1773: //
                   1774: #define CHAINFIST_REACH 64
                   1775: 
                   1776: void weapon_chainfist_fire (edict_t *ent)
                   1777: {
                   1778:        vec3_t  offset;
                   1779:        vec3_t  forward, right, up;
                   1780:        vec3_t  start;
                   1781:        int             damage;
                   1782: 
                   1783:        damage = 15;
                   1784:        if(deathmatch->value)
                   1785:                damage = 30;
                   1786: 
                   1787:        if (is_quad)
                   1788:                damage *= damage_multiplier;
                   1789: 
                   1790:        AngleVectors (ent->client->v_angle, forward, right, up);
                   1791: 
                   1792:        // kick back
                   1793:        VectorScale (forward, -2, ent->client->kick_origin);
                   1794:        ent->client->kick_angles[0] = -1;
                   1795: 
                   1796:        // set start point
                   1797:        VectorSet(offset, 0, 8, ent->viewheight-4);
                   1798:        P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
                   1799: 
                   1800:        fire_player_melee (ent, start, forward, CHAINFIST_REACH, damage, 100, 1, MOD_CHAINFIST);
                   1801: 
                   1802:        PlayerNoise(ent, start, PNOISE_WEAPON);
                   1803: 
                   1804:        ent->client->ps.gunframe++;
                   1805:        ent->client->pers.inventory[ent->client->ammo_index] -= ent->client->pers.weapon->quantity;
                   1806: }
                   1807: 
                   1808: // this spits out some smoke from the motor. it's a two-stroke, you know.
                   1809: void chainfist_smoke (edict_t *ent)
                   1810: {
                   1811:        vec3_t  tempVec, forward, right, up;
                   1812:        vec3_t  offset;
                   1813: 
                   1814:        AngleVectors(ent->client->v_angle, forward, right, up);
                   1815:        VectorSet(offset, 8, 8, ent->viewheight -4);
                   1816:        P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, tempVec);
                   1817: 
                   1818:        gi.WriteByte (svc_temp_entity);
                   1819:        gi.WriteByte (TE_CHAINFIST_SMOKE);
                   1820:        gi.WritePosition (tempVec);
                   1821:        gi.unicast (ent, 0);
                   1822:        // FIXME - this should probably only go to the owner unless we decide to
                   1823:        //              add the visible weapons patch
                   1824: }
                   1825: 
                   1826: #define HOLD_FRAMES                    0
                   1827: 
                   1828: void Weapon_ChainFist (edict_t *ent)
                   1829: {
                   1830:        static int      pause_frames[]  = {0};
                   1831:        static int      fire_frames[]   = {8, 9, 16, 17, 18, 30, 31, 0};
                   1832: 
                   1833:        // these are caches for the sound index. there's probably a better way to do this.
                   1834: //     static int      idle_index;
                   1835: //     static int      attack_index;
                   1836:        float           chance;
                   1837:        int                     last_sequence;
                   1838:        
                   1839:        last_sequence = 0;
                   1840: 
                   1841:        // load chainsaw sounds and store the indexes for later use.
                   1842: //     if(!idle_index && !attack_index)
                   1843: //     {
                   1844: //             idle_index = gi.soundindex("weapons/sawidle.wav");
                   1845: //             attack_index = gi.soundindex("weapons/sawhit.wav");
                   1846: //     }
                   1847: 
                   1848:        if(ent->client->ps.gunframe == 13 ||
                   1849:                ent->client->ps.gunframe == 23)                 // end of attack, go idle
                   1850:                ent->client->ps.gunframe = 32;
                   1851: 
                   1852: #if HOLD_FRAMES
                   1853:        else if(ent->client->ps.gunframe == 9 && ((ent->client->buttons) & BUTTON_ATTACK))
                   1854:                ent->client->ps.gunframe = 7;
                   1855:        else if(ent->client->ps.gunframe == 18 && ((ent->client->buttons) & BUTTON_ATTACK))
                   1856:                ent->client->ps.gunframe = 16;
                   1857: #endif
                   1858: 
                   1859:        // holds for idle sequence
                   1860:        else if(ent->client->ps.gunframe == 42 && (rand()&7))
                   1861:        {
                   1862:                if((ent->client->pers.hand != CENTER_HANDED) && random() < 0.4)
                   1863:                        chainfist_smoke(ent);
                   1864: //             ent->client->ps.gunframe = 40;
                   1865:        }
                   1866:        else if(ent->client->ps.gunframe == 51 && (rand()&7))
                   1867:        {
                   1868:                if((ent->client->pers.hand != CENTER_HANDED) && random() < 0.4)
                   1869:                        chainfist_smoke(ent);
                   1870: //             ent->client->ps.gunframe = 49;
                   1871:        }       
                   1872: 
                   1873:        // set the appropriate weapon sound.
                   1874:        if(ent->client->weaponstate == WEAPON_FIRING)
                   1875: //             ent->client->weapon_sound = attack_index;
                   1876:                ent->client->weapon_sound = gi.soundindex("weapons/sawhit.wav");
                   1877:        else if(ent->client->weaponstate == WEAPON_DROPPING)
                   1878:                ent->client->weapon_sound = 0;
                   1879:        else
                   1880: //             ent->client->weapon_sound = idle_index;
                   1881:                ent->client->weapon_sound = gi.soundindex("weapons/sawidle.wav");
                   1882: 
                   1883:        Weapon_Generic (ent, 4, 32, 57, 60, pause_frames, fire_frames, weapon_chainfist_fire);
                   1884: 
                   1885: //     gi.dprintf("chainfist %d\n", ent->client->ps.gunframe);
                   1886:        if((ent->client->buttons) & BUTTON_ATTACK)
                   1887:        {
                   1888:                if(ent->client->ps.gunframe == 13 ||
                   1889:                        ent->client->ps.gunframe == 23 ||
                   1890:                        ent->client->ps.gunframe == 32)
                   1891:                {
                   1892:                        last_sequence = ent->client->ps.gunframe;
                   1893:                        ent->client->ps.gunframe = 6;
                   1894:                }
                   1895:        }
                   1896: 
                   1897:        if (ent->client->ps.gunframe == 6)
                   1898:        {
                   1899:                chance = random();
                   1900:                if(last_sequence == 13)                 // if we just did sequence 1, do 2 or 3.
                   1901:                        chance -= 0.34;
                   1902:                else if(last_sequence == 23)    // if we just did sequence 2, do 1 or 3
                   1903:                        chance += 0.33;
                   1904:                else if(last_sequence == 32)    // if we just did sequence 3, do 1 or 2
                   1905:                {
                   1906:                        if(chance >= 0.33)
                   1907:                                chance += 0.34;
                   1908:                }
                   1909: 
                   1910:                if(chance < 0.33)
                   1911:                        ent->client->ps.gunframe = 14;
                   1912:                else if(chance < 0.66)
                   1913:                        ent->client->ps.gunframe = 24;
                   1914:        }
                   1915: 
                   1916: }
                   1917: 
                   1918: //
                   1919: // Disintegrator
                   1920: //
                   1921: 
                   1922: void weapon_tracker_fire (edict_t *self)
                   1923: {
                   1924:        vec3_t          forward, right;
                   1925:        vec3_t          start;
                   1926:        vec3_t          end;
                   1927:        vec3_t          offset;
                   1928:        edict_t         *enemy;
                   1929:        trace_t         tr;
                   1930:        int                     damage;
                   1931:        vec3_t          mins, maxs;
                   1932: 
                   1933:        // PMM - felt a little high at 25
                   1934:        if(deathmatch->value)
                   1935:                damage = 30;
                   1936:        else
                   1937:                damage = 45;
                   1938: 
                   1939:        if (is_quad)
                   1940:                damage *= damage_multiplier;            //pgm
                   1941: 
                   1942:        VectorSet(mins, -16, -16, -16);
                   1943:        VectorSet(maxs, 16, 16, 16);
                   1944:        AngleVectors (self->client->v_angle, forward, right, NULL);
                   1945:        VectorSet(offset, 24, 8, self->viewheight-8);
                   1946:        P_ProjectSource (self->client, self->s.origin, offset, forward, right, start);
                   1947: 
                   1948:        // FIXME - can we shorten this? do we need to?
                   1949:        VectorMA (start, 8192, forward, end);
                   1950:        enemy = NULL;
                   1951:        //PMM - doing two traces .. one point and one box.  
                   1952:        tr = gi.trace (start, vec3_origin, vec3_origin, end, self, MASK_SHOT);
                   1953:        if(tr.ent != world)
                   1954:        {
                   1955:                if(tr.ent->svflags & SVF_MONSTER || tr.ent->client || tr.ent->svflags & SVF_DAMAGEABLE)
                   1956:                {
                   1957:                        if(tr.ent->health > 0)
                   1958:                                enemy = tr.ent;
                   1959:                }
                   1960:        }
                   1961:        else
                   1962:        {
                   1963:                tr = gi.trace (start, mins, maxs, end, self, MASK_SHOT);
                   1964:                if(tr.ent != world)
                   1965:                {
                   1966:                        if(tr.ent->svflags & SVF_MONSTER || tr.ent->client || tr.ent->svflags & SVF_DAMAGEABLE)
                   1967:                        {
                   1968:                                if(tr.ent->health > 0)
                   1969:                                        enemy = tr.ent;
                   1970:                        }
                   1971:                }
                   1972:        }
                   1973: 
                   1974:        VectorScale (forward, -2, self->client->kick_origin);
                   1975:        self->client->kick_angles[0] = -1;
                   1976: 
                   1977:        fire_tracker (self, start, forward, damage, 1000, enemy);
                   1978: 
                   1979:        // send muzzle flash
                   1980:        gi.WriteByte (svc_muzzleflash);
                   1981:        gi.WriteShort (self-g_edicts);
                   1982:        gi.WriteByte (MZ_TRACKER);
                   1983:        gi.multicast (self->s.origin, MULTICAST_PVS);
                   1984: 
                   1985:        PlayerNoise(self, start, PNOISE_WEAPON);
                   1986: 
                   1987:        self->client->ps.gunframe++;
                   1988:        self->client->pers.inventory[self->client->ammo_index] -= self->client->pers.weapon->quantity;
                   1989: }
                   1990: 
                   1991: void Weapon_Disintegrator (edict_t *ent)
                   1992: {
                   1993:        static int      pause_frames[]  = {14, 19, 23, 0};
                   1994: //     static int      fire_frames[]   = {7, 0};
                   1995:        static int      fire_frames[]   = {5, 0};
                   1996: 
                   1997:        Weapon_Generic (ent, 4, 9, 29, 34, pause_frames, fire_frames, weapon_tracker_fire);
                   1998: }
                   1999: 
                   2000: /*
                   2001: ======================================================================
                   2002: 
                   2003: ETF RIFLE
                   2004: 
                   2005: ======================================================================
                   2006: */
                   2007: void weapon_etf_rifle_fire (edict_t *ent)
                   2008: {
                   2009:        vec3_t  forward, right, up;
                   2010:        vec3_t  start, tempPt;
                   2011:        int             damage = 8;
                   2012:        int             kick = 3;
                   2013:        int             i;
                   2014:        vec3_t  angles;
                   2015:        vec3_t  offset;
                   2016: 
                   2017:        // PGM - adjusted to use the quantity entry in the weapon structure.
                   2018:        if(ent->client->pers.inventory[ent->client->ammo_index] < ent->client->pers.weapon->quantity)
                   2019:        {
                   2020:                VectorClear (ent->client->kick_origin);
                   2021:                VectorClear (ent->client->kick_angles);
                   2022:                ent->client->ps.gunframe = 8;
                   2023: 
                   2024:                if (level.time >= ent->pain_debounce_time)
                   2025:                {
                   2026:                        gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
                   2027:                        ent->pain_debounce_time = level.time + 1;
                   2028:                }
                   2029:                NoAmmoWeaponChange (ent);
                   2030:                return;
                   2031:        }
                   2032: 
                   2033:        if (is_quad)
                   2034:        {
                   2035:                damage *= damage_multiplier;
                   2036:                kick *= damage_multiplier;
                   2037:        }
                   2038: 
                   2039:        for(i=0;i<3;i++)
                   2040:        {
                   2041:                ent->client->kick_origin[i] = crandom() * 0.85;
                   2042:                ent->client->kick_angles[i] = crandom() * 0.85;
                   2043:        }
                   2044: 
                   2045:        // get start / end positions
                   2046:        VectorAdd (ent->client->v_angle, ent->client->kick_angles, angles);
                   2047: //     AngleVectors (angles, forward, right, NULL);
                   2048: //     gi.dprintf("v_angle: %s\n", vtos(ent->client->v_angle));
                   2049:        AngleVectors (ent->client->v_angle, forward, right, up);
                   2050: 
                   2051:        // FIXME - set correct frames for different offsets.
                   2052: 
                   2053:        if(ent->client->ps.gunframe == 6)                                       // right barrel
                   2054:        {
                   2055: //             gi.dprintf("right\n");
                   2056:                VectorSet(offset, 15, 8, -8);
                   2057:        }
                   2058:        else                                                                            // left barrel
                   2059:        {
                   2060: //             gi.dprintf("left\n");
                   2061:                VectorSet(offset, 15, 6, -8);
                   2062:        }
                   2063:        
                   2064:        VectorCopy (ent->s.origin, tempPt);
                   2065:        tempPt[2] += ent->viewheight;
                   2066:        P_ProjectSource2 (ent->client, tempPt, offset, forward, right, up, start);
                   2067: //     gi.dprintf("start: %s\n", vtos(start));
                   2068:        fire_flechette (ent, start, forward, damage, 750, kick);
                   2069: 
                   2070:        // send muzzle flash
                   2071:        gi.WriteByte (svc_muzzleflash);
                   2072:        gi.WriteShort (ent-g_edicts);
                   2073:        gi.WriteByte (MZ_ETF_RIFLE);
                   2074:        gi.multicast (ent->s.origin, MULTICAST_PVS);
                   2075: 
                   2076:        PlayerNoise(ent, start, PNOISE_WEAPON);
                   2077: 
                   2078:        ent->client->ps.gunframe++;
                   2079:        ent->client->pers.inventory[ent->client->ammo_index] -= ent->client->pers.weapon->quantity;
                   2080: }
                   2081: 
                   2082: void Weapon_ETF_Rifle (edict_t *ent)
                   2083: {
                   2084:        static int      pause_frames[]  = {18, 28, 0};
                   2085:        static int      fire_frames[]   = {6, 7, 0};
                   2086: //     static int      idle_seq;
                   2087: 
                   2088:        // note - if you change the fire frame number, fix the offset in weapon_etf_rifle_fire.
                   2089: 
                   2090: //     if (!(ent->client->buttons & BUTTON_ATTACK))
                   2091: //             ent->client->machinegun_shots = 0;
                   2092: 
                   2093:        if (ent->client->weaponstate == WEAPON_FIRING)
                   2094:        {
                   2095:                if (ent->client->pers.inventory[ent->client->ammo_index] <= 0)
                   2096:                        ent->client->ps.gunframe = 8;
                   2097:        }
                   2098: 
                   2099:        Weapon_Generic (ent, 4, 7, 37, 41, pause_frames, fire_frames, weapon_etf_rifle_fire);
                   2100: 
                   2101:        if(ent->client->ps.gunframe == 8 && (ent->client->buttons & BUTTON_ATTACK))
                   2102:                ent->client->ps.gunframe = 6;
                   2103: 
                   2104: //     gi.dprintf("etf rifle %d\n", ent->client->ps.gunframe);
                   2105: }
                   2106: 
                   2107: // pgm - this now uses ent->client->pers.weapon->quantity like all the other weapons
                   2108: //#define HEATBEAM_AMMO_USE            2               
                   2109: #define        HEATBEAM_DM_DMG                 15
                   2110: #define HEATBEAM_SP_DMG                        15
                   2111: 
                   2112: void Heatbeam_Fire (edict_t *ent)
                   2113: {
                   2114:        vec3_t          start;
                   2115:        vec3_t          forward, right, up;
                   2116:        vec3_t          offset;
                   2117:        int                     damage;
                   2118:        int                     kick;
                   2119: 
                   2120:        // for comparison, the hyperblaster is 15/20
                   2121:        // jim requested more damage, so try 15/15 --- PGM 07/23/98
                   2122:        if (deathmatch->value)
                   2123:                damage = HEATBEAM_DM_DMG;
                   2124:        else
                   2125:                damage = HEATBEAM_SP_DMG;
                   2126: 
                   2127:        if (deathmatch->value)  // really knock 'em around in deathmatch
                   2128:                kick = 75;
                   2129:        else
                   2130:                kick = 30;
                   2131: 
                   2132: //     if(ent->client->pers.inventory[ent->client->ammo_index] < HEATBEAM_AMMO_USE)
                   2133: //     {
                   2134: //             NoAmmoWeaponChange (ent);
                   2135: //             return;
                   2136: //     }
                   2137: 
                   2138:        ent->client->ps.gunframe++;
                   2139:        ent->client->ps.gunindex = gi.modelindex ("models/weapons/v_beamer2/tris.md2");
                   2140: 
                   2141:        if (is_quad)
                   2142:        {
                   2143:                damage *= damage_multiplier;
                   2144:                kick *= damage_multiplier;
                   2145:        }
                   2146: 
                   2147:        VectorClear (ent->client->kick_origin);
                   2148:        VectorClear (ent->client->kick_angles);
                   2149: 
                   2150:        // get start / end positions
                   2151:        AngleVectors (ent->client->v_angle, forward, right, up);
                   2152: 
                   2153: // This offset is the "view" offset for the beam start (used by trace)
                   2154:        
                   2155:        VectorSet(offset, 7, 2, ent->viewheight-3);
                   2156:        P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
                   2157: 
                   2158:        // This offset is the entity offset
                   2159:        VectorSet(offset, 2, 7, -3);
                   2160: 
                   2161:        fire_heat (ent, start, forward, offset, damage, kick, false);
                   2162: 
                   2163:        // send muzzle flash
                   2164:        gi.WriteByte (svc_muzzleflash);
                   2165:        gi.WriteShort (ent-g_edicts);
                   2166:        gi.WriteByte (MZ_HEATBEAM | is_silenced);
                   2167:        gi.multicast (ent->s.origin, MULTICAST_PVS);
                   2168: 
                   2169:        PlayerNoise(ent, start, PNOISE_WEAPON);
                   2170: 
                   2171:        if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
                   2172:                ent->client->pers.inventory[ent->client->ammo_index] -= ent->client->pers.weapon->quantity;
                   2173: 
                   2174: }
                   2175: 
                   2176: void Weapon_Heatbeam (edict_t *ent)
                   2177: {
                   2178: //     static int      pause_frames[]  = {38, 43, 51, 61, 0};
                   2179: //     static int      fire_frames[]   = {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0};
                   2180:        static int      pause_frames[]  = {35, 0};
                   2181: //     static int      fire_frames[]   = {9, 0};
                   2182:        static int      fire_frames[]   = {9, 10, 11, 12, 0};
                   2183: //     static int      attack_index;
                   2184: //     static int  off_model, on_model;
                   2185: 
                   2186: //     if ((g_showlogic) && (g_showlogic->value)) {
                   2187: //             gi.dprintf ("Frame %d, skin %d\n", ent->client->ps.gunframe, ent->client->ps.gunskin);
                   2188: //     }
                   2189:        
                   2190: //     if (!attack_index)
                   2191: //     {
                   2192: //             attack_index = gi.soundindex ("weapons/bfg__l1a.wav");
                   2193: //             off_model = gi.modelindex ("models/weapons/v_beamer/tris.md2");
                   2194: //             on_model = gi.modelindex ("models/weapons/v_beamer2/tris.md2");
                   2195:                //ent->client->ps.gunindex = gi.modelindex(ent->client->pers.weapon->view_model);
                   2196: //     }
                   2197: 
                   2198:        if (ent->client->weaponstate == WEAPON_FIRING)
                   2199:        {
                   2200: //             ent->client->weapon_sound = attack_index;
                   2201:                ent->client->weapon_sound = gi.soundindex ("weapons/bfg__l1a.wav");
                   2202:                if ((ent->client->pers.inventory[ent->client->ammo_index] >= 2) && ((ent->client->buttons) & BUTTON_ATTACK))
                   2203:                {
                   2204: //                     if(ent->client->ps.gunframe >= 9 && ((ent->client->buttons) & BUTTON_ATTACK))
                   2205: //                     if(ent->client->ps.gunframe >= 12 && ((ent->client->buttons) & BUTTON_ATTACK))
                   2206:                        if(ent->client->ps.gunframe >= 13)
                   2207:                        {
                   2208:                                ent->client->ps.gunframe = 9;
                   2209: //                             ent->client->ps.gunframe = 8;
                   2210: //                             ent->client->ps.gunskin = 0;
                   2211: //                             ent->client->ps.gunindex = on_model;
                   2212:                                ent->client->ps.gunindex = gi.modelindex ("models/weapons/v_beamer2/tris.md2");
                   2213:                        }
                   2214:                        else
                   2215:                        {
                   2216: //                             ent->client->ps.gunskin = 1;
                   2217: //                             ent->client->ps.gunindex = on_model;
                   2218:                                ent->client->ps.gunindex = gi.modelindex ("models/weapons/v_beamer2/tris.md2");
                   2219:                        }
                   2220:                }
                   2221:                else
                   2222:                {
                   2223: //                     ent->client->ps.gunframe = 10;
                   2224:                        ent->client->ps.gunframe = 13;
                   2225: //                     ent->client->ps.gunskin = 1;
                   2226: //                     ent->client->ps.gunindex = off_model;
                   2227:                        ent->client->ps.gunindex = gi.modelindex ("models/weapons/v_beamer/tris.md2");
                   2228:                }
                   2229:        }
                   2230:        else
                   2231:        {
                   2232: //             ent->client->ps.gunskin = 1;
                   2233: //             ent->client->ps.gunindex = off_model;
                   2234:                ent->client->ps.gunindex = gi.modelindex ("models/weapons/v_beamer/tris.md2");
                   2235:                ent->client->weapon_sound = 0;
                   2236:        }
                   2237: 
                   2238: //     Weapon_Generic (ent, 8, 9, 39, 44, pause_frames, fire_frames, Heatbeam_Fire);
                   2239:        Weapon_Generic (ent, 8, 12, 39, 44, pause_frames, fire_frames, Heatbeam_Fire);
                   2240: }

unix.superglobalmegacorp.com

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