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