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