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