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