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