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