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