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 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 		return;
235 	}
236 	// RAFAEL
237 	if ( ent->client->pers.inventory[ITEM_INDEX (FindItem ("cells"))]
238 		&& ent->client->pers.inventory[ITEM_INDEX (FindItem ("ionripper"))])
239 	{
240 		ent->client->newweapon = FindItem ("ionripper");
241 		return;
242 	}
243 
244 	if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("cells"))]
245 		&&  ent->client->pers.inventory[ITEM_INDEX(FindItem("hyperblaster"))] )
246 	{
247 		ent->client->newweapon = FindItem ("hyperblaster");
248 		return;
249 	}
250 	if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("bullets"))]
251 		&&  ent->client->pers.inventory[ITEM_INDEX(FindItem("chaingun"))] )
252 	{
253 		ent->client->newweapon = FindItem ("chaingun");
254 		return;
255 	}
256 	if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("bullets"))]
257 		&&  ent->client->pers.inventory[ITEM_INDEX(FindItem("machinegun"))] )
258 	{
259 		ent->client->newweapon = FindItem ("machinegun");
260 		return;
261 	}
262 	if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("shells"))] > 1
263 		&&  ent->client->pers.inventory[ITEM_INDEX(FindItem("super shotgun"))] )
264 	{
265 		ent->client->newweapon = FindItem ("super shotgun");
266 		return;
267 	}
268 	if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("shells"))]
269 		&&  ent->client->pers.inventory[ITEM_INDEX(FindItem("shotgun"))] )
270 	{
271 		ent->client->newweapon = FindItem ("shotgun");
272 		return;
273 	}
274 	ent->client->newweapon = FindItem ("blaster");
275 }
276 
277 /*
278 =================
279 Think_Weapon
280 
281 Called by ClientBeginServerFrame and ClientThink
282 =================
283 */
Think_Weapon(edict_t * ent)284 void Think_Weapon (edict_t *ent)
285 {
286 	// if just died, put the weapon away
287 	if (ent->health < 1)
288 	{
289 		ent->client->newweapon = NULL;
290 		ChangeWeapon (ent);
291 	}
292 
293 	// call active weapon think routine
294 	if (ent->client->pers.weapon && ent->client->pers.weapon->weaponthink)
295 	{
296 		is_quad = (ent->client->quad_framenum > level.framenum);
297 		// RAFAEL
298 		is_quadfire = (ent->client->quadfire_framenum > level.framenum);
299 		if (ent->client->silencer_shots)
300 			is_silenced = MZ_SILENCED;
301 		else
302 			is_silenced = 0;
303 		ent->client->pers.weapon->weaponthink (ent);
304 	}
305 }
306 
307 
308 /*
309 ================
310 Use_Weapon
311 
312 Make the weapon ready if there is ammo
313 ================
314 */
Use_Weapon(edict_t * ent,gitem_t * item)315 void Use_Weapon (edict_t *ent, gitem_t *item)
316 {
317 	int			ammo_index;
318 	gitem_t		*ammo_item;
319 
320 	// see if we're already using it
321 	if (item == ent->client->pers.weapon)
322 		return;
323 
324 	if (item->ammo && !g_select_empty->value && !(item->flags & IT_AMMO))
325 	{
326 		ammo_item = FindItem(item->ammo);
327 		ammo_index = ITEM_INDEX(ammo_item);
328 
329 		if (!ent->client->pers.inventory[ammo_index])
330 		{
331 #ifdef WITH_ACEBOT
332 		safe_cprintf
333 #else
334 		gi.cprintf
335 #endif
336 			 (ent, PRINT_HIGH, "No %s for %s.\n", ammo_item->pickup_name, item->pickup_name);
337 			return;
338 		}
339 
340 		if (ent->client->pers.inventory[ammo_index] < item->quantity)
341 		{
342 #ifdef WITH_ACEBOT
343 		safe_cprintf
344 #else
345 		gi.cprintf
346 #endif
347 			 (ent, PRINT_HIGH, "Not enough %s for %s.\n", ammo_item->pickup_name, item->pickup_name);
348 			return;
349 		}
350 	}
351 
352 	// change to this weapon when down
353 	ent->client->newweapon = item;
354 }
355 
356 // RAFAEL 14-APR-98
Use_Weapon2(edict_t * ent,gitem_t * item)357 void Use_Weapon2 (edict_t *ent, gitem_t *item)
358 {
359 	int			ammo_index;
360 	gitem_t		*ammo_item;
361 	gitem_t		*nextitem;
362 	int			index;
363 
364 	if (strcmp (item->pickup_name, "HyperBlaster") == 0)
365 	{
366 		if (item == ent->client->pers.weapon)
367 		{
368 			item = FindItem ("Ionripper");
369 			index = ITEM_INDEX (item);
370 			if (!ent->client->pers.inventory[index])
371 			{
372 				item = FindItem ("HyperBlaster");
373 			}
374 		}
375 	}
376 
377 	else if (strcmp (item->pickup_name, "Railgun") == 0)
378   	{
379 		ammo_item = FindItem(item->ammo);
380 		ammo_index = ITEM_INDEX(ammo_item);
381 		if (!ent->client->pers.inventory[ammo_index])
382 		{
383 			nextitem = FindItem ("Phalanx");
384 			ammo_item = FindItem(nextitem->ammo);
385 			ammo_index = ITEM_INDEX(ammo_item);
386 			if (ent->client->pers.inventory[ammo_index])
387 			{
388 				item = FindItem ("Phalanx");
389 				index = ITEM_INDEX (item);
390 				if (!ent->client->pers.inventory[index])
391 				{
392 					item = FindItem ("Railgun");
393 				}
394 			}
395 		}
396 		else if (item == ent->client->pers.weapon)
397 		{
398 			item = FindItem ("Phalanx");
399 			index = ITEM_INDEX (item);
400 			if (!ent->client->pers.inventory[index])
401 			{
402 				item = FindItem ("Railgun");
403 			}
404 		}
405 
406 	}
407 
408 
409 	// see if we're already using it
410 	if (item == ent->client->pers.weapon)
411 		return;
412 
413 	if (item->ammo)
414 	{
415 		ammo_item = FindItem(item->ammo);
416 		ammo_index = ITEM_INDEX(ammo_item);
417 		if (!ent->client->pers.inventory[ammo_index] && !g_select_empty->value)
418 		{
419 #ifdef WITH_ACEBOT
420 		safe_cprintf
421 #else
422 		gi.cprintf
423 #endif
424 			 (ent, PRINT_HIGH, "No %s for %s.\n", ammo_item->pickup_name, item->pickup_name);
425 			return;
426 		}
427 	}
428 
429 	// change to this weapon when down
430 	ent->client->newweapon = item;
431 
432 }
433 // END 14-APR-98
434 
435 /*
436 ================
437 Drop_Weapon
438 ================
439 */
Drop_Weapon(edict_t * ent,gitem_t * item)440 void Drop_Weapon (edict_t *ent, gitem_t *item)
441 {
442 	int		index;
443 
444 	if ((int)(dmflags->value) & DF_WEAPONS_STAY)
445 		return;
446 
447 	index = ITEM_INDEX(item);
448 	// see if we're already using it
449 	if ( ((item == ent->client->pers.weapon) || (item == ent->client->newweapon))&& (ent->client->pers.inventory[index] == 1) )
450 	{
451 #ifdef WITH_ACEBOT
452 		safe_cprintf
453 #else
454 		gi.cprintf
455 #endif
456 		 (ent, PRINT_HIGH, "Can't drop current weapon\n");
457 		return;
458 	}
459 
460 	Drop_Item (ent, item);
461 	ent->client->pers.inventory[index]--;
462 }
463 
464 
465 /*
466 ================
467 Weapon_Generic
468 
469 A generic function to handle the basics of weapon thinking
470 ================
471 */
472 #define FRAME_FIRE_FIRST		(FRAME_ACTIVATE_LAST + 1)
473 #define FRAME_IDLE_FIRST		(FRAME_FIRE_LAST + 1)
474 #define FRAME_DEACTIVATE_FIRST	(FRAME_IDLE_LAST + 1)
475 
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))476 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))
477 {
478 	int		n;
479 
480 	if (ent->client->weaponstate == WEAPON_DROPPING)
481 	{
482 		if (ent->client->ps.gunframe == FRAME_DEACTIVATE_LAST)
483 		{
484 			ChangeWeapon (ent);
485 			return;
486 		}
487 		else if ((FRAME_DEACTIVATE_LAST - ent->client->ps.gunframe) == 4)
488 		{
489 			ent->client->anim_priority = ANIM_REVERSE;
490 			if(ent->client->ps.pmove.pm_flags & PMF_DUCKED)
491 			{
492 				ent->s.frame = FRAME_crpain4+1;
493 				ent->client->anim_end = FRAME_crpain1;
494 			}
495 			else
496 			{
497 				ent->s.frame = FRAME_pain304+1;
498 				ent->client->anim_end = FRAME_pain301;
499 
500 			}
501 		}
502 
503 		ent->client->ps.gunframe++;
504 		return;
505 	}
506 
507 	if (ent->client->weaponstate == WEAPON_ACTIVATING)
508 	{
509 		if (ent->client->ps.gunframe == FRAME_ACTIVATE_LAST)
510 		{
511 			ent->client->weaponstate = WEAPON_READY;
512 			ent->client->ps.gunframe = FRAME_IDLE_FIRST;
513 			return;
514 		}
515 
516 		ent->client->ps.gunframe++;
517 		return;
518 	}
519 
520 	if ((ent->client->newweapon) && (ent->client->weaponstate != WEAPON_FIRING))
521 	{
522 		ent->client->weaponstate = WEAPON_DROPPING;
523 		ent->client->ps.gunframe = FRAME_DEACTIVATE_FIRST;
524 
525 		if ((FRAME_DEACTIVATE_LAST - FRAME_DEACTIVATE_FIRST) < 4)
526 		{
527 			ent->client->anim_priority = ANIM_REVERSE;
528 			if(ent->client->ps.pmove.pm_flags & PMF_DUCKED)
529 			{
530 				ent->s.frame = FRAME_crpain4+1;
531 				ent->client->anim_end = FRAME_crpain1;
532 			}
533 			else
534 			{
535 				ent->s.frame = FRAME_pain304+1;
536 				ent->client->anim_end = FRAME_pain301;
537 
538 			}
539 		}
540 		return;
541 	}
542 
543 	if (ent->client->weaponstate == WEAPON_READY)
544 	{
545 		if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
546 		{
547 			ent->client->latched_buttons &= ~BUTTON_ATTACK;
548 			if ((!ent->client->ammo_index) ||
549 				( ent->client->pers.inventory[ent->client->ammo_index] >= ent->client->pers.weapon->quantity))
550 			{
551 				ent->client->ps.gunframe = FRAME_FIRE_FIRST;
552 				ent->client->weaponstate = WEAPON_FIRING;
553 
554 				// start the animation
555 				ent->client->anim_priority = ANIM_ATTACK;
556 				if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
557 				{
558 					ent->s.frame = FRAME_crattak1-1;
559 					ent->client->anim_end = FRAME_crattak9;
560 				}
561 				else
562 				{
563 					ent->s.frame = FRAME_attack1-1;
564 					ent->client->anim_end = FRAME_attack8;
565 				}
566 			}
567 			else
568 			{
569 				if (level.time >= ent->pain_debounce_time)
570 				{
571 					gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
572 					ent->pain_debounce_time = level.time + 1;
573 				}
574 				NoAmmoWeaponChange (ent);
575 			}
576 		}
577 		else
578 		{
579 			if (ent->client->ps.gunframe == FRAME_IDLE_LAST)
580 			{
581 				ent->client->ps.gunframe = FRAME_IDLE_FIRST;
582 				return;
583 			}
584 
585 			if (pause_frames)
586 			{
587 				for (n = 0; pause_frames[n]; n++)
588 				{
589 					if (ent->client->ps.gunframe == pause_frames[n])
590 					{
591 						if (rand()&15)
592 							return;
593 					}
594 				}
595 			}
596 
597 			ent->client->ps.gunframe++;
598 			return;
599 		}
600 	}
601 
602 	if (ent->client->weaponstate == WEAPON_FIRING)
603 	{
604 		for (n = 0; fire_frames[n]; n++)
605 		{
606 			if (ent->client->ps.gunframe == fire_frames[n])
607 			{
608 				if (ent->client->quad_framenum > level.framenum)
609 					gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage3.wav"), 1, ATTN_NORM, 0);
610 
611 				fire (ent);
612 				break;
613 			}
614 		}
615 
616 		if (!fire_frames[n])
617 			ent->client->ps.gunframe++;
618 
619 		if (ent->client->ps.gunframe == FRAME_IDLE_FIRST+1)
620 			ent->client->weaponstate = WEAPON_READY;
621 	}
622 }
623 
624 
625 /*
626 ======================================================================
627 
628 GRENADE
629 
630 ======================================================================
631 */
632 
633 #define GRENADE_TIMER		3.0
634 #define GRENADE_MINSPEED	400
635 #define GRENADE_MAXSPEED	800
636 
weapon_grenade_fire(edict_t * ent,qboolean held)637 void weapon_grenade_fire (edict_t *ent, qboolean held)
638 {
639 	vec3_t	offset;
640 	vec3_t	forward, right;
641 	vec3_t	start;
642 	int		damage = 125;
643 	float	timer;
644 	int		speed;
645 	float	radius;
646 
647 	radius = damage+40;
648 	if (is_quad)
649 		damage *= 4;
650 
651 	VectorSet(offset, 8, 8, ent->viewheight-8);
652 	AngleVectors (ent->client->v_angle, forward, right, NULL);
653 	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
654 
655 	timer = ent->client->grenade_time - level.time;
656 	speed = GRENADE_MINSPEED + (GRENADE_TIMER - timer) * ((GRENADE_MAXSPEED - GRENADE_MINSPEED) / GRENADE_TIMER);
657 	fire_grenade2 (ent, start, forward, damage, speed, timer, radius, held);
658 
659 	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
660 		ent->client->pers.inventory[ent->client->ammo_index]--;
661 
662 	ent->client->grenade_time = level.time + 1.0;
663 
664 	if (ent->health <= 0)
665 		return;
666 
667 	if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
668 	{
669 		ent->client->anim_priority = ANIM_ATTACK;
670 		ent->s.frame = FRAME_crattak1-1;
671 		ent->client->anim_end = FRAME_crattak3;
672 	}
673 	else
674 	{
675 		ent->client->anim_priority = ANIM_REVERSE;
676 		ent->s.frame = FRAME_wave08;
677 		ent->client->anim_end = FRAME_wave01;
678 	}
679 }
680 
Weapon_Grenade(edict_t * ent)681 void Weapon_Grenade (edict_t *ent)
682 {
683 	if ((ent->client->newweapon) && (ent->client->weaponstate == WEAPON_READY))
684 	{
685 		ChangeWeapon (ent);
686 		return;
687 	}
688 
689 	if (ent->client->weaponstate == WEAPON_ACTIVATING)
690 	{
691 		ent->client->weaponstate = WEAPON_READY;
692 		ent->client->ps.gunframe = 16;
693 		return;
694 	}
695 
696 	if (ent->client->weaponstate == WEAPON_READY)
697 	{
698 		if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
699 		{
700 			ent->client->latched_buttons &= ~BUTTON_ATTACK;
701 			if (ent->client->pers.inventory[ent->client->ammo_index])
702 			{
703 				ent->client->ps.gunframe = 1;
704 				ent->client->weaponstate = WEAPON_FIRING;
705 				ent->client->grenade_time = 0;
706 			}
707 			else
708 			{
709 				if (level.time >= ent->pain_debounce_time)
710 				{
711 					gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
712 					ent->pain_debounce_time = level.time + 1;
713 				}
714 				NoAmmoWeaponChange (ent);
715 			}
716 			return;
717 		}
718 
719 		if ((ent->client->ps.gunframe == 29) || (ent->client->ps.gunframe == 34) || (ent->client->ps.gunframe == 39) || (ent->client->ps.gunframe == 48))
720 		{
721 			if (rand()&15)
722 				return;
723 		}
724 
725 		if (++ent->client->ps.gunframe > 48)
726 			ent->client->ps.gunframe = 16;
727 		return;
728 	}
729 
730 	if (ent->client->weaponstate == WEAPON_FIRING)
731 	{
732 		if (ent->client->ps.gunframe == 5)
733 			gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/hgrena1b.wav"), 1, ATTN_NORM, 0);
734 
735 		if (ent->client->ps.gunframe == 11)
736 		{
737 			if (!ent->client->grenade_time)
738 			{
739 				ent->client->grenade_time = level.time + GRENADE_TIMER + 0.2;
740 				ent->client->weapon_sound = gi.soundindex("weapons/hgrenc1b.wav");
741 			}
742 
743 			// they waited too long, detonate it in their hand
744 			if (!ent->client->grenade_blew_up && level.time >= ent->client->grenade_time)
745 			{
746 				ent->client->weapon_sound = 0;
747 				weapon_grenade_fire (ent, true);
748 				ent->client->grenade_blew_up = true;
749 			}
750 
751 			if (ent->client->buttons & BUTTON_ATTACK)
752 				return;
753 
754 			if (ent->client->grenade_blew_up)
755 			{
756 				if (level.time >= ent->client->grenade_time)
757 				{
758 					ent->client->ps.gunframe = 15;
759 					ent->client->grenade_blew_up = false;
760 				}
761 				else
762 				{
763 					return;
764 				}
765 			}
766 		}
767 
768 		if (ent->client->ps.gunframe == 12)
769 		{
770 			ent->client->weapon_sound = 0;
771 			weapon_grenade_fire (ent, false);
772 		}
773 
774 		if ((ent->client->ps.gunframe == 15) && (level.time < ent->client->grenade_time))
775 			return;
776 
777 		ent->client->ps.gunframe++;
778 
779 		if (ent->client->ps.gunframe == 16)
780 		{
781 			ent->client->grenade_time = 0;
782 			ent->client->weaponstate = WEAPON_READY;
783 		}
784 	}
785 }
786 
787 /*
788 ======================================================================
789 
790 GRENADE LAUNCHER
791 
792 ======================================================================
793 */
794 
weapon_grenadelauncher_fire(edict_t * ent)795 void weapon_grenadelauncher_fire (edict_t *ent)
796 {
797 	vec3_t	offset;
798 	vec3_t	forward, right;
799 	vec3_t	start;
800 	int		damage = 120;
801 	float	radius;
802 
803 	radius = damage+40;
804 	if (is_quad)
805 		damage *= 4;
806 
807 	VectorSet(offset, 8, 8, ent->viewheight-8);
808 	AngleVectors (ent->client->v_angle, forward, right, NULL);
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 	fire_grenade (ent, start, forward, damage, 600, 2.5, radius);
815 
816 	gi.WriteByte (svc_muzzleflash);
817 	gi.WriteShort (ent-g_edicts);
818 	gi.WriteByte (MZ_GRENADE | is_silenced);
819 	gi.multicast (ent->s.origin, MULTICAST_PVS);
820 
821 	ent->client->ps.gunframe++;
822 
823 	PlayerNoise(ent, start, PNOISE_WEAPON);
824 
825 	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
826 		ent->client->pers.inventory[ent->client->ammo_index]--;
827 }
828 
Weapon_GrenadeLauncher(edict_t * ent)829 void Weapon_GrenadeLauncher (edict_t *ent)
830 {
831 	static int	pause_frames[]	= {34, 51, 59, 0};
832 	static int	fire_frames[]	= {6, 0};
833 
834 	Weapon_Generic (ent, 5, 16, 59, 64, pause_frames, fire_frames, weapon_grenadelauncher_fire);
835 
836 	// RAFAEL
837 	if (is_quadfire)
838 		Weapon_Generic (ent, 5, 16, 59, 64, pause_frames, fire_frames, weapon_grenadelauncher_fire);
839 
840 }
841 
842 /*
843 ======================================================================
844 
845 ROCKET
846 
847 ======================================================================
848 */
849 
Weapon_RocketLauncher_Fire(edict_t * ent)850 void Weapon_RocketLauncher_Fire (edict_t *ent)
851 {
852 	vec3_t	offset, start;
853 	vec3_t	forward, right;
854 	int		damage;
855 	float	damage_radius;
856 	int		radius_damage;
857 
858 	damage = 100 + (int)(random() * 20.0);
859 	radius_damage = 120;
860 	damage_radius = 120;
861 	if (is_quad)
862 	{
863 		damage *= 4;
864 		radius_damage *= 4;
865 	}
866 
867 	AngleVectors (ent->client->v_angle, forward, right, NULL);
868 
869 	VectorScale (forward, -2, ent->client->kick_origin);
870 	ent->client->kick_angles[0] = -1;
871 
872 	VectorSet(offset, 8, 8, ent->viewheight-8);
873 	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
874 	fire_rocket (ent, start, forward, damage, 650, damage_radius, radius_damage);
875 
876 	// send muzzle flash
877 	gi.WriteByte (svc_muzzleflash);
878 	gi.WriteShort (ent-g_edicts);
879 	gi.WriteByte (MZ_ROCKET | is_silenced);
880 	gi.multicast (ent->s.origin, MULTICAST_PVS);
881 
882 	ent->client->ps.gunframe++;
883 
884 	PlayerNoise(ent, start, PNOISE_WEAPON);
885 
886 	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
887 		ent->client->pers.inventory[ent->client->ammo_index]--;
888 }
889 
Weapon_RocketLauncher(edict_t * ent)890 void Weapon_RocketLauncher (edict_t *ent)
891 {
892 	static int	pause_frames[]	= {25, 33, 42, 50, 0};
893 	static int	fire_frames[]	= {5, 0};
894 
895 	Weapon_Generic (ent, 4, 12, 50, 54, pause_frames, fire_frames, Weapon_RocketLauncher_Fire);
896 
897 
898 	// RAFAEL
899 	if (is_quadfire)
900 		Weapon_Generic (ent, 4, 12, 50, 54, pause_frames, fire_frames, Weapon_RocketLauncher_Fire);
901 
902 
903 }
904 
905 
906 /*
907 ======================================================================
908 
909 BLASTER / HYPERBLASTER
910 
911 ======================================================================
912 */
913 
Blaster_Fire(edict_t * ent,vec3_t g_offset,int damage,qboolean hyper,int effect)914 void Blaster_Fire (edict_t *ent, vec3_t g_offset, int damage, qboolean hyper, int effect)
915 {
916 	vec3_t	forward, right;
917 	vec3_t	start;
918 	vec3_t	offset;
919 
920 	if (is_quad)
921 		damage *= 4;
922 	AngleVectors (ent->client->v_angle, forward, right, NULL);
923 	VectorSet(offset, 24, 8, ent->viewheight-8);
924 	VectorAdd (offset, g_offset, offset);
925 	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
926 
927 	VectorScale (forward, -2, ent->client->kick_origin);
928 	ent->client->kick_angles[0] = -1;
929 
930 	fire_blaster (ent, start, forward, damage, 1000, effect, hyper);
931 
932 	// send muzzle flash
933 	gi.WriteByte (svc_muzzleflash);
934 	gi.WriteShort (ent-g_edicts);
935 	if (hyper)
936 		gi.WriteByte (MZ_HYPERBLASTER | is_silenced);
937 	else
938 		gi.WriteByte (MZ_BLASTER | is_silenced);
939 	gi.multicast (ent->s.origin, MULTICAST_PVS);
940 
941 	PlayerNoise(ent, start, PNOISE_WEAPON);
942 }
943 
944 
Weapon_Blaster_Fire(edict_t * ent)945 void Weapon_Blaster_Fire (edict_t *ent)
946 {
947 	int		damage;
948 
949 	if (deathmatch->value)
950 		damage = 15;
951 	else
952 		damage = 10;
953 	Blaster_Fire (ent, vec3_origin, damage, false, EF_BLASTER);
954 	ent->client->ps.gunframe++;
955 }
956 
Weapon_Blaster(edict_t * ent)957 void Weapon_Blaster (edict_t *ent)
958 {
959 	static int	pause_frames[]	= {19, 32, 0};
960 	static int	fire_frames[]	= {5, 0};
961 
962 	Weapon_Generic (ent, 4, 8, 52, 55, pause_frames, fire_frames, Weapon_Blaster_Fire);
963 
964 	// RAFAEL
965 	if (is_quadfire)
966 		Weapon_Generic (ent, 4, 8, 52, 55, pause_frames, fire_frames, Weapon_Blaster_Fire);
967 
968 }
969 
970 
Weapon_HyperBlaster_Fire(edict_t * ent)971 void Weapon_HyperBlaster_Fire (edict_t *ent)
972 {
973 	float	rotation;
974 	vec3_t	offset;
975 	int		effect;
976 	int		damage;
977 
978 	ent->client->weapon_sound = gi.soundindex("weapons/hyprbl1a.wav");
979 
980 	if (!(ent->client->buttons & BUTTON_ATTACK))
981 	{
982 		ent->client->ps.gunframe++;
983 	}
984 	else
985 	{
986 		if (! ent->client->pers.inventory[ent->client->ammo_index] )
987 		{
988 			if (level.time >= ent->pain_debounce_time)
989 			{
990 				gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
991 				ent->pain_debounce_time = level.time + 1;
992 			}
993 			NoAmmoWeaponChange (ent);
994 		}
995 		else
996 		{
997 			rotation = (ent->client->ps.gunframe - 5) * 2*M_PI/6;
998 			offset[0] = -4 * sin(rotation);
999 			offset[1] = 0;
1000 			offset[2] = 4 * cos(rotation);
1001 
1002 			if ((ent->client->ps.gunframe == 6) || (ent->client->ps.gunframe == 9))
1003 				effect = EF_HYPERBLASTER;
1004 			else
1005 				effect = 0;
1006 			if (deathmatch->value)
1007 				damage = 15;
1008 			else
1009 				damage = 20;
1010 			Blaster_Fire (ent, offset, damage, true, effect);
1011 			if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1012 				ent->client->pers.inventory[ent->client->ammo_index]--;
1013 
1014 			ent->client->anim_priority = ANIM_ATTACK;
1015 			if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
1016 			{
1017 				ent->s.frame = FRAME_crattak1 - 1;
1018 				ent->client->anim_end = FRAME_crattak9;
1019 			}
1020 			else
1021 			{
1022 				ent->s.frame = FRAME_attack1 - 1;
1023 				ent->client->anim_end = FRAME_attack8;
1024 			}
1025 		}
1026 
1027 		ent->client->ps.gunframe++;
1028 		if (ent->client->ps.gunframe == 12 && ent->client->pers.inventory[ent->client->ammo_index])
1029 			ent->client->ps.gunframe = 6;
1030 	}
1031 
1032 	if (ent->client->ps.gunframe == 12)
1033 	{
1034 		gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/hyprbd1a.wav"), 1, ATTN_NORM, 0);
1035 		ent->client->weapon_sound = 0;
1036 	}
1037 
1038 }
1039 
Weapon_HyperBlaster(edict_t * ent)1040 void Weapon_HyperBlaster (edict_t *ent)
1041 {
1042 	static int	pause_frames[]	= {0};
1043 	static int	fire_frames[]	= {6, 7, 8, 9, 10, 11, 0};
1044 
1045 	Weapon_Generic (ent, 5, 20, 49, 53, pause_frames, fire_frames, Weapon_HyperBlaster_Fire);
1046 
1047 
1048 	// RAFAEL
1049 	if (is_quadfire)
1050 		Weapon_Generic (ent, 5, 20, 49, 53, pause_frames, fire_frames, Weapon_HyperBlaster_Fire);
1051 
1052 }
1053 
1054 #ifdef GAME_MOD
Extr_Shell_Touch(edict_t * self,edict_t * other,cplane_t * plane,csurface_t * surf)1055 void Extr_Shell_Touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
1056 {
1057 	gi.sound(self, CHAN_VOICE, gi.soundindex("misc/brass_shell.wav"), 1, ATTN_NORM, 0);
1058 	self->solid = SOLID_NOT;
1059 }
1060 
Extr_Shell(edict_t * self,char * modelname,vec3_t start,vec3_t aimdir,int speed,vec3_t velocity,char * kierunek)1061 void Extr_Shell (edict_t *self, char *modelname, vec3_t start, vec3_t aimdir, int speed, vec3_t velocity, char *kierunek)
1062 {
1063 	edict_t *Extr_Shell;
1064 	vec3_t dir;
1065 	vec3_t forward, right, up;
1066 
1067 	if (deathmatch->value || coop->value) {
1068 		if (!eject_bullets_dm_coop->value)
1069                 	return;
1070 	}
1071 
1072 	vectoangles (aimdir, dir);
1073 	AngleVectors (dir, forward, right,  up);
1074 
1075 	Extr_Shell = G_Spawn();
1076 
1077 	VectorCopy (start, Extr_Shell->s.origin);
1078 	VectorCopy (aimdir, Extr_Shell->movedir);
1079 	VectorCopy (velocity, Extr_Shell->velocity);
1080 	vectoangles (aimdir, Extr_Shell->s.angles);
1081 	VectorMA (Extr_Shell->velocity, 120 + random()*20, up, Extr_Shell->velocity);
1082 
1083 	if (!stricmp(kierunek, "right"))
1084 		VectorMA (Extr_Shell->velocity, -80 - random()*20, right, Extr_Shell->velocity);
1085 	else
1086 		VectorMA (Extr_Shell->velocity, 80 + random()*20, right, Extr_Shell->velocity);
1087 
1088 	Extr_Shell->avelocity[0] = random()*600;
1089 	Extr_Shell->avelocity[1] = random()*600;
1090 	Extr_Shell->avelocity[2] = random()*600;
1091 		gi.setmodel (Extr_Shell, modelname);
1092 
1093 	Extr_Shell->movetype = MOVETYPE_BOUNCE;
1094 	Extr_Shell->clipmask = MASK_SHOT;
1095 	Extr_Shell->solid = SOLID_BBOX;
1096 	Extr_Shell->owner = self;
1097 
1098 	VectorSet(Extr_Shell->mins, -1.5, -0.6, -0.55);
1099 	VectorSet(Extr_Shell->maxs, 1.5, 0.6, 0.55);
1100 
1101 	Extr_Shell->nextthink = level.time + 25 + random()*1;
1102 	Extr_Shell->think = G_FreeEdict;
1103 	Extr_Shell->touch = Extr_Shell_Touch;
1104 	Extr_Shell->classname = "Extr_Shell";
1105 		gi.linkentity (Extr_Shell);
1106 }
1107 #endif
1108 /*
1109 ======================================================================
1110 
1111 MACHINEGUN / CHAINGUN
1112 
1113 ======================================================================
1114 */
1115 
Machinegun_Fire(edict_t * ent)1116 void Machinegun_Fire (edict_t *ent)
1117 {
1118 	int	i;
1119 	vec3_t		start;
1120 	vec3_t		forward, right;
1121 	vec3_t		angles;
1122 	int			damage = 8;
1123 	int			kick = 2;
1124 	vec3_t		offset;
1125 #ifdef GAME_MOD
1126     	vec3_t 		start_shell, forward_shell, left_shell, offset_shell;
1127 #endif
1128 	if (!(ent->client->buttons & BUTTON_ATTACK))
1129 	{
1130 		ent->client->machinegun_shots = 0;
1131 		ent->client->ps.gunframe++;
1132 		return;
1133 	}
1134 
1135 	if (ent->client->ps.gunframe == 5)
1136 		ent->client->ps.gunframe = 4;
1137 	else
1138 		ent->client->ps.gunframe = 5;
1139 
1140 	if (ent->client->pers.inventory[ent->client->ammo_index] < 1)
1141 	{
1142 		ent->client->ps.gunframe = 6;
1143 		if (level.time >= ent->pain_debounce_time)
1144 		{
1145 			gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
1146 			ent->pain_debounce_time = level.time + 1;
1147 		}
1148 		NoAmmoWeaponChange (ent);
1149 		return;
1150 	}
1151 
1152 	if (is_quad)
1153 	{
1154 		damage *= 4;
1155 		kick *= 4;
1156 	}
1157 
1158 	for (i=1 ; i<3 ; i++)
1159 	{
1160 		ent->client->kick_origin[i] = crandom() * 0.35;
1161 		ent->client->kick_angles[i] = crandom() * 0.7;
1162 	}
1163 	ent->client->kick_origin[0] = crandom() * 0.35;
1164 	ent->client->kick_angles[0] = ent->client->machinegun_shots * -1.5;
1165 
1166 	// raise the gun as it is firing
1167 	if (!deathmatch->value)
1168 	{
1169 		ent->client->machinegun_shots++;
1170 		if (ent->client->machinegun_shots > 9)
1171 			ent->client->machinegun_shots = 9;
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, "leftt");
1181 	}
1182 #endif
1183 	// get start / end positions
1184 	VectorAdd (ent->client->v_angle, ent->client->kick_angles, angles);
1185 	AngleVectors (angles, forward, right, NULL);
1186 	VectorSet(offset, 0, 8, ent->viewheight-8);
1187 	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1188 	fire_bullet (ent, start, forward, damage, kick, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MOD_MACHINEGUN);
1189 
1190 	gi.WriteByte (svc_muzzleflash);
1191 	gi.WriteShort (ent-g_edicts);
1192 	gi.WriteByte (MZ_MACHINEGUN | is_silenced);
1193 	gi.multicast (ent->s.origin, MULTICAST_PVS);
1194 
1195 	PlayerNoise(ent, start, PNOISE_WEAPON);
1196 
1197 	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1198 		ent->client->pers.inventory[ent->client->ammo_index]--;
1199 
1200 	ent->client->anim_priority = ANIM_ATTACK;
1201 	if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
1202 	{
1203 		ent->s.frame = FRAME_crattak1 - (int) (random()+0.25);
1204 		ent->client->anim_end = FRAME_crattak9;
1205 	}
1206 	else
1207 	{
1208 		ent->s.frame = FRAME_attack1 - (int) (random()+0.25);
1209 		ent->client->anim_end = FRAME_attack8;
1210 	}
1211 }
1212 
Weapon_Machinegun(edict_t * ent)1213 void Weapon_Machinegun (edict_t *ent)
1214 {
1215 	static int	pause_frames[]	= {23, 45, 0};
1216 	static int	fire_frames[]	= {4, 5, 0};
1217 
1218 	Weapon_Generic (ent, 3, 5, 45, 49, pause_frames, fire_frames, Machinegun_Fire);
1219 
1220 	// RAFAEL
1221 	if (is_quadfire)
1222 		Weapon_Generic (ent, 3, 5, 45, 49, pause_frames, fire_frames, Machinegun_Fire);
1223 
1224 }
1225 
Chaingun_Fire(edict_t * ent)1226 void Chaingun_Fire (edict_t *ent)
1227 {
1228 	int			i;
1229 	int			shots;
1230 	vec3_t		start;
1231 	vec3_t		forward, right, up;
1232 	float		r, u;
1233 	vec3_t		offset;
1234 	int			damage;
1235 	int			kick = 2;
1236 #ifdef GAME_MOD
1237     	vec3_t 		start_shell, forward_shell, left_shell, offset_shell;
1238 #endif
1239 	if (deathmatch->value)
1240 		damage = 6;
1241 	else
1242 		damage = 8;
1243 
1244 	if (ent->client->ps.gunframe == 5)
1245 		gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnu1a.wav"), 1, ATTN_IDLE, 0);
1246 
1247 	if ((ent->client->ps.gunframe == 14) && !(ent->client->buttons & BUTTON_ATTACK))
1248 	{
1249 		ent->client->ps.gunframe = 32;
1250 		ent->client->weapon_sound = 0;
1251 		return;
1252 	}
1253 	else if ((ent->client->ps.gunframe == 21) && (ent->client->buttons & BUTTON_ATTACK)
1254 		&& ent->client->pers.inventory[ent->client->ammo_index])
1255 	{
1256 		ent->client->ps.gunframe = 15;
1257 	}
1258 	else
1259 	{
1260 		ent->client->ps.gunframe++;
1261 	}
1262 
1263 	if (ent->client->ps.gunframe == 22)
1264 	{
1265 		ent->client->weapon_sound = 0;
1266 		gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnd1a.wav"), 1, ATTN_IDLE, 0);
1267 	}
1268 	else
1269 	{
1270 		ent->client->weapon_sound = gi.soundindex("weapons/chngnl1a.wav");
1271 	}
1272 
1273 	ent->client->anim_priority = ANIM_ATTACK;
1274 	if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
1275 	{
1276 		ent->s.frame = FRAME_crattak1 - (ent->client->ps.gunframe & 1);
1277 		ent->client->anim_end = FRAME_crattak9;
1278 	}
1279 	else
1280 	{
1281 		ent->s.frame = FRAME_attack1 - (ent->client->ps.gunframe & 1);
1282 		ent->client->anim_end = FRAME_attack8;
1283 	}
1284 
1285 	if (ent->client->ps.gunframe <= 9)
1286 		shots = 1;
1287 	else if (ent->client->ps.gunframe <= 14)
1288 	{
1289 		if (ent->client->buttons & BUTTON_ATTACK)
1290 			shots = 2;
1291 		else
1292 			shots = 1;
1293 	}
1294 	else
1295 		shots = 3;
1296 
1297 	if (ent->client->pers.inventory[ent->client->ammo_index] < shots)
1298 		shots = ent->client->pers.inventory[ent->client->ammo_index];
1299 
1300 	if (!shots)
1301 	{
1302 		if (level.time >= ent->pain_debounce_time)
1303 		{
1304 			gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
1305 			ent->pain_debounce_time = level.time + 1;
1306 		}
1307 		NoAmmoWeaponChange (ent);
1308 		return;
1309 	}
1310 
1311 	if (is_quad)
1312 	{
1313 		damage *= 4;
1314 		kick *= 4;
1315 	}
1316 
1317 	for (i=0 ; i<3 ; i++)
1318 	{
1319 		ent->client->kick_origin[i] = crandom() * 0.35;
1320 		ent->client->kick_angles[i] = crandom() * 0.7;
1321 	}
1322 
1323 #ifdef GAME_MOD
1324   	if (eject_bullets->value) {
1325 	VectorSet(offset_shell, 12, 8.7, ent->viewheight-3.2);
1326 	AngleVectors (ent->client->v_angle, forward_shell, left_shell, NULL);
1327 	P_ProjectSource (ent->client, ent->s.origin, offset_shell, forward_shell, left_shell, start_shell);
1328 	VectorScale (forward_shell, 2, ent->client->kick_origin);
1329 	Extr_Shell (ent, "models/shells/m_shell.md2", start_shell, forward_shell, 2, ent->velocity, "left");
1330 	}
1331 #endif
1332 	for (i=0 ; i<shots ; i++)
1333 	{
1334 		// get start / end positions
1335 		AngleVectors (ent->client->v_angle, forward, right, up);
1336 		r = 7 + crandom()*4;
1337 		u = crandom()*4;
1338 		VectorSet(offset, 0, r, u + ent->viewheight-8);
1339 		P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1340 
1341 		fire_bullet (ent, start, forward, damage, kick, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MOD_CHAINGUN);
1342 	}
1343 
1344 	// send muzzle flash
1345 	gi.WriteByte (svc_muzzleflash);
1346 	gi.WriteShort (ent-g_edicts);
1347 	gi.WriteByte ((MZ_CHAINGUN1 + shots - 1) | is_silenced);
1348 	gi.multicast (ent->s.origin, MULTICAST_PVS);
1349 
1350 	PlayerNoise(ent, start, PNOISE_WEAPON);
1351 
1352 	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1353 		ent->client->pers.inventory[ent->client->ammo_index] -= shots;
1354 }
1355 
1356 
Weapon_Chaingun(edict_t * ent)1357 void Weapon_Chaingun (edict_t *ent)
1358 {
1359 	static int	pause_frames[]	= {38, 43, 51, 61, 0};
1360 	static int	fire_frames[]	= {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0};
1361 
1362 	Weapon_Generic (ent, 4, 31, 61, 64, pause_frames, fire_frames, Chaingun_Fire);
1363 
1364 
1365 	// RAFAEL
1366 	if (is_quadfire)
1367 		Weapon_Generic (ent, 4, 31, 61, 64, pause_frames, fire_frames, Chaingun_Fire);
1368 
1369 }
1370 
1371 
1372 /*
1373 ======================================================================
1374 
1375 SHOTGUN / SUPERSHOTGUN
1376 
1377 ======================================================================
1378 */
1379 
weapon_shotgun_fire(edict_t * ent)1380 void weapon_shotgun_fire (edict_t *ent)
1381 {
1382 	vec3_t		start;
1383 	vec3_t		forward, right;
1384 	vec3_t		offset;
1385 	int			damage = 4;
1386 	int			kick = 8;
1387 #ifdef GAME_MOD
1388 	vec3_t 		start_shell, forward_shell, left_shell, offset_shell;
1389 #endif
1390 	if (ent->client->ps.gunframe == 9)
1391 	{
1392 		ent->client->ps.gunframe++;
1393 		return;
1394 	}
1395 
1396 	AngleVectors (ent->client->v_angle, forward, right, NULL);
1397 
1398 	VectorScale (forward, -2, ent->client->kick_origin);
1399 	ent->client->kick_angles[0] = -2;
1400 
1401 	VectorSet(offset, 0, 8,  ent->viewheight-8);
1402 	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1403 
1404 #ifdef GAME_MOD
1405   	if (eject_bullets->value) {
1406      	VectorSet(offset_shell, 12, 8.7, ent->viewheight-3.2);
1407 	AngleVectors (ent->client->v_angle, forward_shell, left_shell, NULL);
1408 	P_ProjectSource (ent->client, ent->s.origin, offset_shell, forward_shell, left_shell, start_shell);
1409 	VectorScale (forward_shell, -2, ent->client->kick_origin);
1410 	Extr_Shell (ent, "models/shells/s_shell.md2", start_shell, forward_shell, 2, ent->velocity, "right");
1411 	}
1412 #endif
1413 	if (is_quad)
1414 	{
1415 		damage *= 4;
1416 		kick *= 4;
1417 	}
1418 
1419 	if (deathmatch->value)
1420 		fire_shotgun (ent, start, forward, damage, kick, 500, 500, DEFAULT_DEATHMATCH_SHOTGUN_COUNT, MOD_SHOTGUN);
1421 	else
1422 		fire_shotgun (ent, start, forward, damage, kick, 500, 500, DEFAULT_SHOTGUN_COUNT, MOD_SHOTGUN);
1423 
1424 	// send muzzle flash
1425 	gi.WriteByte (svc_muzzleflash);
1426 	gi.WriteShort (ent-g_edicts);
1427 	gi.WriteByte (MZ_SHOTGUN | is_silenced);
1428 	gi.multicast (ent->s.origin, MULTICAST_PVS);
1429 
1430 	ent->client->ps.gunframe++;
1431 	PlayerNoise(ent, start, PNOISE_WEAPON);
1432 
1433 	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1434 		ent->client->pers.inventory[ent->client->ammo_index]--;
1435 }
1436 
Weapon_Shotgun(edict_t * ent)1437 void Weapon_Shotgun (edict_t *ent)
1438 {
1439 	static int	pause_frames[]	= {22, 28, 34, 0};
1440 	static int	fire_frames[]	= {8, 9, 0};
1441 
1442 	Weapon_Generic (ent, 7, 18, 36, 39, pause_frames, fire_frames, weapon_shotgun_fire);
1443 
1444 
1445 	// RAFAEL
1446 	if (is_quadfire)
1447 		Weapon_Generic (ent, 7, 18, 36, 39, pause_frames, fire_frames, weapon_shotgun_fire);
1448 }
1449 
1450 
weapon_supershotgun_fire(edict_t * ent)1451 void weapon_supershotgun_fire (edict_t *ent)
1452 {
1453 	vec3_t		start;
1454 	vec3_t		forward, right;
1455 	vec3_t		offset;
1456 	vec3_t		v;
1457 	int			damage = 6;
1458 	int			kick = 12;
1459 #ifdef GAME_MOD
1460     	vec3_t 		start_shell, forward_shell, left_shell, offset_shell;
1461 #endif
1462 	AngleVectors (ent->client->v_angle, forward, right, NULL);
1463 
1464 	VectorScale (forward, -2, ent->client->kick_origin);
1465 	ent->client->kick_angles[0] = -2;
1466 
1467 	VectorSet(offset, 0, 8,  ent->viewheight-8);
1468 	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1469 
1470 	if (is_quad)
1471 	{
1472 		damage *= 4;
1473 		kick *= 4;
1474 	}
1475 
1476 #ifdef GAME_MOD
1477   	if (eject_bullets->value) {
1478 	VectorSet(offset_shell, 12, 8.7, ent->viewheight-3.2);
1479 	AngleVectors (ent->client->v_angle, forward_shell, left_shell, NULL);
1480 	P_ProjectSource (ent->client, ent->s.origin, offset_shell, forward_shell, left_shell, start_shell);
1481 	VectorScale (forward_shell, -2, ent->client->kick_origin);
1482 	Extr_Shell (ent, "models/shells/s_shell.md2", start_shell, forward_shell, 2, ent->velocity, "right");
1483 
1484 
1485 	VectorSet(offset_shell, 15, 10.9, ent->viewheight-5.4);
1486 	AngleVectors (ent->client->v_angle, forward_shell, left_shell, NULL);
1487 	P_ProjectSource (ent->client, ent->s.origin, offset_shell, forward_shell, left_shell, start_shell);
1488 	VectorScale (forward_shell, 0, ent->client->kick_origin);
1489 	Extr_Shell (ent, "models/shells/s_shell.md2", start_shell, forward_shell, 4, ent->velocity, "right");
1490 	}
1491 #endif
1492 	v[PITCH] = ent->client->v_angle[PITCH];
1493 	v[YAW]   = ent->client->v_angle[YAW] - 5;
1494 	v[ROLL]  = ent->client->v_angle[ROLL];
1495 	AngleVectors (v, forward, NULL, NULL);
1496 	fire_shotgun (ent, start, forward, damage, kick, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT/2, MOD_SSHOTGUN);
1497 	v[YAW]   = ent->client->v_angle[YAW] + 5;
1498 	AngleVectors (v, forward, NULL, NULL);
1499 	fire_shotgun (ent, start, forward, damage, kick, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT/2, MOD_SSHOTGUN);
1500 
1501 	// send muzzle flash
1502 	gi.WriteByte (svc_muzzleflash);
1503 	gi.WriteShort (ent-g_edicts);
1504 	gi.WriteByte (MZ_SSHOTGUN | is_silenced);
1505 	gi.multicast (ent->s.origin, MULTICAST_PVS);
1506 
1507 	ent->client->ps.gunframe++;
1508 	PlayerNoise(ent, start, PNOISE_WEAPON);
1509 
1510 	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1511 		ent->client->pers.inventory[ent->client->ammo_index] -= 2;
1512 }
1513 
Weapon_SuperShotgun(edict_t * ent)1514 void Weapon_SuperShotgun (edict_t *ent)
1515 {
1516 	static int	pause_frames[]	= {29, 42, 57, 0};
1517 	static int	fire_frames[]	= {7, 0};
1518 
1519 	Weapon_Generic (ent, 6, 17, 57, 61, pause_frames, fire_frames, weapon_supershotgun_fire);
1520 
1521 
1522 	// RAFAEL
1523 	if (is_quadfire)
1524 		Weapon_Generic (ent, 6, 17, 57, 61, pause_frames, fire_frames, weapon_supershotgun_fire);
1525 }
1526 
1527 
1528 
1529 /*
1530 ======================================================================
1531 
1532 RAILGUN
1533 
1534 ======================================================================
1535 */
1536 
weapon_railgun_fire(edict_t * ent)1537 void weapon_railgun_fire (edict_t *ent)
1538 {
1539 	vec3_t		start;
1540 	vec3_t		forward, right;
1541 	vec3_t		offset;
1542 	int			damage;
1543 	int			kick;
1544 
1545 	if (deathmatch->value)
1546 	{	// normal damage is too extreme in dm
1547 		damage = 100;
1548 		kick = 200;
1549 	}
1550 	else
1551 	{
1552 		damage = 150;
1553 		kick = 250;
1554 	}
1555 
1556 	if (is_quad)
1557 	{
1558 		damage *= 4;
1559 		kick *= 4;
1560 	}
1561 
1562 	AngleVectors (ent->client->v_angle, forward, right, NULL);
1563 
1564 	VectorScale (forward, -3, ent->client->kick_origin);
1565 	ent->client->kick_angles[0] = -3;
1566 
1567 	VectorSet(offset, 0, 7,  ent->viewheight-8);
1568 	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1569 	fire_rail (ent, start, forward, damage, kick);
1570 
1571 	// send muzzle flash
1572 	gi.WriteByte (svc_muzzleflash);
1573 	gi.WriteShort (ent-g_edicts);
1574 	gi.WriteByte (MZ_RAILGUN | is_silenced);
1575 	gi.multicast (ent->s.origin, MULTICAST_PVS);
1576 
1577 	ent->client->ps.gunframe++;
1578 	PlayerNoise(ent, start, PNOISE_WEAPON);
1579 
1580 	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1581 		ent->client->pers.inventory[ent->client->ammo_index]--;
1582 }
1583 
1584 
Weapon_Railgun(edict_t * ent)1585 void Weapon_Railgun (edict_t *ent)
1586 {
1587 	static int	pause_frames[]	= {56, 0};
1588 	static int	fire_frames[]	= {4, 0};
1589 
1590 	Weapon_Generic (ent, 3, 18, 56, 61, pause_frames, fire_frames, weapon_railgun_fire);
1591 
1592 
1593 	// RAFAEL
1594 	if (is_quadfire)
1595 		Weapon_Generic (ent, 3, 18, 56, 61, pause_frames, fire_frames, weapon_railgun_fire);
1596 }
1597 
1598 
1599 /*
1600 ======================================================================
1601 
1602 BFG10K
1603 
1604 ======================================================================
1605 */
1606 
weapon_bfg_fire(edict_t * ent)1607 void weapon_bfg_fire (edict_t *ent)
1608 {
1609 	vec3_t	offset, start;
1610 	vec3_t	forward, right;
1611 	int		damage;
1612 	float	damage_radius = 1000;
1613 
1614 	if (deathmatch->value)
1615 		damage = 200;
1616 	else
1617 		damage = 500;
1618 
1619 	if (ent->client->ps.gunframe == 9)
1620 	{
1621 		// send muzzle flash
1622 		gi.WriteByte (svc_muzzleflash);
1623 		gi.WriteShort (ent-g_edicts);
1624 		gi.WriteByte (MZ_BFG | is_silenced);
1625 		gi.multicast (ent->s.origin, MULTICAST_PVS);
1626 
1627 		ent->client->ps.gunframe++;
1628 
1629 		PlayerNoise(ent, start, PNOISE_WEAPON);
1630 		return;
1631 	}
1632 
1633 	// cells can go down during windup (from power armor hits), so
1634 	// check again and abort firing if we don't have enough now
1635 	if (ent->client->pers.inventory[ent->client->ammo_index] < 50)
1636 	{
1637 		ent->client->ps.gunframe++;
1638 		return;
1639 	}
1640 
1641 	if (is_quad)
1642 		damage *= 4;
1643 
1644 	AngleVectors (ent->client->v_angle, forward, right, NULL);
1645 
1646 	VectorScale (forward, -2, ent->client->kick_origin);
1647 
1648 	// make a big pitch kick with an inverse fall
1649 	ent->client->v_dmg_pitch = -40;
1650 	ent->client->v_dmg_roll = crandom()*8;
1651 	ent->client->v_dmg_time = level.time + DAMAGE_TIME;
1652 
1653 	VectorSet(offset, 8, 8, ent->viewheight-8);
1654 	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1655 	fire_bfg (ent, start, forward, damage, 400, damage_radius);
1656 
1657 	ent->client->ps.gunframe++;
1658 
1659 	PlayerNoise(ent, start, PNOISE_WEAPON);
1660 
1661 	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1662 		ent->client->pers.inventory[ent->client->ammo_index] -= 50;
1663 }
1664 
Weapon_BFG(edict_t * ent)1665 void Weapon_BFG (edict_t *ent)
1666 {
1667 	static int	pause_frames[]	= {39, 45, 50, 55, 0};
1668 	static int	fire_frames[]	= {9, 17, 0};
1669 
1670 	Weapon_Generic (ent, 8, 32, 55, 58, pause_frames, fire_frames, weapon_bfg_fire);
1671 
1672 	// RAFAEL
1673 	if (is_quadfire)
1674 		Weapon_Generic (ent, 8, 32, 55, 58, pause_frames, fire_frames, weapon_bfg_fire);
1675 }
1676 
1677 
1678 //======================================================================
1679 
1680 
1681 // RAFAEL
1682 /*
1683 	RipperGun
1684 */
1685 
weapon_ionripper_fire(edict_t * ent)1686 void weapon_ionripper_fire (edict_t *ent)
1687 {
1688 	vec3_t	start;
1689 	vec3_t	forward, right;
1690 	vec3_t	offset;
1691 	vec3_t	tempang;
1692 	int		damage;
1693 	int		kick;
1694 
1695 	if (deathmatch->value)
1696 	{
1697 		// tone down for deathmatch
1698 		damage = 30;
1699 		kick = 40;
1700 	}
1701 	else
1702 	{
1703 		damage = 50;
1704 		kick = 60;
1705 	}
1706 
1707 	if (is_quad)
1708 	{
1709 		damage *= 4;
1710 		kick *= 4;
1711 	}
1712 
1713 	VectorCopy (ent->client->v_angle, tempang);
1714 	tempang[YAW] += crandom();
1715 
1716 	AngleVectors (tempang, forward, right, NULL);
1717 
1718 	VectorScale (forward, -3, ent->client->kick_origin);
1719 	ent->client->kick_angles[0] = -3;
1720 
1721 	// VectorSet (offset, 0, 7, ent->viewheight - 8);
1722 	VectorSet (offset, 16, 7, ent->viewheight - 8);
1723 
1724 	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1725 
1726 	fire_ionripper (ent, start, forward, damage, 500, EF_IONRIPPER);
1727 
1728 	// send muzzle flash
1729 	gi.WriteByte (svc_muzzleflash);
1730 	gi.WriteShort (ent - g_edicts);
1731 	gi.WriteByte (MZ_IONRIPPER | is_silenced);
1732 	gi.multicast (ent->s.origin, MULTICAST_PVS);
1733 
1734 	ent->client->ps.gunframe++;
1735 	PlayerNoise (ent, start, PNOISE_WEAPON);
1736 
1737 	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1738 		ent->client->pers.inventory[ent->client->ammo_index] -= ent->client->pers.weapon->quantity;
1739 
1740 	if (ent->client->pers.inventory[ent->client->ammo_index] < 0)
1741 		ent->client->pers.inventory[ent->client->ammo_index] = 0;
1742 }
1743 
1744 
Weapon_Ionripper(edict_t * ent)1745 void Weapon_Ionripper (edict_t *ent)
1746 {
1747 	static int pause_frames[] = {36, 0};
1748 	static int fire_frames[] = {5, 0};
1749 
1750 	Weapon_Generic (ent, 4, 6, 36, 39, pause_frames, fire_frames, weapon_ionripper_fire);
1751 
1752 	if (is_quadfire)
1753 		Weapon_Generic (ent, 4, 6, 36, 39, pause_frames, fire_frames, weapon_ionripper_fire);
1754 }
1755 
1756 
1757 //
1758 //	Phalanx
1759 //
1760 
weapon_phalanx_fire(edict_t * ent)1761 void weapon_phalanx_fire (edict_t *ent)
1762 {
1763 	vec3_t		start;
1764 	vec3_t		forward, right, up;
1765 	vec3_t		offset;
1766 	vec3_t		v;
1767 	int			kick = 12;
1768 	int			damage;
1769 	float		damage_radius;
1770 	int			radius_damage;
1771 
1772 	damage = 70 + (int)(random() * 10.0);
1773 	radius_damage = 120;
1774 	damage_radius = 120;
1775 
1776 	if (is_quad)
1777 	{
1778 		damage *= 4;
1779 		radius_damage *= 4;
1780 	}
1781 
1782 	AngleVectors (ent->client->v_angle, forward, right, NULL);
1783 
1784 	VectorScale (forward, -2, ent->client->kick_origin);
1785 	ent->client->kick_angles[0] = -2;
1786 
1787 	VectorSet(offset, 0, 8,  ent->viewheight-8);
1788 	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1789 
1790 	if (ent->client->ps.gunframe == 8)
1791 	{
1792 		v[PITCH] = ent->client->v_angle[PITCH];
1793 		v[YAW]   = ent->client->v_angle[YAW] - 1.5;
1794 		v[ROLL]  = ent->client->v_angle[ROLL];
1795 		AngleVectors (v, forward, right, up);
1796 
1797 		radius_damage = 30;
1798 		damage_radius = 120;
1799 
1800 		fire_plasma (ent, start, forward, damage, 725, damage_radius, radius_damage);
1801 
1802 		if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1803 			ent->client->pers.inventory[ent->client->ammo_index]--;
1804 	}
1805 	else
1806 	{
1807 		v[PITCH] = ent->client->v_angle[PITCH];
1808 		v[YAW]   = ent->client->v_angle[YAW] + 1.5;
1809 		v[ROLL]  = ent->client->v_angle[ROLL];
1810 		AngleVectors (v, forward, right, up);
1811 		fire_plasma (ent, start, forward, damage, 725, damage_radius, radius_damage);
1812 
1813 		// send muzzle flash
1814 		gi.WriteByte (svc_muzzleflash);
1815 		gi.WriteShort (ent-g_edicts);
1816 		gi.WriteByte (MZ_PHALANX | is_silenced);
1817 		gi.multicast (ent->s.origin, MULTICAST_PVS);
1818 
1819 		PlayerNoise(ent, start, PNOISE_WEAPON);
1820 	}
1821 
1822 	ent->client->ps.gunframe++;
1823 
1824 }
1825 
Weapon_Phalanx(edict_t * ent)1826 void Weapon_Phalanx (edict_t *ent)
1827 {
1828 	static int	pause_frames[]	= {29, 42, 55, 0};
1829 	static int	fire_frames[]	= {7, 8, 0};
1830 
1831 	Weapon_Generic (ent, 5, 20, 58, 63, pause_frames, fire_frames, weapon_phalanx_fire);
1832 
1833 	if (is_quadfire)
1834 		Weapon_Generic (ent, 5, 20, 58, 63, pause_frames, fire_frames, weapon_phalanx_fire);
1835 
1836 }
1837 
1838 /*
1839 ======================================================================
1840 
1841 TRAP
1842 
1843 ======================================================================
1844 */
1845 
1846 #define TRAP_TIMER			5.0
1847 #define TRAP_MINSPEED		300
1848 #define TRAP_MAXSPEED		700
1849 
weapon_trap_fire(edict_t * ent,qboolean held)1850 void weapon_trap_fire (edict_t *ent, qboolean held)
1851 {
1852 	vec3_t	offset;
1853 	vec3_t	forward, right;
1854 	vec3_t	start;
1855 	int		damage = 125;
1856 	float	timer;
1857 	int		speed;
1858 	float	radius;
1859 
1860 	radius = damage+40;
1861 	if (is_quad)
1862 		damage *= 4;
1863 
1864 	VectorSet(offset, 8, 8, ent->viewheight-8);
1865 	AngleVectors (ent->client->v_angle, forward, right, NULL);
1866 	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1867 
1868 	timer = ent->client->grenade_time - level.time;
1869 	speed = GRENADE_MINSPEED + (GRENADE_TIMER - timer) * ((GRENADE_MAXSPEED - GRENADE_MINSPEED) / GRENADE_TIMER);
1870 	// fire_grenade2 (ent, start, forward, damage, speed, timer, radius, held);
1871 	fire_trap (ent, start, forward, damage, speed, timer, radius, held);
1872 
1873 // you don't get infinite traps!  ZOID
1874 //	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1875 
1876 	ent->client->pers.inventory[ent->client->ammo_index]--;
1877 
1878 	ent->client->grenade_time = level.time + 1.0;
1879 }
1880 
Weapon_Trap(edict_t * ent)1881 void Weapon_Trap (edict_t *ent)
1882 {
1883 	if ((ent->client->newweapon) && (ent->client->weaponstate == WEAPON_READY))
1884 	{
1885 		ChangeWeapon (ent);
1886 		return;
1887 	}
1888 
1889 	if (ent->client->weaponstate == WEAPON_ACTIVATING)
1890 	{
1891 		ent->client->weaponstate = WEAPON_READY;
1892 		ent->client->ps.gunframe = 16;
1893 		return;
1894 	}
1895 
1896 	if (ent->client->weaponstate == WEAPON_READY)
1897 	{
1898 		if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
1899 		{
1900 			ent->client->latched_buttons &= ~BUTTON_ATTACK;
1901 			if (ent->client->pers.inventory[ent->client->ammo_index])
1902 			{
1903 				ent->client->ps.gunframe = 1;
1904 				ent->client->weaponstate = WEAPON_FIRING;
1905 				ent->client->grenade_time = 0;
1906 			}
1907 			else
1908 			{
1909 				if (level.time >= ent->pain_debounce_time)
1910 				{
1911 					gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
1912 					ent->pain_debounce_time = level.time + 1;
1913 				}
1914 				NoAmmoWeaponChange (ent);
1915 			}
1916 			return;
1917 		}
1918 
1919 		if ((ent->client->ps.gunframe == 29) || (ent->client->ps.gunframe == 34) || (ent->client->ps.gunframe == 39) || (ent->client->ps.gunframe == 48))
1920 		{
1921 			if (rand()&15)
1922 				return;
1923 		}
1924 
1925 		if (++ent->client->ps.gunframe > 48)
1926 			ent->client->ps.gunframe = 16;
1927 		return;
1928 	}
1929 
1930 	if (ent->client->weaponstate == WEAPON_FIRING)
1931 	{
1932 		if (ent->client->ps.gunframe == 5)
1933 			// RAFAEL 16-APR-98
1934 			// gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/hgrena1b.wav"), 1, ATTN_NORM, 0);
1935 			gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/trapcock.wav"), 1, ATTN_NORM, 0);
1936 			// END 16-APR-98
1937 
1938 		if (ent->client->ps.gunframe == 11)
1939 		{
1940 			if (!ent->client->grenade_time)
1941 			{
1942 				ent->client->grenade_time = level.time + GRENADE_TIMER + 0.2;
1943 				// RAFAEL 16-APR-98
1944 				ent->client->weapon_sound = gi.soundindex("weapons/traploop.wav");
1945 				// END 16-APR-98
1946 			}
1947 
1948 			// they waited too long, detonate it in their hand
1949 			if (!ent->client->grenade_blew_up && level.time >= ent->client->grenade_time)
1950 			{
1951 				ent->client->weapon_sound = 0;
1952 				weapon_trap_fire (ent, true);
1953 				ent->client->grenade_blew_up = true;
1954 			}
1955 
1956 			if (ent->client->buttons & BUTTON_ATTACK)
1957 				return;
1958 
1959 			if (ent->client->grenade_blew_up)
1960 			{
1961 				if (level.time >= ent->client->grenade_time)
1962 				{
1963 					ent->client->ps.gunframe = 15;
1964 					ent->client->grenade_blew_up = false;
1965 				}
1966 				else
1967 				{
1968 					return;
1969 				}
1970 			}
1971 		}
1972 
1973 		if (ent->client->ps.gunframe == 12)
1974 		{
1975 			ent->client->weapon_sound = 0;
1976 			weapon_trap_fire (ent, false);
1977 			if (ent->client->pers.inventory[ent->client->ammo_index] == 0)
1978 				NoAmmoWeaponChange (ent);
1979 		}
1980 
1981 		if ((ent->client->ps.gunframe == 15) && (level.time < ent->client->grenade_time))
1982 			return;
1983 
1984 		ent->client->ps.gunframe++;
1985 
1986 		if (ent->client->ps.gunframe == 16)
1987 		{
1988 			ent->client->grenade_time = 0;
1989 			ent->client->weaponstate = WEAPON_READY;
1990 		}
1991 	}
1992 }
1993