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