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