1 #include "g_local.h"
2 #include "m_player.h"
3 
4 void ClientUserinfoChanged (edict_t *ent, char *userinfo);
5 
6 void SP_misc_teleporter_dest (edict_t *ent);
7 
8 //
9 // Gross, ugly, disgustuing hack section
10 //
11 
12 // this function is an ugly as hell hack to fix some map flaws
13 //
14 // the coop spawn spots on some maps are SNAFU.  There are coop spots
15 // with the wrong targetname as well as spots with no name at all
16 //
17 // we use carnal knowledge of the maps to fix the coop spot targetnames to match
18 // that of the nearest named single player spot
19 
SP_FixCoopSpots(edict_t * self)20 static void SP_FixCoopSpots (edict_t *self)
21 {
22 	edict_t	*spot;
23 	vec3_t	d;
24 
25 	spot = NULL;
26 
27 	while(1)
28 	{
29 		spot = G_Find(spot, FOFS(classname), "info_player_start");
30 		if (!spot)
31 			return;
32 		if (!spot->targetname)
33 			continue;
34 		VectorSubtract(self->s.origin, spot->s.origin, d);
35 		if (VectorLength(d) < 384)
36 		{
37 			if ((!self->targetname) || Q_stricmp(self->targetname, spot->targetname) != 0)
38 			{
39 //				gi.dprintf("FixCoopSpots changed %s at %s targetname from %s to %s\n", self->classname, vtos(self->s.origin), self->targetname, spot->targetname);
40 				self->targetname = spot->targetname;
41 			}
42 			return;
43 		}
44 	}
45 }
46 
47 // now if that one wasn't ugly enough for you then try this one on for size
48 // some maps don't have any coop spots at all, so we need to create them
49 // where they should have been
50 
SP_CreateCoopSpots(edict_t * self)51 static void SP_CreateCoopSpots (edict_t *self)
52 {
53 	edict_t	*spot;
54 
55 	if(Q_stricmp(level.mapname, "security") == 0)
56 	{
57 		spot = G_Spawn();
58 		spot->classname = "info_player_coop";
59 		spot->s.origin[0] = 188 - 64;
60 		spot->s.origin[1] = -164;
61 		spot->s.origin[2] = 80;
62 		spot->targetname = "jail3";
63 		spot->s.angles[1] = 90;
64 
65 		spot = G_Spawn();
66 		spot->classname = "info_player_coop";
67 		spot->s.origin[0] = 188 + 64;
68 		spot->s.origin[1] = -164;
69 		spot->s.origin[2] = 80;
70 		spot->targetname = "jail3";
71 		spot->s.angles[1] = 90;
72 
73 		spot = G_Spawn();
74 		spot->classname = "info_player_coop";
75 		spot->s.origin[0] = 188 + 128;
76 		spot->s.origin[1] = -164;
77 		spot->s.origin[2] = 80;
78 		spot->targetname = "jail3";
79 		spot->s.angles[1] = 90;
80 
81 		return;
82 	}
83 }
84 
85 
86 /*QUAKED info_player_start (1 0 0) (-16 -16 -24) (16 16 32)
87 The normal starting point for a level.
88 */
SP_info_player_start(edict_t * self)89 void SP_info_player_start(edict_t *self)
90 {
91 	if (!coop->value)
92 		return;
93 	if(Q_stricmp(level.mapname, "security") == 0)
94 	{
95 		// invoke one of our gross, ugly, disgusting hacks
96 		self->think = SP_CreateCoopSpots;
97 		self->nextthink = level.time + FRAMETIME;
98 	}
99 }
100 
101 /*QUAKED info_player_deathmatch (1 0 1) (-16 -16 -24) (16 16 32)
102 potential spawning position for deathmatch games
103 */
SP_info_player_deathmatch(edict_t * self)104 void SP_info_player_deathmatch(edict_t *self)
105 {
106 	if (!deathmatch->value)
107 	{
108 		G_FreeEdict (self);
109 		return;
110 	}
111 	SP_misc_teleporter_dest (self);
112 }
113 
114 /*QUAKED info_player_coop (1 0 1) (-16 -16 -24) (16 16 32)
115 potential spawning position for coop games
116 */
117 
SP_info_player_coop(edict_t * self)118 void SP_info_player_coop(edict_t *self)
119 {
120 	if (!coop->value)
121 	{
122 		G_FreeEdict (self);
123 		return;
124 	}
125 
126 	if((Q_stricmp(level.mapname, "jail2") == 0)   ||
127 	   (Q_stricmp(level.mapname, "jail4") == 0)   ||
128 	   (Q_stricmp(level.mapname, "mine1") == 0)   ||
129 	   (Q_stricmp(level.mapname, "mine2") == 0)   ||
130 	   (Q_stricmp(level.mapname, "mine3") == 0)   ||
131 	   (Q_stricmp(level.mapname, "mine4") == 0)   ||
132 	   (Q_stricmp(level.mapname, "lab") == 0)     ||
133 	   (Q_stricmp(level.mapname, "boss1") == 0)   ||
134 	   (Q_stricmp(level.mapname, "fact3") == 0)   ||
135 	   (Q_stricmp(level.mapname, "biggun") == 0)  ||
136 	   (Q_stricmp(level.mapname, "space") == 0)   ||
137 	   (Q_stricmp(level.mapname, "command") == 0) ||
138 	   (Q_stricmp(level.mapname, "power2") == 0) ||
139 	   (Q_stricmp(level.mapname, "strike") == 0))
140 	{
141 		// invoke one of our gross, ugly, disgusting hacks
142 		self->think = SP_FixCoopSpots;
143 		self->nextthink = level.time + FRAMETIME;
144 	}
145 }
146 
147 /*QUAKED info_player_coop_lava (1 0 1) (-16 -16 -24) (16 16 32)
148 potential spawning position for coop games on rmine2 where lava level
149 needs to be checked
150 */
SP_info_player_coop_lava(edict_t * self)151 void SP_info_player_coop_lava(edict_t *self)
152 {
153 	if (!coop->value)
154 	{
155 		G_FreeEdict (self);
156 		return;
157 	}
158 }
159 
160 /*QUAKED info_player_intermission (1 0 1) (-16 -16 -24) (16 16 32)
161 The deathmatch intermission point will be at one of these
162 Use 'angles' instead of 'angle', so you can set pitch or roll as well as yaw.  'pitch yaw roll'
163 */
SP_info_player_intermission(void)164 void SP_info_player_intermission(void)
165 {
166 }
167 
168 
169 //=======================================================================
170 
171 
player_pain(edict_t * self,edict_t * other,float kick,int damage)172 void player_pain (edict_t *self, edict_t *other, float kick, int damage)
173 {
174 	// player pain is handled at the end of the frame in P_DamageFeedback
175 }
176 
177 
IsFemale(edict_t * ent)178 qboolean IsFemale (edict_t *ent)
179 {
180 	char		*info;
181 
182 	if (!ent->client)
183 		return false;
184 
185 	info = Info_ValueForKey (ent->client->pers.userinfo, "gender");
186 	if (info[0] == 'f' || info[0] == 'F')
187 		return true;
188 	return false;
189 }
190 
IsNeutral(edict_t * ent)191 qboolean IsNeutral (edict_t *ent)
192 {
193 	char		*info;
194 
195 	if (!ent->client)
196 		return false;
197 
198 	info = Info_ValueForKey (ent->client->pers.userinfo, "gender");
199 	if (info[0] != 'f' && info[0] != 'F' && info[0] != 'm' && info[0] != 'M')
200 		return true;
201 	return false;
202 }
203 
ClientObituary(edict_t * self,edict_t * inflictor,edict_t * attacker)204 void ClientObituary (edict_t *self, edict_t *inflictor, edict_t *attacker)
205 {
206 	int			mod;
207 	char		*message;
208 	char		*message2;
209 	qboolean	ff;
210 
211 	if (coop->value && attacker->client)
212 		meansOfDeath |= MOD_FRIENDLY_FIRE;
213 
214 	if (deathmatch->value || coop->value)
215 	{
216 		ff = meansOfDeath & MOD_FRIENDLY_FIRE;
217 		mod = meansOfDeath & ~MOD_FRIENDLY_FIRE;
218 		message = NULL;
219 		message2 = "";
220 
221 		switch (mod)
222 		{
223 			case MOD_SUICIDE:
224 				message = "suicides";
225 				break;
226 			case MOD_FALLING:
227 				message = "cratered";
228 				break;
229 			case MOD_CRUSH:
230 				message = "was squished";
231 				break;
232 			case MOD_WATER:
233 				message = "sank like a rock";
234 				break;
235 			case MOD_SLIME:
236 				message = "melted";
237 				break;
238 			case MOD_LAVA:
239 				message = "does a back flip into the lava";
240 				break;
241 			case MOD_EXPLOSIVE:
242 			case MOD_BARREL:
243 				message = "blew up";
244 				break;
245 			case MOD_EXIT:
246 				message = "found a way out";
247 				break;
248 			case MOD_TARGET_LASER:
249 				message = "saw the light";
250 				break;
251 			case MOD_TARGET_BLASTER:
252 				message = "got blasted";
253 				break;
254 			case MOD_BOMB:
255 			case MOD_SPLASH:
256 			case MOD_TRIGGER_HURT:
257 				message = "was in the wrong place";
258 				break;
259 		}
260 		if (attacker == self)
261 		{
262 			switch (mod)
263 			{
264 				case MOD_HELD_GRENADE:
265 					message = "tried to put the pin back in";
266 					break;
267 				case MOD_HG_SPLASH:
268 				case MOD_G_SPLASH:
269 					if (IsNeutral(self))
270 						message = "tripped on its own grenade";
271 					else if (IsFemale(self))
272 						message = "tripped on her own grenade";
273 					else
274 						message = "tripped on his own grenade";
275 					break;
276 				case MOD_R_SPLASH:
277 					if (IsNeutral(self))
278 						message = "blew itself up";
279 					else if (IsFemale(self))
280 						message = "blew herself up";
281 					else
282 						message = "blew himself up";
283 					break;
284 				case MOD_BFG_BLAST:
285 					message = "should have used a smaller gun";
286 					break;
287 //ROGUE
288 				case MOD_DOPPLE_EXPLODE:
289 					if (IsNeutral(self))
290 						message = "got caught in it's own trap";
291 					else if (IsFemale(self))
292 						message = "got caught in her own trap";
293 					else
294 						message = "got caught in his own trap";
295 					break;
296 //ROGUE
297 				default:
298 					if (IsNeutral(self))
299 						message = "killed itself";
300 					else if (IsFemale(self))
301 						message = "killed herself";
302 					else
303 						message = "killed himself";
304 					break;
305 			}
306 		}
307 		if (message)
308 		{
309 			gi.bprintf (PRINT_MEDIUM, "%s %s.\n", self->client->pers.netname, message);
310 			if (deathmatch->value)
311 				self->client->resp.score--;
312 			self->enemy = NULL;
313 			return;
314 		}
315 
316 		self->enemy = attacker;
317 		if (attacker && attacker->client)
318 		{
319 			switch (mod)
320 			{
321 			case MOD_BLASTER:
322 				message = "was blasted by";
323 				break;
324 			case MOD_SHOTGUN:
325 				message = "was gunned down by";
326 				break;
327 			case MOD_SSHOTGUN:
328 				message = "was blown away by";
329 				message2 = "'s super shotgun";
330 				break;
331 			case MOD_MACHINEGUN:
332 				message = "was machinegunned by";
333 				break;
334 			case MOD_CHAINGUN:
335 				message = "was cut in half by";
336 				message2 = "'s chaingun";
337 				break;
338 			case MOD_GRENADE:
339 				message = "was popped by";
340 				message2 = "'s grenade";
341 				break;
342 			case MOD_G_SPLASH:
343 				message = "was shredded by";
344 				message2 = "'s shrapnel";
345 				break;
346 			case MOD_ROCKET:
347 				message = "ate";
348 				message2 = "'s rocket";
349 				break;
350 			case MOD_R_SPLASH:
351 				message = "almost dodged";
352 				message2 = "'s rocket";
353 				break;
354 			case MOD_HYPERBLASTER:
355 				message = "was melted by";
356 				message2 = "'s hyperblaster";
357 				break;
358 			case MOD_RAILGUN:
359 				message = "was railed by";
360 				break;
361 			case MOD_BFG_LASER:
362 				message = "saw the pretty lights from";
363 				message2 = "'s BFG";
364 				break;
365 			case MOD_BFG_BLAST:
366 				message = "was disintegrated by";
367 				message2 = "'s BFG blast";
368 				break;
369 			case MOD_BFG_EFFECT:
370 				message = "couldn't hide from";
371 				message2 = "'s BFG";
372 				break;
373 			case MOD_HANDGRENADE:
374 				message = "caught";
375 				message2 = "'s handgrenade";
376 				break;
377 			case MOD_HG_SPLASH:
378 				message = "didn't see";
379 				message2 = "'s handgrenade";
380 				break;
381 			case MOD_HELD_GRENADE:
382 				message = "feels";
383 				message2 = "'s pain";
384 				break;
385 			case MOD_TELEFRAG:
386 				message = "tried to invade";
387 				message2 = "'s personal space";
388 				break;
389 
390 //===============
391 //ROGUE
392 			case MOD_CHAINFIST:
393 				message = "was shredded by";
394 				message2 = "'s ripsaw";
395 				break;
396 			case MOD_DISINTEGRATOR:
397 				message = "lost his grip courtesy of";
398 				message2 = "'s disintegrator";
399 				break;
400 			case MOD_ETF_RIFLE:
401 				message = "was perforated by";
402 				break;
403 			case MOD_HEATBEAM:
404 				message = "was scorched by";
405 				message2 = "'s plasma beam";
406 				break;
407 			case MOD_TESLA:
408 				message = "was enlightened by";
409 				message2 = "'s tesla mine";
410 				break;
411 			case MOD_PROX:
412 				message = "got too close to";
413 				message2 = "'s proximity mine";
414 				break;
415 			case MOD_NUKE:
416 				message = "was nuked by";
417 				message2 = "'s antimatter bomb";
418 				break;
419 			case MOD_VENGEANCE_SPHERE:
420 				message = "was purged by";
421 				message2 = "'s vengeance sphere";
422 				break;
423 			case MOD_DEFENDER_SPHERE:
424 				message = "had a blast with";
425 				message2 = "'s defender sphere";
426 				break;
427 			case MOD_HUNTER_SPHERE:
428 				message = "was killed like a dog by";
429 				message2 = "'s hunter sphere";
430 				break;
431 			case MOD_TRACKER:
432 				message = "was annihilated by";
433 				message2 = "'s disruptor";
434 				break;
435 			case MOD_DOPPLE_EXPLODE:
436 				message = "was blown up by";
437 				message2 = "'s doppleganger";
438 				break;
439 			case MOD_DOPPLE_VENGEANCE:
440 				message = "was purged by";
441 				message2 = "'s doppleganger";
442 				break;
443 			case MOD_DOPPLE_HUNTER:
444 				message = "was hunted down by";
445 				message2 = "'s doppleganger";
446 				break;
447 //ROGUE
448 //===============
449 			}
450 			if (message)
451 			{
452 				gi.bprintf (PRINT_MEDIUM,"%s %s %s%s\n", self->client->pers.netname, message, attacker->client->pers.netname, message2);
453 //ROGUE
454 				if (gamerules && gamerules->value)
455 				{
456 					if(DMGame.Score)
457 					{
458 						if(ff)
459 							DMGame.Score(attacker, self, -1);
460 						else
461 							DMGame.Score(attacker, self, 1);
462 					}
463 					return;
464 				}
465 //ROGUE
466 
467 				if (deathmatch->value)
468 				{
469 					if (ff)
470 						attacker->client->resp.score--;
471 					else
472 						attacker->client->resp.score++;
473 				}
474 				return;
475 			}
476 		}
477 	}
478 
479 	gi.bprintf (PRINT_MEDIUM,"%s died.\n", self->client->pers.netname);
480 
481 //ROGUE
482 //	if (g_showlogic && g_showlogic->value)
483 //	{
484 //		if (mod == MOD_UNKNOWN)
485 //			gi.dprintf ("Player killed by MOD_UNKNOWN\n");
486 //		else
487 //			gi.dprintf ("Player killed by undefined mod %d\n", mod);
488 //	}
489 //ROGUE
490 
491 	if (deathmatch->value)
492 //ROGUE
493 	{
494 		if (gamerules && gamerules->value)
495 		{
496 			if(DMGame.Score)
497 			{
498 				DMGame.Score(self, self, -1);
499 			}
500 			return;
501 		}
502 		else
503 			self->client->resp.score--;
504 	}
505 //ROGUE
506 
507 }
508 
509 
510 void Touch_Item (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf);
511 
TossClientWeapon(edict_t * self)512 void TossClientWeapon (edict_t *self)
513 {
514 	gitem_t		*item;
515 	edict_t		*drop;
516 	qboolean	quad;
517 	float		spread;
518 
519 	if (!deathmatch->value)
520 		return;
521 
522 	item = self->client->pers.weapon;
523 	if (! self->client->pers.inventory[self->client->ammo_index] )
524 		item = NULL;
525 	if (item && (strcmp (item->pickup_name, "Blaster") == 0))
526 		item = NULL;
527 
528 	if (!((int)(dmflags->value) & DF_QUAD_DROP))
529 		quad = false;
530 	else
531 		quad = (self->client->quad_framenum > (level.framenum + 10));
532 
533 	if (item && quad)
534 		spread = 22.5;
535 	else
536 		spread = 0.0;
537 
538 	if (item)
539 	{
540 		self->client->v_angle[YAW] -= spread;
541 		drop = Drop_Item (self, item);
542 		self->client->v_angle[YAW] += spread;
543 		drop->spawnflags = DROPPED_PLAYER_ITEM;
544 	}
545 
546 	if (quad)
547 	{
548 		self->client->v_angle[YAW] += spread;
549 		drop = Drop_Item (self, FindItemByClassname ("item_quad"));
550 		self->client->v_angle[YAW] -= spread;
551 		drop->spawnflags |= DROPPED_PLAYER_ITEM;
552 
553 		drop->touch = Touch_Item;
554 		drop->nextthink = level.time + (self->client->quad_framenum - level.framenum) * FRAMETIME;
555 		drop->think = G_FreeEdict;
556 	}
557 }
558 
559 
560 /*
561 ==================
562 LookAtKiller
563 ==================
564 */
LookAtKiller(edict_t * self,edict_t * inflictor,edict_t * attacker)565 void LookAtKiller (edict_t *self, edict_t *inflictor, edict_t *attacker)
566 {
567 	vec3_t		dir;
568 
569 	if (attacker && attacker != world && attacker != self)
570 	{
571 		VectorSubtract (attacker->s.origin, self->s.origin, dir);
572 	}
573 	else if (inflictor && inflictor != world && inflictor != self)
574 	{
575 		VectorSubtract (inflictor->s.origin, self->s.origin, dir);
576 	}
577 	else
578 	{
579 		self->client->killer_yaw = self->s.angles[YAW];
580 		return;
581 	}
582 	// PMM - fixed to correct for pitch of 0
583 	if (dir[0])
584 		self->client->killer_yaw = 180/M_PI*atan2(dir[1], dir[0]);
585 	else if (dir[1] > 0)
586 		self->client->killer_yaw = 90;
587 	else if (dir[1] < 0)
588 		self->client->killer_yaw = 270;
589 	else
590 		self->client->killer_yaw = 0;
591 }
592 
593 /*
594 ==================
595 player_die
596 ==================
597 */
player_die(edict_t * self,edict_t * inflictor,edict_t * attacker,int damage,vec3_t point)598 void player_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
599 {
600 	int		n;
601 
602 	VectorClear (self->avelocity);
603 
604 	self->takedamage = DAMAGE_YES;
605 	self->movetype = MOVETYPE_TOSS;
606 
607 	self->s.modelindex2 = 0;	// remove linked weapon model
608 
609 	self->s.angles[0] = 0;
610 	self->s.angles[2] = 0;
611 
612 	self->s.sound = 0;
613 	self->client->weapon_sound = 0;
614 
615 	self->maxs[2] = -8;
616 
617 //	self->solid = SOLID_NOT;
618 	self->svflags |= SVF_DEADMONSTER;
619 
620 	if (!self->deadflag)
621 	{
622 		self->client->respawn_time = level.time + 1.0;
623 		LookAtKiller (self, inflictor, attacker);
624 		self->client->ps.pmove.pm_type = PM_DEAD;
625 		ClientObituary (self, inflictor, attacker);
626 		TossClientWeapon (self);
627 		if (deathmatch->value)
628 			Cmd_Help_f (self);		// show scores
629 
630 		// clear inventory
631 		// this is kind of ugly, but it's how we want to handle keys in coop
632 		for (n = 0; n < game.num_items; n++)
633 		{
634 			if (coop->value && itemlist[n].flags & IT_KEY)
635 				self->client->resp.coop_respawn.inventory[n] = self->client->pers.inventory[n];
636 			self->client->pers.inventory[n] = 0;
637 		}
638 	}
639 
640 	if(gamerules && gamerules->value)	// if we're in a dm game, alert the game
641 	{
642 		if(DMGame.PlayerDeath)
643 			DMGame.PlayerDeath(self, inflictor, attacker);
644 	}
645 
646 	// remove powerups
647 	self->client->quad_framenum = 0;
648 	self->client->invincible_framenum = 0;
649 	self->client->breather_framenum = 0;
650 	self->client->enviro_framenum = 0;
651 	self->flags &= ~FL_POWER_ARMOR;
652 
653 //==============
654 // ROGUE stuff
655 	self->client->double_framenum = 0;
656 
657 	// if there's a sphere around, let it know the player died.
658 	// vengeance and hunter will die if they're not attacking,
659 	// defender should always die
660 	if(self->client->owned_sphere)
661 	{
662 		edict_t *sphere;
663 
664 		sphere = self->client->owned_sphere;
665 		sphere->die(sphere, self, self, 0, vec3_origin);
666 	}
667 
668 	// if we've been killed by the tracker, GIB!
669 	if((meansOfDeath & ~MOD_FRIENDLY_FIRE) == MOD_TRACKER)
670 	{
671 		self->health = -100;
672 		damage = 400;
673 	}
674 
675 	// make sure no trackers are still hurting us.
676 	if(self->client->tracker_pain_framenum)
677 	{
678 		RemoveAttackingPainDaemons (self);
679 	}
680 
681 	// if we got obliterated by the nuke, don't gib
682 	if ((self->health < -80) && (meansOfDeath == MOD_NUKE))
683 		self->flags |= FL_NOGIB;
684 
685 // ROGUE
686 //==============
687 
688 	if (self->health < -40)
689 	{
690 		// PMM
691 		// don't toss gibs if we got vaped by the nuke
692 		if (!(self->flags & FL_NOGIB))
693 		{
694 		// pmm
695 			// gib
696 			gi.sound (self, CHAN_BODY, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
697 
698 			// more meaty gibs for your dollar!
699 			if((deathmatch->value) && (self->health < -80))
700 			{
701 				for (n= 0; n < 4; n++)
702 					ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
703 			}
704 
705 			for (n= 0; n < 4; n++)
706 				ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
707 		// PMM
708 		}
709 		self->flags &= ~FL_NOGIB;
710 		// pmm
711 
712 		ThrowClientHead (self, damage);
713 
714 		self->takedamage = DAMAGE_NO;
715 	}
716 	else
717 	{	// normal death
718 		if (!self->deadflag)
719 		{
720 			static int i;
721 
722 			i = (i+1)%3;
723 			// start a death animation
724 			self->client->anim_priority = ANIM_DEATH;
725 			if (self->client->ps.pmove.pm_flags & PMF_DUCKED)
726 			{
727 				self->s.frame = FRAME_crdeath1-1;
728 				self->client->anim_end = FRAME_crdeath5;
729 			}
730 			else switch (i)
731 			{
732 			case 0:
733 				self->s.frame = FRAME_death101-1;
734 				self->client->anim_end = FRAME_death106;
735 				break;
736 			case 1:
737 				self->s.frame = FRAME_death201-1;
738 				self->client->anim_end = FRAME_death206;
739 				break;
740 			case 2:
741 				self->s.frame = FRAME_death301-1;
742 				self->client->anim_end = FRAME_death308;
743 				break;
744 			}
745 			gi.sound (self, CHAN_VOICE, gi.soundindex(va("*death%i.wav", (rand()%4)+1)), 1, ATTN_NORM, 0);
746 		}
747 	}
748 
749 	self->deadflag = DEAD_DEAD;
750 
751 	gi.linkentity (self);
752 }
753 
754 //=======================================================================
755 
756 /*
757 ==============
758 InitClientPersistant
759 
760 This is only called when the game first initializes in single player,
761 but is called after each death and level change in deathmatch
762 ==============
763 */
InitClientPersistant(gclient_t * client)764 void InitClientPersistant (gclient_t *client)
765 {
766 	gitem_t		*item;
767 
768 	memset (&client->pers, 0, sizeof(client->pers));
769 
770 	item = FindItem("Blaster");
771 	client->pers.selected_item = ITEM_INDEX(item);
772 	client->pers.inventory[client->pers.selected_item] = 1;
773 
774 	client->pers.weapon = item;
775 
776 	client->pers.health			= 100;
777 	client->pers.max_health		= 100;
778 
779 	client->pers.max_bullets	= 200;
780 	client->pers.max_shells		= 100;
781 	client->pers.max_rockets	= 50;
782 	client->pers.max_grenades	= 50;
783 	client->pers.max_cells		= 200;
784 	client->pers.max_slugs		= 50;
785 
786 //ROGUE
787 	// FIXME - give these real numbers....
788 	client->pers.max_prox		= 50;
789 	client->pers.max_tesla		= 50;
790 	client->pers.max_flechettes = 200;
791 #ifndef KILL_DISRUPTOR
792 	client->pers.max_rounds     = 100;
793 #endif
794 //ROGUE
795 
796 	client->pers.connected = true;
797 }
798 
799 
InitClientResp(gclient_t * client)800 void InitClientResp (gclient_t *client)
801 {
802 	memset (&client->resp, 0, sizeof(client->resp));
803 	client->resp.enterframe = level.framenum;
804 	client->resp.coop_respawn = client->pers;
805 }
806 
807 /*
808 ==================
809 SaveClientData
810 
811 Some information that should be persistant, like health,
812 is still stored in the edict structure, so it needs to
813 be mirrored out to the client structure before all the
814 edicts are wiped.
815 ==================
816 */
SaveClientData(void)817 void SaveClientData (void)
818 {
819 	int		i;
820 	edict_t	*ent;
821 
822 	for (i=0 ; i<game.maxclients ; i++)
823 	{
824 		ent = &g_edicts[1+i];
825 		if (!ent->inuse)
826 			continue;
827 		game.clients[i].pers.health = ent->health;
828 		game.clients[i].pers.max_health = ent->max_health;
829 		game.clients[i].pers.savedFlags = (ent->flags & (FL_GODMODE|FL_NOTARGET|FL_POWER_ARMOR));
830 		if (coop->value)
831 			game.clients[i].pers.score = ent->client->resp.score;
832 	}
833 }
834 
FetchClientEntData(edict_t * ent)835 void FetchClientEntData (edict_t *ent)
836 {
837 	ent->health = ent->client->pers.health;
838 	ent->max_health = ent->client->pers.max_health;
839 	ent->flags |= ent->client->pers.savedFlags;
840 	if (coop->value)
841 		ent->client->resp.score = ent->client->pers.score;
842 }
843 
844 
845 
846 /*
847 =======================================================================
848 
849   SelectSpawnPoint
850 
851 =======================================================================
852 */
853 
854 /*
855 ================
856 PlayersRangeFromSpot
857 
858 Returns the distance to the nearest player from the given spot
859 ================
860 */
PlayersRangeFromSpot(edict_t * spot)861 float	PlayersRangeFromSpot (edict_t *spot)
862 {
863 	edict_t	*player;
864 	float	bestplayerdistance;
865 	vec3_t	v;
866 	int		n;
867 	float	playerdistance;
868 
869 
870 	bestplayerdistance = 9999999;
871 
872 	for (n = 1; n <= maxclients->value; n++)
873 	{
874 		player = &g_edicts[n];
875 
876 		if (!player->inuse)
877 			continue;
878 
879 		if (player->health <= 0)
880 			continue;
881 
882 		VectorSubtract (spot->s.origin, player->s.origin, v);
883 		playerdistance = VectorLength (v);
884 
885 		if (playerdistance < bestplayerdistance)
886 			bestplayerdistance = playerdistance;
887 	}
888 
889 	return bestplayerdistance;
890 }
891 
892 /*
893 ================
894 SelectRandomDeathmatchSpawnPoint
895 
896 go to a random point, but NOT the two points closest
897 to other players
898 ================
899 */
SelectRandomDeathmatchSpawnPoint(void)900 edict_t *SelectRandomDeathmatchSpawnPoint (void)
901 {
902 	edict_t	*spot, *spot1, *spot2;
903 	int		count = 0;
904 	int		selection;
905 	float	range, range1, range2;
906 
907 	spot = NULL;
908 	range1 = range2 = 99999;
909 	spot1 = spot2 = NULL;
910 
911 	while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL)
912 	{
913 		count++;
914 		range = PlayersRangeFromSpot(spot);
915 		if (range < range1)
916 		{
917 			range1 = range;
918 			spot1 = spot;
919 		}
920 		else if (range < range2)
921 		{
922 			range2 = range;
923 			spot2 = spot;
924 		}
925 	}
926 
927 	if (!count)
928 		return NULL;
929 
930 	if (count <= 2)
931 	{
932 		spot1 = spot2 = NULL;
933 	}
934 	else
935 		count -= 2;
936 
937 	selection = rand() % count;
938 
939 	spot = NULL;
940 	do
941 	{
942 		spot = G_Find (spot, FOFS(classname), "info_player_deathmatch");
943 		if (spot == spot1 || spot == spot2)
944 			selection++;
945 	} while(selection--);
946 
947 	return spot;
948 }
949 
950 /*
951 ================
952 SelectFarthestDeathmatchSpawnPoint
953 
954 ================
955 */
SelectFarthestDeathmatchSpawnPoint(void)956 edict_t *SelectFarthestDeathmatchSpawnPoint (void)
957 {
958 	edict_t	*bestspot;
959 	float	bestdistance, bestplayerdistance;
960 	edict_t	*spot;
961 
962 
963 	spot = NULL;
964 	bestspot = NULL;
965 	bestdistance = 0;
966 	while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL)
967 	{
968 		bestplayerdistance = PlayersRangeFromSpot (spot);
969 
970 		if (bestplayerdistance > bestdistance)
971 		{
972 			bestspot = spot;
973 			bestdistance = bestplayerdistance;
974 		}
975 	}
976 
977 	if (bestspot)
978 	{
979 		return bestspot;
980 	}
981 
982 	// if there is a player just spawned on each and every start spot
983 	// we have no choice to turn one into a telefrag meltdown
984 	spot = G_Find (NULL, FOFS(classname), "info_player_deathmatch");
985 
986 	return spot;
987 }
988 
SelectDeathmatchSpawnPoint(void)989 edict_t *SelectDeathmatchSpawnPoint (void)
990 {
991 	if ( (int)(dmflags->value) & DF_SPAWN_FARTHEST)
992 		return SelectFarthestDeathmatchSpawnPoint ();
993 	else
994 		return SelectRandomDeathmatchSpawnPoint ();
995 }
996 
997 //===============
998 //ROGUE
SelectLavaCoopSpawnPoint(edict_t * ent)999 edict_t *SelectLavaCoopSpawnPoint (edict_t *ent)
1000 {
1001 	int		index;
1002 	edict_t	*spot = NULL;
1003 	float	lavatop;
1004 	edict_t	*lava;
1005 	edict_t *pointWithLeastLava;
1006 	float	lowest;
1007 	edict_t *spawnPoints [64];
1008 	vec3_t	center;
1009 	int		numPoints;
1010 	edict_t *highestlava;
1011 
1012 	lavatop = -99999;
1013 	highestlava = NULL;
1014 
1015 	// first, find the highest lava
1016 	// remember that some will stop moving when they've filled their
1017 	// areas...
1018 	lava = NULL;
1019 	while (1)
1020 	{
1021 		lava = G_Find (lava, FOFS(classname), "func_door");
1022 		if(!lava)
1023 			break;
1024 
1025 		VectorAdd (lava->absmax, lava->absmin, center);
1026 		VectorScale (center, 0.5, center);
1027 
1028 		if(lava->spawnflags & 2 && (gi.pointcontents(center) & MASK_WATER))
1029 		{
1030 			if (lava->absmax[2] > lavatop)
1031 			{
1032 				lavatop = lava->absmax[2];
1033 				highestlava = lava;
1034 			}
1035 		}
1036 	}
1037 
1038 	// if we didn't find ANY lava, then return NULL
1039 	if (!highestlava)
1040 		return NULL;
1041 
1042 	// find the top of the lava and include a small margin of error (plus bbox size)
1043 	lavatop = highestlava->absmax[2] + 64;
1044 
1045 	// find all the lava spawn points and store them in spawnPoints[]
1046 	spot = NULL;
1047 	numPoints = 0;
1048 	while(spot = G_Find (spot, FOFS(classname), "info_player_coop_lava"))
1049 	{
1050 		if(numPoints == 64)
1051 			break;
1052 
1053 		spawnPoints[numPoints++] = spot;
1054 	}
1055 
1056 	if(numPoints < 1)
1057 		return NULL;
1058 
1059 	// walk up the sorted list and return the lowest, open, non-lava spawn point
1060 	spot = NULL;
1061 	lowest = 999999;
1062 	pointWithLeastLava = NULL;
1063 	for (index = 0; index < numPoints; index++)
1064 	{
1065 		if(spawnPoints[index]->s.origin[2] < lavatop)
1066 			continue;
1067 
1068 		if(PlayersRangeFromSpot(spawnPoints[index]) > 32)
1069 		{
1070 			if(spawnPoints[index]->s.origin[2] < lowest)
1071 			{
1072 				// save the last point
1073 				pointWithLeastLava = spawnPoints[index];
1074 				lowest = spawnPoints[index]->s.origin[2];
1075 			}
1076 		}
1077 	}
1078 
1079 	// FIXME - better solution????
1080 	// well, we may telefrag someone, but oh well...
1081 	if(pointWithLeastLava)
1082 		return pointWithLeastLava;
1083 
1084 	return NULL;
1085 }
1086 //ROGUE
1087 //===============
1088 
SelectCoopSpawnPoint(edict_t * ent)1089 edict_t *SelectCoopSpawnPoint (edict_t *ent)
1090 {
1091 	int		index;
1092 	edict_t	*spot = NULL;
1093 	char	*target;
1094 
1095 //ROGUE
1096 	// rogue hack, but not too gross...
1097 	if (!Q_stricmp(level.mapname, "rmine2p") || !Q_stricmp(level.mapname, "rmine2"))
1098 		return SelectLavaCoopSpawnPoint (ent);
1099 //ROGUE
1100 
1101 	index = ent->client - game.clients;
1102 
1103 	// player 0 starts in normal player spawn point
1104 	if (!index)
1105 		return NULL;
1106 
1107 	spot = NULL;
1108 
1109 	// assume there are four coop spots at each spawnpoint
1110 	while (1)
1111 	{
1112 		spot = G_Find (spot, FOFS(classname), "info_player_coop");
1113 		if (!spot)
1114 			return NULL;	// we didn't have enough...
1115 
1116 		target = spot->targetname;
1117 		if (!target)
1118 			target = "";
1119 		if ( Q_stricmp(game.spawnpoint, target) == 0 )
1120 		{	// this is a coop spawn point for one of the clients here
1121 			index--;
1122 			if (!index)
1123 				return spot;		// this is it
1124 		}
1125 	}
1126 
1127 
1128 	return spot;
1129 }
1130 
1131 
1132 /*
1133 ===========
1134 SelectSpawnPoint
1135 
1136 Chooses a player start, deathmatch start, coop start, etc
1137 ============
1138 */
SelectSpawnPoint(edict_t * ent,vec3_t origin,vec3_t angles)1139 void	SelectSpawnPoint (edict_t *ent, vec3_t origin, vec3_t angles)
1140 {
1141 	edict_t	*spot = NULL;
1142 
1143 	if (deathmatch->value)
1144 		spot = SelectDeathmatchSpawnPoint ();
1145 	else if (coop->value)
1146 		spot = SelectCoopSpawnPoint (ent);
1147 
1148 	// find a single player start spot
1149 	if (!spot)
1150 	{
1151 		while ((spot = G_Find (spot, FOFS(classname), "info_player_start")) != NULL)
1152 		{
1153 			if (!game.spawnpoint[0] && !spot->targetname)
1154 				break;
1155 
1156 			if (!game.spawnpoint[0] || !spot->targetname)
1157 				continue;
1158 
1159 			if (Q_stricmp(game.spawnpoint, spot->targetname) == 0)
1160 				break;
1161 		}
1162 
1163 		if (!spot)
1164 		{
1165 			if (!game.spawnpoint[0])
1166 			{	// there wasn't a spawnpoint without a target, so use any
1167 				spot = G_Find (spot, FOFS(classname), "info_player_start");
1168 			}
1169 			if (!spot)
1170 				gi.error ("Couldn't find spawn point %s\n", game.spawnpoint);
1171 		}
1172 	}
1173 
1174 	VectorCopy (spot->s.origin, origin);
1175 	origin[2] += 9;
1176 	VectorCopy (spot->s.angles, angles);
1177 }
1178 
1179 //======================================================================
1180 
1181 
InitBodyQue(void)1182 void InitBodyQue (void)
1183 {
1184 	int		i;
1185 	edict_t	*ent;
1186 
1187 	level.body_que = 0;
1188 	for (i=0; i<BODY_QUEUE_SIZE ; i++)
1189 	{
1190 		ent = G_Spawn();
1191 		ent->classname = "bodyque";
1192 	}
1193 }
1194 
body_die(edict_t * self,edict_t * inflictor,edict_t * attacker,int damage,vec3_t point)1195 void body_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
1196 {
1197 	int	n;
1198 
1199 	if (self->health < -40)
1200 	{
1201 		gi.sound (self, CHAN_BODY, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
1202 		for (n= 0; n < 4; n++)
1203 			ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
1204 		self->s.origin[2] -= 48;
1205 		ThrowClientHead (self, damage);
1206 		self->takedamage = DAMAGE_NO;
1207 	}
1208 }
1209 
CopyToBodyQue(edict_t * ent)1210 void CopyToBodyQue (edict_t *ent)
1211 {
1212 	edict_t		*body;
1213 
1214 	// grab a body que and cycle to the next one
1215 	body = &g_edicts[(int)maxclients->value + level.body_que + 1];
1216 	level.body_que = (level.body_que + 1) % BODY_QUEUE_SIZE;
1217 
1218 	// FIXME: send an effect on the removed body
1219 
1220 	gi.unlinkentity (ent);
1221 
1222 	gi.unlinkentity (body);
1223 	body->s = ent->s;
1224 	body->s.number = body - g_edicts;
1225 
1226 	body->svflags = ent->svflags;
1227 	VectorCopy (ent->mins, body->mins);
1228 	VectorCopy (ent->maxs, body->maxs);
1229 	VectorCopy (ent->absmin, body->absmin);
1230 	VectorCopy (ent->absmax, body->absmax);
1231 	VectorCopy (ent->size, body->size);
1232 	body->solid = ent->solid;
1233 	body->clipmask = ent->clipmask;
1234 	body->owner = ent->owner;
1235 	body->movetype = ent->movetype;
1236 
1237 	body->die = body_die;
1238 	body->takedamage = DAMAGE_YES;
1239 
1240 	gi.linkentity (body);
1241 }
1242 
1243 
respawn(edict_t * self)1244 void respawn (edict_t *self)
1245 {
1246 	if (deathmatch->value || coop->value)
1247 	{
1248 		// spectators don't leave bodies
1249 		if (self->movetype != MOVETYPE_NOCLIP)
1250 			CopyToBodyQue (self);
1251 		self->svflags &= ~SVF_NOCLIENT;
1252 		PutClientInServer (self);
1253 
1254 		// add a teleportation effect
1255 		self->s.event = EV_PLAYER_TELEPORT;
1256 
1257 		// hold in place briefly
1258 		self->client->ps.pmove.pm_flags = PMF_TIME_TELEPORT;
1259 		self->client->ps.pmove.pm_time = 14;
1260 
1261 		self->client->respawn_time = level.time;
1262 
1263 		return;
1264 	}
1265 
1266 	// restart the entire server
1267 	gi.AddCommandString ("menu_loadgame\n");
1268 }
1269 
1270 /*
1271  * only called when pers.spectator changes
1272  * note that resp.spectator should be the opposite of pers.spectator here
1273  */
spectator_respawn(edict_t * ent)1274 void spectator_respawn (edict_t *ent)
1275 {
1276 	int i, numspec;
1277 
1278 	// if the user wants to become a spectator, make sure he doesn't
1279 	// exceed max_spectators
1280 
1281 	if (ent->client->pers.spectator)
1282 	{
1283 		char *value = Info_ValueForKey (ent->client->pers.userinfo, "spectator");
1284 		if (*spectator_password->string &&
1285 			strcmp(spectator_password->string, "none") &&
1286 			strcmp(spectator_password->string, value))
1287 		{
1288 			gi.cprintf(ent, PRINT_HIGH, "Spectator password incorrect.\n");
1289 			ent->client->pers.spectator = false;
1290 			gi.WriteByte (svc_stufftext);
1291 			gi.WriteString ("spectator 0\n");
1292 			gi.unicast(ent, true);
1293 			return;
1294 		}
1295 
1296 		// count spectators
1297 		for (i = 1, numspec = 0; i <= maxclients->value; i++)
1298 		{
1299 			if (g_edicts[i].inuse && g_edicts[i].client->pers.spectator)
1300 				numspec++;
1301 		}
1302 
1303 		if (numspec >= maxspectators->value)
1304 		{
1305 			gi.cprintf(ent, PRINT_HIGH, "Server spectator limit is full.");
1306 			ent->client->pers.spectator = false;
1307 			// reset his spectator var
1308 			gi.WriteByte (svc_stufftext);
1309 			gi.WriteString ("spectator 0\n");
1310 			gi.unicast(ent, true);
1311 			return;
1312 		}
1313 	}
1314 	else
1315 	{
1316 		// he was a spectator and wants to join the game
1317 		// he must have the right password
1318 		char *value = Info_ValueForKey (ent->client->pers.userinfo, "password");
1319 		if (*password->string && strcmp(password->string, "none") &&
1320 			strcmp(password->string, value))
1321 		{
1322 			gi.cprintf(ent, PRINT_HIGH, "Password incorrect.\n");
1323 			ent->client->pers.spectator = true;
1324 			gi.WriteByte (svc_stufftext);
1325 			gi.WriteString ("spectator 1\n");
1326 			gi.unicast(ent, true);
1327 			return;
1328 		}
1329 	}
1330 
1331 	// clear score on respawn
1332 	ent->client->pers.score = ent->client->resp.score = 0;
1333 
1334 	ent->svflags &= ~SVF_NOCLIENT;
1335 	PutClientInServer (ent);
1336 
1337 	// add a teleportation effect
1338 	if (!ent->client->pers.spectator)
1339 	{
1340 		// send effect
1341 		gi.WriteByte (svc_muzzleflash);
1342 		gi.WriteShort (ent-g_edicts);
1343 		gi.WriteByte (MZ_LOGIN);
1344 		gi.multicast (ent->s.origin, MULTICAST_PVS);
1345 
1346 		// hold in place briefly
1347 		ent->client->ps.pmove.pm_flags = PMF_TIME_TELEPORT;
1348 		ent->client->ps.pmove.pm_time = 14;
1349 	}
1350 
1351 	ent->client->respawn_time = level.time;
1352 
1353 	if (ent->client->pers.spectator)
1354 		gi.bprintf (PRINT_HIGH, "%s has moved to the sidelines\n", ent->client->pers.netname);
1355 	else
1356 		gi.bprintf (PRINT_HIGH, "%s joined the game\n", ent->client->pers.netname);
1357 }
1358 
1359 //==============================================================
1360 
1361 
1362 /*
1363 ===========
1364 PutClientInServer
1365 
1366 Called when a player connects to a server or respawns in
1367 a deathmatch.
1368 ============
1369 */
PutClientInServer(edict_t * ent)1370 void PutClientInServer (edict_t *ent)
1371 {
1372 	vec3_t	mins = {-16, -16, -24};
1373 	vec3_t	maxs = {16, 16, 32};
1374 	int		index;
1375 	vec3_t	spawn_origin, spawn_angles;
1376 	gclient_t	*client;
1377 	int		i;
1378 	client_persistant_t	saved;
1379 	client_respawn_t	resp;
1380 
1381 	// find a spawn point
1382 	// do it before setting health back up, so farthest
1383 	// ranging doesn't count this client
1384 	if(gamerules && gamerules->value && DMGame.SelectSpawnPoint)		// PGM
1385 		DMGame.SelectSpawnPoint (ent, spawn_origin, spawn_angles);		// PGM
1386 	else																// PGM
1387 		SelectSpawnPoint (ent, spawn_origin, spawn_angles);
1388 
1389 	index = ent-g_edicts-1;
1390 	client = ent->client;
1391 
1392 	// deathmatch wipes most client data every spawn
1393 	if (deathmatch->value)
1394 	{
1395 		char		userinfo[MAX_INFO_STRING];
1396 
1397 		resp = client->resp;
1398 		memcpy (userinfo, client->pers.userinfo, sizeof(userinfo));
1399 		InitClientPersistant (client);
1400 		ClientUserinfoChanged (ent, userinfo);
1401 	}
1402 	else if (coop->value)
1403 	{
1404 //		int			n;
1405 		char		userinfo[MAX_INFO_STRING];
1406 
1407 		resp = client->resp;
1408 		memcpy (userinfo, client->pers.userinfo, sizeof(userinfo));
1409 		// this is kind of ugly, but it's how we want to handle keys in coop
1410 //		for (n = 0; n < game.num_items; n++)
1411 //		{
1412 //			if (itemlist[n].flags & IT_KEY)
1413 //				resp.coop_respawn.inventory[n] = client->pers.inventory[n];
1414 //		}
1415 		resp.coop_respawn.game_helpchanged = client->pers.game_helpchanged;
1416 		resp.coop_respawn.helpchanged = client->pers.helpchanged;
1417 		client->pers = resp.coop_respawn;
1418 		ClientUserinfoChanged (ent, userinfo);
1419 		if (resp.score > client->pers.score)
1420 			client->pers.score = resp.score;
1421 	}
1422 	else
1423 	{
1424 		memset (&resp, 0, sizeof(resp));
1425 	}
1426 
1427 	// clear everything but the persistant data
1428 	saved = client->pers;
1429 	memset (client, 0, sizeof(*client));
1430 	client->pers = saved;
1431 	if (client->pers.health <= 0)
1432 		InitClientPersistant(client);
1433 	client->resp = resp;
1434 
1435 	// copy some data from the client to the entity
1436 	FetchClientEntData (ent);
1437 
1438 	// clear entity values
1439 	ent->groundentity = NULL;
1440 	ent->client = &game.clients[index];
1441 	ent->takedamage = DAMAGE_AIM;
1442 	ent->movetype = MOVETYPE_WALK;
1443 	ent->viewheight = 22;
1444 	ent->inuse = true;
1445 	ent->classname = "player";
1446 	ent->mass = 200;
1447 	ent->solid = SOLID_BBOX;
1448 	ent->deadflag = DEAD_NO;
1449 	ent->air_finished = level.time + 12;
1450 	ent->clipmask = MASK_PLAYERSOLID;
1451 	ent->model = "players/male/tris.md2";
1452 	ent->pain = player_pain;
1453 	ent->die = player_die;
1454 	ent->waterlevel = 0;
1455 	ent->watertype = 0;
1456 	ent->flags &= ~FL_NO_KNOCKBACK;
1457 	ent->svflags &= ~SVF_DEADMONSTER;
1458 
1459 	ent->flags &= ~FL_SAM_RAIMI;		// PGM - turn off sam raimi flag
1460 
1461 	VectorCopy (mins, ent->mins);
1462 	VectorCopy (maxs, ent->maxs);
1463 	VectorClear (ent->velocity);
1464 
1465 	// clear playerstate values
1466 	memset (&ent->client->ps, 0, sizeof(client->ps));
1467 
1468 	client->ps.pmove.origin[0] = spawn_origin[0]*8;
1469 	client->ps.pmove.origin[1] = spawn_origin[1]*8;
1470 	client->ps.pmove.origin[2] = spawn_origin[2]*8;
1471 
1472 	if (deathmatch->value && ((int)dmflags->value & DF_FIXED_FOV))
1473 	{
1474 		client->ps.fov = 90;
1475 	}
1476 	else
1477 	{
1478 		client->ps.fov = atoi(Info_ValueForKey(client->pers.userinfo, "fov"));
1479 		if (client->ps.fov < 1)
1480 			client->ps.fov = 90;
1481 		else if (client->ps.fov > 160)
1482 			client->ps.fov = 160;
1483 	}
1484 
1485 //PGM
1486 	if (client->pers.weapon)
1487 		client->ps.gunindex = gi.modelindex(client->pers.weapon->view_model);
1488 	else
1489 		client->ps.gunindex = 0;
1490 //PGM
1491 
1492 	// clear entity state values
1493 	ent->s.effects = 0;
1494 	ent->s.modelindex = 255;		// will use the skin specified model
1495 	ent->s.modelindex2 = 255;		// custom gun model
1496 	// sknum is player num and weapon number
1497 	// weapon number will be added in changeweapon
1498 	ent->s.skinnum = ent - g_edicts - 1;
1499 
1500 	ent->s.frame = 0;
1501 	VectorCopy (spawn_origin, ent->s.origin);
1502 	ent->s.origin[2] += 1;	// make sure off ground
1503 	VectorCopy (ent->s.origin, ent->s.old_origin);
1504 
1505 	// set the delta angle
1506 	for (i=0 ; i<3 ; i++)
1507 		client->ps.pmove.delta_angles[i] = ANGLE2SHORT(spawn_angles[i] - client->resp.cmd_angles[i]);
1508 
1509 	ent->s.angles[PITCH] = 0;
1510 	ent->s.angles[YAW] = spawn_angles[YAW];
1511 	ent->s.angles[ROLL] = 0;
1512 	VectorCopy (ent->s.angles, client->ps.viewangles);
1513 	VectorCopy (ent->s.angles, client->v_angle);
1514 
1515 	// spawn a spectator
1516 	if (client->pers.spectator)
1517 	{
1518 		client->chase_target = NULL;
1519 
1520 		client->resp.spectator = true;
1521 
1522 		ent->movetype = MOVETYPE_NOCLIP;
1523 		ent->solid = SOLID_NOT;
1524 		ent->svflags |= SVF_NOCLIENT;
1525 		ent->client->ps.gunindex = 0;
1526 		gi.linkentity (ent);
1527 		return;
1528 	}
1529 	else
1530 		client->resp.spectator = false;
1531 
1532 	if (!KillBox (ent))
1533 	{	// could't spawn in?
1534 	}
1535 
1536 	gi.linkentity (ent);
1537 
1538 	// my tribute to cash's level-specific hacks. I hope I live
1539 	// up to his trailblazing cheese.
1540 	if(Q_stricmp(level.mapname, "rboss") == 0)
1541 	{
1542 		// if you get on to rboss in single player or coop, ensure
1543 		// the player has the nuke key. (not in DM)
1544 		if(!(deathmatch->value))
1545 		{
1546 			gitem_t		*item;
1547 
1548 			item = FindItem("Antimatter Bomb");
1549 			client->pers.selected_item = ITEM_INDEX(item);
1550 			client->pers.inventory[client->pers.selected_item] = 1;
1551 		}
1552 	}
1553 
1554 	// force the current weapon up
1555 	client->newweapon = client->pers.weapon;
1556 	ChangeWeapon (ent);
1557 }
1558 
1559 /*
1560 =====================
1561 ClientBeginDeathmatch
1562 
1563 A client has just connected to the server in
1564 deathmatch mode, so clear everything out before starting them.
1565 =====================
1566 */
ClientBeginDeathmatch(edict_t * ent)1567 void ClientBeginDeathmatch (edict_t *ent)
1568 {
1569 	G_InitEdict (ent);
1570 
1571 	InitClientResp (ent->client);
1572 
1573 	//PGM
1574 	if(gamerules && gamerules->value && DMGame.ClientBegin)
1575 	{
1576 		DMGame.ClientBegin (ent);
1577 	}
1578 	//PGM
1579 
1580 		// locate ent at a spawn point
1581 	PutClientInServer (ent);
1582 
1583 	if (level.intermissiontime)
1584 	{
1585 		MoveClientToIntermission (ent);
1586 	}
1587 	else
1588 	{
1589 		// send effect
1590 		gi.WriteByte (svc_muzzleflash);
1591 		gi.WriteShort (ent-g_edicts);
1592 		gi.WriteByte (MZ_LOGIN);
1593 		gi.multicast (ent->s.origin, MULTICAST_PVS);
1594 	}
1595 
1596 	gi.bprintf (PRINT_HIGH, "%s entered the game\n", ent->client->pers.netname);
1597 
1598 	// make sure all view stuff is valid
1599 	ClientEndServerFrame (ent);
1600 }
1601 
1602 
1603 /*
1604 ===========
1605 ClientBegin
1606 
1607 called when a client has finished connecting, and is ready
1608 to be placed into the game.  This will happen every level load.
1609 ============
1610 */
ClientBegin(edict_t * ent)1611 void ClientBegin (edict_t *ent)
1612 {
1613 	int		i;
1614 
1615 	ent->client = game.clients + (ent - g_edicts - 1);
1616 
1617 	if (deathmatch->value)
1618 	{
1619 		ClientBeginDeathmatch (ent);
1620 		return;
1621 	}
1622 
1623 	// if there is already a body waiting for us (a loadgame), just
1624 	// take it, otherwise spawn one from scratch
1625 	if (ent->inuse == true)
1626 	{
1627 		// the client has cleared the client side viewangles upon
1628 		// connecting to the server, which is different than the
1629 		// state when the game is saved, so we need to compensate
1630 		// with deltaangles
1631 		for (i=0 ; i<3 ; i++)
1632 			ent->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(ent->client->ps.viewangles[i]);
1633 	}
1634 	else
1635 	{
1636 		// a spawn point will completely reinitialize the entity
1637 		// except for the persistant data that was initialized at
1638 		// ClientConnect() time
1639 		G_InitEdict (ent);
1640 		ent->classname = "player";
1641 		InitClientResp (ent->client);
1642 		PutClientInServer (ent);
1643 	}
1644 
1645 	if (level.intermissiontime)
1646 	{
1647 		MoveClientToIntermission (ent);
1648 	}
1649 	else
1650 	{
1651 		// send effect if in a multiplayer game
1652 		if (game.maxclients > 1)
1653 		{
1654 			gi.WriteByte (svc_muzzleflash);
1655 			gi.WriteShort (ent-g_edicts);
1656 			gi.WriteByte (MZ_LOGIN);
1657 			gi.multicast (ent->s.origin, MULTICAST_PVS);
1658 
1659 			gi.bprintf (PRINT_HIGH, "%s entered the game\n", ent->client->pers.netname);
1660 		}
1661 	}
1662 
1663 	// make sure all view stuff is valid
1664 	ClientEndServerFrame (ent);
1665 }
1666 
1667 /*
1668 ===========
1669 ClientUserInfoChanged
1670 
1671 called whenever the player updates a userinfo variable.
1672 
1673 The game can override any of the settings in place
1674 (forcing skins or names, etc) before copying it off.
1675 ============
1676 */
ClientUserinfoChanged(edict_t * ent,char * userinfo)1677 void ClientUserinfoChanged (edict_t *ent, char *userinfo)
1678 {
1679 	char	*s;
1680 	int		playernum;
1681 
1682 	// check for malformed or illegal info strings
1683 	if (!Info_Validate(userinfo))
1684 	{
1685 		strcpy (userinfo, "\\name\\badinfo\\skin\\male/grunt");
1686 	}
1687 
1688 	// set name
1689 	s = Info_ValueForKey (userinfo, "name");
1690 	strncpy (ent->client->pers.netname, s, sizeof(ent->client->pers.netname)-1);
1691 
1692 	// set spectator
1693 	s = Info_ValueForKey (userinfo, "spectator");
1694 	// spectators are only supported in deathmatch
1695 	// if (deathmatch->value && strcmp(s, "0"))
1696 	if (deathmatch->value && *s && strcmp(s, "0"))
1697 		ent->client->pers.spectator = true;
1698 	else
1699 		ent->client->pers.spectator = false;
1700 
1701 	// set skin
1702 	s = Info_ValueForKey (userinfo, "skin");
1703 
1704 	playernum = ent-g_edicts-1;
1705 
1706 	// combine name and skin into a configstring
1707 	gi.configstring (CS_PLAYERSKINS+playernum, va("%s\\%s", ent->client->pers.netname, s) );
1708 
1709 	// fov
1710 	if (deathmatch->value && ((int)dmflags->value & DF_FIXED_FOV))
1711 	{
1712 		ent->client->ps.fov = 90;
1713 	}
1714 	else
1715 	{
1716 		ent->client->ps.fov = atoi(Info_ValueForKey(userinfo, "fov"));
1717 		if (ent->client->ps.fov < 1)
1718 			ent->client->ps.fov = 90;
1719 		else if (ent->client->ps.fov > 160)
1720 			ent->client->ps.fov = 160;
1721 	}
1722 
1723 	// handedness
1724 	s = Info_ValueForKey (userinfo, "hand");
1725 	if (strlen(s))
1726 	{
1727 		ent->client->pers.hand = atoi(s);
1728 	}
1729 
1730 	// save off the userinfo in case we want to check something later
1731 	strncpy (ent->client->pers.userinfo, userinfo, sizeof(ent->client->pers.userinfo)-1);
1732 }
1733 
1734 
1735 /*
1736 ===========
1737 ClientConnect
1738 
1739 Called when a player begins connecting to the server.
1740 The game can refuse entrance to a client by returning false.
1741 If the client is allowed, the connection process will continue
1742 and eventually get to ClientBegin()
1743 Changing levels will NOT cause this to be called again, but
1744 loadgames will.
1745 ============
1746 */
ClientConnect(edict_t * ent,char * userinfo)1747 qboolean ClientConnect (edict_t *ent, char *userinfo)
1748 {
1749 	char	*value;
1750 
1751 	// check to see if they are on the banned IP list
1752 	value = Info_ValueForKey (userinfo, "ip");
1753 	if (SV_FilterPacket(value))
1754 	{
1755 		Info_SetValueForKey(userinfo, "rejmsg", "Banned.");
1756 		return false;
1757 	}
1758 
1759 	// check for a spectator
1760 	value = Info_ValueForKey (userinfo, "spectator");
1761 //	if (deathmatch->value && strcmp(value, "0"))
1762 	if (deathmatch->value && *value && strcmp(value, "0"))
1763 	{
1764 		int i, numspec;
1765 
1766 		if (*spectator_password->string &&
1767 			strcmp(spectator_password->string, "none") &&
1768 			strcmp(spectator_password->string, value))
1769 		{
1770 			Info_SetValueForKey(userinfo, "rejmsg", "Spectator password required or incorrect.");
1771 			return false;
1772 		}
1773 
1774 		// count spectators
1775 		for (i = numspec = 0; i < maxclients->value; i++)
1776 		{
1777 			if (g_edicts[i+1].inuse && g_edicts[i+1].client->pers.spectator)
1778 				numspec++;
1779 		}
1780 
1781 		if (numspec >= maxspectators->value)
1782 		{
1783 			Info_SetValueForKey(userinfo, "rejmsg", "Server spectator limit is full.");
1784 			return false;
1785 		}
1786 	}
1787 	else
1788 	{
1789 		// check for a password
1790 		value = Info_ValueForKey (userinfo, "password");
1791 		if (*password->string && strcmp(password->string, "none") &&
1792 			strcmp(password->string, value))
1793 		{
1794 			Info_SetValueForKey(userinfo, "rejmsg", "Password required or incorrect.");
1795 			return false;
1796 		}
1797 	}
1798 
1799 
1800 	// they can connect
1801 	ent->client = game.clients + (ent - g_edicts - 1);
1802 
1803 	// if there is already a body waiting for us (a loadgame), just
1804 	// take it, otherwise spawn one from scratch
1805 	if (ent->inuse == false)
1806 	{
1807 		// clear the respawning variables
1808 		InitClientResp (ent->client);
1809 		if (!game.autosaved || !ent->client->pers.weapon)
1810 			InitClientPersistant (ent->client);
1811 	}
1812 
1813 	ClientUserinfoChanged (ent, userinfo);
1814 
1815 	if (game.maxclients > 1)
1816 		gi.dprintf ("%s connected\n", ent->client->pers.netname);
1817 
1818 	ent->svflags = 0; // make sure we start with known default
1819 	ent->client->pers.connected = true;
1820 	return true;
1821 }
1822 
1823 /*
1824 ===========
1825 ClientDisconnect
1826 
1827 Called when a player drops from the server.
1828 Will not be called between levels.
1829 ============
1830 */
ClientDisconnect(edict_t * ent)1831 void ClientDisconnect (edict_t *ent)
1832 {
1833 	int		playernum;
1834 
1835 	if (!ent->client)
1836 		return;
1837 
1838 	gi.bprintf (PRINT_HIGH, "%s disconnected\n", ent->client->pers.netname);
1839 
1840 //============
1841 //ROGUE
1842 	// make sure no trackers are still hurting us.
1843 	if(ent->client->tracker_pain_framenum)
1844 		RemoveAttackingPainDaemons (ent);
1845 
1846 	if (ent->client->owned_sphere)
1847 	{
1848 		if(ent->client->owned_sphere->inuse)
1849 			G_FreeEdict (ent->client->owned_sphere);
1850 		ent->client->owned_sphere = NULL;
1851 	}
1852 
1853 	if (gamerules && gamerules->value)
1854 	{
1855 		if(DMGame.PlayerDisconnect)
1856 			DMGame.PlayerDisconnect(ent);
1857 	}
1858 //ROGUE
1859 //============
1860 
1861 	// send effect
1862 	gi.WriteByte (svc_muzzleflash);
1863 	gi.WriteShort (ent-g_edicts);
1864 	gi.WriteByte (MZ_LOGOUT);
1865 	gi.multicast (ent->s.origin, MULTICAST_PVS);
1866 
1867 	gi.unlinkentity (ent);
1868 	ent->s.modelindex = 0;
1869 	ent->solid = SOLID_NOT;
1870 	ent->inuse = false;
1871 	ent->classname = "disconnected";
1872 	ent->client->pers.connected = false;
1873 
1874 	playernum = ent-g_edicts-1;
1875 	gi.configstring (CS_PLAYERSKINS+playernum, "");
1876 }
1877 
1878 
1879 //==============================================================
1880 
1881 
1882 edict_t	*pm_passent;
1883 
1884 // pmove doesn't need to know about passent and contentmask
PM_trace(vec3_t start,vec3_t mins,vec3_t maxs,vec3_t end)1885 trace_t	PM_trace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end)
1886 {
1887 	if (pm_passent->health > 0)
1888 		return gi.trace (start, mins, maxs, end, pm_passent, MASK_PLAYERSOLID);
1889 	else
1890 		return gi.trace (start, mins, maxs, end, pm_passent, MASK_DEADSOLID);
1891 }
1892 
CheckBlock(void * b,int c)1893 unsigned CheckBlock (void *b, int c)
1894 {
1895 	int	v,i;
1896 	v = 0;
1897 	for (i=0 ; i<c ; i++)
1898 		v+= ((byte *)b)[i];
1899 	return v;
1900 }
PrintPmove(pmove_t * pm)1901 void PrintPmove (pmove_t *pm)
1902 {
1903 	unsigned	c1, c2;
1904 
1905 	c1 = CheckBlock (&pm->s, sizeof(pm->s));
1906 	c2 = CheckBlock (&pm->cmd, sizeof(pm->cmd));
1907 	Com_Printf ("sv %3i:%i %i\n", pm->cmd.impulse, c1, c2);
1908 }
1909 
1910 /*
1911 ==============
1912 ClientThink
1913 
1914 This will be called once for each client frame, which will
1915 usually be a couple times for each server frame.
1916 ==============
1917 */
ClientThink(edict_t * ent,usercmd_t * ucmd)1918 void ClientThink (edict_t *ent, usercmd_t *ucmd)
1919 {
1920 	gclient_t	*client;
1921 	edict_t	*other;
1922 	int		i, j;
1923 	pmove_t	pm;
1924 
1925 	level.current_entity = ent;
1926 	client = ent->client;
1927 
1928 	if (level.intermissiontime)
1929 	{
1930 		client->ps.pmove.pm_type = PM_FREEZE;
1931 		// can exit intermission after five seconds
1932 		if (level.time > level.intermissiontime + 5.0
1933 			&& (ucmd->buttons & BUTTON_ANY) )
1934 			level.exitintermission = true;
1935 		return;
1936 	}
1937 
1938 	pm_passent = ent;
1939 
1940 	if (ent->client->chase_target)
1941 	{
1942 		client->resp.cmd_angles[0] = SHORT2ANGLE(ucmd->angles[0]);
1943 		client->resp.cmd_angles[1] = SHORT2ANGLE(ucmd->angles[1]);
1944 		client->resp.cmd_angles[2] = SHORT2ANGLE(ucmd->angles[2]);
1945 	}
1946 	else
1947 	{
1948 		// set up for pmove
1949 		memset (&pm, 0, sizeof(pm));
1950 
1951 		if (ent->movetype == MOVETYPE_NOCLIP)
1952 			client->ps.pmove.pm_type = PM_SPECTATOR;
1953 		else if (ent->s.modelindex != 255)
1954 			client->ps.pmove.pm_type = PM_GIB;
1955 		else if (ent->deadflag)
1956 			client->ps.pmove.pm_type = PM_DEAD;
1957 		else
1958 			client->ps.pmove.pm_type = PM_NORMAL;
1959 
1960 	//PGM	trigger_gravity support
1961 	//	client->ps.pmove.gravity = sv_gravity->value;
1962 		client->ps.pmove.gravity = sv_gravity->value * ent->gravity;
1963 	//PGM
1964 		pm.s = client->ps.pmove;
1965 
1966 		for (i=0 ; i<3 ; i++)
1967 		{
1968 			pm.s.origin[i] = ent->s.origin[i]*8;
1969 			pm.s.velocity[i] = ent->velocity[i]*8;
1970 		}
1971 
1972 		if (memcmp(&client->old_pmove, &pm.s, sizeof(pm.s)))
1973 		{
1974 			pm.snapinitial = true;
1975 	//		gi.dprintf ("pmove changed!\n");
1976 		}
1977 
1978 		pm.cmd = *ucmd;
1979 
1980 		pm.trace = PM_trace;	// adds default parms
1981 		pm.pointcontents = gi.pointcontents;
1982 
1983 		// perform a pmove
1984 		gi.Pmove (&pm);
1985 
1986 		// save results of pmove
1987 		client->ps.pmove = pm.s;
1988 		client->old_pmove = pm.s;
1989 
1990 		for (i=0 ; i<3 ; i++)
1991 		{
1992 			ent->s.origin[i] = pm.s.origin[i]*0.125;
1993 			ent->velocity[i] = pm.s.velocity[i]*0.125;
1994 		}
1995 
1996 		VectorCopy (pm.mins, ent->mins);
1997 		VectorCopy (pm.maxs, ent->maxs);
1998 
1999 		client->resp.cmd_angles[0] = SHORT2ANGLE(ucmd->angles[0]);
2000 		client->resp.cmd_angles[1] = SHORT2ANGLE(ucmd->angles[1]);
2001 		client->resp.cmd_angles[2] = SHORT2ANGLE(ucmd->angles[2]);
2002 
2003 		if (ent->groundentity && !pm.groundentity && (pm.cmd.upmove >= 10) && (pm.waterlevel == 0))
2004 		{
2005 			gi.sound(ent, CHAN_VOICE, gi.soundindex("*jump1.wav"), 1, ATTN_NORM, 0);
2006 			PlayerNoise(ent, ent->s.origin, PNOISE_SELF);
2007 		}
2008 
2009 	//ROGUE sam raimi cam support
2010 		if(ent->flags & FL_SAM_RAIMI)
2011 			ent->viewheight = 8;
2012 		else
2013 			ent->viewheight = pm.viewheight;
2014 	//ROGUE
2015 
2016 		ent->waterlevel = pm.waterlevel;
2017 		ent->watertype = pm.watertype;
2018 		ent->groundentity = pm.groundentity;
2019 		if (pm.groundentity)
2020 			ent->groundentity_linkcount = pm.groundentity->linkcount;
2021 
2022 		if (ent->deadflag)
2023 		{
2024 			client->ps.viewangles[ROLL] = 40;
2025 			client->ps.viewangles[PITCH] = -15;
2026 			client->ps.viewangles[YAW] = client->killer_yaw;
2027 		}
2028 		else
2029 		{
2030 			VectorCopy (pm.viewangles, client->v_angle);
2031 			VectorCopy (pm.viewangles, client->ps.viewangles);
2032 		}
2033 
2034 		gi.linkentity (ent);
2035 
2036 	//PGM trigger_gravity support
2037 		ent->gravity = 1.0;
2038 	//PGM
2039 		if (ent->movetype != MOVETYPE_NOCLIP)
2040 			G_TouchTriggers (ent);
2041 
2042 		// touch other objects
2043 		for (i=0 ; i<pm.numtouch ; i++)
2044 		{
2045 			other = pm.touchents[i];
2046 			for (j=0 ; j<i ; j++)
2047 				if (pm.touchents[j] == other)
2048 					break;
2049 			if (j != i)
2050 				continue;	// duplicated
2051 			if (!other->touch)
2052 				continue;
2053 			other->touch (other, ent, NULL, NULL);
2054 		}
2055 	}
2056 
2057 	client->oldbuttons = client->buttons;
2058 	client->buttons = ucmd->buttons;
2059 	client->latched_buttons |= client->buttons & ~client->oldbuttons;
2060 
2061 	// save light level the player is standing on for
2062 	// monster sighting AI
2063 	ent->light_level = ucmd->lightlevel;
2064 
2065 	// fire weapon from final position if needed
2066 	if (client->latched_buttons & BUTTON_ATTACK)
2067 	{
2068 		if (client->resp.spectator)
2069 		{
2070 			client->latched_buttons = 0;
2071 
2072 			if (client->chase_target)
2073 			{
2074 				client->chase_target = NULL;
2075 				client->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION;
2076 			}
2077 			else
2078 				GetChaseTarget(ent);
2079 		}
2080 		else if (!client->weapon_thunk)
2081 		{
2082 			client->weapon_thunk = true;
2083 			Think_Weapon (ent);
2084 		}
2085 	}
2086 
2087 	if (client->resp.spectator)
2088 	{
2089 		if (ucmd->upmove >= 10)
2090 		{
2091 			if (!(client->ps.pmove.pm_flags & PMF_JUMP_HELD))
2092 			{
2093 				client->ps.pmove.pm_flags |= PMF_JUMP_HELD;
2094 				if (client->chase_target)
2095 					ChaseNext(ent);
2096 				else
2097 					GetChaseTarget(ent);
2098 			}
2099 		}
2100 		else
2101 			client->ps.pmove.pm_flags &= ~PMF_JUMP_HELD;
2102 	}
2103 
2104 	// update chase cam if being followed
2105 	for (i = 1; i <= maxclients->value; i++)
2106 	{
2107 		other = g_edicts + i;
2108 		if (other->inuse && other->client->chase_target == ent)
2109 			UpdateChaseCam(other);
2110 	}
2111 }
2112 
2113 
2114 /*
2115 ==============
2116 ClientBeginServerFrame
2117 
2118 This will be called once for each server frame, before running
2119 any other entities in the world.
2120 ==============
2121 */
ClientBeginServerFrame(edict_t * ent)2122 void ClientBeginServerFrame (edict_t *ent)
2123 {
2124 	gclient_t	*client;
2125 	int			buttonMask;
2126 
2127 	if (level.intermissiontime)
2128 		return;
2129 
2130 	client = ent->client;
2131 
2132 	if (deathmatch->value &&
2133 		client->pers.spectator != client->resp.spectator &&
2134 		(level.time - client->respawn_time) >= 5)
2135 	{
2136 		spectator_respawn(ent);
2137 		return;
2138 	}
2139 
2140 	// run weapon animations if it hasn't been done by a ucmd_t
2141 	if (!client->weapon_thunk && !client->resp.spectator)
2142 		Think_Weapon (ent);
2143 	else
2144 		client->weapon_thunk = false;
2145 
2146 	if (ent->deadflag)
2147 	{
2148 		// wait for any button just going down
2149 		if ( level.time > client->respawn_time)
2150 		{
2151 			// in deathmatch, only wait for attack button
2152 			if (deathmatch->value)
2153 				buttonMask = BUTTON_ATTACK;
2154 			else
2155 				buttonMask = -1;
2156 
2157 			if ( ( client->latched_buttons & buttonMask ) ||
2158 				(deathmatch->value && ((int)dmflags->value & DF_FORCE_RESPAWN) ) )
2159 			{
2160 				respawn(ent);
2161 				client->latched_buttons = 0;
2162 			}
2163 		}
2164 		return;
2165 	}
2166 
2167 	// add player trail so monsters can follow
2168 	if (!deathmatch->value)
2169 		if (!visible (ent, PlayerTrail_LastSpot() ) )
2170 			PlayerTrail_Add (ent->s.old_origin);
2171 
2172 	client->latched_buttons = 0;
2173 }
2174 
2175 /*
2176 ==============
2177 RemoveAttackingPainDaemons
2178 
2179 This is called to clean up the pain daemons that the disruptor attaches
2180 to clients to damage them.
2181 ==============
2182 */
RemoveAttackingPainDaemons(edict_t * self)2183 void RemoveAttackingPainDaemons (edict_t *self)
2184 {
2185 	edict_t *tracker;
2186 
2187 	tracker = G_Find (NULL, FOFS(classname), "pain daemon");
2188 	while(tracker)
2189 	{
2190 		if(tracker->enemy == self)
2191 			G_FreeEdict(tracker);
2192 		tracker = G_Find (tracker, FOFS(classname), "pain daemon");
2193 	}
2194 
2195 	if(self->client)
2196 		self->client->tracker_pain_framenum = 0;
2197 }
2198