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 
P_ProjectSource(gclient_t * client,vec3_t point,vec3_t distance,vec3_t forward,vec3_t right,vec3_t result)33 static 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_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))380 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))
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)
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 		ent->client->ps.gunframe = FRAME_DEACTIVATE_FIRST;
433 
434 		if ((FRAME_DEACTIVATE_LAST - FRAME_DEACTIVATE_FIRST) < 4)
435 		{
436 			ent->client->anim_priority = ANIM_REVERSE;
437 			if(ent->client->ps.pmove.pm_flags & PMF_DUCKED)
438 			{
439 				ent->s.frame = FRAME_crpain4+1;
440 				ent->client->anim_end = FRAME_crpain1;
441 			}
442 			else
443 			{
444 				ent->s.frame = FRAME_pain304+1;
445 				ent->client->anim_end = FRAME_pain301;
446 
447 			}
448 		}
449 		return;
450 	}
451 
452 	if (ent->client->weaponstate == WEAPON_READY)
453 	{
454 		if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
455 		{
456 			ent->client->latched_buttons &= ~BUTTON_ATTACK;
457 			if ((!ent->client->ammo_index) ||
458 				( ent->client->pers.inventory[ent->client->ammo_index] >= ent->client->pers.weapon->quantity))
459 			{
460 				ent->client->ps.gunframe = FRAME_FIRE_FIRST;
461 				ent->client->weaponstate = WEAPON_FIRING;
462 
463 				// start the animation
464 				ent->client->anim_priority = ANIM_ATTACK;
465 				if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
466 				{
467 					ent->s.frame = FRAME_crattak1-1;
468 					ent->client->anim_end = FRAME_crattak9;
469 				}
470 				else
471 				{
472 					ent->s.frame = FRAME_attack1-1;
473 					ent->client->anim_end = FRAME_attack8;
474 				}
475 			}
476 			else
477 			{
478 				if (level.time >= ent->pain_debounce_time)
479 				{
480 					gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
481 					ent->pain_debounce_time = level.time + 1;
482 				}
483 				NoAmmoWeaponChange (ent);
484 			}
485 		}
486 		else
487 		{
488 			if (ent->client->ps.gunframe == FRAME_IDLE_LAST)
489 			{
490 				ent->client->ps.gunframe = FRAME_IDLE_FIRST;
491 				return;
492 			}
493 
494 			if (pause_frames)
495 			{
496 				for (n = 0; pause_frames[n]; n++)
497 				{
498 					if (ent->client->ps.gunframe == pause_frames[n])
499 					{
500 						if (rand()&15)
501 							return;
502 					}
503 				}
504 			}
505 
506 			ent->client->ps.gunframe++;
507 			return;
508 		}
509 	}
510 
511 	if (ent->client->weaponstate == WEAPON_FIRING)
512 	{
513 		for (n = 0; fire_frames[n]; n++)
514 		{
515 			if (ent->client->ps.gunframe == fire_frames[n])
516 			{
517 				if (ent->client->quad_framenum > level.framenum)
518 					gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage3.wav"), 1, ATTN_NORM, 0);
519 
520 				fire (ent);
521 				break;
522 			}
523 		}
524 
525 		if (!fire_frames[n])
526 			ent->client->ps.gunframe++;
527 
528 		if (ent->client->ps.gunframe == FRAME_IDLE_FIRST+1)
529 			ent->client->weaponstate = WEAPON_READY;
530 	}
531 }
532 
533 
534 /*
535 ======================================================================
536 
537 GRENADE
538 
539 ======================================================================
540 */
541 
542 #define GRENADE_TIMER		3.0
543 #define GRENADE_MINSPEED	400
544 #define GRENADE_MAXSPEED	800
545 
weapon_grenade_fire(edict_t * ent,qboolean held)546 void weapon_grenade_fire (edict_t *ent, qboolean held)
547 {
548 	vec3_t	offset;
549 	vec3_t	forward, right;
550 	vec3_t	start;
551 	int		damage = 125;
552 	float	timer;
553 	int		speed;
554 	float	radius;
555 
556 	radius = damage+40;
557 	if (is_quad)
558 		damage *= 4;
559 
560 	VectorSet(offset, 8, 8, ent->viewheight-8);
561 	AngleVectors (ent->client->v_angle, forward, right, NULL);
562 	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
563 
564 	timer = ent->client->grenade_time - level.time;
565 	speed = GRENADE_MINSPEED + (GRENADE_TIMER - timer) * ((GRENADE_MAXSPEED - GRENADE_MINSPEED) / GRENADE_TIMER);
566 	fire_grenade2 (ent, start, forward, damage, speed, timer, radius, held);
567 
568 	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
569 		ent->client->pers.inventory[ent->client->ammo_index]--;
570 
571 	ent->client->grenade_time = level.time + 1.0;
572 
573 	if(ent->deadflag || ent->s.modelindex != 255) // VWep animations screw up corpses
574 	{
575 		return;
576 	}
577 
578 	if (ent->health <= 0)
579 		return;
580 
581 	if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
582 	{
583 		ent->client->anim_priority = ANIM_ATTACK;
584 		ent->s.frame = FRAME_crattak1-1;
585 		ent->client->anim_end = FRAME_crattak3;
586 	}
587 	else
588 	{
589 		ent->client->anim_priority = ANIM_REVERSE;
590 		ent->s.frame = FRAME_wave08;
591 		ent->client->anim_end = FRAME_wave01;
592 	}
593 }
594 
Weapon_Grenade(edict_t * ent)595 void Weapon_Grenade (edict_t *ent)
596 {
597 	if ((ent->client->newweapon) && (ent->client->weaponstate == WEAPON_READY))
598 	{
599 		ChangeWeapon (ent);
600 		return;
601 	}
602 
603 	if (ent->client->weaponstate == WEAPON_ACTIVATING)
604 	{
605 		ent->client->weaponstate = WEAPON_READY;
606 		ent->client->ps.gunframe = 16;
607 		return;
608 	}
609 
610 	if (ent->client->weaponstate == WEAPON_READY)
611 	{
612 		if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
613 		{
614 			ent->client->latched_buttons &= ~BUTTON_ATTACK;
615 			if (ent->client->pers.inventory[ent->client->ammo_index])
616 			{
617 				ent->client->ps.gunframe = 1;
618 				ent->client->weaponstate = WEAPON_FIRING;
619 				ent->client->grenade_time = 0;
620 			}
621 			else
622 			{
623 				if (level.time >= ent->pain_debounce_time)
624 				{
625 					gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
626 					ent->pain_debounce_time = level.time + 1;
627 				}
628 				NoAmmoWeaponChange (ent);
629 			}
630 			return;
631 		}
632 
633 		if ((ent->client->ps.gunframe == 29) || (ent->client->ps.gunframe == 34) || (ent->client->ps.gunframe == 39) || (ent->client->ps.gunframe == 48))
634 		{
635 			if (rand()&15)
636 				return;
637 		}
638 
639 		if (++ent->client->ps.gunframe > 48)
640 			ent->client->ps.gunframe = 16;
641 		return;
642 	}
643 
644 	if (ent->client->weaponstate == WEAPON_FIRING)
645 	{
646 		if (ent->client->ps.gunframe == 5)
647 			gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/hgrena1b.wav"), 1, ATTN_NORM, 0);
648 
649 		if (ent->client->ps.gunframe == 11)
650 		{
651 			if (!ent->client->grenade_time)
652 			{
653 				ent->client->grenade_time = level.time + GRENADE_TIMER + 0.2;
654 				ent->client->weapon_sound = gi.soundindex("weapons/hgrenc1b.wav");
655 			}
656 
657 			// they waited too long, detonate it in their hand
658 			if (!ent->client->grenade_blew_up && level.time >= ent->client->grenade_time)
659 			{
660 				ent->client->weapon_sound = 0;
661 				weapon_grenade_fire (ent, true);
662 				ent->client->grenade_blew_up = true;
663 			}
664 
665 			if (ent->client->buttons & BUTTON_ATTACK)
666 				return;
667 
668 			if (ent->client->grenade_blew_up)
669 			{
670 				if (level.time >= ent->client->grenade_time)
671 				{
672 					ent->client->ps.gunframe = 15;
673 					ent->client->grenade_blew_up = false;
674 				}
675 				else
676 				{
677 					return;
678 				}
679 			}
680 		}
681 
682 		if (ent->client->ps.gunframe == 12)
683 		{
684 			ent->client->weapon_sound = 0;
685 			weapon_grenade_fire (ent, false);
686 		}
687 
688 		if ((ent->client->ps.gunframe == 15) && (level.time < ent->client->grenade_time))
689 			return;
690 
691 		ent->client->ps.gunframe++;
692 
693 		if (ent->client->ps.gunframe == 16)
694 		{
695 			ent->client->grenade_time = 0;
696 			ent->client->weaponstate = WEAPON_READY;
697 		}
698 	}
699 }
700 
701 /*
702 ======================================================================
703 
704 GRENADE LAUNCHER
705 
706 ======================================================================
707 */
708 
weapon_grenadelauncher_fire(edict_t * ent)709 void weapon_grenadelauncher_fire (edict_t *ent)
710 {
711 	vec3_t	offset;
712 	vec3_t	forward, right;
713 	vec3_t	start;
714 	int		damage = 120;
715 	float	radius;
716 
717 	radius = damage+40;
718 	if (is_quad)
719 		damage *= 4;
720 
721 	VectorSet(offset, 8, 8, ent->viewheight-8);
722 	AngleVectors (ent->client->v_angle, forward, right, NULL);
723 	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
724 
725 	VectorScale (forward, -2, ent->client->kick_origin);
726 	ent->client->kick_angles[0] = -1;
727 
728 	fire_grenade (ent, start, forward, damage, 600, 2.5, radius);
729 
730 	gi.WriteByte (svc_muzzleflash);
731 	gi.WriteShort (ent-g_edicts);
732 	gi.WriteByte (MZ_GRENADE | is_silenced);
733 	gi.multicast (ent->s.origin, MULTICAST_PVS);
734 
735 	ent->client->ps.gunframe++;
736 
737 	PlayerNoise(ent, start, PNOISE_WEAPON);
738 
739 	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
740 		ent->client->pers.inventory[ent->client->ammo_index]--;
741 }
742 
Weapon_GrenadeLauncher(edict_t * ent)743 void Weapon_GrenadeLauncher (edict_t *ent)
744 {
745 	static int	pause_frames[]	= {34, 51, 59, 0};
746 	static int	fire_frames[]	= {6, 0};
747 
748 	Weapon_Generic (ent, 5, 16, 59, 64, pause_frames, fire_frames, weapon_grenadelauncher_fire);
749 }
750 
751 /*
752 ======================================================================
753 
754 ROCKET
755 
756 ======================================================================
757 */
758 
Weapon_RocketLauncher_Fire(edict_t * ent)759 void Weapon_RocketLauncher_Fire (edict_t *ent)
760 {
761 	vec3_t	offset, start;
762 	vec3_t	forward, right;
763 	int		damage;
764 	float	damage_radius;
765 	int		radius_damage;
766 
767 	damage = 100 + (int)(random() * 20.0);
768 	radius_damage = 120;
769 	damage_radius = 120;
770 	if (is_quad)
771 	{
772 		damage *= 4;
773 		radius_damage *= 4;
774 	}
775 
776 	AngleVectors (ent->client->v_angle, forward, right, NULL);
777 
778 	VectorScale (forward, -2, ent->client->kick_origin);
779 	ent->client->kick_angles[0] = -1;
780 
781 	VectorSet(offset, 8, 8, ent->viewheight-8);
782 	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
783 	fire_rocket (ent, start, forward, damage, 650, damage_radius, radius_damage);
784 
785 	// send muzzle flash
786 	gi.WriteByte (svc_muzzleflash);
787 	gi.WriteShort (ent-g_edicts);
788 	gi.WriteByte (MZ_ROCKET | is_silenced);
789 	gi.multicast (ent->s.origin, MULTICAST_PVS);
790 
791 	ent->client->ps.gunframe++;
792 
793 	PlayerNoise(ent, start, PNOISE_WEAPON);
794 
795 	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
796 		ent->client->pers.inventory[ent->client->ammo_index]--;
797 }
798 
Weapon_RocketLauncher(edict_t * ent)799 void Weapon_RocketLauncher (edict_t *ent)
800 {
801 	static int	pause_frames[]	= {25, 33, 42, 50, 0};
802 	static int	fire_frames[]	= {5, 0};
803 
804 	Weapon_Generic (ent, 4, 12, 50, 54, pause_frames, fire_frames, Weapon_RocketLauncher_Fire);
805 }
806 
807 
808 /*
809 ======================================================================
810 
811 BLASTER / HYPERBLASTER
812 
813 ======================================================================
814 */
815 
Blaster_Fire(edict_t * ent,vec3_t g_offset,int damage,qboolean hyper,int effect)816 void Blaster_Fire (edict_t *ent, vec3_t g_offset, int damage, qboolean hyper, int effect)
817 {
818 	vec3_t	forward, right;
819 	vec3_t	start;
820 	vec3_t	offset;
821 
822 	if (is_quad)
823 		damage *= 4;
824 	AngleVectors (ent->client->v_angle, forward, right, NULL);
825 	VectorSet(offset, 24, 8, ent->viewheight-8);
826 	VectorAdd (offset, g_offset, offset);
827 	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
828 
829 	VectorScale (forward, -2, ent->client->kick_origin);
830 	ent->client->kick_angles[0] = -1;
831 
832 	fire_blaster (ent, start, forward, damage, 1000, effect, hyper);
833 
834 	// send muzzle flash
835 	gi.WriteByte (svc_muzzleflash);
836 	gi.WriteShort (ent-g_edicts);
837 	if (hyper)
838 		gi.WriteByte (MZ_HYPERBLASTER | is_silenced);
839 	else
840 		gi.WriteByte (MZ_BLASTER | is_silenced);
841 	gi.multicast (ent->s.origin, MULTICAST_PVS);
842 
843 	PlayerNoise(ent, start, PNOISE_WEAPON);
844 }
845 
846 
Weapon_Blaster_Fire(edict_t * ent)847 void Weapon_Blaster_Fire (edict_t *ent)
848 {
849 	int		damage;
850 
851 	if (deathmatch->value)
852 		damage = 15;
853 	else
854 		damage = 10;
855 	Blaster_Fire (ent, vec3_origin, damage, false, EF_BLASTER);
856 	ent->client->ps.gunframe++;
857 }
858 
Weapon_Blaster(edict_t * ent)859 void Weapon_Blaster (edict_t *ent)
860 {
861 	static int	pause_frames[]	= {19, 32, 0};
862 	static int	fire_frames[]	= {5, 0};
863 
864 	Weapon_Generic (ent, 4, 8, 52, 55, pause_frames, fire_frames, Weapon_Blaster_Fire);
865 }
866 
867 
Weapon_HyperBlaster_Fire(edict_t * ent)868 void Weapon_HyperBlaster_Fire (edict_t *ent)
869 {
870 	float	rotation;
871 	vec3_t	offset;
872 	int		effect;
873 	int		damage;
874 
875 	ent->client->weapon_sound = gi.soundindex("weapons/hyprbl1a.wav");
876 
877 	if (!(ent->client->buttons & BUTTON_ATTACK))
878 	{
879 		ent->client->ps.gunframe++;
880 	}
881 	else
882 	{
883 		if (! ent->client->pers.inventory[ent->client->ammo_index] )
884 		{
885 			if (level.time >= ent->pain_debounce_time)
886 			{
887 				gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
888 				ent->pain_debounce_time = level.time + 1;
889 			}
890 			NoAmmoWeaponChange (ent);
891 		}
892 		else
893 		{
894 			rotation = (ent->client->ps.gunframe - 5) * 2*M_PI/6;
895 			offset[0] = -4 * sin(rotation);
896 			offset[1] = 0;
897 			offset[2] = 4 * cos(rotation);
898 
899 			if ((ent->client->ps.gunframe == 6) || (ent->client->ps.gunframe == 9))
900 				effect = EF_HYPERBLASTER;
901 			else
902 				effect = 0;
903 			if (deathmatch->value)
904 				damage = 15;
905 			else
906 				damage = 20;
907 			Blaster_Fire (ent, offset, damage, true, effect);
908 			if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
909 				ent->client->pers.inventory[ent->client->ammo_index]--;
910 
911 			ent->client->anim_priority = ANIM_ATTACK;
912 			if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
913 			{
914 				ent->s.frame = FRAME_crattak1 - 1;
915 				ent->client->anim_end = FRAME_crattak9;
916 			}
917 			else
918 			{
919 				ent->s.frame = FRAME_attack1 - 1;
920 				ent->client->anim_end = FRAME_attack8;
921 			}
922 		}
923 
924 		ent->client->ps.gunframe++;
925 		if (ent->client->ps.gunframe == 12 && ent->client->pers.inventory[ent->client->ammo_index])
926 			ent->client->ps.gunframe = 6;
927 	}
928 
929 	if (ent->client->ps.gunframe == 12)
930 	{
931 		gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/hyprbd1a.wav"), 1, ATTN_NORM, 0);
932 		ent->client->weapon_sound = 0;
933 	}
934 
935 }
936 
Weapon_HyperBlaster(edict_t * ent)937 void Weapon_HyperBlaster (edict_t *ent)
938 {
939 	static int	pause_frames[]	= {0};
940 	static int	fire_frames[]	= {6, 7, 8, 9, 10, 11, 0};
941 
942 	Weapon_Generic (ent, 5, 20, 49, 53, pause_frames, fire_frames, Weapon_HyperBlaster_Fire);
943 }
944 
945 /*
946 ======================================================================
947 
948 MACHINEGUN / CHAINGUN
949 
950 ======================================================================
951 */
952 
Machinegun_Fire(edict_t * ent)953 void Machinegun_Fire (edict_t *ent)
954 {
955 	int	i;
956 	vec3_t		start;
957 	vec3_t		forward, right;
958 	vec3_t		angles;
959 	int			damage = 8;
960 	int			kick = 2;
961 	vec3_t		offset;
962 
963 	if (!(ent->client->buttons & BUTTON_ATTACK))
964 	{
965 		ent->client->machinegun_shots = 0;
966 		ent->client->ps.gunframe++;
967 		return;
968 	}
969 
970 	if (ent->client->ps.gunframe == 5)
971 		ent->client->ps.gunframe = 4;
972 	else
973 		ent->client->ps.gunframe = 5;
974 
975 	if (ent->client->pers.inventory[ent->client->ammo_index] < 1)
976 	{
977 		ent->client->ps.gunframe = 6;
978 		if (level.time >= ent->pain_debounce_time)
979 		{
980 			gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
981 			ent->pain_debounce_time = level.time + 1;
982 		}
983 		NoAmmoWeaponChange (ent);
984 		return;
985 	}
986 
987 	if (is_quad)
988 	{
989 		damage *= 4;
990 		kick *= 4;
991 	}
992 
993 	for (i=1 ; i<3 ; i++)
994 	{
995 		ent->client->kick_origin[i] = crandom() * 0.35;
996 		ent->client->kick_angles[i] = crandom() * 0.7;
997 	}
998 	ent->client->kick_origin[0] = crandom() * 0.35;
999 	ent->client->kick_angles[0] = ent->client->machinegun_shots * -1.5;
1000 
1001 	// raise the gun as it is firing
1002 	if (!deathmatch->value)
1003 	{
1004 		ent->client->machinegun_shots++;
1005 		if (ent->client->machinegun_shots > 9)
1006 			ent->client->machinegun_shots = 9;
1007 	}
1008 
1009 	// get start / end positions
1010 	VectorAdd (ent->client->v_angle, ent->client->kick_angles, angles);
1011 	AngleVectors (angles, forward, right, NULL);
1012 	VectorSet(offset, 0, 8, ent->viewheight-8);
1013 	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1014 	fire_bullet (ent, start, forward, damage, kick, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MOD_MACHINEGUN);
1015 
1016 	gi.WriteByte (svc_muzzleflash);
1017 	gi.WriteShort (ent-g_edicts);
1018 	gi.WriteByte (MZ_MACHINEGUN | is_silenced);
1019 	gi.multicast (ent->s.origin, MULTICAST_PVS);
1020 
1021 	PlayerNoise(ent, start, PNOISE_WEAPON);
1022 
1023 	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1024 		ent->client->pers.inventory[ent->client->ammo_index]--;
1025 
1026 	ent->client->anim_priority = ANIM_ATTACK;
1027 	if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
1028 	{
1029 		ent->s.frame = FRAME_crattak1 - (int) (random()+0.25);
1030 		ent->client->anim_end = FRAME_crattak9;
1031 	}
1032 	else
1033 	{
1034 		ent->s.frame = FRAME_attack1 - (int) (random()+0.25);
1035 		ent->client->anim_end = FRAME_attack8;
1036 	}
1037 }
1038 
Weapon_Machinegun(edict_t * ent)1039 void Weapon_Machinegun (edict_t *ent)
1040 {
1041 	static int	pause_frames[]	= {23, 45, 0};
1042 	static int	fire_frames[]	= {4, 5, 0};
1043 
1044 	Weapon_Generic (ent, 3, 5, 45, 49, pause_frames, fire_frames, Machinegun_Fire);
1045 }
1046 
Chaingun_Fire(edict_t * ent)1047 void Chaingun_Fire (edict_t *ent)
1048 {
1049 	int			i;
1050 	int			shots;
1051 	vec3_t		start;
1052 	vec3_t		forward, right, up;
1053 	float		r, u;
1054 	vec3_t		offset;
1055 	int			damage;
1056 	int			kick = 2;
1057 
1058 	if (deathmatch->value)
1059 		damage = 6;
1060 	else
1061 		damage = 8;
1062 
1063 	if (ent->client->ps.gunframe == 5)
1064 		gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnu1a.wav"), 1, ATTN_IDLE, 0);
1065 
1066 	if ((ent->client->ps.gunframe == 14) && !(ent->client->buttons & BUTTON_ATTACK))
1067 	{
1068 		ent->client->ps.gunframe = 32;
1069 		ent->client->weapon_sound = 0;
1070 		return;
1071 	}
1072 	else if ((ent->client->ps.gunframe == 21) && (ent->client->buttons & BUTTON_ATTACK)
1073 		&& ent->client->pers.inventory[ent->client->ammo_index])
1074 	{
1075 		ent->client->ps.gunframe = 15;
1076 	}
1077 	else
1078 	{
1079 		ent->client->ps.gunframe++;
1080 	}
1081 
1082 	if (ent->client->ps.gunframe == 22)
1083 	{
1084 		ent->client->weapon_sound = 0;
1085 		gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnd1a.wav"), 1, ATTN_IDLE, 0);
1086 	}
1087 	else
1088 	{
1089 		ent->client->weapon_sound = gi.soundindex("weapons/chngnl1a.wav");
1090 	}
1091 
1092 	ent->client->anim_priority = ANIM_ATTACK;
1093 	if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
1094 	{
1095 		ent->s.frame = FRAME_crattak1 - (ent->client->ps.gunframe & 1);
1096 		ent->client->anim_end = FRAME_crattak9;
1097 	}
1098 	else
1099 	{
1100 		ent->s.frame = FRAME_attack1 - (ent->client->ps.gunframe & 1);
1101 		ent->client->anim_end = FRAME_attack8;
1102 	}
1103 
1104 	if (ent->client->ps.gunframe <= 9)
1105 		shots = 1;
1106 	else if (ent->client->ps.gunframe <= 14)
1107 	{
1108 		if (ent->client->buttons & BUTTON_ATTACK)
1109 			shots = 2;
1110 		else
1111 			shots = 1;
1112 	}
1113 	else
1114 		shots = 3;
1115 
1116 	if (ent->client->pers.inventory[ent->client->ammo_index] < shots)
1117 		shots = ent->client->pers.inventory[ent->client->ammo_index];
1118 
1119 	if (!shots)
1120 	{
1121 		if (level.time >= ent->pain_debounce_time)
1122 		{
1123 			gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
1124 			ent->pain_debounce_time = level.time + 1;
1125 		}
1126 		NoAmmoWeaponChange (ent);
1127 		return;
1128 	}
1129 
1130 	if (is_quad)
1131 	{
1132 		damage *= 4;
1133 		kick *= 4;
1134 	}
1135 
1136 	for (i=0 ; i<3 ; i++)
1137 	{
1138 		ent->client->kick_origin[i] = crandom() * 0.35;
1139 		ent->client->kick_angles[i] = crandom() * 0.7;
1140 	}
1141 
1142 	for (i=0 ; i<shots ; i++)
1143 	{
1144 		// get start / end positions
1145 		AngleVectors (ent->client->v_angle, forward, right, up);
1146 		r = 7 + crandom()*4;
1147 		u = crandom()*4;
1148 		VectorSet(offset, 0, r, u + ent->viewheight-8);
1149 		P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1150 
1151 		fire_bullet (ent, start, forward, damage, kick, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MOD_CHAINGUN);
1152 	}
1153 
1154 	// send muzzle flash
1155 	gi.WriteByte (svc_muzzleflash);
1156 	gi.WriteShort (ent-g_edicts);
1157 	gi.WriteByte ((MZ_CHAINGUN1 + shots - 1) | is_silenced);
1158 	gi.multicast (ent->s.origin, MULTICAST_PVS);
1159 
1160 	PlayerNoise(ent, start, PNOISE_WEAPON);
1161 
1162 	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1163 		ent->client->pers.inventory[ent->client->ammo_index] -= shots;
1164 }
1165 
1166 
Weapon_Chaingun(edict_t * ent)1167 void Weapon_Chaingun (edict_t *ent)
1168 {
1169 	static int	pause_frames[]	= {38, 43, 51, 61, 0};
1170 	static int	fire_frames[]	= {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0};
1171 
1172 	Weapon_Generic (ent, 4, 31, 61, 64, pause_frames, fire_frames, Chaingun_Fire);
1173 }
1174 
1175 
1176 /*
1177 ======================================================================
1178 
1179 SHOTGUN / SUPERSHOTGUN
1180 
1181 ======================================================================
1182 */
1183 
weapon_shotgun_fire(edict_t * ent)1184 void weapon_shotgun_fire (edict_t *ent)
1185 {
1186 	vec3_t		start;
1187 	vec3_t		forward, right;
1188 	vec3_t		offset;
1189 	int			damage = 4;
1190 	int			kick = 8;
1191 
1192 	if (ent->client->ps.gunframe == 9)
1193 	{
1194 		ent->client->ps.gunframe++;
1195 		return;
1196 	}
1197 
1198 	AngleVectors (ent->client->v_angle, forward, right, NULL);
1199 
1200 	VectorScale (forward, -2, ent->client->kick_origin);
1201 	ent->client->kick_angles[0] = -2;
1202 
1203 	VectorSet(offset, 0, 8,  ent->viewheight-8);
1204 	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1205 
1206 	if (is_quad)
1207 	{
1208 		damage *= 4;
1209 		kick *= 4;
1210 	}
1211 
1212 	if (deathmatch->value)
1213 		fire_shotgun (ent, start, forward, damage, kick, 500, 500, DEFAULT_DEATHMATCH_SHOTGUN_COUNT, MOD_SHOTGUN);
1214 	else
1215 		fire_shotgun (ent, start, forward, damage, kick, 500, 500, DEFAULT_SHOTGUN_COUNT, MOD_SHOTGUN);
1216 
1217 	// send muzzle flash
1218 	gi.WriteByte (svc_muzzleflash);
1219 	gi.WriteShort (ent-g_edicts);
1220 	gi.WriteByte (MZ_SHOTGUN | is_silenced);
1221 	gi.multicast (ent->s.origin, MULTICAST_PVS);
1222 
1223 	ent->client->ps.gunframe++;
1224 	PlayerNoise(ent, start, PNOISE_WEAPON);
1225 
1226 	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1227 		ent->client->pers.inventory[ent->client->ammo_index]--;
1228 }
1229 
Weapon_Shotgun(edict_t * ent)1230 void Weapon_Shotgun (edict_t *ent)
1231 {
1232 	static int	pause_frames[]	= {22, 28, 34, 0};
1233 	static int	fire_frames[]	= {8, 9, 0};
1234 
1235 	Weapon_Generic (ent, 7, 18, 36, 39, pause_frames, fire_frames, weapon_shotgun_fire);
1236 }
1237 
1238 
weapon_supershotgun_fire(edict_t * ent)1239 void weapon_supershotgun_fire (edict_t *ent)
1240 {
1241 	vec3_t		start;
1242 	vec3_t		forward, right;
1243 	vec3_t		offset;
1244 	vec3_t		v;
1245 	int			damage = 6;
1246 	int			kick = 12;
1247 
1248 	AngleVectors (ent->client->v_angle, forward, right, NULL);
1249 
1250 	VectorScale (forward, -2, ent->client->kick_origin);
1251 	ent->client->kick_angles[0] = -2;
1252 
1253 	VectorSet(offset, 0, 8,  ent->viewheight-8);
1254 	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1255 
1256 	if (is_quad)
1257 	{
1258 		damage *= 4;
1259 		kick *= 4;
1260 	}
1261 
1262 	v[PITCH] = ent->client->v_angle[PITCH];
1263 	v[YAW]   = ent->client->v_angle[YAW] - 5;
1264 	v[ROLL]  = ent->client->v_angle[ROLL];
1265 	AngleVectors (v, forward, NULL, NULL);
1266 	fire_shotgun (ent, start, forward, damage, kick, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT/2, MOD_SSHOTGUN);
1267 	v[YAW]   = ent->client->v_angle[YAW] + 5;
1268 	AngleVectors (v, forward, NULL, NULL);
1269 	fire_shotgun (ent, start, forward, damage, kick, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT/2, MOD_SSHOTGUN);
1270 
1271 	// send muzzle flash
1272 	gi.WriteByte (svc_muzzleflash);
1273 	gi.WriteShort (ent-g_edicts);
1274 	gi.WriteByte (MZ_SSHOTGUN | is_silenced);
1275 	gi.multicast (ent->s.origin, MULTICAST_PVS);
1276 
1277 	ent->client->ps.gunframe++;
1278 	PlayerNoise(ent, start, PNOISE_WEAPON);
1279 
1280 	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1281 		ent->client->pers.inventory[ent->client->ammo_index] -= 2;
1282 }
1283 
Weapon_SuperShotgun(edict_t * ent)1284 void Weapon_SuperShotgun (edict_t *ent)
1285 {
1286 	static int	pause_frames[]	= {29, 42, 57, 0};
1287 	static int	fire_frames[]	= {7, 0};
1288 
1289 	Weapon_Generic (ent, 6, 17, 57, 61, pause_frames, fire_frames, weapon_supershotgun_fire);
1290 }
1291 
1292 
1293 
1294 /*
1295 ======================================================================
1296 
1297 RAILGUN
1298 
1299 ======================================================================
1300 */
1301 
weapon_railgun_fire(edict_t * ent)1302 void weapon_railgun_fire (edict_t *ent)
1303 {
1304 	vec3_t		start;
1305 	vec3_t		forward, right;
1306 	vec3_t		offset;
1307 	int			damage;
1308 	int			kick;
1309 
1310 	if (deathmatch->value)
1311 	{	// normal damage is too extreme in dm
1312 		damage = 100;
1313 		kick = 200;
1314 	}
1315 	else
1316 	{
1317 		damage = 150;
1318 		kick = 250;
1319 	}
1320 
1321 	if (is_quad)
1322 	{
1323 		damage *= 4;
1324 		kick *= 4;
1325 	}
1326 
1327 	AngleVectors (ent->client->v_angle, forward, right, NULL);
1328 
1329 	VectorScale (forward, -3, ent->client->kick_origin);
1330 	ent->client->kick_angles[0] = -3;
1331 
1332 	VectorSet(offset, 0, 7,  ent->viewheight-8);
1333 	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1334 	fire_rail (ent, start, forward, damage, kick);
1335 
1336 	// send muzzle flash
1337 	gi.WriteByte (svc_muzzleflash);
1338 	gi.WriteShort (ent-g_edicts);
1339 	gi.WriteByte (MZ_RAILGUN | is_silenced);
1340 	gi.multicast (ent->s.origin, MULTICAST_PVS);
1341 
1342 	ent->client->ps.gunframe++;
1343 	PlayerNoise(ent, start, PNOISE_WEAPON);
1344 
1345 	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1346 		ent->client->pers.inventory[ent->client->ammo_index]--;
1347 }
1348 
1349 
Weapon_Railgun(edict_t * ent)1350 void Weapon_Railgun (edict_t *ent)
1351 {
1352 	static int	pause_frames[]	= {56, 0};
1353 	static int	fire_frames[]	= {4, 0};
1354 
1355 	Weapon_Generic (ent, 3, 18, 56, 61, pause_frames, fire_frames, weapon_railgun_fire);
1356 }
1357 
1358 
1359 /*
1360 ======================================================================
1361 
1362 BFG10K
1363 
1364 ======================================================================
1365 */
1366 
weapon_bfg_fire(edict_t * ent)1367 void weapon_bfg_fire (edict_t *ent)
1368 {
1369 	vec3_t	offset, start;
1370 	vec3_t	forward, right;
1371 	int		damage;
1372 	float	damage_radius = 1000;
1373 
1374 	if (deathmatch->value)
1375 		damage = 200;
1376 	else
1377 		damage = 500;
1378 
1379 	if (ent->client->ps.gunframe == 9)
1380 	{
1381 		// send muzzle flash
1382 		gi.WriteByte (svc_muzzleflash);
1383 		gi.WriteShort (ent-g_edicts);
1384 		gi.WriteByte (MZ_BFG | is_silenced);
1385 		gi.multicast (ent->s.origin, MULTICAST_PVS);
1386 
1387 		ent->client->ps.gunframe++;
1388 
1389 		PlayerNoise(ent, start, PNOISE_WEAPON);
1390 		return;
1391 	}
1392 
1393 	// cells can go down during windup (from power armor hits), so
1394 	// check again and abort firing if we don't have enough now
1395 	if (ent->client->pers.inventory[ent->client->ammo_index] < 50)
1396 	{
1397 		ent->client->ps.gunframe++;
1398 		return;
1399 	}
1400 
1401 	if (is_quad)
1402 		damage *= 4;
1403 
1404 	AngleVectors (ent->client->v_angle, forward, right, NULL);
1405 
1406 	VectorScale (forward, -2, ent->client->kick_origin);
1407 
1408 	// make a big pitch kick with an inverse fall
1409 	ent->client->v_dmg_pitch = -40;
1410 	ent->client->v_dmg_roll = crandom()*8;
1411 	ent->client->v_dmg_time = level.time + DAMAGE_TIME;
1412 
1413 	VectorSet(offset, 8, 8, ent->viewheight-8);
1414 	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1415 	fire_bfg (ent, start, forward, damage, 400, damage_radius);
1416 
1417 	ent->client->ps.gunframe++;
1418 
1419 	PlayerNoise(ent, start, PNOISE_WEAPON);
1420 
1421 	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1422 		ent->client->pers.inventory[ent->client->ammo_index] -= 50;
1423 }
1424 
Weapon_BFG(edict_t * ent)1425 void Weapon_BFG (edict_t *ent)
1426 {
1427 	static int	pause_frames[]	= {39, 45, 50, 55, 0};
1428 	static int	fire_frames[]	= {9, 17, 0};
1429 
1430 	Weapon_Generic (ent, 8, 32, 55, 58, pause_frames, fire_frames, weapon_bfg_fire);
1431 }
1432 
1433 
1434 //======================================================================
1435