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