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