|
|
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: static 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: 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))
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)
400: {
401: ent->client->weaponstate = WEAPON_READY;
402: ent->client->ps.gunframe = FRAME_IDLE_FIRST;
403: return;
404: }
405:
406: ent->client->ps.gunframe++;
407: return;
408: }
409:
410: if ((ent->client->newweapon) && (ent->client->weaponstate != WEAPON_FIRING))
411: {
412: ent->client->weaponstate = WEAPON_DROPPING;
413: ent->client->ps.gunframe = FRAME_DEACTIVATE_FIRST;
414:
415: if ((FRAME_DEACTIVATE_LAST - FRAME_DEACTIVATE_FIRST) < 4)
416: {
417: ent->client->anim_priority = ANIM_REVERSE;
418: if(ent->client->ps.pmove.pm_flags & PMF_DUCKED)
419: {
420: ent->s.frame = FRAME_crpain4+1;
421: ent->client->anim_end = FRAME_crpain1;
422: }
423: else
424: {
425: ent->s.frame = FRAME_pain304+1;
426: ent->client->anim_end = FRAME_pain301;
427:
428: }
429: }
430: return;
431: }
432:
433: if (ent->client->weaponstate == WEAPON_READY)
434: {
435: if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
436: {
437: ent->client->latched_buttons &= ~BUTTON_ATTACK;
438: if ((!ent->client->ammo_index) ||
439: ( ent->client->pers.inventory[ent->client->ammo_index] >= ent->client->pers.weapon->quantity))
440: {
441: ent->client->ps.gunframe = FRAME_FIRE_FIRST;
442: ent->client->weaponstate = WEAPON_FIRING;
443:
444: // start the animation
445: ent->client->anim_priority = ANIM_ATTACK;
446: if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
447: {
448: ent->s.frame = FRAME_crattak1-1;
449: ent->client->anim_end = FRAME_crattak9;
450: }
451: else
452: {
453: ent->s.frame = FRAME_attack1-1;
454: ent->client->anim_end = FRAME_attack8;
455: }
456: }
457: else
458: {
459: if (level.time >= ent->pain_debounce_time)
460: {
461: gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
462: ent->pain_debounce_time = level.time + 1;
463: }
464: NoAmmoWeaponChange (ent);
465: }
466: }
467: else
468: {
469: if (ent->client->ps.gunframe == FRAME_IDLE_LAST)
470: {
471: ent->client->ps.gunframe = FRAME_IDLE_FIRST;
472: return;
473: }
474:
475: if (pause_frames)
476: {
477: for (n = 0; pause_frames[n]; n++)
478: {
479: if (ent->client->ps.gunframe == pause_frames[n])
480: {
481: if (rand()&15)
482: return;
483: }
484: }
485: }
486:
487: ent->client->ps.gunframe++;
488: return;
489: }
490: }
491:
492: if (ent->client->weaponstate == WEAPON_FIRING)
493: {
494: for (n = 0; fire_frames[n]; n++)
495: {
496: if (ent->client->ps.gunframe == fire_frames[n])
497: {
498: if (ent->client->quad_framenum > level.framenum)
499: gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage3.wav"), 1, ATTN_NORM, 0);
500:
501: fire (ent);
502: break;
503: }
504: }
505:
506: if (!fire_frames[n])
507: ent->client->ps.gunframe++;
508:
509: if (ent->client->ps.gunframe == FRAME_IDLE_FIRST+1)
510: ent->client->weaponstate = WEAPON_READY;
511: }
512: }
513:
514:
515: /*
516: ======================================================================
517:
518: GRENADE
519:
520: ======================================================================
521: */
522:
523: #define GRENADE_TIMER 3.0
524: #define GRENADE_MINSPEED 400
525: #define GRENADE_MAXSPEED 800
526:
527: void weapon_grenade_fire (edict_t *ent, qboolean held)
528: {
529: vec3_t offset;
530: vec3_t forward, right;
531: vec3_t start;
532: int damage = 125;
533: float timer;
534: int speed;
535: float radius;
536:
537: radius = damage+40;
538: if (is_quad)
539: damage *= 4;
540:
541: VectorSet(offset, 8, 8, ent->viewheight-8);
542: AngleVectors (ent->client->v_angle, forward, right, NULL);
543: P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
544:
545: timer = ent->client->grenade_time - level.time;
546: speed = GRENADE_MINSPEED + (GRENADE_TIMER - timer) * ((GRENADE_MAXSPEED - GRENADE_MINSPEED) / GRENADE_TIMER);
547: fire_grenade2 (ent, start, forward, damage, speed, timer, radius, held);
548:
549: if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
550: ent->client->pers.inventory[ent->client->ammo_index]--;
551:
552: ent->client->grenade_time = level.time + 1.0;
553:
554: if(ent->deadflag || ent->s.modelindex != 255) // VWep animations screw up corpses
555: {
556: return;
557: }
558:
559: if (ent->health <= 0)
560: return;
561:
562: if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
563: {
564: ent->client->anim_priority = ANIM_ATTACK;
565: ent->s.frame = FRAME_crattak1-1;
566: ent->client->anim_end = FRAME_crattak3;
567: }
568: else
569: {
570: ent->client->anim_priority = ANIM_REVERSE;
571: ent->s.frame = FRAME_wave08;
572: ent->client->anim_end = FRAME_wave01;
573: }
574: }
575:
576: void Weapon_Grenade (edict_t *ent)
577: {
578: if ((ent->client->newweapon) && (ent->client->weaponstate == WEAPON_READY))
579: {
580: ChangeWeapon (ent);
581: return;
582: }
583:
584: if (ent->client->weaponstate == WEAPON_ACTIVATING)
585: {
586: ent->client->weaponstate = WEAPON_READY;
587: ent->client->ps.gunframe = 16;
588: return;
589: }
590:
591: if (ent->client->weaponstate == WEAPON_READY)
592: {
593: if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
594: {
595: ent->client->latched_buttons &= ~BUTTON_ATTACK;
596: if (ent->client->pers.inventory[ent->client->ammo_index])
597: {
598: ent->client->ps.gunframe = 1;
599: ent->client->weaponstate = WEAPON_FIRING;
600: ent->client->grenade_time = 0;
601: }
602: else
603: {
604: if (level.time >= ent->pain_debounce_time)
605: {
606: gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
607: ent->pain_debounce_time = level.time + 1;
608: }
609: NoAmmoWeaponChange (ent);
610: }
611: return;
612: }
613:
614: if ((ent->client->ps.gunframe == 29) || (ent->client->ps.gunframe == 34) || (ent->client->ps.gunframe == 39) || (ent->client->ps.gunframe == 48))
615: {
616: if (rand()&15)
617: return;
618: }
619:
620: if (++ent->client->ps.gunframe > 48)
621: ent->client->ps.gunframe = 16;
622: return;
623: }
624:
625: if (ent->client->weaponstate == WEAPON_FIRING)
626: {
627: if (ent->client->ps.gunframe == 5)
628: gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/hgrena1b.wav"), 1, ATTN_NORM, 0);
629:
630: if (ent->client->ps.gunframe == 11)
631: {
632: if (!ent->client->grenade_time)
633: {
634: ent->client->grenade_time = level.time + GRENADE_TIMER + 0.2;
635: ent->client->weapon_sound = gi.soundindex("weapons/hgrenc1b.wav");
636: }
637:
638: // they waited too long, detonate it in their hand
639: if (!ent->client->grenade_blew_up && level.time >= ent->client->grenade_time)
640: {
641: ent->client->weapon_sound = 0;
642: weapon_grenade_fire (ent, true);
643: ent->client->grenade_blew_up = true;
644: }
645:
646: if (ent->client->buttons & BUTTON_ATTACK)
647: return;
648:
649: if (ent->client->grenade_blew_up)
650: {
651: if (level.time >= ent->client->grenade_time)
652: {
653: ent->client->ps.gunframe = 15;
654: ent->client->grenade_blew_up = false;
655: }
656: else
657: {
658: return;
659: }
660: }
661: }
662:
663: if (ent->client->ps.gunframe == 12)
664: {
665: ent->client->weapon_sound = 0;
666: weapon_grenade_fire (ent, false);
667: }
668:
669: if ((ent->client->ps.gunframe == 15) && (level.time < ent->client->grenade_time))
670: return;
671:
672: ent->client->ps.gunframe++;
673:
674: if (ent->client->ps.gunframe == 16)
675: {
676: ent->client->grenade_time = 0;
677: ent->client->weaponstate = WEAPON_READY;
678: }
679: }
680: }
681:
682: /*
683: ======================================================================
684:
685: GRENADE LAUNCHER
686:
687: ======================================================================
688: */
689:
690: void weapon_grenadelauncher_fire (edict_t *ent)
691: {
692: vec3_t offset;
693: vec3_t forward, right;
694: vec3_t start;
695: int damage = 120;
696: float radius;
697:
698: radius = damage+40;
699: if (is_quad)
700: damage *= 4;
701:
702: VectorSet(offset, 8, 8, ent->viewheight-8);
703: AngleVectors (ent->client->v_angle, forward, right, NULL);
704: P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
705:
706: VectorScale (forward, -2, ent->client->kick_origin);
707: ent->client->kick_angles[0] = -1;
708:
709: fire_grenade (ent, start, forward, damage, 600, 2.5, radius);
710:
711: gi.WriteByte (svc_muzzleflash);
712: gi.WriteShort (ent-g_edicts);
713: gi.WriteByte (MZ_GRENADE | is_silenced);
714: gi.multicast (ent->s.origin, MULTICAST_PVS);
715:
716: ent->client->ps.gunframe++;
717:
718: PlayerNoise(ent, start, PNOISE_WEAPON);
719:
720: if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
721: ent->client->pers.inventory[ent->client->ammo_index]--;
722: }
723:
724: void Weapon_GrenadeLauncher (edict_t *ent)
725: {
726: static int pause_frames[] = {34, 51, 59, 0};
727: static int fire_frames[] = {6, 0};
728:
729: Weapon_Generic (ent, 5, 16, 59, 64, pause_frames, fire_frames, weapon_grenadelauncher_fire);
730: }
731:
732: /*
733: ======================================================================
734:
735: ROCKET
736:
737: ======================================================================
738: */
739:
740: void Weapon_RocketLauncher_Fire (edict_t *ent)
741: {
742: vec3_t offset, start;
743: vec3_t forward, right;
744: int damage;
745: float damage_radius;
746: int radius_damage;
747:
748: damage = 100 + (int)(random() * 20.0);
749: radius_damage = 120;
750: damage_radius = 120;
751: if (is_quad)
752: {
753: damage *= 4;
754: radius_damage *= 4;
755: }
756:
757: AngleVectors (ent->client->v_angle, forward, right, NULL);
758:
759: VectorScale (forward, -2, ent->client->kick_origin);
760: ent->client->kick_angles[0] = -1;
761:
762: VectorSet(offset, 8, 8, ent->viewheight-8);
763: P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
764: fire_rocket (ent, start, forward, damage, 650, damage_radius, radius_damage);
765:
766: // send muzzle flash
767: gi.WriteByte (svc_muzzleflash);
768: gi.WriteShort (ent-g_edicts);
769: gi.WriteByte (MZ_ROCKET | is_silenced);
770: gi.multicast (ent->s.origin, MULTICAST_PVS);
771:
772: ent->client->ps.gunframe++;
773:
774: PlayerNoise(ent, start, PNOISE_WEAPON);
775:
776: if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
777: ent->client->pers.inventory[ent->client->ammo_index]--;
778: }
779:
780: void Weapon_RocketLauncher (edict_t *ent)
781: {
782: static int pause_frames[] = {25, 33, 42, 50, 0};
783: static int fire_frames[] = {5, 0};
784:
785: Weapon_Generic (ent, 4, 12, 50, 54, pause_frames, fire_frames, Weapon_RocketLauncher_Fire);
786: }
787:
788:
789: /*
790: ======================================================================
791:
792: BLASTER / HYPERBLASTER
793:
794: ======================================================================
795: */
796:
797: void Blaster_Fire (edict_t *ent, vec3_t g_offset, int damage, qboolean hyper, int effect)
798: {
799: vec3_t forward, right;
800: vec3_t start;
801: vec3_t offset;
802:
803: if (is_quad)
804: damage *= 4;
805: AngleVectors (ent->client->v_angle, forward, right, NULL);
806: VectorSet(offset, 24, 8, ent->viewheight-8);
807: VectorAdd (offset, g_offset, offset);
808: P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
809:
810: VectorScale (forward, -2, ent->client->kick_origin);
811: ent->client->kick_angles[0] = -1;
812:
813: fire_blaster (ent, start, forward, damage, 1000, effect, hyper);
814:
815: // send muzzle flash
816: gi.WriteByte (svc_muzzleflash);
817: gi.WriteShort (ent-g_edicts);
818: if (hyper)
819: gi.WriteByte (MZ_HYPERBLASTER | is_silenced);
820: else
821: gi.WriteByte (MZ_BLASTER | is_silenced);
822: gi.multicast (ent->s.origin, MULTICAST_PVS);
823:
824: PlayerNoise(ent, start, PNOISE_WEAPON);
825: }
826:
827:
828: void Weapon_Blaster_Fire (edict_t *ent)
829: {
830: int damage;
831:
832: if (deathmatch->value)
833: damage = 15;
834: else
835: damage = 10;
836: Blaster_Fire (ent, vec3_origin, damage, false, EF_BLASTER);
837: ent->client->ps.gunframe++;
838: }
839:
840: void Weapon_Blaster (edict_t *ent)
841: {
842: static int pause_frames[] = {19, 32, 0};
843: static int fire_frames[] = {5, 0};
844:
845: Weapon_Generic (ent, 4, 8, 52, 55, pause_frames, fire_frames, Weapon_Blaster_Fire);
846: }
847:
848:
849: void Weapon_HyperBlaster_Fire (edict_t *ent)
850: {
851: float rotation;
852: vec3_t offset;
853: int effect;
854: int damage;
855:
856: ent->client->weapon_sound = gi.soundindex("weapons/hyprbl1a.wav");
857:
858: if (!(ent->client->buttons & BUTTON_ATTACK))
859: {
860: ent->client->ps.gunframe++;
861: }
862: else
863: {
864: if (! ent->client->pers.inventory[ent->client->ammo_index] )
865: {
866: if (level.time >= ent->pain_debounce_time)
867: {
868: gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
869: ent->pain_debounce_time = level.time + 1;
870: }
871: NoAmmoWeaponChange (ent);
872: }
873: else
874: {
875: rotation = (ent->client->ps.gunframe - 5) * 2*M_PI/6;
876: offset[0] = -4 * sin(rotation);
877: offset[1] = 0;
878: offset[2] = 4 * cos(rotation);
879:
880: if ((ent->client->ps.gunframe == 6) || (ent->client->ps.gunframe == 9))
881: effect = EF_HYPERBLASTER;
882: else
883: effect = 0;
884: if (deathmatch->value)
885: damage = 15;
886: else
887: damage = 20;
888: Blaster_Fire (ent, offset, damage, true, effect);
889: if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
890: ent->client->pers.inventory[ent->client->ammo_index]--;
891:
892: ent->client->anim_priority = ANIM_ATTACK;
893: if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
894: {
895: ent->s.frame = FRAME_crattak1 - 1;
896: ent->client->anim_end = FRAME_crattak9;
897: }
898: else
899: {
900: ent->s.frame = FRAME_attack1 - 1;
901: ent->client->anim_end = FRAME_attack8;
902: }
903: }
904:
905: ent->client->ps.gunframe++;
906: if (ent->client->ps.gunframe == 12 && ent->client->pers.inventory[ent->client->ammo_index])
907: ent->client->ps.gunframe = 6;
908: }
909:
910: if (ent->client->ps.gunframe == 12)
911: {
912: gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/hyprbd1a.wav"), 1, ATTN_NORM, 0);
913: ent->client->weapon_sound = 0;
914: }
915:
916: }
917:
918: void Weapon_HyperBlaster (edict_t *ent)
919: {
920: static int pause_frames[] = {0};
921: static int fire_frames[] = {6, 7, 8, 9, 10, 11, 0};
922:
923: Weapon_Generic (ent, 5, 20, 49, 53, pause_frames, fire_frames, Weapon_HyperBlaster_Fire);
924: }
925:
926: /*
927: ======================================================================
928:
929: MACHINEGUN / CHAINGUN
930:
931: ======================================================================
932: */
933:
934: void Machinegun_Fire (edict_t *ent)
935: {
936: int i;
937: vec3_t start;
938: vec3_t forward, right;
939: vec3_t angles;
940: int damage = 8;
941: int kick = 2;
942: vec3_t offset;
943:
944: if (!(ent->client->buttons & BUTTON_ATTACK))
945: {
946: ent->client->machinegun_shots = 0;
947: ent->client->ps.gunframe++;
948: return;
949: }
950:
951: if (ent->client->ps.gunframe == 5)
952: ent->client->ps.gunframe = 4;
953: else
954: ent->client->ps.gunframe = 5;
955:
956: if (ent->client->pers.inventory[ent->client->ammo_index] < 1)
957: {
958: ent->client->ps.gunframe = 6;
959: if (level.time >= ent->pain_debounce_time)
960: {
961: gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
962: ent->pain_debounce_time = level.time + 1;
963: }
964: NoAmmoWeaponChange (ent);
965: return;
966: }
967:
968: if (is_quad)
969: {
970: damage *= 4;
971: kick *= 4;
972: }
973:
974: for (i=1 ; i<3 ; i++)
975: {
976: ent->client->kick_origin[i] = crandom() * 0.35;
977: ent->client->kick_angles[i] = crandom() * 0.7;
978: }
979: ent->client->kick_origin[0] = crandom() * 0.35;
980: ent->client->kick_angles[0] = ent->client->machinegun_shots * -1.5;
981:
982: // raise the gun as it is firing
983: if (!deathmatch->value)
984: {
985: ent->client->machinegun_shots++;
986: if (ent->client->machinegun_shots > 9)
987: ent->client->machinegun_shots = 9;
988: }
989:
990: // get start / end positions
991: VectorAdd (ent->client->v_angle, ent->client->kick_angles, angles);
992: AngleVectors (angles, forward, right, NULL);
993: VectorSet(offset, 0, 8, ent->viewheight-8);
994: P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
995: fire_bullet (ent, start, forward, damage, kick, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MOD_MACHINEGUN);
996:
997: gi.WriteByte (svc_muzzleflash);
998: gi.WriteShort (ent-g_edicts);
999: gi.WriteByte (MZ_MACHINEGUN | is_silenced);
1000: gi.multicast (ent->s.origin, MULTICAST_PVS);
1001:
1002: PlayerNoise(ent, start, PNOISE_WEAPON);
1003:
1004: if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1005: ent->client->pers.inventory[ent->client->ammo_index]--;
1006:
1007: ent->client->anim_priority = ANIM_ATTACK;
1008: if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
1009: {
1010: ent->s.frame = FRAME_crattak1 - (int) (random()+0.25);
1011: ent->client->anim_end = FRAME_crattak9;
1012: }
1013: else
1014: {
1015: ent->s.frame = FRAME_attack1 - (int) (random()+0.25);
1016: ent->client->anim_end = FRAME_attack8;
1017: }
1018: }
1019:
1020: void Weapon_Machinegun (edict_t *ent)
1021: {
1022: static int pause_frames[] = {23, 45, 0};
1023: static int fire_frames[] = {4, 5, 0};
1024:
1025: Weapon_Generic (ent, 3, 5, 45, 49, pause_frames, fire_frames, Machinegun_Fire);
1026: }
1027:
1028: void Chaingun_Fire (edict_t *ent)
1029: {
1030: int i;
1031: int shots;
1032: vec3_t start;
1033: vec3_t forward, right, up;
1034: float r, u;
1035: vec3_t offset;
1036: int damage;
1037: int kick = 2;
1038:
1039: if (deathmatch->value)
1040: damage = 6;
1041: else
1042: damage = 8;
1043:
1044: if (ent->client->ps.gunframe == 5)
1045: gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnu1a.wav"), 1, ATTN_IDLE, 0);
1046:
1047: if ((ent->client->ps.gunframe == 14) && !(ent->client->buttons & BUTTON_ATTACK))
1048: {
1049: ent->client->ps.gunframe = 32;
1050: ent->client->weapon_sound = 0;
1051: return;
1052: }
1053: else if ((ent->client->ps.gunframe == 21) && (ent->client->buttons & BUTTON_ATTACK)
1054: && ent->client->pers.inventory[ent->client->ammo_index])
1055: {
1056: ent->client->ps.gunframe = 15;
1057: }
1058: else
1059: {
1060: ent->client->ps.gunframe++;
1061: }
1062:
1063: if (ent->client->ps.gunframe == 22)
1064: {
1065: ent->client->weapon_sound = 0;
1066: gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnd1a.wav"), 1, ATTN_IDLE, 0);
1067: }
1068: else
1069: {
1070: ent->client->weapon_sound = gi.soundindex("weapons/chngnl1a.wav");
1071: }
1072:
1073: ent->client->anim_priority = ANIM_ATTACK;
1074: if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
1075: {
1076: ent->s.frame = FRAME_crattak1 - (ent->client->ps.gunframe & 1);
1077: ent->client->anim_end = FRAME_crattak9;
1078: }
1079: else
1080: {
1081: ent->s.frame = FRAME_attack1 - (ent->client->ps.gunframe & 1);
1082: ent->client->anim_end = FRAME_attack8;
1083: }
1084:
1085: if (ent->client->ps.gunframe <= 9)
1086: shots = 1;
1087: else if (ent->client->ps.gunframe <= 14)
1088: {
1089: if (ent->client->buttons & BUTTON_ATTACK)
1090: shots = 2;
1091: else
1092: shots = 1;
1093: }
1094: else
1095: shots = 3;
1096:
1097: if (ent->client->pers.inventory[ent->client->ammo_index] < shots)
1098: shots = ent->client->pers.inventory[ent->client->ammo_index];
1099:
1100: if (!shots)
1101: {
1102: if (level.time >= ent->pain_debounce_time)
1103: {
1104: gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
1105: ent->pain_debounce_time = level.time + 1;
1106: }
1107: NoAmmoWeaponChange (ent);
1108: return;
1109: }
1110:
1111: if (is_quad)
1112: {
1113: damage *= 4;
1114: kick *= 4;
1115: }
1116:
1117: for (i=0 ; i<3 ; i++)
1118: {
1119: ent->client->kick_origin[i] = crandom() * 0.35;
1120: ent->client->kick_angles[i] = crandom() * 0.7;
1121: }
1122:
1123: for (i=0 ; i<shots ; i++)
1124: {
1125: // get start / end positions
1126: AngleVectors (ent->client->v_angle, forward, right, up);
1127: r = 7 + crandom()*4;
1128: u = crandom()*4;
1129: VectorSet(offset, 0, r, u + ent->viewheight-8);
1130: P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1131:
1132: fire_bullet (ent, start, forward, damage, kick, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MOD_CHAINGUN);
1133: }
1134:
1135: // send muzzle flash
1136: gi.WriteByte (svc_muzzleflash);
1137: gi.WriteShort (ent-g_edicts);
1138: gi.WriteByte ((MZ_CHAINGUN1 + shots - 1) | is_silenced);
1139: gi.multicast (ent->s.origin, MULTICAST_PVS);
1140:
1141: PlayerNoise(ent, start, PNOISE_WEAPON);
1142:
1143: if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1144: ent->client->pers.inventory[ent->client->ammo_index] -= shots;
1145: }
1146:
1147:
1148: void Weapon_Chaingun (edict_t *ent)
1149: {
1150: static int pause_frames[] = {38, 43, 51, 61, 0};
1151: static int fire_frames[] = {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0};
1152:
1153: Weapon_Generic (ent, 4, 31, 61, 64, pause_frames, fire_frames, Chaingun_Fire);
1154: }
1155:
1156:
1157: /*
1158: ======================================================================
1159:
1160: SHOTGUN / SUPERSHOTGUN
1161:
1162: ======================================================================
1163: */
1164:
1165: void weapon_shotgun_fire (edict_t *ent)
1166: {
1167: vec3_t start;
1168: vec3_t forward, right;
1169: vec3_t offset;
1170: int damage = 4;
1171: int kick = 8;
1172:
1173: if (ent->client->ps.gunframe == 9)
1174: {
1175: ent->client->ps.gunframe++;
1176: return;
1177: }
1178:
1179: AngleVectors (ent->client->v_angle, forward, right, NULL);
1180:
1181: VectorScale (forward, -2, ent->client->kick_origin);
1182: ent->client->kick_angles[0] = -2;
1183:
1184: VectorSet(offset, 0, 8, ent->viewheight-8);
1185: P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1186:
1187: if (is_quad)
1188: {
1189: damage *= 4;
1190: kick *= 4;
1191: }
1192:
1193: if (deathmatch->value)
1194: fire_shotgun (ent, start, forward, damage, kick, 500, 500, DEFAULT_DEATHMATCH_SHOTGUN_COUNT, MOD_SHOTGUN);
1195: else
1196: fire_shotgun (ent, start, forward, damage, kick, 500, 500, DEFAULT_SHOTGUN_COUNT, MOD_SHOTGUN);
1197:
1198: // send muzzle flash
1199: gi.WriteByte (svc_muzzleflash);
1200: gi.WriteShort (ent-g_edicts);
1201: gi.WriteByte (MZ_SHOTGUN | is_silenced);
1202: gi.multicast (ent->s.origin, MULTICAST_PVS);
1203:
1204: ent->client->ps.gunframe++;
1205: PlayerNoise(ent, start, PNOISE_WEAPON);
1206:
1207: if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1208: ent->client->pers.inventory[ent->client->ammo_index]--;
1209: }
1210:
1211: void Weapon_Shotgun (edict_t *ent)
1212: {
1213: static int pause_frames[] = {22, 28, 34, 0};
1214: static int fire_frames[] = {8, 9, 0};
1215:
1216: Weapon_Generic (ent, 7, 18, 36, 39, pause_frames, fire_frames, weapon_shotgun_fire);
1217: }
1218:
1219:
1220: void weapon_supershotgun_fire (edict_t *ent)
1221: {
1222: vec3_t start;
1223: vec3_t forward, right;
1224: vec3_t offset;
1225: vec3_t v;
1226: int damage = 6;
1227: int kick = 12;
1228:
1229: AngleVectors (ent->client->v_angle, forward, right, NULL);
1230:
1231: VectorScale (forward, -2, ent->client->kick_origin);
1232: ent->client->kick_angles[0] = -2;
1233:
1234: VectorSet(offset, 0, 8, ent->viewheight-8);
1235: P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1236:
1237: if (is_quad)
1238: {
1239: damage *= 4;
1240: kick *= 4;
1241: }
1242:
1243: v[PITCH] = ent->client->v_angle[PITCH];
1244: v[YAW] = ent->client->v_angle[YAW] - 5;
1245: v[ROLL] = ent->client->v_angle[ROLL];
1246: AngleVectors (v, forward, NULL, NULL);
1247: fire_shotgun (ent, start, forward, damage, kick, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT/2, MOD_SSHOTGUN);
1248: v[YAW] = ent->client->v_angle[YAW] + 5;
1249: AngleVectors (v, forward, NULL, NULL);
1250: fire_shotgun (ent, start, forward, damage, kick, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT/2, MOD_SSHOTGUN);
1251:
1252: // send muzzle flash
1253: gi.WriteByte (svc_muzzleflash);
1254: gi.WriteShort (ent-g_edicts);
1255: gi.WriteByte (MZ_SSHOTGUN | is_silenced);
1256: gi.multicast (ent->s.origin, MULTICAST_PVS);
1257:
1258: ent->client->ps.gunframe++;
1259: PlayerNoise(ent, start, PNOISE_WEAPON);
1260:
1261: if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1262: ent->client->pers.inventory[ent->client->ammo_index] -= 2;
1263: }
1264:
1265: void Weapon_SuperShotgun (edict_t *ent)
1266: {
1267: static int pause_frames[] = {29, 42, 57, 0};
1268: static int fire_frames[] = {7, 0};
1269:
1270: Weapon_Generic (ent, 6, 17, 57, 61, pause_frames, fire_frames, weapon_supershotgun_fire);
1271: }
1272:
1273:
1274:
1275: /*
1276: ======================================================================
1277:
1278: RAILGUN
1279:
1280: ======================================================================
1281: */
1282:
1283: void weapon_railgun_fire (edict_t *ent)
1284: {
1285: vec3_t start;
1286: vec3_t forward, right;
1287: vec3_t offset;
1288: int damage;
1289: int kick;
1290:
1291: if (deathmatch->value)
1292: { // normal damage is too extreme in dm
1293: damage = 100;
1294: kick = 200;
1295: }
1296: else
1297: {
1298: damage = 150;
1299: kick = 250;
1300: }
1301:
1302: if (is_quad)
1303: {
1304: damage *= 4;
1305: kick *= 4;
1306: }
1307:
1308: AngleVectors (ent->client->v_angle, forward, right, NULL);
1309:
1310: VectorScale (forward, -3, ent->client->kick_origin);
1311: ent->client->kick_angles[0] = -3;
1312:
1313: VectorSet(offset, 0, 7, ent->viewheight-8);
1314: P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1315: fire_rail (ent, start, forward, damage, kick);
1316:
1317: // send muzzle flash
1318: gi.WriteByte (svc_muzzleflash);
1319: gi.WriteShort (ent-g_edicts);
1320: gi.WriteByte (MZ_RAILGUN | is_silenced);
1321: gi.multicast (ent->s.origin, MULTICAST_PVS);
1322:
1323: ent->client->ps.gunframe++;
1324: PlayerNoise(ent, start, PNOISE_WEAPON);
1325:
1326: if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1327: ent->client->pers.inventory[ent->client->ammo_index]--;
1328: }
1329:
1330:
1331: void Weapon_Railgun (edict_t *ent)
1332: {
1333: static int pause_frames[] = {56, 0};
1334: static int fire_frames[] = {4, 0};
1335:
1336: Weapon_Generic (ent, 3, 18, 56, 61, pause_frames, fire_frames, weapon_railgun_fire);
1337: }
1338:
1339:
1340: /*
1341: ======================================================================
1342:
1343: BFG10K
1344:
1345: ======================================================================
1346: */
1347:
1348: void weapon_bfg_fire (edict_t *ent)
1349: {
1350: vec3_t offset, start;
1351: vec3_t forward, right;
1352: int damage;
1353: float damage_radius = 1000;
1354:
1355: if (deathmatch->value)
1356: damage = 200;
1357: else
1358: damage = 500;
1359:
1360: if (ent->client->ps.gunframe == 9)
1361: {
1362: // send muzzle flash
1363: gi.WriteByte (svc_muzzleflash);
1364: gi.WriteShort (ent-g_edicts);
1365: gi.WriteByte (MZ_BFG | is_silenced);
1366: gi.multicast (ent->s.origin, MULTICAST_PVS);
1367:
1368: ent->client->ps.gunframe++;
1369:
1370: PlayerNoise(ent, start, PNOISE_WEAPON);
1371: return;
1372: }
1373:
1374: // cells can go down during windup (from power armor hits), so
1375: // check again and abort firing if we don't have enough now
1376: if (ent->client->pers.inventory[ent->client->ammo_index] < 50)
1377: {
1378: ent->client->ps.gunframe++;
1379: return;
1380: }
1381:
1382: if (is_quad)
1383: damage *= 4;
1384:
1385: AngleVectors (ent->client->v_angle, forward, right, NULL);
1386:
1387: VectorScale (forward, -2, ent->client->kick_origin);
1388:
1389: // make a big pitch kick with an inverse fall
1390: ent->client->v_dmg_pitch = -40;
1391: ent->client->v_dmg_roll = crandom()*8;
1392: ent->client->v_dmg_time = level.time + DAMAGE_TIME;
1393:
1394: VectorSet(offset, 8, 8, ent->viewheight-8);
1395: P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1396: fire_bfg (ent, start, forward, damage, 400, damage_radius);
1397:
1398: ent->client->ps.gunframe++;
1399:
1400: PlayerNoise(ent, start, PNOISE_WEAPON);
1401:
1402: if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1403: ent->client->pers.inventory[ent->client->ammo_index] -= 50;
1404: }
1405:
1406: void Weapon_BFG (edict_t *ent)
1407: {
1408: static int pause_frames[] = {39, 45, 50, 55, 0};
1409: static int fire_frames[] = {9, 17, 0};
1410:
1411: Weapon_Generic (ent, 8, 32, 55, 58, pause_frames, fire_frames, weapon_bfg_fire);
1412: }
1413:
1414:
1415: //======================================================================
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.