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