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