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