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