1 // g_weapon.c
2 
3 #include "g_local.h"
4 #include "m_player.h"
5 
6 
7 static qboolean	is_quad;
8 static byte		is_silenced;
9 
10 //PGM
11 static byte		damage_multiplier;
12 //PGM
13 
14 void weapon_grenade_fire (edict_t *ent, qboolean held);
15 
16 //========
17 //ROGUE
P_DamageModifier(edict_t * ent)18 byte P_DamageModifier(edict_t *ent)
19 {
20 	is_quad = 0;
21 	damage_multiplier = 1;
22 
23 	if(ent->client->quad_framenum > level.framenum)
24 	{
25 		damage_multiplier *= 4;
26 		is_quad = 1;
27 
28 		// if we're quad and DF_NO_STACK_DOUBLE is on, return now.
29 		if(((int)(dmflags->value) & DF_NO_STACK_DOUBLE))
30 			return damage_multiplier;
31 	}
32 	if(ent->client->double_framenum > level.framenum)
33 	{
34 		if ((deathmatch->value) || (damage_multiplier == 1))
35 		{
36 			damage_multiplier *= 2;
37 			is_quad = 1;
38 		}
39 	}
40 
41 	return damage_multiplier;
42 }
43 //ROGUE
44 //========
45 
P_ProjectSource(gclient_t * client,vec3_t point,vec3_t distance,vec3_t forward,vec3_t right,vec3_t result)46 static void P_ProjectSource (gclient_t *client, vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result)
47 {
48 	vec3_t	_distance;
49 
50 	VectorCopy (distance, _distance);
51 	if (client->pers.hand == LEFT_HANDED)
52 		_distance[1] *= -1;
53 	else if (client->pers.hand == CENTER_HANDED)
54 		_distance[1] = 0;
55 	G_ProjectSource (point, _distance, forward, right, result);
56 }
57 
P_ProjectSource2(gclient_t * client,vec3_t point,vec3_t distance,vec3_t forward,vec3_t right,vec3_t up,vec3_t result)58 static void P_ProjectSource2 (gclient_t *client, vec3_t point, vec3_t distance, vec3_t forward,
59 							  vec3_t right, vec3_t up, vec3_t result)
60 {
61 	vec3_t	_distance;
62 
63 	VectorCopy (distance, _distance);
64 	if (client->pers.hand == LEFT_HANDED)
65 		_distance[1] *= -1;
66 	else if (client->pers.hand == CENTER_HANDED)
67 		_distance[1] = 0;
68 	G_ProjectSource2 (point, _distance, forward, right, up, result);
69 }
70 
71 /*
72 ===============
73 PlayerNoise
74 
75 Each player can have two noise objects associated with it:
76 a personal noise (jumping, pain, weapon firing), and a weapon
77 target noise (bullet wall impacts)
78 
79 Monsters that don't directly see the player can move
80 to a noise in hopes of seeing the player from there.
81 ===============
82 */
PlayerNoise(edict_t * who,vec3_t where,int type)83 void PlayerNoise(edict_t *who, vec3_t where, int type)
84 {
85 	edict_t		*noise;
86 
87 	if (type == PNOISE_WEAPON)
88 	{
89 		if (who->client->silencer_shots)
90 		{
91 			who->client->silencer_shots--;
92 			return;
93 		}
94 	}
95 
96 	if (deathmatch->value)
97 		return;
98 
99 	if (who->flags & FL_NOTARGET)
100 		return;
101 
102 	if (who->flags & FL_DISGUISED)
103 	{
104 		if (type == PNOISE_WEAPON)
105 		{
106 			level.disguise_violator = who;
107 			level.disguise_violation_framenum = level.framenum + 5;
108 		}
109 		else
110 			return;
111 	}
112 
113 	if (!who->mynoise)
114 	{
115 		noise = G_Spawn();
116 		noise->classname = "player_noise";
117 		VectorSet (noise->mins, -8, -8, -8);
118 		VectorSet (noise->maxs, 8, 8, 8);
119 		noise->owner = who;
120 		noise->svflags = SVF_NOCLIENT;
121 		who->mynoise = noise;
122 
123 		noise = G_Spawn();
124 		noise->classname = "player_noise";
125 		VectorSet (noise->mins, -8, -8, -8);
126 		VectorSet (noise->maxs, 8, 8, 8);
127 		noise->owner = who;
128 		noise->svflags = SVF_NOCLIENT;
129 		who->mynoise2 = noise;
130 	}
131 
132 	if (type == PNOISE_SELF || type == PNOISE_WEAPON)
133 	{
134 		noise = who->mynoise;
135 		level.sound_entity = noise;
136 		level.sound_entity_framenum = level.framenum;
137 	}
138 	else // type == PNOISE_IMPACT
139 	{
140 		noise = who->mynoise2;
141 		level.sound2_entity = noise;
142 		level.sound2_entity_framenum = level.framenum;
143 	}
144 
145 	VectorCopy (where, noise->s.origin);
146 	VectorSubtract (where, noise->maxs, noise->absmin);
147 	VectorAdd (where, noise->maxs, noise->absmax);
148 	noise->teleport_time = level.time;
149 	gi.linkentity (noise);
150 }
151 
152 
Pickup_Weapon(edict_t * ent,edict_t * other)153 qboolean Pickup_Weapon (edict_t *ent, edict_t *other)
154 {
155 	int			index;
156 	gitem_t		*ammo;
157 
158 	index = ITEM_INDEX(ent->item);
159 
160 	if ( ( ((int)(dmflags->value) & DF_WEAPONS_STAY) || coop->value)
161 		&& other->client->pers.inventory[index])
162 	{
163 		if (!(ent->spawnflags & (DROPPED_ITEM | DROPPED_PLAYER_ITEM) ) )
164 			return false;	// leave the weapon for others to pickup
165 	}
166 
167 	other->client->pers.inventory[index]++;
168 
169 	if (!(ent->spawnflags & DROPPED_ITEM) )
170 	{
171 		// give them some ammo with it
172 		// PGM -- IF APPROPRIATE!
173 		if(ent->item->ammo)			//PGM
174 		{
175 			ammo = FindItem (ent->item->ammo);
176 			if ( (int)dmflags->value & DF_INFINITE_AMMO )
177 				Add_Ammo (other, ammo, 1000);
178 			else
179 				Add_Ammo (other, ammo, ammo->quantity);
180 		}
181 
182 		if (! (ent->spawnflags & DROPPED_PLAYER_ITEM) )
183 		{
184 			if (deathmatch->value)
185 			{
186 				if ((int)(dmflags->value) & DF_WEAPONS_STAY)
187 					ent->flags |= FL_RESPAWN;
188 				else
189 					SetRespawn (ent, 30);
190 			}
191 			if (coop->value)
192 				ent->flags |= FL_RESPAWN;
193 		}
194 	}
195 
196 	if (other->client->pers.weapon != ent->item &&
197 		(other->client->pers.inventory[index] == 1) &&
198 		( !deathmatch->value || other->client->pers.weapon == FindItem("blaster") ) )
199 		other->client->newweapon = ent->item;
200 
201 	return true;
202 }
203 
204 
205 /*
206 ===============
207 ChangeWeapon
208 
209 The old weapon has been dropped all the way, so make the new one
210 current
211 ===============
212 */
ChangeWeapon(edict_t * ent)213 void ChangeWeapon (edict_t *ent)
214 {
215 	int i;
216 
217 	if (ent->client->grenade_time)
218 	{
219 		ent->client->grenade_time = level.time;
220 		ent->client->weapon_sound = 0;
221 		weapon_grenade_fire (ent, false);
222 		ent->client->grenade_time = 0;
223 	}
224 
225 	ent->client->pers.lastweapon = ent->client->pers.weapon;
226 	ent->client->pers.weapon = ent->client->newweapon;
227 	ent->client->newweapon = NULL;
228 	ent->client->machinegun_shots = 0;
229 
230 	// set visible model
231 	if (ent->s.modelindex == 255)
232 	{
233 		if (ent->client->pers.weapon)
234 			i = ((ent->client->pers.weapon->weapmodel & 0xff) << 8);
235 		else
236 			i = 0;
237 		ent->s.skinnum = (ent - g_edicts - 1) | i;
238 	}
239 
240 	if (ent->client->pers.weapon && ent->client->pers.weapon->ammo)
241 		ent->client->ammo_index = ITEM_INDEX(FindItem(ent->client->pers.weapon->ammo));
242 	else
243 		ent->client->ammo_index = 0;
244 
245 	if (!ent->client->pers.weapon)
246 	{	// dead
247 		ent->client->ps.gunindex = 0;
248 		return;
249 	}
250 
251 	ent->client->weaponstate = WEAPON_ACTIVATING;
252 	ent->client->ps.gunframe = 0;
253 	ent->client->ps.gunindex = gi.modelindex(ent->client->pers.weapon->view_model);
254 
255 	ent->client->anim_priority = ANIM_PAIN;
256 	if(ent->client->ps.pmove.pm_flags & PMF_DUCKED)
257 	{
258 			ent->s.frame = FRAME_crpain1;
259 			ent->client->anim_end = FRAME_crpain4;
260 	}
261 	else
262 	{
263 			ent->s.frame = FRAME_pain301;
264 			ent->client->anim_end = FRAME_pain304;
265 
266 	}
267 }
268 
269 /*
270 =================
271 NoAmmoWeaponChange
272 =================
273 */
274 
275 // PMM - added rogue weapons to the list
276 
NoAmmoWeaponChange(edict_t * ent)277 void NoAmmoWeaponChange (edict_t *ent)
278 {
279 	if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("slugs"))]
280 		&&  ent->client->pers.inventory[ITEM_INDEX(FindItem("railgun"))] )
281 	{
282 		ent->client->newweapon = FindItem ("railgun");
283 		return;
284 	}
285 	// ROGUE
286 	if ( (ent->client->pers.inventory[ITEM_INDEX(FindItem("cells"))] >= 2)
287 		&&  ent->client->pers.inventory[ITEM_INDEX(FindItem("Plasma Beam"))] )
288 	{
289 		ent->client->newweapon = FindItem ("Plasma Beam");
290 		return;
291 	}
292 	// -ROGUE
293 	/*
294 	if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("cells"))]
295 		&&  ent->client->pers.inventory[ITEM_INDEX(FindItem("hyperblaster"))] )
296 	{
297 		ent->client->newweapon = FindItem ("hyperblaster");
298 		return;
299 	}
300 	*/
301 	// ROGUE
302 	if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("flechettes"))]
303 		&&  ent->client->pers.inventory[ITEM_INDEX(FindItem("etf rifle"))] )
304 	{
305 		ent->client->newweapon = FindItem ("etf rifle");
306 		return;
307 	}
308 	// -ROGUE
309 	if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("bullets"))]
310 		&&  ent->client->pers.inventory[ITEM_INDEX(FindItem("chaingun"))] )
311 	{
312 		ent->client->newweapon = FindItem ("chaingun");
313 		return;
314 	}
315 	if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("bullets"))]
316 		&&  ent->client->pers.inventory[ITEM_INDEX(FindItem("machinegun"))] )
317 	{
318 		ent->client->newweapon = FindItem ("machinegun");
319 		return;
320 	}
321 	if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("shells"))] > 1
322 		&&  ent->client->pers.inventory[ITEM_INDEX(FindItem("super shotgun"))] )
323 	{
324 		ent->client->newweapon = FindItem ("super shotgun");
325 		return;
326 	}
327 	if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("shells"))]
328 		&&  ent->client->pers.inventory[ITEM_INDEX(FindItem("shotgun"))] )
329 	{
330 		ent->client->newweapon = FindItem ("shotgun");
331 		return;
332 	}
333 	ent->client->newweapon = FindItem ("blaster");
334 }
335 
336 /*
337 =================
338 Think_Weapon
339 
340 Called by ClientBeginServerFrame and ClientThink
341 =================
342 */
Think_Weapon(edict_t * ent)343 void Think_Weapon (edict_t *ent)
344 {
345 	// if just died, put the weapon away
346 	if (ent->health < 1)
347 	{
348 		ent->client->newweapon = NULL;
349 		ChangeWeapon (ent);
350 	}
351 
352 	// call active weapon think routine
353 	if (ent->client->pers.weapon && ent->client->pers.weapon->weaponthink)
354 	{
355 //PGM
356 		P_DamageModifier(ent);
357 //		is_quad = (ent->client->quad_framenum > level.framenum);
358 //PGM
359 		if (ent->client->silencer_shots)
360 			is_silenced = MZ_SILENCED;
361 		else
362 			is_silenced = 0;
363 		ent->client->pers.weapon->weaponthink (ent);
364 	}
365 }
366 
367 
368 /*
369 ================
370 Use_Weapon
371 
372 Make the weapon ready if there is ammo
373 ================
374 */
Use_Weapon(edict_t * ent,gitem_t * item)375 void Use_Weapon (edict_t *ent, gitem_t *item)
376 {
377 	int			ammo_index;
378 	gitem_t		*ammo_item;
379 
380 	// see if we're already using it
381 	if (item == ent->client->pers.weapon)
382 		return;
383 
384 	if (item->ammo && !g_select_empty->value && !(item->flags & IT_AMMO))
385 	{
386 		ammo_item = FindItem(item->ammo);
387 		ammo_index = ITEM_INDEX(ammo_item);
388 
389 		if (!ent->client->pers.inventory[ammo_index])
390 		{
391 			gi.cprintf (ent, PRINT_HIGH, "No %s for %s.\n", ammo_item->pickup_name, item->pickup_name);
392 			return;
393 		}
394 
395 		if (ent->client->pers.inventory[ammo_index] < item->quantity)
396 		{
397 			gi.cprintf (ent, PRINT_HIGH, "Not enough %s for %s.\n", ammo_item->pickup_name, item->pickup_name);
398 			return;
399 		}
400 	}
401 
402 	// change to this weapon when down
403 	ent->client->newweapon = item;
404 }
405 
406 
407 
408 /*
409 ================
410 Drop_Weapon
411 ================
412 */
Drop_Weapon(edict_t * ent,gitem_t * item)413 void Drop_Weapon (edict_t *ent, gitem_t *item)
414 {
415 	int		index;
416 
417 	if ((int)(dmflags->value) & DF_WEAPONS_STAY)
418 		return;
419 
420 	index = ITEM_INDEX(item);
421 	// see if we're already using it
422 	if ( ((item == ent->client->pers.weapon) || (item == ent->client->newweapon))&& (ent->client->pers.inventory[index] == 1) )
423 	{
424 		gi.cprintf (ent, PRINT_HIGH, "Can't drop current weapon\n");
425 		return;
426 	}
427 
428 	Drop_Item (ent, item);
429 	ent->client->pers.inventory[index]--;
430 }
431 
432 
433 /*
434 ================
435 Weapon_Generic
436 
437 A generic function to handle the basics of weapon thinking
438 ================
439 */
440 #define FRAME_FIRE_FIRST		(FRAME_ACTIVATE_LAST + 1)
441 #define FRAME_IDLE_FIRST		(FRAME_FIRE_LAST + 1)
442 #define FRAME_DEACTIVATE_FIRST	(FRAME_IDLE_LAST + 1)
443 
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))444 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))
445 {
446 	int		n;
447 
448 	if(ent->deadflag || ent->s.modelindex != 255) // VWep animations screw up corpses
449 	{
450 		return;
451 	}
452 
453 	if (ent->client->weaponstate == WEAPON_DROPPING)
454 	{
455 		if (ent->client->ps.gunframe == FRAME_DEACTIVATE_LAST)
456 		{
457 			ChangeWeapon (ent);
458 			return;
459 		}
460 		else if ((FRAME_DEACTIVATE_LAST - ent->client->ps.gunframe) == 4)
461 		{
462 			ent->client->anim_priority = ANIM_REVERSE;
463 			if(ent->client->ps.pmove.pm_flags & PMF_DUCKED)
464 			{
465 				ent->s.frame = FRAME_crpain4+1;
466 				ent->client->anim_end = FRAME_crpain1;
467 			}
468 			else
469 			{
470 				ent->s.frame = FRAME_pain304+1;
471 				ent->client->anim_end = FRAME_pain301;
472 
473 			}
474 		}
475 
476 		ent->client->ps.gunframe++;
477 		return;
478 	}
479 
480 	if (ent->client->weaponstate == WEAPON_ACTIVATING)
481 	{
482 		if (ent->client->ps.gunframe == FRAME_ACTIVATE_LAST)
483 		{
484 			ent->client->weaponstate = WEAPON_READY;
485 			ent->client->ps.gunframe = FRAME_IDLE_FIRST;
486 			return;
487 		}
488 
489 		ent->client->ps.gunframe++;
490 		return;
491 	}
492 
493 	if ((ent->client->newweapon) && (ent->client->weaponstate != WEAPON_FIRING))
494 	{
495 		ent->client->weaponstate = WEAPON_DROPPING;
496 		ent->client->ps.gunframe = FRAME_DEACTIVATE_FIRST;
497 
498 		if ((FRAME_DEACTIVATE_LAST - FRAME_DEACTIVATE_FIRST) < 4)
499 		{
500 			ent->client->anim_priority = ANIM_REVERSE;
501 			if(ent->client->ps.pmove.pm_flags & PMF_DUCKED)
502 			{
503 				ent->s.frame = FRAME_crpain4+1;
504 				ent->client->anim_end = FRAME_crpain1;
505 			}
506 			else
507 			{
508 				ent->s.frame = FRAME_pain304+1;
509 				ent->client->anim_end = FRAME_pain301;
510 
511 			}
512 		}
513 		return;
514 	}
515 
516 	if (ent->client->weaponstate == WEAPON_READY)
517 	{
518 		if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
519 		{
520 			ent->client->latched_buttons &= ~BUTTON_ATTACK;
521 			if ((!ent->client->ammo_index) ||
522 				( ent->client->pers.inventory[ent->client->ammo_index] >= ent->client->pers.weapon->quantity))
523 			{
524 				ent->client->ps.gunframe = FRAME_FIRE_FIRST;
525 				ent->client->weaponstate = WEAPON_FIRING;
526 
527 				// start the animation
528 				ent->client->anim_priority = ANIM_ATTACK;
529 				if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
530 				{
531 					ent->s.frame = FRAME_crattak1-1;
532 					ent->client->anim_end = FRAME_crattak9;
533 				}
534 				else
535 				{
536 					ent->s.frame = FRAME_attack1-1;
537 					ent->client->anim_end = FRAME_attack8;
538 				}
539 			}
540 			else
541 			{
542 				if (level.time >= ent->pain_debounce_time)
543 				{
544 					gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
545 					ent->pain_debounce_time = level.time + 1;
546 				}
547 				NoAmmoWeaponChange (ent);
548 			}
549 		}
550 		else
551 		{
552 			if (ent->client->ps.gunframe == FRAME_IDLE_LAST)
553 			{
554 				ent->client->ps.gunframe = FRAME_IDLE_FIRST;
555 				return;
556 			}
557 
558 			if (pause_frames)
559 			{
560 				for (n = 0; pause_frames[n]; n++)
561 				{
562 					if (ent->client->ps.gunframe == pause_frames[n])
563 					{
564 						if (rand()&15)
565 							return;
566 					}
567 				}
568 			}
569 
570 			ent->client->ps.gunframe++;
571 			return;
572 		}
573 	}
574 
575 	if (ent->client->weaponstate == WEAPON_FIRING)
576 	{
577 		for (n = 0; fire_frames[n]; n++)
578 		{
579 			if (ent->client->ps.gunframe == fire_frames[n])
580 			{
581 				// FIXME - double should use different sound
582 				if (ent->client->quad_framenum > level.framenum)
583 					gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage3.wav"), 1, ATTN_NORM, 0);
584 				else if (ent->client->double_framenum > level.framenum)
585 					gi.sound(ent, CHAN_ITEM, gi.soundindex("misc/ddamage3.wav"), 1, ATTN_NORM, 0);
586 
587 				fire (ent);
588 				break;
589 			}
590 		}
591 
592 		if (!fire_frames[n])
593 			ent->client->ps.gunframe++;
594 
595 		if (ent->client->ps.gunframe == FRAME_IDLE_FIRST+1)
596 			ent->client->weaponstate = WEAPON_READY;
597 	}
598 }
599 
600 
601 /*
602 ======================================================================
603 
604 GRENADE
605 
606 ======================================================================
607 */
608 
609 #define GRENADE_TIMER		3.0
610 #define GRENADE_MINSPEED	400
611 #define GRENADE_MAXSPEED	800
612 
weapon_grenade_fire(edict_t * ent,qboolean held)613 void weapon_grenade_fire (edict_t *ent, qboolean held)
614 {
615 	vec3_t	offset;
616 	vec3_t	forward, right, up;
617 	vec3_t	start;
618 	int		damage = 125;
619 	float	timer;
620 	int		speed;
621 	float	radius;
622 
623 	radius = damage+40;
624 	if (is_quad)
625 //		damage *= 4;
626 		damage *= damage_multiplier;		// PGM
627 
628 	AngleVectors (ent->client->v_angle, forward, right, up);
629 	if (ent->client->pers.weapon->tag == AMMO_TESLA)
630 	{
631 //		VectorSet(offset, 0, -12, ent->viewheight-26);
632 		VectorSet(offset, 0, -4, ent->viewheight-22);
633 	}
634 	else
635 	{
636 //		VectorSet(offset, 8, 8, ent->viewheight-8);
637 		VectorSet(offset, 2, 6, ent->viewheight-14);
638 	}
639 	P_ProjectSource2 (ent->client, ent->s.origin, offset, forward, right, up, start);
640 
641 	timer = ent->client->grenade_time - level.time;
642 	speed = GRENADE_MINSPEED + (GRENADE_TIMER - timer) * ((GRENADE_MAXSPEED - GRENADE_MINSPEED) / GRENADE_TIMER);
643 	if (speed > GRENADE_MAXSPEED)
644 		speed = GRENADE_MAXSPEED;
645 
646 //	fire_grenade2 (ent, start, forward, damage, speed, timer, radius, held);
647 
648 // ============
649 // PGM
650 	switch(ent->client->pers.weapon->tag)
651 	{
652 		case AMMO_GRENADES:
653 			fire_grenade2 (ent, start, forward, damage, speed, timer, radius, held);
654 			break;
655 		case AMMO_TESLA:
656 			fire_tesla (ent, start, forward, damage_multiplier, speed);
657 			break;
658 		default:
659 			fire_prox (ent, start, forward, damage_multiplier, speed);
660 			break;
661 	}
662 // PGM
663 // ============
664 
665 	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
666 		ent->client->pers.inventory[ent->client->ammo_index]--;
667 
668 	ent->client->grenade_time = level.time + 1.0;
669 
670 	if(ent->deadflag || ent->s.modelindex != 255) // VWep animations screw up corpses
671 	{
672 		return;
673 	}
674 
675 	if (ent->health <= 0)
676 		return;
677 
678 	if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
679 	{
680 		ent->client->anim_priority = ANIM_ATTACK;
681 		ent->s.frame = FRAME_crattak1-1;
682 		ent->client->anim_end = FRAME_crattak3;
683 	}
684 	else
685 	{
686 		ent->client->anim_priority = ANIM_REVERSE;
687 		ent->s.frame = FRAME_wave08;
688 		ent->client->anim_end = FRAME_wave01;
689 	}
690 }
691 /*
692 void Weapon_Grenade (edict_t *ent)
693 {
694 	if ((ent->client->newweapon) && (ent->client->weaponstate == WEAPON_READY))
695 	{
696 		ChangeWeapon (ent);
697 		return;
698 	}
699 
700 	if (ent->client->weaponstate == WEAPON_ACTIVATING)
701 	{
702 		ent->client->weaponstate = WEAPON_READY;
703 		ent->client->ps.gunframe = 16;
704 		return;
705 	}
706 
707 	if (ent->client->weaponstate == WEAPON_READY)
708 	{
709 		if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
710 		{
711 			ent->client->latched_buttons &= ~BUTTON_ATTACK;
712 			if (ent->client->pers.inventory[ent->client->ammo_index])
713 			{
714 				ent->client->ps.gunframe = 1;
715 				ent->client->weaponstate = WEAPON_FIRING;
716 				ent->client->grenade_time = 0;
717 			}
718 			else
719 			{
720 				if (level.time >= ent->pain_debounce_time)
721 				{
722 					gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
723 					ent->pain_debounce_time = level.time + 1;
724 				}
725 				NoAmmoWeaponChange (ent);
726 			}
727 			return;
728 		}
729 
730 		if ((ent->client->ps.gunframe == 29) || (ent->client->ps.gunframe == 34) || (ent->client->ps.gunframe == 39) || (ent->client->ps.gunframe == 48))
731 		{
732 			if (rand()&15)
733 				return;
734 		}
735 
736 		if (++ent->client->ps.gunframe > 48)
737 			ent->client->ps.gunframe = 16;
738 		return;
739 	}
740 
741 	if (ent->client->weaponstate == WEAPON_FIRING)
742 	{
743 		if (ent->client->ps.gunframe == 5)
744 			gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/hgrena1b.wav"), 1, ATTN_NORM, 0);
745 
746 		if (ent->client->ps.gunframe == 11)
747 		{
748 			if (!ent->client->grenade_time)
749 			{
750 				ent->client->grenade_time = level.time + GRENADE_TIMER + 0.2;
751 				ent->client->weapon_sound = gi.soundindex("weapons/hgrenc1b.wav");
752 			}
753 
754 			// they waited too long, detonate it in their hand
755 			if (!ent->client->grenade_blew_up && level.time >= ent->client->grenade_time)
756 			{
757 				ent->client->weapon_sound = 0;
758 				weapon_grenade_fire (ent, true);
759 				ent->client->grenade_blew_up = true;
760 			}
761 
762 			if (ent->client->buttons & BUTTON_ATTACK)
763 				return;
764 
765 			if (ent->client->grenade_blew_up)
766 			{
767 				if (level.time >= ent->client->grenade_time)
768 				{
769 					ent->client->ps.gunframe = 15;
770 					ent->client->grenade_blew_up = false;
771 				}
772 				else
773 				{
774 					return;
775 				}
776 			}
777 		}
778 
779 		if (ent->client->ps.gunframe == 12)
780 		{
781 			ent->client->weapon_sound = 0;
782 			weapon_grenade_fire (ent, false);
783 		}
784 
785 		if ((ent->client->ps.gunframe == 15) && (level.time < ent->client->grenade_time))
786 			return;
787 
788 		ent->client->ps.gunframe++;
789 
790 		if (ent->client->ps.gunframe == 16)
791 		{
792 			ent->client->grenade_time = 0;
793 			ent->client->weaponstate = WEAPON_READY;
794 		}
795 	}
796 }
797 */
798 
799 #define FRAME_IDLE_FIRST		(FRAME_FIRE_LAST + 1)
800 
801 //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))
802 //									15                      48						5						11					12				29,34,39,48
Throw_Generic(edict_t * ent,int FRAME_FIRE_LAST,int FRAME_IDLE_LAST,int FRAME_THROW_SOUND,int FRAME_THROW_HOLD,int FRAME_THROW_FIRE,int * pause_frames,int EXPLODE,void (* fire)(edict_t * ent,qboolean held))803 void Throw_Generic (edict_t *ent, int FRAME_FIRE_LAST, int FRAME_IDLE_LAST, int FRAME_THROW_SOUND,
804 					int FRAME_THROW_HOLD, int FRAME_THROW_FIRE, int *pause_frames, int EXPLODE,
805 					void (*fire)(edict_t *ent, qboolean held))
806 {
807 	int n;
808 
809 	if ((ent->client->newweapon) && (ent->client->weaponstate == WEAPON_READY))
810 	{
811 		ChangeWeapon (ent);
812 		return;
813 	}
814 
815 	if (ent->client->weaponstate == WEAPON_ACTIVATING)
816 	{
817 		ent->client->weaponstate = WEAPON_READY;
818 		ent->client->ps.gunframe = FRAME_IDLE_FIRST;
819 		return;
820 	}
821 
822 	if (ent->client->weaponstate == WEAPON_READY)
823 	{
824 		if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
825 		{
826 			ent->client->latched_buttons &= ~BUTTON_ATTACK;
827 			if (ent->client->pers.inventory[ent->client->ammo_index])
828 			{
829 				ent->client->ps.gunframe = 1;
830 				ent->client->weaponstate = WEAPON_FIRING;
831 				ent->client->grenade_time = 0;
832 			}
833 			else
834 			{
835 				if (level.time >= ent->pain_debounce_time)
836 				{
837 					gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
838 					ent->pain_debounce_time = level.time + 1;
839 				}
840 				NoAmmoWeaponChange (ent);
841 			}
842 			return;
843 		}
844 
845 		if (ent->client->ps.gunframe == FRAME_IDLE_LAST)
846 		{
847 			ent->client->ps.gunframe = FRAME_IDLE_FIRST;
848 			return;
849 		}
850 
851 		if (pause_frames)
852 		{
853 			for (n = 0; pause_frames[n]; n++)
854 			{
855 				if (ent->client->ps.gunframe == pause_frames[n])
856 				{
857 					if (rand()&15)
858 						return;
859 				}
860 			}
861 		}
862 
863 		ent->client->ps.gunframe++;
864 		return;
865 	}
866 
867 	if (ent->client->weaponstate == WEAPON_FIRING)
868 	{
869 		if (ent->client->ps.gunframe == FRAME_THROW_SOUND)
870 			gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/hgrena1b.wav"), 1, ATTN_NORM, 0);
871 
872 		if (ent->client->ps.gunframe == FRAME_THROW_HOLD)
873 		{
874 			if (!ent->client->grenade_time)
875 			{
876 				ent->client->grenade_time = level.time + GRENADE_TIMER + 0.2;
877 				switch(ent->client->pers.weapon->tag)
878 				{
879 					case AMMO_GRENADES:
880 						ent->client->weapon_sound = gi.soundindex("weapons/hgrenc1b.wav");
881 						break;
882 				}
883 			}
884 
885 			// they waited too long, detonate it in their hand
886 			if (EXPLODE && !ent->client->grenade_blew_up && level.time >= ent->client->grenade_time)
887 			{
888 				ent->client->weapon_sound = 0;
889 				fire (ent, true);
890 				ent->client->grenade_blew_up = true;
891 			}
892 
893 			if (ent->client->buttons & BUTTON_ATTACK)
894 				return;
895 
896 			if (ent->client->grenade_blew_up)
897 			{
898 				if (level.time >= ent->client->grenade_time)
899 				{
900 					ent->client->ps.gunframe = FRAME_FIRE_LAST;
901 					ent->client->grenade_blew_up = false;
902 				}
903 				else
904 				{
905 					return;
906 				}
907 			}
908 		}
909 
910 		if (ent->client->ps.gunframe == FRAME_THROW_FIRE)
911 		{
912 			ent->client->weapon_sound = 0;
913 			fire (ent, true);
914 		}
915 
916 		if ((ent->client->ps.gunframe == FRAME_FIRE_LAST) && (level.time < ent->client->grenade_time))
917 			return;
918 
919 		ent->client->ps.gunframe++;
920 
921 		if (ent->client->ps.gunframe == FRAME_IDLE_FIRST)
922 		{
923 			ent->client->grenade_time = 0;
924 			ent->client->weaponstate = WEAPON_READY;
925 		}
926 	}
927 }
928 
929 //void Throw_Generic (edict_t *ent, int FRAME_FIRE_LAST, int FRAME_IDLE_LAST, int FRAME_THROW_SOUND,
930 //						int FRAME_THROW_HOLD, int FRAME_THROW_FIRE, int *pause_frames,
931 //						int EXPLOSION_TIME, void (*fire)(edict_t *ent))
932 
Weapon_Grenade(edict_t * ent)933 void Weapon_Grenade (edict_t *ent)
934 {
935 	static int	pause_frames[]	= {29,34,39,48,0};
936 
937 	Throw_Generic (ent, 15, 48, 5, 11, 12, pause_frames, GRENADE_TIMER, weapon_grenade_fire);
938 }
939 
Weapon_Prox(edict_t * ent)940 void Weapon_Prox (edict_t *ent)
941 {
942 	static int	pause_frames[]	= {22, 29, 0};
943 
944 	Throw_Generic (ent, 7, 27, 99, 2, 4, pause_frames, 0, weapon_grenade_fire);
945 }
946 
Weapon_Tesla(edict_t * ent)947 void Weapon_Tesla (edict_t *ent)
948 {
949 	static int	pause_frames[]	= {21, 0};
950 
951 	if ((ent->client->ps.gunframe > 1) && (ent->client->ps.gunframe < 9))
952 	{
953 		ent->client->ps.gunindex = gi.modelindex  ("models/weapons/v_tesla2/tris.md2");
954 	}
955 	else
956 	{
957 		ent->client->ps.gunindex = gi.modelindex  ("models/weapons/v_tesla/tris.md2");
958 	}
959 
960 	Throw_Generic (ent, 8, 32, 99, 1, 2, pause_frames, 0, weapon_grenade_fire);
961 }
962 
963 
964 
965 /*
966 ======================================================================
967 
968 GRENADE LAUNCHER
969 
970 ======================================================================
971 */
972 
weapon_grenadelauncher_fire(edict_t * ent)973 void weapon_grenadelauncher_fire (edict_t *ent)
974 {
975 	vec3_t	offset;
976 	vec3_t	forward, right;
977 	vec3_t	start;
978 //	int		damage = 120;
979 	int		damage;			// PGM
980 	float	radius;
981 
982 // =====
983 // PGM
984 	switch(ent->client->pers.weapon->tag)
985 	{
986 		case AMMO_PROX:
987 			damage = 90;
988 			break;
989 		default:
990 			damage = 120;
991 			break;
992 	}
993 // PGM
994 // =====
995 
996 	radius = damage+40;
997 	if (is_quad)
998 //		damage *= 4;
999 		damage *= damage_multiplier;		//pgm
1000 
1001 	VectorSet(offset, 8, 8, ent->viewheight-8);
1002 	AngleVectors (ent->client->v_angle, forward, right, NULL);
1003 	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1004 
1005 	VectorScale (forward, -2, ent->client->kick_origin);
1006 	ent->client->kick_angles[0] = -1;
1007 
1008 //	fire_grenade (ent, start, forward, damage, 600, 2.5, radius);
1009 // =====
1010 // PGM
1011 	switch(ent->client->pers.weapon->tag)
1012 	{
1013 		case AMMO_PROX:
1014 			fire_prox (ent, start, forward, damage_multiplier, 600);
1015 			break;
1016 		default:
1017 			fire_grenade (ent, start, forward, damage, 600, 2.5, radius);
1018 			break;
1019 	}
1020 // PGM
1021 // =====
1022 
1023 	gi.WriteByte (svc_muzzleflash);
1024 	gi.WriteShort (ent-g_edicts);
1025 	gi.WriteByte (MZ_GRENADE | is_silenced);
1026 	gi.multicast (ent->s.origin, MULTICAST_PVS);
1027 
1028 	ent->client->ps.gunframe++;
1029 
1030 	PlayerNoise(ent, start, PNOISE_WEAPON);
1031 
1032 	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1033 		ent->client->pers.inventory[ent->client->ammo_index]--;
1034 }
1035 
Weapon_GrenadeLauncher(edict_t * ent)1036 void Weapon_GrenadeLauncher (edict_t *ent)
1037 {
1038 	static int	pause_frames[]	= {34, 51, 59, 0};
1039 	static int	fire_frames[]	= {6, 0};
1040 
1041 	Weapon_Generic (ent, 5, 16, 59, 64, pause_frames, fire_frames, weapon_grenadelauncher_fire);
1042 }
1043 
1044 //==========
1045 //PGM
Weapon_ProxLauncher(edict_t * ent)1046 void Weapon_ProxLauncher (edict_t *ent)
1047 {
1048 	static int      pause_frames[]  = {34, 51, 59, 0};
1049 	static int      fire_frames[]   = {6, 0};
1050 
1051 	Weapon_Generic (ent, 5, 16, 59, 64, pause_frames, fire_frames, weapon_grenadelauncher_fire);
1052 }
1053 //PGM
1054 //==========
1055 
1056 /*
1057 ======================================================================
1058 
1059 ROCKET
1060 
1061 ======================================================================
1062 */
1063 
Weapon_RocketLauncher_Fire(edict_t * ent)1064 void Weapon_RocketLauncher_Fire (edict_t *ent)
1065 {
1066 	vec3_t	offset, start;
1067 	vec3_t	forward, right;
1068 	int		damage;
1069 	float	damage_radius;
1070 	int		radius_damage;
1071 
1072 	damage = 100 + (int)(random() * 20.0);
1073 	radius_damage = 120;
1074 	damage_radius = 120;
1075 	if (is_quad)
1076 	{
1077 //PGM
1078 //		damage *= 4;
1079 		damage *= damage_multiplier;
1080 //		radius_damage *= 4;
1081 		radius_damage *= damage_multiplier;
1082 //PGM
1083 	}
1084 
1085 	AngleVectors (ent->client->v_angle, forward, right, NULL);
1086 
1087 	VectorScale (forward, -2, ent->client->kick_origin);
1088 	ent->client->kick_angles[0] = -1;
1089 
1090 	VectorSet(offset, 8, 8, ent->viewheight-8);
1091 	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1092 	fire_rocket (ent, start, forward, damage, 650, damage_radius, radius_damage);
1093 
1094 	// send muzzle flash
1095 	gi.WriteByte (svc_muzzleflash);
1096 	gi.WriteShort (ent-g_edicts);
1097 	gi.WriteByte (MZ_ROCKET | is_silenced);
1098 	gi.multicast (ent->s.origin, MULTICAST_PVS);
1099 
1100 	ent->client->ps.gunframe++;
1101 
1102 	PlayerNoise(ent, start, PNOISE_WEAPON);
1103 
1104 	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1105 		ent->client->pers.inventory[ent->client->ammo_index]--;
1106 }
1107 
Weapon_RocketLauncher(edict_t * ent)1108 void Weapon_RocketLauncher (edict_t *ent)
1109 {
1110 	static int	pause_frames[]	= {25, 33, 42, 50, 0};
1111 	static int	fire_frames[]	= {5, 0};
1112 
1113 	Weapon_Generic (ent, 4, 12, 50, 54, pause_frames, fire_frames, Weapon_RocketLauncher_Fire);
1114 }
1115 
1116 
1117 /*
1118 ======================================================================
1119 
1120 BLASTER / HYPERBLASTER
1121 
1122 ======================================================================
1123 */
1124 
Blaster_Fire(edict_t * ent,vec3_t g_offset,int damage,qboolean hyper,int effect)1125 void Blaster_Fire (edict_t *ent, vec3_t g_offset, int damage, qboolean hyper, int effect)
1126 {
1127 	vec3_t	forward, right;
1128 	vec3_t	start;
1129 	vec3_t	offset;
1130 
1131 	if (is_quad)
1132 //		damage *= 4;
1133 		damage *= damage_multiplier;		//pgm
1134 
1135 	AngleVectors (ent->client->v_angle, forward, right, NULL);
1136 	VectorSet(offset, 24, 8, ent->viewheight-8);
1137 	VectorAdd (offset, g_offset, offset);
1138 	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1139 
1140 	VectorScale (forward, -2, ent->client->kick_origin);
1141 	ent->client->kick_angles[0] = -1;
1142 
1143 	fire_blaster (ent, start, forward, damage, 1000, effect, hyper);
1144 
1145 	// send muzzle flash
1146 	gi.WriteByte (svc_muzzleflash);
1147 	gi.WriteShort (ent-g_edicts);
1148 	if (hyper)
1149 		gi.WriteByte (MZ_HYPERBLASTER | is_silenced);
1150 	else
1151 		gi.WriteByte (MZ_BLASTER | is_silenced);
1152 	gi.multicast (ent->s.origin, MULTICAST_PVS);
1153 
1154 	PlayerNoise(ent, start, PNOISE_WEAPON);
1155 }
1156 
1157 
Weapon_Blaster_Fire(edict_t * ent)1158 void Weapon_Blaster_Fire (edict_t *ent)
1159 {
1160 	int		damage;
1161 
1162 	if (deathmatch->value)
1163 		damage = 15;
1164 	else
1165 		damage = 10;
1166 	Blaster_Fire (ent, vec3_origin, damage, false, EF_BLASTER);
1167 	ent->client->ps.gunframe++;
1168 }
1169 
Weapon_Blaster(edict_t * ent)1170 void Weapon_Blaster (edict_t *ent)
1171 {
1172 	static int	pause_frames[]	= {19, 32, 0};
1173 	static int	fire_frames[]	= {5, 0};
1174 
1175 	Weapon_Generic (ent, 4, 8, 52, 55, pause_frames, fire_frames, Weapon_Blaster_Fire);
1176 }
1177 
1178 
Weapon_HyperBlaster_Fire(edict_t * ent)1179 void Weapon_HyperBlaster_Fire (edict_t *ent)
1180 {
1181 	float	rotation;
1182 	vec3_t	offset;
1183 	int		effect;
1184 	int		damage;
1185 
1186 	ent->client->weapon_sound = gi.soundindex("weapons/hyprbl1a.wav");
1187 
1188 	if (!(ent->client->buttons & BUTTON_ATTACK))
1189 	{
1190 		ent->client->ps.gunframe++;
1191 	}
1192 	else
1193 	{
1194 		if (! ent->client->pers.inventory[ent->client->ammo_index] )
1195 		{
1196 			if (level.time >= ent->pain_debounce_time)
1197 			{
1198 				gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
1199 				ent->pain_debounce_time = level.time + 1;
1200 			}
1201 			NoAmmoWeaponChange (ent);
1202 		}
1203 		else
1204 		{
1205 			rotation = (ent->client->ps.gunframe - 5) * 2*M_PI/6;
1206 			offset[0] = -4 * sin(rotation);
1207 			offset[1] = 0;
1208 			offset[2] = 4 * cos(rotation);
1209 
1210 			if ((ent->client->ps.gunframe == 6) || (ent->client->ps.gunframe == 9))
1211 				effect = EF_HYPERBLASTER;
1212 			else
1213 				effect = 0;
1214 			if (deathmatch->value)
1215 				damage = 15;
1216 			else
1217 				damage = 20;
1218 			Blaster_Fire (ent, offset, damage, true, effect);
1219 			if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1220 				ent->client->pers.inventory[ent->client->ammo_index]--;
1221 
1222 			ent->client->anim_priority = ANIM_ATTACK;
1223 			if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
1224 			{
1225 				ent->s.frame = FRAME_crattak1 - 1;
1226 				ent->client->anim_end = FRAME_crattak9;
1227 			}
1228 			else
1229 			{
1230 				ent->s.frame = FRAME_attack1 - 1;
1231 				ent->client->anim_end = FRAME_attack8;
1232 			}
1233 		}
1234 
1235 		ent->client->ps.gunframe++;
1236 		if (ent->client->ps.gunframe == 12 && ent->client->pers.inventory[ent->client->ammo_index])
1237 			ent->client->ps.gunframe = 6;
1238 	}
1239 
1240 	if (ent->client->ps.gunframe == 12)
1241 	{
1242 		gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/hyprbd1a.wav"), 1, ATTN_NORM, 0);
1243 		ent->client->weapon_sound = 0;
1244 	}
1245 
1246 }
1247 
Weapon_HyperBlaster(edict_t * ent)1248 void Weapon_HyperBlaster (edict_t *ent)
1249 {
1250 	static int	pause_frames[]	= {0};
1251 	static int	fire_frames[]	= {6, 7, 8, 9, 10, 11, 0};
1252 
1253 	Weapon_Generic (ent, 5, 20, 49, 53, pause_frames, fire_frames, Weapon_HyperBlaster_Fire);
1254 }
1255 
1256 /*
1257 ======================================================================
1258 
1259 MACHINEGUN / CHAINGUN
1260 
1261 ======================================================================
1262 */
1263 
Machinegun_Fire(edict_t * ent)1264 void Machinegun_Fire (edict_t *ent)
1265 {
1266 	int	i;
1267 	vec3_t		start;
1268 	vec3_t		forward, right;
1269 	vec3_t		angles;
1270 	int			damage = 8;
1271 	int			kick = 2;
1272 	vec3_t		offset;
1273 
1274 	if (!(ent->client->buttons & BUTTON_ATTACK))
1275 	{
1276 		ent->client->machinegun_shots = 0;
1277 		ent->client->ps.gunframe++;
1278 		return;
1279 	}
1280 
1281 	if (ent->client->ps.gunframe == 5)
1282 		ent->client->ps.gunframe = 4;
1283 	else
1284 		ent->client->ps.gunframe = 5;
1285 
1286 	if (ent->client->pers.inventory[ent->client->ammo_index] < 1)
1287 	{
1288 		ent->client->ps.gunframe = 6;
1289 		if (level.time >= ent->pain_debounce_time)
1290 		{
1291 			gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
1292 			ent->pain_debounce_time = level.time + 1;
1293 		}
1294 		NoAmmoWeaponChange (ent);
1295 		return;
1296 	}
1297 
1298 	if (is_quad)
1299 	{
1300 //PGM
1301 //		damage *= 4;
1302 		damage *= damage_multiplier;
1303 //		kick *= 4;
1304 		kick *= damage_multiplier;
1305 //PGM
1306 	}
1307 
1308 	for (i=1 ; i<3 ; i++)
1309 	{
1310 		ent->client->kick_origin[i] = crandom() * 0.35;
1311 		ent->client->kick_angles[i] = crandom() * 0.7;
1312 	}
1313 	ent->client->kick_origin[0] = crandom() * 0.35;
1314 	ent->client->kick_angles[0] = ent->client->machinegun_shots * -1.5;
1315 
1316 	// raise the gun as it is firing
1317 	if (!deathmatch->value)
1318 	{
1319 		ent->client->machinegun_shots++;
1320 		if (ent->client->machinegun_shots > 9)
1321 			ent->client->machinegun_shots = 9;
1322 	}
1323 
1324 	// get start / end positions
1325 	VectorAdd (ent->client->v_angle, ent->client->kick_angles, angles);
1326 	AngleVectors (angles, forward, right, NULL);
1327 	VectorSet(offset, 0, 8, ent->viewheight-8);
1328 	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1329 	fire_bullet (ent, start, forward, damage, kick, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MOD_MACHINEGUN);
1330 
1331 	gi.WriteByte (svc_muzzleflash);
1332 	gi.WriteShort (ent-g_edicts);
1333 	gi.WriteByte (MZ_MACHINEGUN | is_silenced);
1334 	gi.multicast (ent->s.origin, MULTICAST_PVS);
1335 
1336 	PlayerNoise(ent, start, PNOISE_WEAPON);
1337 
1338 	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1339 		ent->client->pers.inventory[ent->client->ammo_index]--;
1340 
1341 	ent->client->anim_priority = ANIM_ATTACK;
1342 	if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
1343 	{
1344 		ent->s.frame = FRAME_crattak1 - (int) (random()+0.25);
1345 		ent->client->anim_end = FRAME_crattak9;
1346 	}
1347 	else
1348 	{
1349 		ent->s.frame = FRAME_attack1 - (int) (random()+0.25);
1350 		ent->client->anim_end = FRAME_attack8;
1351 	}
1352 }
1353 
Weapon_Machinegun(edict_t * ent)1354 void Weapon_Machinegun (edict_t *ent)
1355 {
1356 	static int	pause_frames[]	= {23, 45, 0};
1357 	static int	fire_frames[]	= {4, 5, 0};
1358 
1359 	Weapon_Generic (ent, 3, 5, 45, 49, pause_frames, fire_frames, Machinegun_Fire);
1360 }
1361 
Chaingun_Fire(edict_t * ent)1362 void Chaingun_Fire (edict_t *ent)
1363 {
1364 	int			i;
1365 	int			shots;
1366 	vec3_t		start;
1367 	vec3_t		forward, right, up;
1368 	float		r, u;
1369 	vec3_t		offset;
1370 	int			damage;
1371 	int			kick = 2;
1372 
1373 	if (deathmatch->value)
1374 		damage = 6;
1375 	else
1376 		damage = 8;
1377 
1378 	if (ent->client->ps.gunframe == 5)
1379 		gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnu1a.wav"), 1, ATTN_IDLE, 0);
1380 
1381 	if ((ent->client->ps.gunframe == 14) && !(ent->client->buttons & BUTTON_ATTACK))
1382 	{
1383 		ent->client->ps.gunframe = 32;
1384 		ent->client->weapon_sound = 0;
1385 		return;
1386 	}
1387 	else if ((ent->client->ps.gunframe == 21) && (ent->client->buttons & BUTTON_ATTACK)
1388 		&& ent->client->pers.inventory[ent->client->ammo_index])
1389 	{
1390 		ent->client->ps.gunframe = 15;
1391 	}
1392 	else
1393 	{
1394 		ent->client->ps.gunframe++;
1395 	}
1396 
1397 	if (ent->client->ps.gunframe == 22)
1398 	{
1399 		ent->client->weapon_sound = 0;
1400 		gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnd1a.wav"), 1, ATTN_IDLE, 0);
1401 	}
1402 	else
1403 	{
1404 		ent->client->weapon_sound = gi.soundindex("weapons/chngnl1a.wav");
1405 	}
1406 
1407 	ent->client->anim_priority = ANIM_ATTACK;
1408 	if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
1409 	{
1410 		ent->s.frame = FRAME_crattak1 - (ent->client->ps.gunframe & 1);
1411 		ent->client->anim_end = FRAME_crattak9;
1412 	}
1413 	else
1414 	{
1415 		ent->s.frame = FRAME_attack1 - (ent->client->ps.gunframe & 1);
1416 		ent->client->anim_end = FRAME_attack8;
1417 	}
1418 
1419 	if (ent->client->ps.gunframe <= 9)
1420 		shots = 1;
1421 	else if (ent->client->ps.gunframe <= 14)
1422 	{
1423 		if (ent->client->buttons & BUTTON_ATTACK)
1424 			shots = 2;
1425 		else
1426 			shots = 1;
1427 	}
1428 	else
1429 		shots = 3;
1430 
1431 	if (ent->client->pers.inventory[ent->client->ammo_index] < shots)
1432 		shots = ent->client->pers.inventory[ent->client->ammo_index];
1433 
1434 	if (!shots)
1435 	{
1436 		if (level.time >= ent->pain_debounce_time)
1437 		{
1438 			gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
1439 			ent->pain_debounce_time = level.time + 1;
1440 		}
1441 		NoAmmoWeaponChange (ent);
1442 		return;
1443 	}
1444 
1445 	if (is_quad)
1446 	{
1447 //PGM
1448 //		damage *= 4;
1449 		damage *= damage_multiplier;
1450 //		kick *= 4;
1451 		kick *= damage_multiplier;
1452 //PGM
1453 	}
1454 
1455 	for (i=0 ; i<3 ; i++)
1456 	{
1457 		ent->client->kick_origin[i] = crandom() * 0.35;
1458 		ent->client->kick_angles[i] = crandom() * 0.7;
1459 	}
1460 
1461 	for (i=0 ; i<shots ; i++)
1462 	{
1463 		// get start / end positions
1464 		AngleVectors (ent->client->v_angle, forward, right, up);
1465 		r = 7 + crandom()*4;
1466 		u = crandom()*4;
1467 		VectorSet(offset, 0, r, u + ent->viewheight-8);
1468 		P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1469 
1470 		fire_bullet (ent, start, forward, damage, kick, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MOD_CHAINGUN);
1471 	}
1472 
1473 	// send muzzle flash
1474 	gi.WriteByte (svc_muzzleflash);
1475 	gi.WriteShort (ent-g_edicts);
1476 	gi.WriteByte ((MZ_CHAINGUN1 + shots - 1) | is_silenced);
1477 	gi.multicast (ent->s.origin, MULTICAST_PVS);
1478 
1479 	PlayerNoise(ent, start, PNOISE_WEAPON);
1480 
1481 	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1482 		ent->client->pers.inventory[ent->client->ammo_index] -= shots;
1483 }
1484 
1485 
Weapon_Chaingun(edict_t * ent)1486 void Weapon_Chaingun (edict_t *ent)
1487 {
1488 	static int	pause_frames[]	= {38, 43, 51, 61, 0};
1489 	static int	fire_frames[]	= {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0};
1490 
1491 	Weapon_Generic (ent, 4, 31, 61, 64, pause_frames, fire_frames, Chaingun_Fire);
1492 }
1493 
1494 
1495 /*
1496 ======================================================================
1497 
1498 SHOTGUN / SUPERSHOTGUN
1499 
1500 ======================================================================
1501 */
1502 
weapon_shotgun_fire(edict_t * ent)1503 void weapon_shotgun_fire (edict_t *ent)
1504 {
1505 	vec3_t		start;
1506 	vec3_t		forward, right;
1507 	vec3_t		offset;
1508 	int			damage = 4;
1509 	int			kick = 8;
1510 
1511 	if (ent->client->ps.gunframe == 9)
1512 	{
1513 		ent->client->ps.gunframe++;
1514 		return;
1515 	}
1516 
1517 	AngleVectors (ent->client->v_angle, forward, right, NULL);
1518 
1519 	VectorScale (forward, -2, ent->client->kick_origin);
1520 	ent->client->kick_angles[0] = -2;
1521 
1522 	VectorSet(offset, 0, 8,  ent->viewheight-8);
1523 	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1524 
1525 	if (is_quad)
1526 	{
1527 //PGM
1528 //		damage *= 4;
1529 		damage *= damage_multiplier;
1530 //		kick *= 4;
1531 		kick *= damage_multiplier;
1532 //PGM
1533 	}
1534 
1535 	if (deathmatch->value)
1536 		fire_shotgun (ent, start, forward, damage, kick, 500, 500, DEFAULT_DEATHMATCH_SHOTGUN_COUNT, MOD_SHOTGUN);
1537 	else
1538 		fire_shotgun (ent, start, forward, damage, kick, 500, 500, DEFAULT_SHOTGUN_COUNT, MOD_SHOTGUN);
1539 
1540 	// send muzzle flash
1541 	gi.WriteByte (svc_muzzleflash);
1542 	gi.WriteShort (ent-g_edicts);
1543 	gi.WriteByte (MZ_SHOTGUN | is_silenced);
1544 	gi.multicast (ent->s.origin, MULTICAST_PVS);
1545 
1546 	ent->client->ps.gunframe++;
1547 	PlayerNoise(ent, start, PNOISE_WEAPON);
1548 
1549 	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1550 		ent->client->pers.inventory[ent->client->ammo_index]--;
1551 }
1552 
Weapon_Shotgun(edict_t * ent)1553 void Weapon_Shotgun (edict_t *ent)
1554 {
1555 	static int	pause_frames[]	= {22, 28, 34, 0};
1556 	static int	fire_frames[]	= {8, 9, 0};
1557 
1558 	Weapon_Generic (ent, 7, 18, 36, 39, pause_frames, fire_frames, weapon_shotgun_fire);
1559 }
1560 
1561 
weapon_supershotgun_fire(edict_t * ent)1562 void weapon_supershotgun_fire (edict_t *ent)
1563 {
1564 	vec3_t		start;
1565 	vec3_t		forward, right;
1566 	vec3_t		offset;
1567 	vec3_t		v;
1568 	int			damage = 6;
1569 	int			kick = 12;
1570 
1571 	AngleVectors (ent->client->v_angle, forward, right, NULL);
1572 
1573 	VectorScale (forward, -2, ent->client->kick_origin);
1574 	ent->client->kick_angles[0] = -2;
1575 
1576 	VectorSet(offset, 0, 8,  ent->viewheight-8);
1577 	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1578 
1579 	if (is_quad)
1580 	{
1581 //PGM
1582 //		damage *= 4;
1583 		damage *= damage_multiplier;
1584 //		kick *= 4;
1585 		kick *= damage_multiplier;
1586 //PGM
1587 	}
1588 
1589 	v[PITCH] = ent->client->v_angle[PITCH];
1590 	v[YAW]   = ent->client->v_angle[YAW] - 5;
1591 	v[ROLL]  = ent->client->v_angle[ROLL];
1592 	AngleVectors (v, forward, NULL, NULL);
1593 	fire_shotgun (ent, start, forward, damage, kick, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT/2, MOD_SSHOTGUN);
1594 	v[YAW]   = ent->client->v_angle[YAW] + 5;
1595 	AngleVectors (v, forward, NULL, NULL);
1596 	fire_shotgun (ent, start, forward, damage, kick, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT/2, MOD_SSHOTGUN);
1597 
1598 	// send muzzle flash
1599 	gi.WriteByte (svc_muzzleflash);
1600 	gi.WriteShort (ent-g_edicts);
1601 	gi.WriteByte (MZ_SSHOTGUN | is_silenced);
1602 	gi.multicast (ent->s.origin, MULTICAST_PVS);
1603 
1604 	ent->client->ps.gunframe++;
1605 	PlayerNoise(ent, start, PNOISE_WEAPON);
1606 
1607 	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1608 		ent->client->pers.inventory[ent->client->ammo_index] -= 2;
1609 }
1610 
Weapon_SuperShotgun(edict_t * ent)1611 void Weapon_SuperShotgun (edict_t *ent)
1612 {
1613 	static int	pause_frames[]	= {29, 42, 57, 0};
1614 	static int	fire_frames[]	= {7, 0};
1615 
1616 	Weapon_Generic (ent, 6, 17, 57, 61, pause_frames, fire_frames, weapon_supershotgun_fire);
1617 }
1618 
1619 
1620 
1621 /*
1622 ======================================================================
1623 
1624 RAILGUN
1625 
1626 ======================================================================
1627 */
1628 
weapon_railgun_fire(edict_t * ent)1629 void weapon_railgun_fire (edict_t *ent)
1630 {
1631 	vec3_t		start;
1632 	vec3_t		forward, right;
1633 	vec3_t		offset;
1634 	int			damage;
1635 	int			kick;
1636 
1637 	if (deathmatch->value)
1638 	{	// normal damage is too extreme in dm
1639 		damage = 100;
1640 		kick = 200;
1641 	}
1642 	else
1643 	{
1644 		damage = 150;
1645 		kick = 250;
1646 	}
1647 
1648 	if (is_quad)
1649 	{
1650 //PGM
1651 //		damage *= 4;
1652 		damage *= damage_multiplier;
1653 //		kick *= 4;
1654 		kick *= damage_multiplier;
1655 //PGM
1656 	}
1657 
1658 	AngleVectors (ent->client->v_angle, forward, right, NULL);
1659 
1660 	VectorScale (forward, -3, ent->client->kick_origin);
1661 	ent->client->kick_angles[0] = -3;
1662 
1663 	VectorSet(offset, 0, 7,  ent->viewheight-8);
1664 	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1665 	fire_rail (ent, start, forward, damage, kick);
1666 
1667 	// send muzzle flash
1668 	gi.WriteByte (svc_muzzleflash);
1669 	gi.WriteShort (ent-g_edicts);
1670 	gi.WriteByte (MZ_RAILGUN | is_silenced);
1671 	gi.multicast (ent->s.origin, MULTICAST_PVS);
1672 
1673 	ent->client->ps.gunframe++;
1674 	PlayerNoise(ent, start, PNOISE_WEAPON);
1675 
1676 	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1677 		ent->client->pers.inventory[ent->client->ammo_index]--;
1678 }
1679 
1680 
Weapon_Railgun(edict_t * ent)1681 void Weapon_Railgun (edict_t *ent)
1682 {
1683 	static int	pause_frames[]	= {56, 0};
1684 	static int	fire_frames[]	= {4, 0};
1685 
1686 	Weapon_Generic (ent, 3, 18, 56, 61, pause_frames, fire_frames, weapon_railgun_fire);
1687 }
1688 
1689 
1690 /*
1691 ======================================================================
1692 
1693 BFG10K
1694 
1695 ======================================================================
1696 */
1697 
weapon_bfg_fire(edict_t * ent)1698 void weapon_bfg_fire (edict_t *ent)
1699 {
1700 	vec3_t	offset, start;
1701 	vec3_t	forward, right;
1702 	int		damage;
1703 	float	damage_radius = 1000;
1704 
1705 	if (deathmatch->value)
1706 		damage = 200;
1707 	else
1708 		damage = 500;
1709 
1710 	if (ent->client->ps.gunframe == 9)
1711 	{
1712 		// send muzzle flash
1713 		gi.WriteByte (svc_muzzleflash);
1714 		gi.WriteShort (ent-g_edicts);
1715 		gi.WriteByte (MZ_BFG | is_silenced);
1716 		gi.multicast (ent->s.origin, MULTICAST_PVS);
1717 
1718 		ent->client->ps.gunframe++;
1719 
1720 		PlayerNoise(ent, start, PNOISE_WEAPON);
1721 		return;
1722 	}
1723 
1724 	// cells can go down during windup (from power armor hits), so
1725 	// check again and abort firing if we don't have enough now
1726 	if (ent->client->pers.inventory[ent->client->ammo_index] < 50)
1727 	{
1728 		ent->client->ps.gunframe++;
1729 		return;
1730 	}
1731 
1732 	if (is_quad)
1733 //PGM
1734 //		damage *= 4;
1735 		damage *= damage_multiplier;
1736 //PGM
1737 
1738 	AngleVectors (ent->client->v_angle, forward, right, NULL);
1739 
1740 	VectorScale (forward, -2, ent->client->kick_origin);
1741 
1742 	// make a big pitch kick with an inverse fall
1743 	ent->client->v_dmg_pitch = -40;
1744 	ent->client->v_dmg_roll = crandom()*8;
1745 	ent->client->v_dmg_time = level.time + DAMAGE_TIME;
1746 
1747 	VectorSet(offset, 8, 8, ent->viewheight-8);
1748 	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1749 	fire_bfg (ent, start, forward, damage, 400, damage_radius);
1750 
1751 	ent->client->ps.gunframe++;
1752 
1753 	PlayerNoise(ent, start, PNOISE_WEAPON);
1754 
1755 	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
1756 		ent->client->pers.inventory[ent->client->ammo_index] -= 50;
1757 }
1758 
Weapon_BFG(edict_t * ent)1759 void Weapon_BFG (edict_t *ent)
1760 {
1761 	static int	pause_frames[]	= {39, 45, 50, 55, 0};
1762 	static int	fire_frames[]	= {9, 17, 0};
1763 
1764 	Weapon_Generic (ent, 8, 32, 55, 58, pause_frames, fire_frames, weapon_bfg_fire);
1765 }
1766 
1767 
1768 //======================================================================
1769 // ROGUE MODS BELOW
1770 //======================================================================
1771 
1772 
1773 //
1774 // CHAINFIST
1775 //
1776 #define CHAINFIST_REACH 64
1777 
weapon_chainfist_fire(edict_t * ent)1778 void weapon_chainfist_fire (edict_t *ent)
1779 {
1780 	vec3_t	offset;
1781 	vec3_t	forward, right, up;
1782 	vec3_t	start;
1783 	int		damage;
1784 
1785 	damage = 15;
1786 	if(deathmatch->value)
1787 		damage = 30;
1788 
1789 	if (is_quad)
1790 		damage *= damage_multiplier;
1791 
1792 	AngleVectors (ent->client->v_angle, forward, right, up);
1793 
1794 	// kick back
1795 	VectorScale (forward, -2, ent->client->kick_origin);
1796 	ent->client->kick_angles[0] = -1;
1797 
1798 	// set start point
1799 	VectorSet(offset, 0, 8, ent->viewheight-4);
1800 	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
1801 
1802 	fire_player_melee (ent, start, forward, CHAINFIST_REACH, damage, 100, 1, MOD_CHAINFIST);
1803 
1804 	PlayerNoise(ent, start, PNOISE_WEAPON);
1805 
1806 	ent->client->ps.gunframe++;
1807 	ent->client->pers.inventory[ent->client->ammo_index] -= ent->client->pers.weapon->quantity;
1808 }
1809 
1810 // this spits out some smoke from the motor. it's a two-stroke, you know.
chainfist_smoke(edict_t * ent)1811 void chainfist_smoke (edict_t *ent)
1812 {
1813 	vec3_t	tempVec, forward, right, up;
1814 	vec3_t	offset;
1815 
1816 	AngleVectors(ent->client->v_angle, forward, right, up);
1817 	VectorSet(offset, 8, 8, ent->viewheight -4);
1818 	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, tempVec);
1819 
1820 	gi.WriteByte (svc_temp_entity);
1821 	gi.WriteByte (TE_CHAINFIST_SMOKE);
1822 	gi.WritePosition (tempVec);
1823 	gi.unicast (ent, 0);
1824 //	gi.multicast (tempVec, MULTICAST_PVS);
1825 }
1826 
1827 #define HOLD_FRAMES			0
1828 
Weapon_ChainFist(edict_t * ent)1829 void Weapon_ChainFist (edict_t *ent)
1830 {
1831 	static int	pause_frames[]	= {0};
1832 	static int	fire_frames[]	= {8, 9, 16, 17, 18, 30, 31, 0};
1833 
1834 	// these are caches for the sound index. there's probably a better way to do this.
1835 //	static int	idle_index;
1836 //	static int	attack_index;
1837 	float		chance;
1838 	int			last_sequence;
1839 
1840 	last_sequence = 0;
1841 
1842 	// load chainsaw sounds and store the indexes for later use.
1843 //	if(!idle_index && !attack_index)
1844 //	{
1845 //		idle_index = gi.soundindex("weapons/sawidle.wav");
1846 //		attack_index = gi.soundindex("weapons/sawhit.wav");
1847 //	}
1848 
1849 	if(ent->client->ps.gunframe == 13 ||
1850 		ent->client->ps.gunframe == 23)			// end of attack, go idle
1851 		ent->client->ps.gunframe = 32;
1852 
1853 #if HOLD_FRAMES
1854 	else if(ent->client->ps.gunframe == 9 && ((ent->client->buttons) & BUTTON_ATTACK))
1855 		ent->client->ps.gunframe = 7;
1856 	else if(ent->client->ps.gunframe == 18 && ((ent->client->buttons) & BUTTON_ATTACK))
1857 		ent->client->ps.gunframe = 16;
1858 #endif
1859 
1860 	// holds for idle sequence
1861 	else if(ent->client->ps.gunframe == 42 && (rand()&7))
1862 	{
1863 		if((ent->client->pers.hand != CENTER_HANDED) && random() < 0.4)
1864 			chainfist_smoke(ent);
1865 //		ent->client->ps.gunframe = 40;
1866 	}
1867 	else if(ent->client->ps.gunframe == 51 && (rand()&7))
1868 	{
1869 		if((ent->client->pers.hand != CENTER_HANDED) && random() < 0.4)
1870 			chainfist_smoke(ent);
1871 //		ent->client->ps.gunframe = 49;
1872 	}
1873 
1874 	// set the appropriate weapon sound.
1875 	if(ent->client->weaponstate == WEAPON_FIRING)
1876 //		ent->client->weapon_sound = attack_index;
1877 		ent->client->weapon_sound = gi.soundindex("weapons/sawhit.wav");
1878 	else if(ent->client->weaponstate == WEAPON_DROPPING)
1879 		ent->client->weapon_sound = 0;
1880 	else
1881 //		ent->client->weapon_sound = idle_index;
1882 		ent->client->weapon_sound = gi.soundindex("weapons/sawidle.wav");
1883 
1884 	Weapon_Generic (ent, 4, 32, 57, 60, pause_frames, fire_frames, weapon_chainfist_fire);
1885 
1886 //	gi.dprintf("chainfist %d\n", ent->client->ps.gunframe);
1887 	if((ent->client->buttons) & BUTTON_ATTACK)
1888 	{
1889 		if(ent->client->ps.gunframe == 13 ||
1890 			ent->client->ps.gunframe == 23 ||
1891 			ent->client->ps.gunframe == 32)
1892 		{
1893 			last_sequence = ent->client->ps.gunframe;
1894 			ent->client->ps.gunframe = 6;
1895 		}
1896 	}
1897 
1898 	if (ent->client->ps.gunframe == 6)
1899 	{
1900 		chance = random();
1901 		if(last_sequence == 13)			// if we just did sequence 1, do 2 or 3.
1902 			chance -= 0.34;
1903 		else if(last_sequence == 23)	// if we just did sequence 2, do 1 or 3
1904 			chance += 0.33;
1905 		else if(last_sequence == 32)	// if we just did sequence 3, do 1 or 2
1906 		{
1907 			if(chance >= 0.33)
1908 				chance += 0.34;
1909 		}
1910 
1911 		if(chance < 0.33)
1912 			ent->client->ps.gunframe = 14;
1913 		else if(chance < 0.66)
1914 			ent->client->ps.gunframe = 24;
1915 	}
1916 
1917 }
1918 
1919 //
1920 // Disintegrator
1921 //
1922 
weapon_tracker_fire(edict_t * self)1923 void weapon_tracker_fire (edict_t *self)
1924 {
1925 	vec3_t		forward, right;
1926 	vec3_t		start;
1927 	vec3_t		end;
1928 	vec3_t		offset;
1929 	edict_t		*enemy;
1930 	trace_t		tr;
1931 	int			damage;
1932 	vec3_t		mins, maxs;
1933 
1934 	// PMM - felt a little high at 25
1935 	if(deathmatch->value)
1936 		damage = 30;
1937 	else
1938 		damage = 45;
1939 
1940 	if (is_quad)
1941 		damage *= damage_multiplier;		//pgm
1942 
1943 	VectorSet(mins, -16, -16, -16);
1944 	VectorSet(maxs, 16, 16, 16);
1945 	AngleVectors (self->client->v_angle, forward, right, NULL);
1946 	VectorSet(offset, 24, 8, self->viewheight-8);
1947 	P_ProjectSource (self->client, self->s.origin, offset, forward, right, start);
1948 
1949 	// FIXME - can we shorten this? do we need to?
1950 	VectorMA (start, 8192, forward, end);
1951 	enemy = NULL;
1952 	//PMM - doing two traces .. one point and one box.
1953 	tr = gi.trace (start, vec3_origin, vec3_origin, end, self, MASK_SHOT);
1954 	if(tr.ent != world)
1955 	{
1956 		if(tr.ent->svflags & SVF_MONSTER || tr.ent->client || tr.ent->svflags & SVF_DAMAGEABLE)
1957 		{
1958 			if(tr.ent->health > 0)
1959 				enemy = tr.ent;
1960 		}
1961 	}
1962 	else
1963 	{
1964 		tr = gi.trace (start, mins, maxs, end, self, MASK_SHOT);
1965 		if(tr.ent != world)
1966 		{
1967 			if(tr.ent->svflags & SVF_MONSTER || tr.ent->client || tr.ent->svflags & SVF_DAMAGEABLE)
1968 			{
1969 				if(tr.ent->health > 0)
1970 					enemy = tr.ent;
1971 			}
1972 		}
1973 	}
1974 
1975 	VectorScale (forward, -2, self->client->kick_origin);
1976 	self->client->kick_angles[0] = -1;
1977 
1978 	fire_tracker (self, start, forward, damage, 1000, enemy);
1979 
1980 	// send muzzle flash
1981 	gi.WriteByte (svc_muzzleflash);
1982 	gi.WriteShort (self-g_edicts);
1983 	gi.WriteByte (MZ_TRACKER);
1984 	gi.multicast (self->s.origin, MULTICAST_PVS);
1985 
1986 	PlayerNoise(self, start, PNOISE_WEAPON);
1987 
1988 	self->client->ps.gunframe++;
1989 	self->client->pers.inventory[self->client->ammo_index] -= self->client->pers.weapon->quantity;
1990 }
1991 
Weapon_Disintegrator(edict_t * ent)1992 void Weapon_Disintegrator (edict_t *ent)
1993 {
1994 	static int	pause_frames[]	= {14, 19, 23, 0};
1995 //	static int	fire_frames[]	= {7, 0};
1996 	static int	fire_frames[]	= {5, 0};
1997 
1998 	Weapon_Generic (ent, 4, 9, 29, 34, pause_frames, fire_frames, weapon_tracker_fire);
1999 }
2000 
2001 /*
2002 ======================================================================
2003 
2004 ETF RIFLE
2005 
2006 ======================================================================
2007 */
weapon_etf_rifle_fire(edict_t * ent)2008 void weapon_etf_rifle_fire (edict_t *ent)
2009 {
2010 	vec3_t	forward, right, up;
2011 	vec3_t	start, tempPt;
2012 	int		damage;
2013 	int		kick = 3;
2014 	int		i;
2015 	vec3_t	angles;
2016 	vec3_t	offset;
2017 
2018 	if(deathmatch->value)
2019 		damage = 10;
2020 	else
2021 		damage = 10;
2022 
2023 	// PGM - adjusted to use the quantity entry in the weapon structure.
2024 	if(ent->client->pers.inventory[ent->client->ammo_index] < ent->client->pers.weapon->quantity)
2025 	{
2026 		VectorClear (ent->client->kick_origin);
2027 		VectorClear (ent->client->kick_angles);
2028 		ent->client->ps.gunframe = 8;
2029 
2030 		if (level.time >= ent->pain_debounce_time)
2031 		{
2032 			gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
2033 			ent->pain_debounce_time = level.time + 1;
2034 		}
2035 		NoAmmoWeaponChange (ent);
2036 		return;
2037 	}
2038 
2039 	if (is_quad)
2040 	{
2041 		damage *= damage_multiplier;
2042 		kick *= damage_multiplier;
2043 	}
2044 
2045 	for(i=0;i<3;i++)
2046 	{
2047 		ent->client->kick_origin[i] = crandom() * 0.85;
2048 		ent->client->kick_angles[i] = crandom() * 0.85;
2049 	}
2050 
2051 	// get start / end positions
2052 	VectorAdd (ent->client->v_angle, ent->client->kick_angles, angles);
2053 //	AngleVectors (angles, forward, right, NULL);
2054 //	gi.dprintf("v_angle: %s\n", vtos(ent->client->v_angle));
2055 	AngleVectors (ent->client->v_angle, forward, right, up);
2056 
2057 	// FIXME - set correct frames for different offsets.
2058 
2059 	if(ent->client->ps.gunframe == 6)					// right barrel
2060 	{
2061 //		gi.dprintf("right\n");
2062 		VectorSet(offset, 15, 8, -8);
2063 	}
2064 	else										// left barrel
2065 	{
2066 //		gi.dprintf("left\n");
2067 		VectorSet(offset, 15, 6, -8);
2068 	}
2069 
2070 	VectorCopy (ent->s.origin, tempPt);
2071 	tempPt[2] += ent->viewheight;
2072 	P_ProjectSource2 (ent->client, tempPt, offset, forward, right, up, start);
2073 //	gi.dprintf("start: %s\n", vtos(start));
2074 	fire_flechette (ent, start, forward, damage, 750, kick);
2075 
2076 	// send muzzle flash
2077 	gi.WriteByte (svc_muzzleflash);
2078 	gi.WriteShort (ent-g_edicts);
2079 	gi.WriteByte (MZ_ETF_RIFLE);
2080 	gi.multicast (ent->s.origin, MULTICAST_PVS);
2081 
2082 	PlayerNoise(ent, start, PNOISE_WEAPON);
2083 
2084 	ent->client->ps.gunframe++;
2085 	ent->client->pers.inventory[ent->client->ammo_index] -= ent->client->pers.weapon->quantity;
2086 
2087 	ent->client->anim_priority = ANIM_ATTACK;
2088 	if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
2089 	{
2090 		ent->s.frame = FRAME_crattak1 - 1;
2091 		ent->client->anim_end = FRAME_crattak9;
2092 	}
2093 	else
2094 	{
2095 		ent->s.frame = FRAME_attack1 - 1;
2096 		ent->client->anim_end = FRAME_attack8;
2097 	}
2098 
2099 }
2100 
Weapon_ETF_Rifle(edict_t * ent)2101 void Weapon_ETF_Rifle (edict_t *ent)
2102 {
2103 	static int	pause_frames[]	= {18, 28, 0};
2104 	static int	fire_frames[]	= {6, 7, 0};
2105 //	static int	idle_seq;
2106 
2107 	// note - if you change the fire frame number, fix the offset in weapon_etf_rifle_fire.
2108 
2109 //	if (!(ent->client->buttons & BUTTON_ATTACK))
2110 //		ent->client->machinegun_shots = 0;
2111 
2112 	if (ent->client->weaponstate == WEAPON_FIRING)
2113 	{
2114 		if (ent->client->pers.inventory[ent->client->ammo_index] <= 0)
2115 			ent->client->ps.gunframe = 8;
2116 	}
2117 
2118 	Weapon_Generic (ent, 4, 7, 37, 41, pause_frames, fire_frames, weapon_etf_rifle_fire);
2119 
2120 	if(ent->client->ps.gunframe == 8 && (ent->client->buttons & BUTTON_ATTACK))
2121 		ent->client->ps.gunframe = 6;
2122 
2123 //	gi.dprintf("etf rifle %d\n", ent->client->ps.gunframe);
2124 }
2125 
2126 // pgm - this now uses ent->client->pers.weapon->quantity like all the other weapons
2127 //#define HEATBEAM_AMMO_USE		2
2128 #define	HEATBEAM_DM_DMG			15
2129 #define HEATBEAM_SP_DMG			15
2130 
Heatbeam_Fire(edict_t * ent)2131 void Heatbeam_Fire (edict_t *ent)
2132 {
2133 	vec3_t		start;
2134 	vec3_t		forward, right, up;
2135 	vec3_t		offset;
2136 	int			damage;
2137 	int			kick;
2138 
2139 	// for comparison, the hyperblaster is 15/20
2140 	// jim requested more damage, so try 15/15 --- PGM 07/23/98
2141 	if (deathmatch->value)
2142 		damage = HEATBEAM_DM_DMG;
2143 	else
2144 		damage = HEATBEAM_SP_DMG;
2145 
2146 	if (deathmatch->value)  // really knock 'em around in deathmatch
2147 		kick = 75;
2148 	else
2149 		kick = 30;
2150 
2151 //	if(ent->client->pers.inventory[ent->client->ammo_index] < HEATBEAM_AMMO_USE)
2152 //	{
2153 //		NoAmmoWeaponChange (ent);
2154 //		return;
2155 //	}
2156 
2157 	ent->client->ps.gunframe++;
2158 	ent->client->ps.gunindex = gi.modelindex ("models/weapons/v_beamer2/tris.md2");
2159 
2160 	if (is_quad)
2161 	{
2162 		damage *= damage_multiplier;
2163 		kick *= damage_multiplier;
2164 	}
2165 
2166 	VectorClear (ent->client->kick_origin);
2167 	VectorClear (ent->client->kick_angles);
2168 
2169 	// get start / end positions
2170 	AngleVectors (ent->client->v_angle, forward, right, up);
2171 
2172 // This offset is the "view" offset for the beam start (used by trace)
2173 
2174 	VectorSet(offset, 7, 2, ent->viewheight-3);
2175 	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
2176 
2177 	// This offset is the entity offset
2178 	VectorSet(offset, 2, 7, -3);
2179 
2180 	fire_heat (ent, start, forward, offset, damage, kick, false);
2181 
2182 	// send muzzle flash
2183 	gi.WriteByte (svc_muzzleflash);
2184 	gi.WriteShort (ent-g_edicts);
2185 	gi.WriteByte (MZ_HEATBEAM | is_silenced);
2186 	gi.multicast (ent->s.origin, MULTICAST_PVS);
2187 
2188 	PlayerNoise(ent, start, PNOISE_WEAPON);
2189 
2190 	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
2191 		ent->client->pers.inventory[ent->client->ammo_index] -= ent->client->pers.weapon->quantity;
2192 
2193 	ent->client->anim_priority = ANIM_ATTACK;
2194 	if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
2195 	{
2196 		ent->s.frame = FRAME_crattak1 - 1;
2197 		ent->client->anim_end = FRAME_crattak9;
2198 	}
2199 	else
2200 	{
2201 		ent->s.frame = FRAME_attack1 - 1;
2202 		ent->client->anim_end = FRAME_attack8;
2203 	}
2204 
2205 }
2206 
Weapon_Heatbeam(edict_t * ent)2207 void Weapon_Heatbeam (edict_t *ent)
2208 {
2209 //	static int	pause_frames[]	= {38, 43, 51, 61, 0};
2210 //	static int	fire_frames[]	= {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0};
2211 	static int	pause_frames[]	= {35, 0};
2212 //	static int	fire_frames[]	= {9, 0};
2213 	static int	fire_frames[]	= {9, 10, 11, 12, 0};
2214 //	static int	attack_index;
2215 //	static int  off_model, on_model;
2216 
2217 //	if ((g_showlogic) && (g_showlogic->value)) {
2218 //		gi.dprintf ("Frame %d, skin %d\n", ent->client->ps.gunframe, ent->client->ps.gunskin);
2219 //	}
2220 
2221 //	if (!attack_index)
2222 //	{
2223 //		attack_index = gi.soundindex ("weapons/bfg__l1a.wav");
2224 //		off_model = gi.modelindex ("models/weapons/v_beamer/tris.md2");
2225 //		on_model = gi.modelindex ("models/weapons/v_beamer2/tris.md2");
2226 		//ent->client->ps.gunindex = gi.modelindex(ent->client->pers.weapon->view_model);
2227 //	}
2228 
2229 	if (ent->client->weaponstate == WEAPON_FIRING)
2230 	{
2231 //		ent->client->weapon_sound = attack_index;
2232 		ent->client->weapon_sound = gi.soundindex ("weapons/bfg__l1a.wav");
2233 		if ((ent->client->pers.inventory[ent->client->ammo_index] >= 2) && ((ent->client->buttons) & BUTTON_ATTACK))
2234 		{
2235 //			if(ent->client->ps.gunframe >= 9 && ((ent->client->buttons) & BUTTON_ATTACK))
2236 //			if(ent->client->ps.gunframe >= 12 && ((ent->client->buttons) & BUTTON_ATTACK))
2237 			if(ent->client->ps.gunframe >= 13)
2238 			{
2239 				ent->client->ps.gunframe = 9;
2240 //				ent->client->ps.gunframe = 8;
2241 //				ent->client->ps.gunskin = 0;
2242 //				ent->client->ps.gunindex = on_model;
2243 				ent->client->ps.gunindex = gi.modelindex ("models/weapons/v_beamer2/tris.md2");
2244 			}
2245 			else
2246 			{
2247 //				ent->client->ps.gunskin = 1;
2248 //				ent->client->ps.gunindex = on_model;
2249 				ent->client->ps.gunindex = gi.modelindex ("models/weapons/v_beamer2/tris.md2");
2250 			}
2251 		}
2252 		else
2253 		{
2254 //			ent->client->ps.gunframe = 10;
2255 			ent->client->ps.gunframe = 13;
2256 //			ent->client->ps.gunskin = 1;
2257 //			ent->client->ps.gunindex = off_model;
2258 			ent->client->ps.gunindex = gi.modelindex ("models/weapons/v_beamer/tris.md2");
2259 		}
2260 	}
2261 	else
2262 	{
2263 //		ent->client->ps.gunskin = 1;
2264 //		ent->client->ps.gunindex = off_model;
2265 		ent->client->ps.gunindex = gi.modelindex ("models/weapons/v_beamer/tris.md2");
2266 		ent->client->weapon_sound = 0;
2267 	}
2268 
2269 //	Weapon_Generic (ent, 8, 9, 39, 44, pause_frames, fire_frames, Heatbeam_Fire);
2270 	Weapon_Generic (ent, 8, 12, 39, 44, pause_frames, fire_frames, Heatbeam_Fire);
2271 }
2272