|
|
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.