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