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