|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.