1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 Copyright (C) 2011 COR Entertainment, LLC.
4 
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 
14 See the GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 
20 */
21 // cl_main.c  -- client main loop
22 
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 #include "client.h"
28 #if defined WIN32_VARIANT
29 #include <winsock.h>
30 #endif
31 
32 #if defined UNIX_VARIANT
33 #if defined HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36 #include <sys/socket.h>
37 #include <sys/time.h>
38 #include <netinet/in.h>
39 #include <netdb.h>
40 #include <sys/param.h>
41 #include <sys/ioctl.h>
42 #include <sys/uio.h>
43 #include <errno.h>
44 #endif
45 
46 #if defined HAVE_PUTENV && !defined HAVE__PUTENV
47 #define _putenv putenv
48 #endif
49 
50 
51 cvar_t	*freelook;
52 
53 cvar_t	*adr0;
54 cvar_t	*adr1;
55 cvar_t	*adr2;
56 cvar_t	*adr3;
57 cvar_t	*adr4;
58 cvar_t	*adr5;
59 cvar_t	*adr6;
60 cvar_t	*adr7;
61 cvar_t	*adr8;
62 
63 cvar_t	*cl_stereo_separation;
64 cvar_t	*cl_stereo;
65 
66 cvar_t	*rcon_client_password;
67 cvar_t	*rcon_address;
68 
69 cvar_t	*cl_noskins;
70 cvar_t	*cl_autoskins;
71 cvar_t	*cl_footsteps;
72 cvar_t	*cl_timeout;
73 cvar_t	*cl_predict;
74 cvar_t	*cl_maxfps;
75 cvar_t	*cl_gun;
76 cvar_t  *cl_brass;
77 cvar_t  *cl_showPlayerNames;
78 cvar_t	*cl_playtaunts;
79 cvar_t	*cl_centerprint;
80 cvar_t	*cl_precachecustom;
81 cvar_t	*cl_simpleitems;
82 cvar_t	*cl_flicker;
83 
84 cvar_t	*cl_paindist;
85 cvar_t	*cl_explosiondist;
86 cvar_t	*cl_raindist;
87 
88 cvar_t	*cl_add_particles;
89 cvar_t	*cl_add_lights;
90 cvar_t	*cl_add_entities;
91 cvar_t	*cl_add_blend;
92 
93 cvar_t	*cl_shownet;
94 cvar_t	*cl_showmiss;
95 cvar_t	*cl_showclamp;
96 
97 cvar_t	*cl_paused;
98 cvar_t	*cl_timedemo;
99 cvar_t	*cl_demoquit;
100 
101 cvar_t	*lookspring;
102 cvar_t	*lookstrafe;
103 cvar_t	*sensitivity;
104 cvar_t	*menu_sensitivity;
105 
106 cvar_t	*m_smoothing;
107 cvar_t	*m_pitch;
108 cvar_t	*m_yaw;
109 cvar_t	*m_forward;
110 cvar_t	*m_side;
111 
112 cvar_t	*cl_test;
113 
114 //
115 // userinfo
116 //
117 cvar_t	*info_password;
118 cvar_t	*info_spectator;
119 cvar_t  *info_spectator_password;
120 cvar_t	*name;
121 cvar_t  *stats_password;
122 cvar_t	*pw_hashed;
123 cvar_t	*skin;
124 cvar_t	*rate;
125 cvar_t	*fov;
126 cvar_t	*msg;
127 cvar_t	*hand;
128 cvar_t	*gender;
129 cvar_t	*gender_auto;
130 
131 cvar_t	*cl_vwep;
132 cvar_t	*cl_vehicle_huds;
133 
134 cvar_t  *background_music;
135 cvar_t	*background_music_vol;
136 
137 cvar_t	*scriptsloaded;
138 
139 //master server
140 cvar_t  *cl_master;
141 cvar_t  *cl_master2;
142 
143 //custom huds
144 cvar_t	*cl_hudimage1;
145 cvar_t	*cl_hudimage2;
146 
147 //health aura
148 cvar_t	*cl_healthaura;
149 
150 //blood
151 cvar_t  *cl_noblood;
152 
153 //beam color for disruptor
154 cvar_t  *cl_disbeamclr;
155 
156 cvar_t  *cl_dmlights;
157 
158 //Stats
159 cvar_t  *cl_stats_server;
160 
161 //latest version of the game available
162 cvar_t	*cl_latest_game_version_url;
163 
164 cvar_t	*cl_speedrecord;
165 cvar_t	*cl_alltimespeedrecord;
166 
167 client_static_t	cls;
168 client_state_t	cl;
169 
170 centity_t		cl_entities[MAX_EDICTS];
171 
172 entity_state_t	cl_parse_entities[MAX_PARSE_ENTITIES];
173 
174 extern	cvar_t *allow_download;
175 extern	cvar_t *allow_download_players;
176 extern	cvar_t *allow_download_models;
177 extern	cvar_t *allow_download_sounds;
178 extern	cvar_t *allow_download_maps;
179 
180 #if defined WIN32_VARIANT
181 extern	char map_music[MAX_PATH];
182 extern  char map_music_sec[MAX_PATH];
183 #else
184 extern	char map_music[MAX_OSPATH];
185 extern  char map_music_sec[MAX_OSPATH];
186 #endif
187 
188 extern void RS_FreeAllScripts(void);
189 
190 typedef struct _PLAYERINFO {
191 	char playername[PLAYERNAME_SIZE];
192 	int ping;
193 	int score;
194 } PLAYERINFO;
195 
196 typedef struct _SERVERINFO {
197 	char ip[32];
198 	unsigned short port;
199 	char szHostName[256];
200 	char szMapName[256];
201 	int curClients;
202 	int maxClients;
203 	int starttime;
204 	int	ping;
205 	PLAYERINFO players[64];
206 	int temporary;
207 } SERVERINFO;
208 
209 SERVERINFO servers[64];
210 static int numServers = 0;
211 
212 static size_t szr; // just for unused result warnings
213 
214 //
215 // Fonts
216 //
217 FNT_auto_t			CL_gameFont;
218 static struct FNT_auto_s	_CL_gameFont;
219 FNT_auto_t			CL_centerFont;
220 static struct FNT_auto_s	_CL_centerFont;
221 FNT_auto_t			CL_consoleFont;
222 static struct FNT_auto_s	_CL_consoleFont;
223 FNT_auto_t			CL_menuFont;
224 static struct FNT_auto_s	_CL_menuFont;
225 
226 
227 //======================================================================
228 
229 
230 /*
231 ====================
232 CL_WriteDemoMessage
233 
234 Dumps the current net message, prefixed by the length
235 ====================
236 */
CL_WriteDemoMessage(void)237 void CL_WriteDemoMessage (void)
238 {
239 	int		len, swlen;
240 
241 	// the first eight bytes are just packet sequencing stuff
242 	len = net_message.cursize-8;
243 	swlen = LittleLong(len);
244 	if (!swlen)
245 		return;
246 
247 	szr = fwrite (&swlen, 4, 1, cls.demofile);
248 	szr = fwrite (net_message.data+8,	len, 1, cls.demofile);
249 }
250 
251 
252 /*
253 ====================
254 CL_Stop_f
255 
256 stop recording a demo
257 ====================
258 */
CL_Stop_f(void)259 void CL_Stop_f (void)
260 {
261 	int		len;
262 
263 	if (!cls.demorecording)
264 	{
265 		Com_Printf ("Not recording a demo.\n");
266 		return;
267 	}
268 
269 // finish up
270 	len = -1;
271 	szr = fwrite (&len, 4, 1, cls.demofile);
272 	fclose (cls.demofile);
273 	cls.demofile = NULL;
274 	cls.demorecording = false;
275 	Com_Printf ("Stopped demo.\n");
276 }
277 
278 /*
279 ====================
280 CL_Record_f
281 
282 record <demoname>
283 
284 Begins recording a demo from the current position
285 ====================
286 */
CL_Record_f(void)287 void CL_Record_f (void)
288 {
289 	char	name[MAX_OSPATH];
290 	char	buf_data[MAX_MSGLEN];
291 	sizebuf_t	buf;
292 	int		i;
293 	int		len;
294 	entity_state_t	*ent;
295 	entity_state_t	nullstate;
296 
297 	if (Cmd_Argc() != 2)
298 	{
299 		Com_Printf ("record <demoname>\n");
300 		return;
301 	}
302 
303 	if (cls.demorecording)
304 	{
305 		Com_Printf ("Already recording.\n");
306 		return;
307 	}
308 
309 	if (cls.state != ca_active)
310 	{
311 		Com_Printf ("You must be in a level to record.\n");
312 		return;
313 	}
314 
315 	//
316 	// open the demo file
317 	//
318 	Com_sprintf (name, sizeof(name), "%s/demos/%s.dm2", FS_Gamedir(), Cmd_Argv(1));
319 
320 	Com_Printf ("recording to %s.\n", name);
321 	FS_CreatePath (name);
322 	cls.demofile = fopen (name, "wb");
323 	if (!cls.demofile)
324 	{
325 		Com_Printf ("ERROR: couldn't open.\n");
326 		return;
327 	}
328 	cls.demorecording = true;
329 
330 	// don't start saving messages until a non-delta compressed message is received
331 	cls.demowaiting = true;
332 
333 	//
334 	// write out messages to hold the startup information
335 	//
336 	SZ_Init (&buf, (byte *)buf_data, sizeof(buf_data));
337 	SZ_SetName ( &buf, "CL_Record_f", false );
338 
339 	// send the serverdata
340 	MSG_WriteByte (&buf, svc_serverdata);
341 	MSG_WriteLong (&buf, PROTOCOL_VERSION);
342 	MSG_WriteLong (&buf, 0x10000 + cl.servercount);
343 	MSG_WriteByte (&buf, 1);	// demos are always attract loops
344 	MSG_WriteString (&buf, cl.gamedir);
345 	MSG_WriteShort (&buf, cl.playernum);
346 
347 	MSG_WriteString (&buf, cl.configstrings[CS_NAME]);
348 
349 	// configstrings
350 	for (i=0 ; i<MAX_CONFIGSTRINGS ; i++)
351 	{
352 		if (cl.configstrings[i][0])
353 		{
354 			if (buf.cursize + strlen (cl.configstrings[i]) + 32 > buf.maxsize)
355 			{	// write it out
356 				len = LittleLong (buf.cursize);
357 				szr = fwrite (&len, 4, 1, cls.demofile);
358 				szr = fwrite (buf.data, buf.cursize, 1, cls.demofile);
359 				buf.cursize = 0;
360 			}
361 
362 			MSG_WriteByte (&buf, svc_configstring);
363 			MSG_WriteShort (&buf, i);
364 			MSG_WriteString (&buf, cl.configstrings[i]);
365 		}
366 
367 	}
368 
369 	// baselines
370 	memset (&nullstate, 0, sizeof(nullstate));
371 	for (i=0; i<MAX_EDICTS ; i++)
372 	{
373 		ent = &cl_entities[i].baseline;
374 		if (!ent->modelindex)
375 			continue;
376 
377 		if (buf.cursize + 64 > buf.maxsize)
378 		{	// write it out
379 			len = LittleLong (buf.cursize);
380 			szr = fwrite (&len, 4, 1, cls.demofile);
381 			szr = fwrite (buf.data, buf.cursize, 1, cls.demofile);
382 			buf.cursize = 0;
383 		}
384 
385 		MSG_WriteByte (&buf, svc_spawnbaseline);
386 		MSG_WriteDeltaEntity (&nullstate, &cl_entities[i].baseline, &buf, true, true);
387 	}
388 
389 	MSG_WriteByte (&buf, svc_stufftext);
390 	MSG_WriteString (&buf, "precache\n");
391 
392 	// write it to the demo file
393 
394 	len = LittleLong (buf.cursize);
395 	szr = fwrite (&len, 4, 1, cls.demofile);
396 	szr = fwrite (buf.data, buf.cursize, 1, cls.demofile);
397 
398 	// the rest of the demo file will be individual frames
399 }
400 
401 //======================================================================
402 
403 
404 
405 /*
406 ===================
407 Cmd_ForwardToServer
408 
409 adds the current command line as a clc_stringcmd to the client message.
410 things like godmode, noclip, etc, are commands directed to the server,
411 so when they are typed in at the console, they will need to be forwarded.
412 ===================
413 */
Cmd_ForwardToServer(void)414 void Cmd_ForwardToServer (void)
415 {
416 	char	*cmd;
417 
418 	cmd = Cmd_Argv(0);
419 	if (cls.state <= ca_connected || *cmd == '-' || *cmd == '+')
420 	{
421 		Com_Printf ("Unknown command \"%s\"\n", cmd);
422 		return;
423 	}
424 
425 	MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
426 	SZ_Print (&cls.netchan.message, cmd);
427 	if (Cmd_Argc() > 1)
428 	{
429 		SZ_Print (&cls.netchan.message, " ");
430 		SZ_Print (&cls.netchan.message, Cmd_Args());
431 	}
432 }
433 
CL_Setenv_f(void)434 void CL_Setenv_f( void )
435 {
436 	int argc = Cmd_Argc();
437 
438 	if ( argc > 2 )
439 	{
440 		char buffer[1000];
441 		int i;
442 
443 		strcpy( buffer, Cmd_Argv(1) );
444 		strcat( buffer, "=" );
445 
446 		for ( i = 2; i < argc; i++ )
447 		{
448 			strcat( buffer, Cmd_Argv( i ) );
449 			strcat( buffer, " " );
450 		}
451 
452 		_putenv( buffer );
453 	}
454 	else if ( argc == 2 )
455 	{
456 		char *env = getenv( Cmd_Argv(1) );
457 
458 		if ( env )
459 		{
460 			Com_Printf( "%s=%s\n", Cmd_Argv(1), env );
461 		}
462 		else
463 		{
464 			Com_Printf( "%s undefined\n", Cmd_Argv(1), env );
465 		}
466 	}
467 }
468 
469 
470 /*
471 ==================
472 CL_ForwardToServer_f
473 ==================
474 */
CL_ForwardToServer_f(void)475 void CL_ForwardToServer_f (void)
476 {
477 	if (cls.state != ca_connected && cls.state != ca_active)
478 	{
479 		Com_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0));
480 		return;
481 	}
482 
483 	// don't forward the first argument
484 	if (Cmd_Argc() > 1)
485 	{
486 		MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
487 		SZ_Print (&cls.netchan.message, Cmd_Args());
488 	}
489 }
490 
491 
492 /*
493 ==================
494 CL_Pause_f
495 ==================
496 */
CL_Pause_f(void)497 void CL_Pause_f (void)
498 {
499 	// never pause in multiplayer
500 	if (Cvar_VariableValue ("maxclients") > 1 || !Com_ServerState ())
501 	{
502 		Cvar_SetValue ("paused", 0);
503 		return;
504 	}
505 
506 	Cvar_SetValue ("paused", !cl_paused->integer);
507 }
508 
509 /*
510 ==================
511 CL_Quit_f
512 ==================
513 */
CL_Quit_f(void)514 void CL_Quit_f (void)
515 {
516 	S_StopAllSounds ();
517 	CL_Disconnect ();
518 	Com_Quit ();
519 }
520 
521 /*
522 ================
523 CL_Drop
524 
525 Called after an ERR_DROP was thrown
526 ================
527 */
CL_Drop(void)528 void CL_Drop (void)
529 {
530 	if (cls.state == ca_uninitialized)
531 		return;
532 	if (cls.state != ca_disconnected)
533 		CL_Disconnect ();
534 
535 	// drop loading plaque unless this is the initial game start
536 	if (cls.disable_servercount != -1)
537 		SCR_EndLoadingPlaque ();	// get rid of loading plaque
538 }
539 
540 
541 /*
542 =======================
543 CL_SendConnectPacket
544 
545 We have gotten a challenge from the server, so try and
546 connect.
547 ======================
548 */
CL_SendConnectPacket(void)549 void CL_SendConnectPacket (void)
550 {
551 	netadr_t	adr;
552 	int		port;
553 
554 	if (!NET_StringToAdr (cls.servername, &adr))
555 	{
556 		Com_Printf ("Bad server address\n");
557 		cls.connect_time = 0;
558 		return;
559 	}
560 	if (adr.port == 0)
561 		adr.port = BigShort (PORT_SERVER);
562 
563 	port = Cvar_VariableValue ("qport");
564 	userinfo_modified = false;
565 
566 	Netchan_OutOfBandPrint (NS_CLIENT, adr, "connect %i %i %i \"%s\"\n",
567 		PROTOCOL_VERSION, port, cls.challenge, Cvar_Userinfo() );
568 }
569 
570 /*
571 =================
572 CL_CheckForResend
573 
574 Resend a connect message if the last one has timed out
575 =================
576 */
CL_CheckForResend(void)577 void CL_CheckForResend (void)
578 {
579 	netadr_t	adr;
580 
581 	// if the local server is running and we aren't
582 	// then connect
583 	if (cls.state == ca_disconnected && Com_ServerState() )
584 	{
585 		cls.state = ca_connecting;
586 		strncpy (cls.servername, "localhost", sizeof(cls.servername)-1);
587 		// we don't need a challenge on the localhost
588 		CL_SendConnectPacket ();
589 		return;
590 //		cls.connect_time = -99999;	// CL_CheckForResend() will fire immediately
591 	}
592 
593 	// resend if we haven't gotten a reply yet
594 	if (cls.state != ca_connecting)
595 		return;
596 
597 	if (cls.realtime - cls.connect_time < 3000)
598 		return;
599 
600 	if (!NET_StringToAdr (cls.servername, &adr))
601 	{
602 		Com_Printf ("Bad server address\n");
603 		cls.state = ca_disconnected;
604 		return;
605 	}
606 	if (adr.port == 0)
607 		adr.port = BigShort (PORT_SERVER);
608 
609 	cls.connect_time = cls.realtime;	// for retransmit requests
610 
611 	Com_Printf ("Connecting to %s...\n", cls.servername);
612 
613 	Netchan_OutOfBandPrint (NS_CLIENT, adr, "getchallenge\n");
614 }
615 
616 
617 /*
618 ================
619 CL_Connect_f
620 
621 ================
622 */
CL_Connect_f(void)623 void CL_Connect_f (void)
624 {
625 	char	*server;
626 
627 	if (Cmd_Argc() != 2)
628 	{
629 		Com_Printf ("usage: connect <server>\n");
630 		return;
631 	}
632 
633 	if (Com_ServerState ())
634 	{	// if running a local server, kill it and reissue
635 		SV_Shutdown (va("Server quit\n", msg), false);
636 	}
637 	else
638 	{
639 		CL_Disconnect ();
640 	}
641 
642 	server = Cmd_Argv (1);
643 
644 	NET_Config (true);		// allow remote
645 
646 	CL_Disconnect ();
647 
648 	cls.state = ca_connecting;
649 	strncpy (cls.servername, server, sizeof(cls.servername)-1);
650 	cls.connect_time = -99999;	// CL_CheckForResend() will fire immediately
651 
652 	STATS_RequestVerification();
653 }
654 
655 
656 /*
657 =====================
658 CL_Rcon_f
659 
660   Send the rest of the command line over as
661   an unconnected command.
662 =====================
663 */
CL_Rcon_f(void)664 void CL_Rcon_f (void)
665 {
666 	char		message[1024];
667 	sizebuf_t	buffer;
668 	int		i;
669 	netadr_t	to;
670 
671 	if ( !(rcon_client_password->string && rcon_client_password->string[0]) && Cmd_Argc() < 3)
672 	{
673 		Com_Printf ("You must set 'rcon_password' before issuing an rcon command.\n");
674 		return;
675 	}
676 
677 	NET_Config (true);		// allow remote
678 
679 	SZ_Init( &buffer, (byte *) message, 1024 );
680 	buffer.allowoverflow = true;
681 	SZ_SetName( &buffer, "RCon buffer", false );
682 
683 	SZ_Print (&buffer, "\xff\xff\xff\xffrcon ");
684 	if ( rcon_client_password->string && rcon_client_password->string[0] )
685 	{
686 		SZ_Print (&buffer, "\"");
687 		SZ_Print (&buffer, rcon_client_password->string);
688 		SZ_Print (&buffer, "\" ");
689 	}
690 
691 	for (i=1 ; i<Cmd_Argc() ; i++)
692 	{
693 		SZ_Print (&buffer, "\"");
694 		SZ_Print (&buffer, Cmd_Argv(i));
695 		SZ_Print (&buffer, "\" ");
696 	}
697 
698 	if ( buffer.overflowed )
699 	{
700 		Com_Printf ("Rcon command too long\n");
701 		return;
702 	}
703 
704 	if (cls.state >= ca_connected)
705 		to = cls.netchan.remote_address;
706 	else
707 	{
708 		if (!strlen(rcon_address->string))
709 		{
710 			Com_Printf ("You must either be connected, or set the 'rcon_address' cvar to issue rcon commands\n");
711 
712 			return;
713 		}
714 		NET_StringToAdr (rcon_address->string, &to);
715 		if (to.port == 0)
716 			to.port = BigShort (PORT_SERVER);
717 	}
718 
719 	NET_SendPacket (NS_CLIENT, strlen(message)+1, message, to);
720 }
721 
722 
723 /*
724 =====================
725 CL_ClearState
726 
727 =====================
728 */
CL_ClearState(void)729 void CL_ClearState (void)
730 {
731 	S_StopAllSounds ();
732 	CL_ClearEffects ();
733 	CL_ClearTEnts ();
734 
735 // wipe the entire cl structure
736 	memset (&cl, 0, sizeof(cl));
737 	memset (cl_entities, 0, sizeof(cl_entities));
738 
739 	SZ_Clear (&cls.netchan.message);
740 
741 }
742 
743 /*
744 =====================
745 CL_Disconnect
746 
747 Goes from a connected state to full screen console state
748 Sends a disconnect message to the server
749 This is also called on Com_Error, so it shouldn't cause any errors
750 =====================
751 */
CL_Disconnect(void)752 void CL_Disconnect (void)
753 {
754 	byte	final[32];
755 	int repeat;
756 
757 	if (cls.state == ca_disconnected)
758 		return;
759 
760 	if (cl_timedemo && cl_timedemo->integer)
761 	{
762 		int	time;
763 
764 		time = Sys_Milliseconds () - cl.timedemo_start;
765 		if (time > 0)
766 			Com_Printf ("%i frames, %3.1f seconds: %3.1f fps\n", cl.timedemo_frames,
767 			time/1000.0, cl.timedemo_frames*1000.0 / time);
768 		cl.timedemo_start = 0;
769 	}
770 
771 	VectorClear (cl.refdef.blend);
772 	R_SetPalette(NULL);
773 
774 	M_ForceMenuOff ();
775 
776 	cls.connect_time = 0;
777 
778 	if (cls.demorecording)
779 		CL_Stop_f ();
780 
781 	// send a disconnect message to the server
782 	final[0] = clc_stringcmd;
783 	strcpy ((char *)final+1, "disconnect");
784 	for ( repeat = 3 ; repeat-- ;)
785 		Netchan_Transmit( &cls.netchan, (int)strlen( (char*)final ), final );
786 
787 	CL_ClearState ();
788 
789 	// stop download
790 	if(cls.download){
791 		if(cls.downloadhttp)  // clean up http downloads
792 			CL_HttpDownloadCleanup();
793 		else  // or just stop legacy ones
794 			fclose(cls.download);
795 		cls.download = NULL;
796 	}
797 
798 	cls.state = ca_disconnected;
799 
800 	if 		(cl_demoquit && cl_demoquit->integer &&
801 			cl_timedemo && cl_timedemo->integer) {
802 		CL_Quit_f();
803 	}
804 }
805 
CL_Disconnect_f(void)806 void CL_Disconnect_f (void)
807 {
808 	Com_Error (ERR_DROP, "Disconnected from server");
809 }
810 
811 
812 /*
813 =================
814 CL_Changing_f
815 
816 Just sent as a hint to the client that they should
817 drop to full console
818 =================
819 */
CL_Changing_f(void)820 void CL_Changing_f (void)
821 {
822 	//ZOID
823 	//if we are downloading, we don't change!  This so we don't suddenly stop downloading a map
824 	if (cls.download)
825 		return;
826 
827 	SCR_BeginLoadingPlaque ();
828 	cls.state = ca_connected;	// not active anymore, but not disconnected
829 	Com_Printf ("\nChanging map...\n");
830 }
831 
832 
833 /*
834 =================
835 CL_Reconnect_f
836 
837 The server is changing levels
838 =================
839 */
CL_Reconnect_f(void)840 void CL_Reconnect_f (void)
841 {
842 	//ZOID
843 	//if we are downloading, we don't change!  This so we don't suddenly stop downloading a map
844 	if (cls.download)
845 		return;
846 
847 	S_StopAllSounds ();
848 	if (cls.state == ca_connected) {
849 		Com_Printf ("reconnecting...\n");
850 		cls.state = ca_connected;
851 		MSG_WriteChar (&cls.netchan.message, clc_stringcmd);
852 		MSG_WriteString (&cls.netchan.message, "new");
853 		return;
854 	}
855 
856 	if (*cls.servername) {
857 		if (cls.state >= ca_connected) {
858 			CL_Disconnect();
859 			cls.connect_time = cls.realtime - 1500;
860 		} else
861 			cls.connect_time = -99999; // fire immediately
862 
863 		cls.state = ca_connecting;
864 		Com_Printf ("reconnecting...\n");
865 	}
866 }
867 
868 /*
869 =================
870 CL_ParseStatusMessage
871 
872 Handle a reply from a status request
873 =================
874 */
CL_ParseFullStatusMessage(void)875 void CL_ParseFullStatusMessage (void)
876 {
877 	char	*s;
878 
879 	s = MSG_ReadString(&net_message);
880 
881 	Com_Printf ("TESTING!!!!%s\n", s);
882 	M_AddToServerList (net_from, s);
883 }
884 
885 /*
886 ===================
887 GetServerList
888 
889 Get a list of servers from the master
890 ===================
891 */
GetServerList(void)892 static void GetServerList (void)
893 {
894 	char *requeststring;
895 	netadr_t adr;
896 
897 	// this function may block => sound channels might not be updated
898 	// while it does so => prevent 'looping sound effect' while waiting
899 	// -JR / 20050731 / 2
900 	S_StopAllSounds ();
901 
902 	requeststring = va( "query" );
903 
904 	// send a broadcast packet
905 	Com_Printf( "querying %s...\n", cl_master->string );
906 
907 	if( NET_StringToAdr( cl_master->string, &adr ) ) {
908 		if( !adr.port )
909 			adr.port = BigShort( PORT_MASTER );
910 		Netchan_OutOfBandPrint( NS_CLIENT, adr, requeststring );
911 	}
912 	else
913 	{
914 		Com_Printf( "Bad address: %s\n", cl_master->string);
915 	}
916 
917 	// Query secondary server
918 	Com_Printf( "querying %s...\n", cl_master2->string );
919 	if ( NET_StringToAdr( cl_master2->string, &adr ) ) {
920 		if ( !adr.port )
921 			adr.port = BigShort( PORT_MASTER );
922 		Netchan_OutOfBandPrint( NS_CLIENT, adr, requeststring );
923 	}
924 	else
925 	{
926 		Com_Printf( "Bad address: %s\n", cl_master2->string);
927 	}
928 
929 	// Tactical mode to do:  Query third server - tactical servers will only reside on this server
930 
931 	// Reset server list for incoming responses.
932 	numServers = 0;
933 }
934 /*
935 =================
936 CL_ParseGetServersResponse
937 
938 Handle a reply from getservers message to master server
939 =================
940 */
CL_ParseGetServersResponse()941 static void CL_ParseGetServersResponse()
942 {
943 	cvar_t		*noudp;
944 	cvar_t		*noipx;
945 	netadr_t	adr;
946 	char		adrString[32];
947 	byte		addr[4];
948 	byte		port[2];
949 	int			idx;
950 	unsigned short	uport;
951 	qboolean	dupe;
952 
953 	MSG_BeginReading (&net_message);
954 	MSG_ReadLong (&net_message);	// skip the -1
955 
956 	noudp = Cvar_Get ("noudp", "0", CVAR_NOSET);
957 	if (!noudp->integer)
958 	{
959 		adr.type = NA_BROADCAST;
960 	}
961 	noipx = Cvar_Get ("noipx", "0", CVAR_NOSET);
962 	if (!noipx->integer)
963 	{
964 		adr.type = NA_BROADCAST_IPX;
965 	}
966 
967 	if ( net_message.readcount + 8 < net_message.cursize )
968 		net_message.readcount += 8;
969 
970 	while( net_message.readcount +6 <= net_message.cursize )
971 	{
972 		if (numServers == 64)
973 			break;		// No room left.
974 
975 		MSG_ReadData( &net_message, addr, 4 );
976 		Com_sprintf( adrString, sizeof( adrString ), "%u.%u.%u.%u",
977 				addr[0], addr[1], addr[2], addr[3]);
978 		MSG_ReadData( &net_message, port, 2 ); /* network byte order (bigendian) */
979 		/* convert to unsigned short in host byte order */
980 		uport = (unsigned short) ((port[0] << 8) + port[1]);
981 
982 		dupe = false;
983 		// Check that we don't have a duplicate entry.
984 		for (idx = 0; idx < numServers; idx++) {
985 			if (	!strcmp(servers[idx].ip, adrString) &&
986 					servers[idx].port == uport) {
987 				Com_Printf("Already have: %s:%u\n", adrString,
988 						uport);
989 				dupe = true;
990 				break;
991 			}
992 		}
993 		if (dupe)
994 			continue;
995 
996 		memcpy( &servers[numServers].ip, adrString, sizeof(servers[numServers].ip) );
997 		servers[numServers].port = uport;
998 
999 		if (!NET_StringToAdr (servers[numServers].ip, &adr))
1000 		{
1001 			Com_Printf ("Bad address: %s\n", servers[numServers].ip);
1002 			continue;
1003 		}
1004 
1005 		Com_Printf ("pinging %s:%hu...\n",
1006 				servers[numServers].ip, servers[numServers].port );
1007 
1008 		/* adr.port is in network byte order (bigendian) */
1009 		adr.port = (unsigned short)BigShort( servers[numServers].port );
1010 		if (!adr.port) {
1011 			adr.port = BigShort(PORT_SERVER);
1012 		}
1013 		Netchan_OutOfBandPrint (NS_CLIENT, adr, va("status %i", PROTOCOL_VERSION));
1014 		servers[numServers].starttime = Sys_Milliseconds();
1015 
1016 		++numServers;
1017 	}
1018 }
1019 
1020 /*
1021 =================
1022 CL_GetPingStartTime
1023 
1024 Return ping starttime for server given its address.  Returns 0 if not found.
1025 =================
1026 */
CL_GetPingStartTime(netadr_t adr)1027 int CL_GetPingStartTime(netadr_t adr)
1028 {
1029 	int		idx;
1030 	char		adrString[32];
1031 	unsigned short	port;
1032 
1033 	Com_sprintf(adrString, sizeof(adrString), "%u.%u.%u.%u",
1034 			adr.ip[0], adr.ip[1], adr.ip[2], adr.ip[3]);
1035 	port = (unsigned short) BigShort(adr.port);
1036 	for (idx = 0; idx < numServers; idx++) {
1037 		if (! strcmp(adrString, servers[idx].ip) &&
1038 				port == servers[idx].port) {
1039 			return servers[idx].starttime;
1040 		}
1041 	}
1042 	return 0;
1043 }
1044 
1045 /*
1046 =================
1047 CL_PingServers_f
1048 =================
1049 */
1050 static void CL_ReadPackets ();
CL_PingServers_f(void)1051 void CL_PingServers_f (void)
1052 {
1053 
1054 	int			i;
1055 	netadr_t	adr;
1056 	char		name[32];
1057 	char		*adrstring;
1058 	cvar_t		*noudp;
1059 	cvar_t		*noipx;
1060 
1061 	NET_Config (true);		// allow remote
1062 
1063 	GetServerList();		//get list from COR master server
1064 
1065 	// send a broadcast packet
1066 	Com_Printf ("pinging broadcast...\n");
1067 
1068 	noudp = Cvar_Get ("noudp", "0", CVAR_NOSET);
1069 	if (!noudp->integer)
1070 	{
1071 		adr.type = NA_BROADCAST;
1072 		adr.port = BigShort(PORT_SERVER);
1073 		Netchan_OutOfBandPrint (NS_CLIENT, adr, va("status %i", PROTOCOL_VERSION));
1074 
1075 	}
1076 	noipx = Cvar_Get ("noipx", "0", CVAR_NOSET);
1077 	if (!noipx->integer)
1078 	{
1079 		adr.type = NA_BROADCAST_IPX;
1080 		adr.port = BigShort(PORT_SERVER);
1081 		Netchan_OutOfBandPrint (NS_CLIENT, adr, va("status %i", PROTOCOL_VERSION));
1082 	}
1083 
1084 	// send a packet to each address book entry
1085 	for (i=0 ; i<16 ; i++)
1086 	{
1087 		Com_sprintf (name, sizeof(name), "adr%i", i);
1088 		adrstring = Cvar_VariableString (name);
1089 		if (!adrstring || !adrstring[0])
1090 			continue;
1091 
1092 		Com_Printf ("pinging %s...\n", adrstring);
1093 		if (!NET_StringToAdr (adrstring, &adr))
1094 		{
1095 			Com_Printf ("Bad address: %s\n", adrstring);
1096 			continue;
1097 		}
1098 		if (!adr.port)
1099 			adr.port = BigShort(PORT_SERVER);
1100 
1101 		Netchan_OutOfBandPrint (NS_CLIENT, adr, va("status %i", PROTOCOL_VERSION));
1102 
1103 	}
1104 
1105 	// Note that all we have done thus far is
1106 	// - Request server lists from the two master servers
1107 	// - Sent a broadcast to the LAN looking for local servers
1108 	// When CL_ReadPackets gets the responses from the master server, it will
1109 	// automatically ping all the game servers. Ideally, if the net connection
1110 	// is pretty good, we can get that all done in the following loop. The
1111 	// game's main loop will catch any stragglers.
1112 
1113 	// Read packets at 5 ms intervals 60 times. That's 300 ms. Figure maybe
1114 	// 100-150 ms round trip to the master server, then another 100-150 ms
1115 	// round trip to the game servers. So we should be able to grab any
1116 	// servers 150 ping or less and gauge their pings to within 5 ms or so.
1117 #define PING_LOOP_TOTAL_MS		300
1118 #define PING_LOOP_INTERVAL_MS	5
1119 #define PING_LOOP_ITERATIONS	(PING_LOOP_TOTAL_MS/PING_LOOP_INTERVAL_MS)
1120 	for (i = 0; i < PING_LOOP_ITERATIONS; i++)
1121 	{
1122 		#if defined UNIX_VARIANT
1123 			usleep (PING_LOOP_INTERVAL_MS*1000);
1124 		#elif defined WIN32_VARIANT
1125 			Sleep (PING_LOOP_INTERVAL_MS);
1126 		#else
1127 			#warning	client/cl_main.c: CL_PingServers_f (): \
1128 						Do not know what sleep function to use!
1129 			break;
1130 		#endif
1131 		CL_ReadPackets ();
1132 	}
1133 
1134 	// -JD restart the menu music that was stopped during this procedure
1135 	S_StartMenuMusic();
1136 }
1137 
1138 
1139 /*
1140 =================
1141 CL_Skins_f
1142 
1143 Load or download any custom player skins and models
1144 =================
1145 */
CL_Skins_f(void)1146 void CL_Skins_f (void)
1147 {
1148 	int		i;
1149 
1150 	for (i=0 ; i<MAX_CLIENTS ; i++)
1151 	{
1152 		if (!cl.configstrings[CS_PLAYERSKINS+i][0])
1153 			continue;
1154 		Com_Printf ("client %i: %s\n", i, cl.configstrings[CS_PLAYERSKINS+i]);
1155 		SCR_UpdateScreen ();
1156 		Sys_SendKeyEvents ();	// pump message loop
1157 		CL_ParseClientinfo (i);
1158 	}
1159 }
1160 
1161 
1162 /*
1163 =================
1164 CL_ConnectionlessPacket
1165 
1166 Responses to broadcasts, etc
1167 =================
1168 */
CL_ConnectionlessPacket(void)1169 static void CL_ConnectionlessPacket (void)
1170 {
1171 	char	*s;
1172 	char	*c;
1173 
1174 	MSG_BeginReading (&net_message);
1175 	MSG_ReadLong (&net_message);	// skip the -1
1176 
1177 	s = MSG_ReadStringLine (&net_message);
1178 
1179 	Cmd_TokenizeString (s, false);
1180 
1181 	c = Cmd_Argv(0);
1182 
1183 	Com_Printf ("%s: %s\n", NET_AdrToString (net_from), c);
1184 
1185 	if(!strncmp(c, "servers", 7))
1186 	{
1187 		CL_ParseGetServersResponse();
1188 		return;
1189 	}
1190 
1191 	if(!strncmp(c, "vstring", 7))
1192 	{
1193 		s = Cmd_Argv(1);
1194 		switch(currLoginState.requestType)
1195 		{
1196 			case STATSLOGIN:
1197 
1198 				STATS_AuthenticateStats(s);
1199 				break;
1200 			case STATSPWCHANGE:
1201 				STATS_ChangePassword(s);
1202 				break;
1203 		}
1204 		return;
1205 	}
1206 
1207 	if(!strncmp(c, "validated", 9))
1208 	{
1209 		//in cases of changed passwords
1210 		if(currLoginState.requestType == STATSPWCHANGE)
1211 		{
1212 			//make sure the password is stored for future use
1213 			Q_strncpyz2(currLoginState.old_password, stats_password->string, sizeof(currLoginState.old_password));
1214 
1215 			Com_Printf("Password change successful!\n");
1216 		}
1217 		else
1218 		{
1219 			Com_Printf("Account validated!\n");
1220 			currLoginState.validated = true;
1221 		}
1222 		return;
1223 	}
1224 
1225 	// server connection
1226 	if (!strcmp(c, "client_connect"))
1227 	{
1228 		if (cls.state == ca_connected)
1229 		{
1230 			Com_Printf ("Dup connect received.  Ignored.\n");
1231 			return;
1232 		}
1233 		Netchan_Setup (NS_CLIENT, &cls.netchan, net_from, cls.quakePort);
1234 		MSG_WriteChar (&cls.netchan.message, clc_stringcmd);
1235 		MSG_WriteString (&cls.netchan.message, "new");
1236 		cls.state = ca_connected;
1237 
1238 		memset(cls.downloadurl, 0, sizeof(cls.downloadurl));
1239 		if(Cmd_Argc() == 2)  // http download url
1240 		{
1241 			strncpy(cls.downloadurl, Cmd_Argv(1), sizeof(cls.downloadurl) - 1);
1242 		}
1243 		is_localhost = !strcmp(cls.servername, "localhost");
1244 		Netchan_OutOfBandPrint (NS_CLIENT, net_from, va("status %i", PROTOCOL_VERSION));
1245 		return;
1246 	}
1247 
1248 	// remote command from gui front end
1249 	if (!strcmp(c, "cmd"))
1250 	{
1251 		if (!NET_IsLocalAddress(net_from))
1252 		{
1253 			Com_Printf ("Command packet from remote host.  Ignored.\n");
1254 			return;
1255 		}
1256 		Sys_AppActivate ();
1257 		s = MSG_ReadString (&net_message);
1258 		Cbuf_AddText (s);
1259 		Cbuf_AddText ("\n");
1260 		return;
1261 	}
1262 
1263 	// print command from somewhere
1264 	if (!strcmp(c, "print"))
1265 	{
1266 		s = MSG_ReadString (&net_message);
1267 		if (s[0] == '\\')
1268 		{
1269 			char *playerinfo_start;
1270 			if (cls.state >= ca_connected &&
1271 				!memcmp(&net_from, &cls.netchan.remote_address, sizeof(netadr_t)))
1272 				M_UpdateConnectedServerInfo (net_from, s);
1273 			if (cls.key_dest == key_menu)
1274 			{
1275 				M_AddToServerList (net_from, s); //add net_from so we have the addy
1276 			}
1277 			else
1278 			{
1279 				// If someone called pingservers () directly from the console,
1280 				// chances are he wants to read the server list manually
1281 				// anyway.
1282 				playerinfo_start = strchr (s, '\n');
1283 				*playerinfo_start++ = '\0';
1284 				Info_Print (s);
1285 				Com_Printf ("%s", playerinfo_start);
1286 			}
1287 		}
1288 		else
1289 			Com_Printf ("%s", s);
1290 		return;
1291 	}
1292 
1293 	// ping from somewhere
1294 	if (!strcmp(c, "ping"))
1295 	{
1296 		Netchan_OutOfBandPrint (NS_CLIENT, net_from, "ack");
1297 		return;
1298 	}
1299 
1300 	// challenge from the server we are connecting to
1301 	if (!strcmp(c, "challenge"))
1302 	{
1303 		cls.challenge = atoi(Cmd_Argv(1));
1304 		CL_SendConnectPacket ();
1305 		return;
1306 	}
1307 
1308 	// echo request from server
1309 	if (!strcmp(c, "echo"))
1310 	{
1311 		Netchan_OutOfBandPrint (NS_CLIENT, net_from, "%s", Cmd_Argv(1) );
1312 		return;
1313 	}
1314 
1315 	if (!strcmp(c, "teamgame"))
1316 	{
1317 		server_is_team = atoi (Cmd_Argv(1));
1318 		return;
1319 	}
1320 
1321 	Com_Printf ("Unknown command.\n");
1322 }
1323 
1324 
1325 /*
1326 =================
1327 CL_DumpPackets
1328 
1329 A vain attempt to help bad TCP stacks that cause problems
1330 when they overflow
1331 =================
1332 */
CL_DumpPackets(void)1333 void CL_DumpPackets (void)
1334 {
1335 	while (NET_GetPacket (NS_CLIENT, &net_from, &net_message))
1336 	{
1337 		Com_Printf ("dumping a packet\n");
1338 	}
1339 }
1340 
1341 /*
1342 =================
1343 CL_ReadPackets
1344 =================
1345 */
1346 int c_incoming_bytes = 0;
CL_ReadPackets(void)1347 static void CL_ReadPackets (void)
1348 {
1349 	while (NET_GetPacket (NS_CLIENT, &net_from, &net_message))
1350 	{
1351 		c_incoming_bytes += net_message.cursize;
1352 
1353 		//
1354 		// remote command packet
1355 		//
1356 		if (*(int *)net_message.data == -1)
1357 		{
1358 			CL_ConnectionlessPacket ();
1359 			continue;
1360 		}
1361 
1362 		if (cls.state == ca_disconnected || cls.state == ca_connecting)
1363 			continue;		// dump it if not connected
1364 
1365 		if (net_message.cursize < 8)
1366 		{
1367 			Com_Printf ("%s: Runt packet\n",NET_AdrToString(net_from));
1368 			continue;
1369 		}
1370 
1371 		//
1372 		// packet from server
1373 		//
1374 		if (!NET_CompareAdr (net_from, cls.netchan.remote_address))
1375 		{
1376 			Com_DPrintf ("%s:sequenced packet without connection\n"
1377 				,NET_AdrToString(net_from));
1378 			continue;
1379 		}
1380 		if (!Netchan_Process(&cls.netchan, &net_message))
1381 			continue;		// wasn't accepted for some reason
1382 		CL_ParseServerMessage ();
1383 	}
1384 
1385 	//
1386 	// check timeout
1387 	//
1388 	if (cls.state >= ca_connected
1389 	 && cls.realtime - cls.netchan.last_received > cl_timeout->value*1000)
1390 	{
1391 		if (++cl.timeoutcount > 5)	// timeoutcount saves debugger
1392 		{
1393 			Com_Printf ("\nServer connection timed out.\n");
1394 			CL_Disconnect ();
1395 			return;
1396 		}
1397 	}
1398 	else
1399 		cl.timeoutcount = 0;
1400 
1401 }
1402 
1403 
1404 //=============================================================================
1405 
1406 /*
1407 ==============
1408 CL_FixUpGender_f
1409 ==============
1410 */
CL_FixUpGender(void)1411 void CL_FixUpGender(void)
1412 {
1413 	char *p;
1414 	char sk[80];
1415 
1416 	if (gender_auto->integer)
1417 	{
1418 		if (gender->modified)
1419 		{
1420 			// was set directly, don't override the user
1421 			gender->modified = false;
1422 			return;
1423 		}
1424 
1425 		strncpy(sk, skin->string, sizeof(sk) - 2);
1426 		sk[sizeof(sk) - 1] = '\0'; // in case skin->string is 79 chars or more
1427 		if ((p = strchr(sk, '/')) != NULL)
1428 			*p = 0;
1429 		if (Q_strcasecmp(sk, "male") == 0 || Q_strcasecmp(sk, "cyborg") == 0)
1430 			Cvar_Set ("gender", "male");
1431 		else if (Q_strcasecmp(sk, "female") == 0 || Q_strcasecmp(sk, "crackhor") == 0)
1432 			Cvar_Set ("gender", "female");
1433 		else
1434 			Cvar_Set ("gender", "none");
1435 		gender->modified = false;
1436 	}
1437 }
1438 
1439 /*
1440 ==============
1441 CL_Userinfo_f
1442 ==============
1443 */
CL_Userinfo_f(void)1444 void CL_Userinfo_f (void)
1445 {
1446 	Com_Printf ("User info settings:\n");
1447 	Info_Print (Cvar_Userinfo());
1448 }
1449 
1450 /*
1451 =================
1452 CL_Snd_Restart_f
1453 
1454 Restart the sound subsystem so it can pick up
1455 new parameters and flush all sounds
1456 =================
1457 */
CL_Snd_Restart_f(void)1458 void CL_Snd_Restart_f (void)
1459 {
1460 	S_Shutdown ();
1461 	S_Init ();
1462 	CL_RegisterSounds ();
1463 }
1464 
1465 int precache_check; // for autodownload of precache items
1466 int precache_spawncount;
1467 int precache_tex;
1468 int precache_model_skin;
1469 
1470 byte *precache_model; // used for skin checking in alias models
1471 
1472 #define PLAYER_MULT 5
1473 
1474 // ENV_CNT is map load, ENV_CNT+1 is first env map
1475 #define ENV_CNT (CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT)
1476 #define TEXTURE_CNT (ENV_CNT+13)
1477 #define SCRIPT_CNT (TEXTURE_CNT+999)
1478 
1479 static const char *env_suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
1480 
CL_RequestNextDownload(void)1481 void CL_RequestNextDownload (void)
1482 {
1483 	unsigned	map_checksum;		// for detecting cheater maps
1484 	char fn[MAX_OSPATH];
1485 	char map[MAX_OSPATH];
1486 	char script[MAX_OSPATH];
1487 	dmdl_t *pheader;
1488 	int i, j;
1489 
1490 	if (cls.state != ca_connected)
1491 		return;
1492 
1493 	if (!allow_download->integer && precache_check < ENV_CNT)
1494 		precache_check = ENV_CNT;
1495 
1496 	if (precache_check == CS_MODELS) // confirm map
1497 	{
1498 		precache_check = CS_MODELS+2; // 0 isn't used
1499 		if (allow_download_maps->integer)
1500 			if (!CL_CheckOrDownloadFile(cl.configstrings[CS_MODELS+1]))
1501 				return; // started a download
1502 	}
1503 
1504 redoSkins:
1505 	if (precache_check >= CS_MODELS && precache_check < CS_MODELS+MAX_MODELS)
1506 	{
1507 		if (allow_download_models->integer)
1508 		{
1509 			while (precache_check < CS_MODELS+MAX_MODELS &&
1510 				cl.configstrings[precache_check][0])
1511 			{
1512 				if (cl.configstrings[precache_check][0] == '*' ||
1513 					cl.configstrings[precache_check][0] == '#')
1514 				{
1515 					precache_check++;
1516 					continue;
1517 				}
1518 				//do not download player models from this section
1519 				else if (cl.configstrings[precache_check][0] == 'p' &&
1520 					cl.configstrings[precache_check][1] == 'l' &&
1521 					cl.configstrings[precache_check][2] == 'a' &&
1522 					cl.configstrings[precache_check][3] == 'y' &&
1523 					cl.configstrings[precache_check][4] == 'e' &&
1524 					cl.configstrings[precache_check][5] == 'r' &&
1525 					cl.configstrings[precache_check][6] == 's')
1526 				{
1527 					precache_check++;
1528 					continue;
1529 				}
1530 				if (precache_model_skin == 0)
1531 				{
1532 					if (!CL_CheckOrDownloadFile(cl.configstrings[precache_check]))
1533 					{
1534 						precache_model_skin = 1;
1535 						return; // started a download
1536 					}
1537 					precache_model_skin = 1;
1538 				}
1539 
1540 				// checking for skins in the model
1541 				if (!precache_model)
1542 				{
1543 					FS_LoadFile (cl.configstrings[precache_check], (void **)&precache_model);
1544 					if (!precache_model)
1545 					{
1546 						precache_model_skin = 0;
1547 						precache_check++;
1548 						continue; // couldn't load it
1549 					}
1550 					if (LittleLong(*(unsigned *)precache_model) != IDALIASHEADER)
1551 					{
1552 						// not an alias model
1553 						FS_FreeFile(precache_model);
1554 						precache_model = 0;
1555 						precache_model_skin = 0;
1556 						precache_check++;
1557 						continue;
1558 					}
1559 					pheader = (dmdl_t *)precache_model;
1560 					if (LittleLong (pheader->version) != ALIAS_VERSION)
1561 					{
1562 						precache_check++;
1563 						precache_model_skin = 0;
1564 						continue; // couldn't load it
1565 					}
1566 				}
1567 
1568 				pheader = (dmdl_t *)precache_model;
1569 
1570 				while (precache_model_skin - 1 < LittleLong(pheader->num_skins))
1571 				{
1572 					if (!CL_CheckOrDownloadFile((char *)precache_model +
1573 						LittleLong(pheader->ofs_skins) +
1574 						(precache_model_skin - 1)*MAX_SKINNAME))
1575 					{
1576 						precache_model_skin++;
1577 						return; // started a download
1578 					}
1579 					precache_model_skin++;
1580 				}
1581 				if (precache_model)
1582 				{
1583 					FS_FreeFile(precache_model);
1584 					precache_model = 0;
1585 				}
1586 				precache_model_skin = 0;
1587 				precache_check++;
1588 			}
1589 		}
1590 		if (precache_model)
1591 		{
1592 			precache_check = CS_MODELS + 2;
1593 			precache_model_skin = 0;
1594 
1595 			goto redoSkins;
1596 		}
1597 		precache_check = CS_SOUNDS;
1598 	}
1599 
1600 	if (precache_check >= CS_SOUNDS && precache_check < CS_SOUNDS+MAX_SOUNDS)
1601 	{
1602 		if (allow_download_sounds->integer)
1603 		{
1604 			if (precache_check == CS_SOUNDS)
1605 				precache_check++; // zero is blank
1606 			while (precache_check < CS_SOUNDS+MAX_SOUNDS &&
1607 				cl.configstrings[precache_check][0])
1608 			{
1609 				if (cl.configstrings[precache_check][0] == '*')
1610 				{
1611 					precache_check++;
1612 					continue;
1613 				}
1614 				Com_sprintf(fn, sizeof(fn), "sound/%s", cl.configstrings[precache_check++]);
1615 				if (!CL_CheckOrDownloadFile(fn))
1616 					return; // started a download
1617 			}
1618 		}
1619 		precache_check = CS_IMAGES;
1620 	}
1621 	if (precache_check >= CS_IMAGES && precache_check < CS_IMAGES+MAX_IMAGES)
1622 	{
1623 		if (precache_check == CS_IMAGES)
1624 			precache_check++; // zero is blank
1625 		while (precache_check < CS_IMAGES+MAX_IMAGES &&
1626 			cl.configstrings[precache_check][0])
1627 		{
1628 			Com_sprintf(fn, sizeof(fn), "pics/%s.tga", cl.configstrings[precache_check++]);
1629 			if (!CL_CheckOrDownloadFile(fn))
1630 				return; // started a download
1631 		}
1632 		precache_check = CS_PLAYERSKINS;
1633 	}
1634 	if (precache_check >= CS_PLAYERSKINS && precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT)
1635 	{
1636 		if (allow_download_players->integer)
1637 		{
1638 			while (precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT)
1639 			{
1640 				int i, n;
1641 				char model[MAX_QPATH], skin[MAX_QPATH], *p;
1642 
1643 				i = (precache_check - CS_PLAYERSKINS)/PLAYER_MULT;
1644 				n = (precache_check - CS_PLAYERSKINS)%PLAYER_MULT;
1645 
1646 				if (!cl.configstrings[CS_PLAYERSKINS+i][0])
1647 				{
1648 					precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT;
1649 					continue;
1650 				}
1651 
1652 				if ((p = strchr(cl.configstrings[CS_PLAYERSKINS+i], '\\')) != NULL)
1653 					p++;
1654 				else
1655 					p = cl.configstrings[CS_PLAYERSKINS+i];
1656 				strcpy(model, p);
1657 				p = strchr(model, '/');
1658 				if (!p)
1659 					p = strchr(model, '\\');
1660 				if (p)
1661 				{
1662 					*p++ = 0;
1663 					strcpy(skin, p);
1664 				} else
1665 					*skin = 0;
1666 
1667 				switch (n)
1668 				{
1669 					case 0: // model
1670 						Com_sprintf(fn, sizeof(fn), "players/%s/tris.iqm", model);
1671 						if (!CL_CheckOrDownloadFile(fn))
1672 						{
1673 							precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 1;
1674 							return; // started a download
1675 						}
1676 						n++;
1677 						/*FALL THROUGH*/
1678 
1679 					case 1: // weapon model
1680 						Com_sprintf(fn, sizeof(fn), "players/%s/weapon.iqm", model);
1681 						if (!CL_CheckOrDownloadFile(fn)) {
1682 							precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 2;
1683 							return; // started a download
1684 						}
1685 						n++;
1686 						/*FALL THROUGH*/
1687 
1688 					case 2: // weapon skin
1689 						Com_sprintf(fn, sizeof(fn), "players/%s/weapon.jpg", model);
1690 						if (!CL_CheckOrDownloadFile(fn))
1691 						{
1692 							precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 3;
1693 							return; // started a download
1694 						}
1695 						n++;
1696 						/*FALL THROUGH*/
1697 
1698 					case 3: // skin
1699 						Com_sprintf(fn, sizeof(fn), "players/%s/%s.jpg", model, skin);
1700 						if (!CL_CheckOrDownloadFile(fn))
1701 						{
1702 							precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 4;
1703 							return; // started a download
1704 						}
1705 						n++;
1706 						/*FALL THROUGH*/
1707 
1708 					case 4: // skin_i
1709 						Com_sprintf(fn, sizeof(fn), "players/%s/%s_i.jpg", model, skin);
1710 						if (!CL_CheckOrDownloadFile(fn))
1711 						{
1712 							precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 5;
1713 							return; // started a download
1714 						}
1715 						// move on to next model
1716 						precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT;
1717 				}
1718 			}
1719 		}
1720 		// precache phase completed
1721 		precache_check = ENV_CNT;
1722 	}
1723 
1724 	if (precache_check == ENV_CNT)
1725 	{
1726 		precache_check = ENV_CNT + 1;
1727 
1728 		//FIXME: support for new map specification files
1729 		CM_LoadBSP (cl.configstrings[CS_MODELS+1], true, &map_checksum);
1730 
1731 		if (map_checksum != atoi(cl.configstrings[CS_MAPCHECKSUM]))
1732 		{
1733 			Com_Error (ERR_DROP, "Local map version differs from server: %i != '%s'\n",
1734 				map_checksum, cl.configstrings[CS_MAPCHECKSUM]);
1735 			return;
1736 		}
1737 	}
1738 
1739 	if (precache_check > ENV_CNT && precache_check < TEXTURE_CNT)
1740 	{
1741 			if (allow_download->integer && allow_download_maps->integer)
1742 			{
1743 				while (precache_check < TEXTURE_CNT)
1744 				{
1745 					int n = precache_check++ - ENV_CNT - 1;
1746 
1747 					Com_sprintf(fn, sizeof(fn), "env/%s%s.tga",
1748 							cl.configstrings[CS_SKY], env_suf[n/2]);
1749 					if (!CL_CheckOrDownloadFile(fn))
1750 						return; // started a download
1751 				}
1752 			}
1753 			precache_check = TEXTURE_CNT;
1754 	}
1755 	if (precache_check == TEXTURE_CNT)
1756 	{
1757 		precache_check = TEXTURE_CNT+1;
1758 		precache_tex = 0;
1759 	}
1760 
1761 	// confirm existance of textures, download any that don't exist
1762 	if (precache_check == TEXTURE_CNT+1)
1763 	{
1764 		// from qcommon/cmodel.c
1765 		extern int			numtexinfo;
1766 		extern mapsurface_t	map_surfaces[];
1767 
1768 		if (allow_download->integer && allow_download_maps->integer)
1769 		{
1770 			while (precache_tex < numtexinfo)
1771 			{
1772 				char fn[MAX_OSPATH];
1773 
1774 				sprintf(fn, "textures/%s.tga", map_surfaces[precache_tex++].rname);
1775 				if (!CL_CheckOrDownloadFile(fn))
1776 					return; // started a download
1777 			}
1778 		}
1779 		precache_check = SCRIPT_CNT;
1780 	}
1781 
1782 	//get map related scripts
1783 	if (precache_check == SCRIPT_CNT)
1784 	{
1785 		precache_check = SCRIPT_CNT+1;
1786 		if (allow_download_maps->integer)
1787 		{
1788 			//get fog files
1789 			COM_StripExtension ( cl.configstrings[CS_MODELS+1], fn );
1790 
1791 			//remove "maps/" from string
1792 			for(i = 5, j = 0; i < strlen(fn); i++, j++)
1793 			{
1794 				map[j] = fn[i];
1795 			}
1796 			map[i-5] = 0;
1797 
1798 			Com_sprintf(script, sizeof(script), "maps/scripts/%s.fog", map);
1799 			if (!CL_CheckOrDownloadFile(script))
1800 				return; // started a download
1801 		}
1802 	}
1803 
1804 	if (precache_check == SCRIPT_CNT+1)
1805 	{
1806 		precache_check = SCRIPT_CNT+2;
1807 		if (allow_download_maps->integer)
1808 		{
1809 			//get mus files
1810 			COM_StripExtension ( cl.configstrings[CS_MODELS+1], fn );
1811 
1812 			//remove "maps/" from string
1813 			for(i = 5, j = 0; i < strlen(fn); i++, j++)
1814 				map[j] = fn[i];
1815 			map[i-5] = 0;
1816 
1817 			Com_sprintf(script, sizeof(script), "maps/scripts/%s.mus", map);
1818 			if (!CL_CheckOrDownloadFile(script))
1819 				return; // started a download
1820 		}
1821 	}
1822 
1823 	if (precache_check == SCRIPT_CNT+2)
1824 	{
1825 		precache_check = SCRIPT_CNT+3;
1826 		if (allow_download_maps->integer)
1827 		{
1828 			//get rscript files
1829 			COM_StripExtension ( cl.configstrings[CS_MODELS+1], fn );
1830 
1831 			//remove "maps/" from string
1832 			for(i = 5, j = 0; i < strlen(fn); i++, j++)
1833 				map[j] = fn[i];
1834 			map[i-5] = 0;
1835 
1836 			Com_sprintf(script, sizeof(script), "scripts/maps/%s.rscript", map);
1837 			if (!CL_CheckOrDownloadFile(script))
1838 				return; // started a download
1839 		}
1840 	}
1841 
1842 	if (precache_check == SCRIPT_CNT+3) // try downloading lightmap
1843 	{
1844 		precache_check = SCRIPT_CNT+4;
1845 		if (allow_download_maps->integer)
1846 		{
1847 			char *extension;
1848 			strncpy (fn, cl.configstrings[CS_MODELS+1], MAX_OSPATH-1-strlen(".lightmap")+strlen(".bsp"));
1849 			extension = strstr (fn, ".bsp");
1850 			if (extension)
1851 				*extension = 0;
1852 			strcat (fn, ".lightmap");
1853 			if (!CL_CheckOrDownloadFile(fn))
1854 				return; // started a download
1855 		}
1856 	}
1857 
1858 //ZOID
1859 	CL_RegisterSounds ();
1860 	CL_PrepRefresh ();
1861 
1862 	MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
1863 	MSG_WriteString (&cls.netchan.message, va("begin %i\n", precache_spawncount) );
1864 
1865 	{
1866 		netadr_t	adr;
1867 
1868 		if (!NET_StringToAdr (cls.servername, &adr))
1869 		{
1870 			Com_Printf ("Bad address: %s\n",  cls.servername);
1871 			return;
1872 		}
1873 
1874 		// default true to avoid messing up legacy ctf servers
1875 		// legacy DM servers don't send visibility lights anyway
1876 		server_is_team = true;
1877 		Netchan_OutOfBandPrint (NS_CLIENT, adr, "teamgame\n");
1878 	}
1879 }
1880 
1881 
CL_GetRemoteServer(void)1882 netadr_t *CL_GetRemoteServer (void) {
1883 	static netadr_t remoteserver;
1884 	if (cls.state >= ca_connected) {
1885 		remoteserver = cls.netchan.remote_address;
1886 		return &remoteserver;
1887 	}
1888 	return NULL;
1889 }
1890 
1891 
1892 /*
1893 =================
1894 CL_Precache_f
1895 
1896 The server will send this command right
1897 before allowing the client into the server
1898 =================
1899 */
CL_Precache_f(void)1900 void CL_Precache_f (void)
1901 {
1902 	//Yet another hack to let old demos work
1903 	//the old precache sequence
1904 	if (Cmd_Argc() < 2)
1905 	{
1906 		unsigned	map_checksum;		// for detecting cheater maps
1907 
1908 		//FIXME: support for new map specification files
1909 		CM_LoadBSP (cl.configstrings[CS_MODELS+1], true, &map_checksum);
1910 		CL_RegisterSounds ();
1911 		CL_PrepRefresh ();
1912 		return;
1913 	}
1914 
1915 	precache_check = CS_MODELS;
1916 	precache_spawncount = atoi(Cmd_Argv(1));
1917 	precache_model = 0;
1918 	precache_model_skin = 0;
1919 
1920 	CL_RequestNextDownload();
1921 }
1922 
1923 /*
1924 =================
1925 CL_InitLocal
1926 =================
1927 */
CL_InitLocal(void)1928 void CL_InitLocal (void)
1929 {
1930 	cls.state = ca_disconnected;
1931 	cls.realtime = Sys_Milliseconds ();
1932 
1933 	CL_InitInput ();
1934 
1935 	CL_InitHttpDownload();
1936 
1937 	CL_IRCSetup( );
1938 
1939 	adr0 = Cvar_Get( "adr0", "", CVAR_ARCHIVE );
1940 	adr1 = Cvar_Get( "adr1", "", CVAR_ARCHIVE );
1941 	adr2 = Cvar_Get( "adr2", "", CVAR_ARCHIVE );
1942 	adr3 = Cvar_Get( "adr3", "", CVAR_ARCHIVE );
1943 	adr4 = Cvar_Get( "adr4", "", CVAR_ARCHIVE );
1944 	adr5 = Cvar_Get( "adr5", "", CVAR_ARCHIVE );
1945 	adr6 = Cvar_Get( "adr6", "", CVAR_ARCHIVE );
1946 	adr7 = Cvar_Get( "adr7", "", CVAR_ARCHIVE );
1947 	adr8 = Cvar_Get( "adr8", "", CVAR_ARCHIVE );
1948 
1949 //
1950 // register our variables
1951 //
1952 	cl_stereo_separation = Cvar_Get( "cl_stereo_separation", "0.4", CVAR_ARCHIVE | CVARDOC_FLOAT );
1953 	cl_stereo = Cvar_Get( "cl_stereo", "0", CVARDOC_BOOL );
1954 	background_music = Cvar_Get("background_music", "1", CVAR_ARCHIVE | CVARDOC_BOOL);
1955 	background_music_vol = Cvar_Get("background_music_vol", "0.5", CVAR_ARCHIVE | CVARDOC_FLOAT);
1956 
1957 	cl_add_blend = Cvar_Get ("cl_blend", "1", CVAR_ARCHIVE | CVARDOC_BOOL);
1958 	cl_add_lights = Cvar_Get ("cl_lights", "1", CVARDOC_BOOL);
1959 	cl_add_particles = Cvar_Get ("cl_particles", "1", CVARDOC_BOOL);
1960 	cl_add_entities = Cvar_Get ("cl_entities", "1", CVARDOC_BOOL);
1961 	cl_gun = Cvar_Get ("cl_gun", "1", CVAR_ARCHIVE | CVARDOC_BOOL);
1962 	cl_footsteps = Cvar_Get ("cl_footsteps", "1", CVARDOC_BOOL);
1963 	cl_noskins = Cvar_Get ("cl_noskins", "0", CVAR_ARCHIVE | CVARDOC_BOOL);
1964 	cl_autoskins = Cvar_Get ("cl_autoskins", "0", CVARDOC_BOOL);
1965 	cl_predict = Cvar_Get ("cl_predict", "1", CVARDOC_BOOL);
1966 	cl_maxfps = Cvar_Get ("cl_maxfps", "60", CVAR_ARCHIVE | CVARDOC_INT);
1967 	cl_showPlayerNames = Cvar_Get ("cl_showplayernames", "0", CVAR_ARCHIVE | CVARDOC_INT);
1968 	Cvar_Describe (cl_showPlayerNames, "0 means no nametags, 1 means show one nametag in the center of the screen, 2 means show a nametag over each player.");
1969 	cl_healthaura = Cvar_Get ("cl_healthaura", "1", CVAR_ARCHIVE | CVARDOC_BOOL);
1970 	Cvar_Describe (cl_healthaura, "show glowing effects around health pickups.");
1971 	cl_noblood = Cvar_Get ("cl_noblood", "0", CVAR_ARCHIVE | CVARDOC_BOOL);
1972 	cl_disbeamclr = Cvar_Get("cl_disbeamclr", "0", CVAR_ARCHIVE | CVARDOC_INT);
1973 	Cvar_Describe (cl_disbeamclr, "beam color for the disruptor weapon. 0 = green, 1 = blue, 2 = red, 3 = yellow, 4 = purple.");
1974 	cl_brass = Cvar_Get ("cl_brass", "1", CVAR_ARCHIVE | CVARDOC_BOOL);
1975 	cl_dmlights = Cvar_Get("cl_dmlights", "1", CVAR_ARCHIVE | CVARDOC_BOOL);
1976 	cl_playtaunts = Cvar_Get ("cl_playtaunts", "1", CVAR_ARCHIVE | CVARDOC_BOOL);
1977 	cl_centerprint = Cvar_Get ("cl_centerprint", "1", CVAR_ARCHIVE | CVARDOC_BOOL);
1978 	cl_precachecustom = Cvar_Get ("cl_precachecustom", "0", CVAR_ARCHIVE | CVARDOC_BOOL);
1979 	Cvar_Describe (cl_precachecustom, "precache 3rd-party and custom player skins at the first map load.");
1980 	cl_simpleitems = Cvar_Get ("cl_simpleitems", "0", CVAR_ARCHIVE | CVARDOC_BOOL);
1981 	Cvar_Describe (cl_simpleitems, "show sprites instead of models for pickup items.");
1982 	cl_flicker = Cvar_Get ("cl_flicker", "1", CVAR_ARCHIVE | CVARDOC_BOOL);
1983 	Cvar_Describe (cl_flicker, "enable flickering world lighting.");
1984 
1985 	cl_paindist = Cvar_Get ("cl_paindist", "1", CVAR_ARCHIVE);
1986 	cl_explosiondist = Cvar_Get ("cl_explosiondist", "1", CVAR_ARCHIVE);
1987 	cl_raindist = Cvar_Get ("cl_raindist", "1", CVAR_ARCHIVE);
1988 
1989 	cl_upspeed = Cvar_Get ("cl_upspeed", "200", 0);
1990 	cl_forwardspeed = Cvar_Get ("cl_forwardspeed", "200", 0);
1991 	cl_sidespeed = Cvar_Get ("cl_sidespeed", "200", 0);
1992 	cl_yawspeed = Cvar_Get ("cl_yawspeed", "140", 0);
1993 	cl_pitchspeed = Cvar_Get ("cl_pitchspeed", "150", 0);
1994 	cl_anglespeedkey = Cvar_Get ("cl_anglespeedkey", "1.5", 0);
1995 
1996 	cl_run = Cvar_Get ("cl_run", "0", CVAR_ARCHIVE | CVARDOC_BOOL);
1997 	freelook = Cvar_Get( "freelook", "0", CVAR_ARCHIVE | CVARDOC_BOOL);
1998 	lookspring = Cvar_Get ("lookspring", "0", CVAR_ARCHIVE | CVARDOC_BOOL);
1999 	lookstrafe = Cvar_Get ("lookstrafe", "0", CVAR_ARCHIVE | CVARDOC_BOOL);
2000 	m_accel	= Cvar_Get ("m_accel", "1",	CVAR_ARCHIVE | CVARDOC_BOOL);
2001 	sensitivity = Cvar_Get ("sensitivity", "3", CVAR_ARCHIVE | CVARDOC_FLOAT);
2002 	menu_sensitivity = Cvar_Get("menu_sensitivity", "3", CVAR_ARCHIVE | CVARDOC_FLOAT);
2003 
2004 	m_smoothing = Cvar_Get("m_smoothing", "0", CVAR_ARCHIVE | CVARDOC_BOOL);
2005 	m_pitch = Cvar_Get ("m_pitch", "0.022", CVAR_ARCHIVE | CVARDOC_FLOAT);
2006 	m_yaw = Cvar_Get ("m_yaw", "0.022", CVAR_ARCHIVE | CVARDOC_FLOAT);
2007 	m_forward = Cvar_Get ("m_forward", "1", 0);
2008 	m_side = Cvar_Get ("m_side", "1", 0);
2009 
2010 	cl_shownet = Cvar_Get ("cl_shownet", "0", 0);
2011 	cl_showmiss = Cvar_Get ("cl_showmiss", "0", 0);
2012 	cl_showclamp = Cvar_Get ("showclamp", "0", 0);
2013 	cl_timeout = Cvar_Get ("cl_timeout", "120", 0);
2014 	cl_paused = Cvar_Get ("paused", "0", 0);
2015 	cl_timedemo = Cvar_Get ("timedemo", "0", CVARDOC_BOOL);
2016 	Cvar_Describe (cl_timedemo, "play back demos (recorded games) in benchmark mode.");
2017 	cl_demoquit = Cvar_Get ("demoquit", "0", CVARDOC_BOOL);
2018 	Cvar_Describe (cl_demoquit, "quit automatically after a demo has finished.");
2019 
2020 	cl_speedrecord = Cvar_Get ("cl_speedrecord", "450", CVARDOC_INT);
2021 	cl_alltimespeedrecord = Cvar_Get ("cl_alltimespeedrecord", "450", CVAR_ARCHIVE | CVARDOC_INT);
2022 
2023 	rcon_client_password = Cvar_Get ("rcon_password", "", CVARDOC_STR);
2024 	rcon_address = Cvar_Get ("rcon_address", "", CVARDOC_STR);
2025 
2026 	cl_test = Cvar_Get ("cl_test", "0", CVAR_ARCHIVE);
2027 
2028 	//
2029 	// userinfo
2030 	//
2031 	info_password = Cvar_Get ("password", "", CVAR_USERINFO | CVARDOC_STR);
2032 	info_spectator = Cvar_Get ("spectator", "0", CVAR_USERINFO | CVARDOC_BOOL);
2033 	info_spectator_password = Cvar_Get ( "spectator_password", "", CVAR_USERINFO | CVARDOC_STR);
2034 	name = Cvar_Get ("name", "unnamed", CVAR_USERINFO | CVAR_ARCHIVE | CVARDOC_STR);
2035 	stats_password = Cvar_Get("stats_password", "password", CVAR_PROFILE | CVARDOC_STR);
2036 	Q_strncpyz2(currLoginState.old_password, stats_password->string, sizeof(currLoginState.old_password));
2037 	currLoginState.hashed = false;
2038 	pw_hashed = Cvar_Get("stats_pw_hashed", "0", CVAR_PROFILE | CVARDOC_BOOL);
2039 	/* */
2040 	ValidatePlayerName( name->string, (strlen(name->string)+1) );
2041 	/* */
2042 	skin = Cvar_Get ("skin", "male/grunt", CVAR_USERINFO | CVAR_ARCHIVE | CVARDOC_STR);
2043 	rate = Cvar_Get ("rate", "25000", CVAR_USERINFO | CVAR_ARCHIVE | CVARDOC_INT);	// FIXME
2044 	msg = Cvar_Get ("msg", "1", CVAR_USERINFO | CVAR_ARCHIVE);
2045 	hand = Cvar_Get ("hand", "0", CVAR_USERINFO | CVAR_ARCHIVE);
2046 	fov = Cvar_Get ("fov", "90", CVAR_USERINFO | CVAR_ARCHIVE | CVARDOC_INT);
2047 	Cvar_Describe (fov, "horizontal field of view (in degrees.) Maximum 160.");
2048 	gender = Cvar_Get ("gender", "male", CVAR_USERINFO | CVAR_ARCHIVE | CVARDOC_STR);
2049 	gender_auto = Cvar_Get ("gender_auto", "1", CVAR_ARCHIVE);
2050 	gender->modified = false; // clear this so we know when user sets it manually
2051 
2052 	cl_vwep = Cvar_Get ("cl_vwep", "1", CVAR_ARCHIVE | CVARDOC_BOOL);
2053 	cl_vehicle_huds = Cvar_Get ("cl_vehicle_huds", "1", CVAR_ARCHIVE | CVARDOC_BOOL);
2054 
2055 	cl_master = Cvar_Get ("cl_master", "master.corservers.com", CVAR_ARCHIVE | CVARDOC_STR);
2056 	cl_master2 = Cvar_Get ("cl_master2", "master2.corservers.com", CVAR_ARCHIVE | CVARDOC_STR);
2057 
2058 	//custom huds
2059 	cl_hudimage1 = Cvar_Get("cl_hudimage1", "pics/i_health.tga", CVAR_ARCHIVE | CVARDOC_STR);
2060 	cl_hudimage2 = Cvar_Get("cl_hudimage2", "pics/i_score.tga", CVAR_ARCHIVE | CVARDOC_STR);
2061 
2062 	//stats server
2063 	cl_stats_server = Cvar_Get("cl_stats_server", "http://stats.planetarena.org", CVAR_ARCHIVE | CVARDOC_STR);
2064 
2065 	//update checker
2066 	cl_latest_game_version_url = Cvar_Get("cl_latest_game_version_server", "http://red.planetarena.org/version/crx_version", CVAR_ARCHIVE | CVARDOC_STR);
2067 
2068 	//throwaway cvars
2069 	Cvar_Get("g_dm_lights", "1", CVAR_ARCHIVE | CVAR_GAMEINFO | CVARDOC_BOOL); //mark this as archived even if game code doesn't run.
2070 
2071 	//
2072 	// register our commands
2073 	//
2074 	Cmd_AddCommand ("cmd", CL_ForwardToServer_f);
2075 	Cmd_AddCommand ("pause", CL_Pause_f);
2076 	Cmd_AddCommand ("pingservers", CL_PingServers_f);
2077 	Cmd_AddCommand ("skins", CL_Skins_f);
2078 
2079 	Cmd_AddCommand ("userinfo", CL_Userinfo_f);
2080 	Cmd_AddCommand ("snd_restart", CL_Snd_Restart_f);
2081 
2082 	Cmd_AddCommand ("changing", CL_Changing_f);
2083 	Cmd_AddCommand ("disconnect", CL_Disconnect_f);
2084 	Cmd_AddCommand ("record", CL_Record_f);
2085 	Cmd_AddCommand ("stop", CL_Stop_f);
2086 
2087 	Cmd_AddCommand ("quit", CL_Quit_f);
2088 
2089 	Cmd_AddCommand ("connect", CL_Connect_f);
2090 	Cmd_AddCommand ("reconnect", CL_Reconnect_f);
2091 
2092 	Cmd_AddCommand ("rcon", CL_Rcon_f);
2093 
2094 	Cmd_AddCommand ("setenv", CL_Setenv_f );
2095 
2096 	Cmd_AddCommand ("precache", CL_Precache_f);
2097 
2098 	Cmd_AddCommand ("download", CL_Download_f);
2099 
2100 	Cmd_AddCommand ("irc_connect", CL_InitIRC);
2101 	Cmd_AddCommand ("irc_quit", CL_IRCInitiateShutdown);
2102 	Cmd_AddCommand ("irc_say", CL_IRCSay);
2103 
2104 	//
2105 	// forward to server commands
2106 	//
2107 	// the only thing this does is allow command completion
2108 	// to work -- all unknown commands are automatically
2109 	// forwarded to the server. It also prevents the commands
2110 	// from being ignored if they are issued in 'forced' mode.
2111 	Cmd_AddCommand ("wave", NULL);
2112 	Cmd_AddCommand ("inven", NULL);
2113 	Cmd_AddCommand ("kill", NULL);
2114 	Cmd_AddCommand ("use", NULL);
2115 	Cmd_AddCommand ("drop", NULL);
2116 	Cmd_AddCommand ("say", NULL);
2117 	Cmd_AddCommand ("say_team", NULL);
2118 	Cmd_AddCommand ("info", NULL);
2119 	Cmd_AddCommand ("prog", NULL);
2120 	Cmd_AddCommand ("give", NULL);
2121 	Cmd_AddCommand ("god", NULL);
2122 	Cmd_AddCommand ("notarget", NULL);
2123 	Cmd_AddCommand ("noclip", NULL);
2124 	Cmd_AddCommand ("invuse", NULL);
2125 	Cmd_AddCommand ("invprevw", NULL);
2126 	Cmd_AddCommand ("invnextw", NULL);
2127 	Cmd_AddCommand ("invprevp", NULL);
2128 	Cmd_AddCommand ("invnextp", NULL);
2129 	Cmd_AddCommand ("invprev", NULL);
2130 	Cmd_AddCommand ("invnext", NULL);
2131 	Cmd_AddCommand ("invdrop", NULL);
2132 	Cmd_AddCommand ("weapnext", NULL);
2133 	Cmd_AddCommand ("weapprev", NULL);
2134 	Cmd_AddCommand ("weaplast", NULL);
2135 	Cmd_AddCommand ("chatbubble", NULL);
2136 	Cmd_AddCommand ("players", NULL);
2137 	Cmd_AddCommand ("score", NULL);
2138 	Cmd_AddCommand ("vote", NULL);
2139 	Cmd_AddCommand ("putaway", NULL);
2140 	Cmd_AddCommand ("playerlist", NULL);
2141 
2142 	Cvar_SetValue("scriptsloaded", 0);
2143 
2144 	strcpy(map_music, "music/none.wav");
2145 
2146 	//register all our menu gfx
2147 	(void)R_RegisterPic("m_main");
2148 	(void)R_RegisterPic("m_options");
2149 	(void)R_RegisterPic("menu_back");
2150 	(void)R_RegisterPic("m_video");
2151 	(void)R_RegisterPic("m_controls");
2152 	(void)R_RegisterPic("m_player");
2153 	(void)R_RegisterPic("m_bots");
2154 	(void)R_RegisterPic("m_startserver");
2155 	(void)R_RegisterPic("m_dmoptions");
2156 	(void)R_RegisterPic("m_mutators");
2157 	(void)R_RegisterPic("m_single");
2158 	(void)R_RegisterPic("m_quit");
2159 	(void)R_RegisterPic("m_main_mont0");
2160 	(void)R_RegisterPic("m_main_mont1");
2161 	(void)R_RegisterPic("m_main_mont2");
2162 	(void)R_RegisterPic("m_main_mont3");
2163 	(void)R_RegisterPic("m_main_mont4");
2164 	(void)R_RegisterPic("m_main_mont5");
2165 	(void)R_RegisterPic("hud_bomber");
2166 	(void)R_RegisterPic("hud_strafer");
2167 	(void)R_RegisterPic("hud_hover");
2168 	(void)R_RegisterPic("blood_ring");
2169 
2170 	remoteserver_runspeed = 300; //default
2171 }
2172 
2173 
2174 
2175 /*
2176 ===============
2177 CL_WriteConfiguration
2178 
2179 Writes key bindings and archived cvars to config.cfg
2180 ===============
2181 */
CL_WriteConfiguration(void)2182 void CL_WriteConfiguration (void)
2183 {
2184 	FILE	*f;
2185 	char	path[MAX_OSPATH];
2186 
2187 	if (cls.state == ca_uninitialized)
2188 		return;
2189 
2190 	FS_FullWritePath( path, sizeof(path), "config.cfg");
2191 	f = fopen (path, "w");
2192 	if (!f)
2193 	{
2194 		Com_Printf ("Couldn't write config.cfg.\n");
2195 		return;
2196 	}
2197 
2198 	fprintf (f, "// generated by Alien Arena. Use autoexec.cfg for custom settings.\n");
2199 	Key_WriteBindings (f);
2200 	fclose (f);
2201 
2202 	Cvar_WriteVariables (path);
2203 }
2204 
2205 /*
2206 ===============
2207 CL_WriteProfile
2208 
2209 Writes profile information to profile.cfg
2210 ===============
2211 */
CL_WriteProfile(void)2212 void CL_WriteProfile (void)
2213 {
2214 	FILE	*f;
2215 	char	path[MAX_OSPATH];
2216 
2217 	if (cls.state == ca_uninitialized)
2218 		return;
2219 
2220 	if(!currLoginState.hashed)
2221 		return; //We don't ever want to write out non-hashed passwords, period!
2222 
2223 	FS_FullWritePath( path, sizeof(path), "profile.cfg");
2224 	f = fopen (path, "w");
2225 	if (!f)
2226 	{
2227 		Com_Printf ("Couldn't write profile.cfg.\n");
2228 		return;
2229 	}
2230 
2231 	fprintf (f, "// generated by Alien Arena.\n");
2232 	fprintf (f, "set stats_password %s\n", stats_password->string);
2233 	fprintf (f, "set stats_pw_hashed %i\n", pw_hashed->integer);
2234 	fclose (f);
2235 }
2236 
2237 
2238 
2239 /*
2240 ==================
2241 CL_FixCvarCheats
2242 
2243 ==================
2244 */
2245 
2246 typedef struct
2247 {
2248 	char	*name;
2249 	char	*value;
2250 	cvar_t	*var;
2251 } cheatvar_t;
2252 
2253 cheatvar_t cheatvars[] =
2254 {
2255 	{"timescale",     "1", NULL},
2256 	{"timedemo",      "0", NULL},
2257 	{"r_drawworld",   "1", NULL},
2258 	{"cl_testlights", "0", NULL},
2259 	{"r_fullbright",  "0", NULL},
2260 	{"r_drawflat",    "0", NULL},
2261 	{"paused",        "0", NULL},
2262 	{"fixedtime",     "0", NULL},
2263 	{"gl_lightmap",   "0", NULL},
2264 	{"gl_showpolys",  "0", NULL},
2265 	{NULL, NULL, NULL}
2266 };
2267 
CL_FixCvarCheats(void)2268 void CL_FixCvarCheats (void)
2269 {
2270 	static int numcheatvars = 0;
2271 	int			i;
2272 	cheatvar_t	*var;
2273 
2274 	if ( !strcmp(cl.configstrings[CS_MAXCLIENTS], "1")
2275 		|| !cl.configstrings[CS_MAXCLIENTS][0]
2276 		|| cl.attractloop )
2277 		return;		// single player or demo playback can cheat
2278 
2279 	// find all the cvars if we haven't done it yet
2280 	if (!numcheatvars)
2281 	{
2282 		while (cheatvars[numcheatvars].name)
2283 		{
2284 			cheatvars[numcheatvars].var = Cvar_Get (cheatvars[numcheatvars].name,
2285 					cheatvars[numcheatvars].value, 0);
2286 			numcheatvars++;
2287 		}
2288 	}
2289 
2290 	// make sure they are all set to the proper values
2291 	for (i=0, var = cheatvars ; i<numcheatvars ; i++, var++)
2292 	{
2293 		if ( cl.attractloop &&
2294 			(!strcmp( var->name, "timedemo" )
2295 			||
2296 			!strcmp( var->name, "timescale"))
2297 			)
2298 			continue; // allow these when running a .dm2 demo
2299 
2300 		if ( strcmp (var->var->string, var->value) )
2301 		{
2302 			Cvar_Set (var->name, var->value);
2303 		}
2304 	}
2305 }
2306 
CL_CheckFlagStatus(void)2307 void CL_CheckFlagStatus( void )
2308 {
2309 	if(r_gotFlag)
2310 	{
2311 		//start the new music
2312 		S_StartMusic(map_music_sec);
2313 	}
2314 	else if(r_lostFlag)
2315 	{
2316 		//start the original map music back up
2317 		S_StartMusic(map_music);
2318 	}
2319 }
2320 
2321 //============================================================================
2322 
2323 qboolean send_packet_now = false; // instant packets. used during downloads
2324 extern float    r_frametime;      // TODO: move to appropriate .h
2325 extern unsigned sys_frame_time;   // TODO: ditto
2326 
2327 /**
2328  * @brief Top level client-side routine for main loop.
2329  *
2330  * @param msec  the time since the previous CL_Frame.
2331  */
2332 /*
2333  * Notes on time variables:
2334  * cls.frametime :
2335  *  float seconds since last render
2336  *  clamped for packet processing, now unclamped for rendering
2337  *  used in client-to-server move message
2338  *  in CL_AddClEntities(): used in bouncing entities (brass) calculations
2339  *
2340  * r_frametime :
2341  *  unclamped float seconds since last render. Used in particle rendering.
2342  *
2343  * cl.time :
2344  *  critical global timer used in various places.
2345  *  clamped to [cl.frame.servertime-100, cl.frame.servertime] in CL_ParseFrame()
2346  *
2347  * cls.realtime :
2348  *   set to time at start of frame. Updated anywhere else?
2349  *
2350  *  cl.frame.servertime:
2351  *    equivalent to server frame number times 100msecs. see CL_ParseFrame()
2352  */
2353 
2354 /* Packet Rate Limiting Cap in milliseconds
2355  *  msecs=PPS :: 12=83, 13=76, 14=71, 15=66, 16=62
2356  * Current choice is 16msec/62PPS nominal.
2357  *  This matches the default cl_maxfps setting.
2358  *  Which is 60, of course, but because of msec rounding, the result is 62
2359  *  This results in 6 packets per server frame, mostly.
2360  * Packet rate limiting is not invoked unless the PPS is set higher than the FPS.
2361  * Seems like a good idea not to invoke packet rate limiting unless the
2362  *  cl_maxfps is set higher than the default.
2363  *
2364  *  PKTRATE_EARLY is the minimum msecs for catching up when packets are delayed
2365  */
2366 #define PKTRATE_CAP 16
2367 #define PKTRATE_EARLY 12
2368 
CL_Frame(int msec)2369 void CL_Frame( int msec )
2370 {
2371 	// static int lasttimecalled = 0; // TODO: see below, obsolete logging?
2372 
2373 	static int frcjitter[4]   = { 0, -1, 0, 1 };
2374 	static int frcjitter_ix   = 0;
2375 	static int framerate_cap  = 0;
2376 	static int packetrate_cap = 0;
2377 	static int packet_timer   = 0;
2378 	static int render_timer   = 0;
2379 	static int render_counter = 0;
2380 	static int packet_delay = 0;
2381 	int render_trigger;
2382 	int packet_trigger;
2383 	static perftest_t *speedometer = NULL;
2384 	static perftest_t *accelerometer = NULL;
2385 
2386 	if ( dedicated->integer )
2387 	{ // crx running as dedicated server crashes without this.
2388 		return;
2389 	}
2390 
2391 	cls.realtime  = curtime; // time at start of Qcommon_Frame()
2392 	cls.frametime = 0.0f;    // zero here for debug purposes, set below
2393 	cl.time += msec; // clamped to [cl.frame.servertime-100,cl.frame.servertime]
2394 
2395 	/* local timers for decoupling frame rate from packet rate */
2396 	packet_timer += msec;
2397 	render_timer += msec;
2398 
2399     if (!speedometer) {
2400         speedometer = get_perftest("speedometer");
2401         if (speedometer) {
2402             speedometer->is_timerate = false;
2403             speedometer->cvar = Cvar_Get("cl_showspeedometer", "0", CVAR_ARCHIVE);
2404             strcpy (speedometer->format, "speed %4.0f u/s");
2405             speedometer->scale = 1.0f;///12.3f;
2406         }
2407     }
2408 
2409     if (!accelerometer) {
2410     	accelerometer = get_perftest("acceleromter");
2411     	if (accelerometer) {
2412     		accelerometer->is_timerate = true;
2413     		accelerometer->cvar = Cvar_Get("cl_showaccelerometer", "0", CVAR_ARCHIVE);
2414     		strcpy (accelerometer->format, "accel %4.0f u/s/s");
2415     		accelerometer->scale = 1.0f;
2416     	}
2417     }
2418 
2419 
2420 	/*
2421 	 * update maximum FPS.
2422 	 * framerate_cap is in msecs/frame and is user specified.
2423 	 * Note: Quake2World sets a hard lower limit of 30. Not sure if
2424 	 *   that is needed; to be determined if that is a good thing to do.
2425 	 */
2426 	if ( cl_maxfps->modified  )
2427 	{
2428 		if ( cl_maxfps->value < 30.0f )
2429 		{
2430 			Com_Printf("Warning: cl_maxfps set to less than 30.\n");
2431 			if ( cl_maxfps->value < 1.0f )
2432 			{
2433 				Cvar_ForceSet( "cl_maxfps", "1" );
2434 			}
2435 		}
2436 		cl_maxfps->modified = false;
2437 		framerate_cap = 0; // force a recalculation
2438 	}
2439 	if ( framerate_cap < 1 )
2440 	{
2441 		framerate_cap = (int)(ceil( 1000.0f / cl_maxfps->value ));
2442 		if ( framerate_cap < 1 )
2443 		{
2444 			framerate_cap = 1;
2445 		}
2446 		Com_DPrintf("framerate_cap set to %i msec\n", framerate_cap );
2447 	}
2448 
2449 	/*
2450 	 * Set nominal milliseconds-per-packet for client-to-server messages.
2451 	 * Idea is to be timely in getting and transmitting player input without
2452 	 *   congesting the server.
2453 	 * Plan is to not implement a user setting for this unless a need for that
2454 	 *   is discovered.
2455 	 * If the cl_maxfps is set low, then FPS will limit PPS, and
2456 	 *  packet rate limiting is bypassed.
2457 	 */
2458 	if ( cls.state == ca_connected )
2459 	{ // receiving configstrings from the server, run at nominal 10PPS
2460 		// avoids unnecessary load on the server
2461 		if ( packetrate_cap != 100 )
2462 			Com_DPrintf("packet rate change: 10 PPS\n");
2463 		packetrate_cap = 100;
2464 	}
2465 	else if ( framerate_cap >= PKTRATE_CAP )
2466 	{ // do not to throttle packet sending, run in sync with render
2467 		if ( packetrate_cap != -1)
2468 			Com_DPrintf("packetrate change: framerate\n");
2469 		packetrate_cap = -1;
2470 	}
2471 	else
2472 	{ // packet rate limiting
2473 		if ( packetrate_cap != PKTRATE_CAP )
2474 			Com_DPrintf("packetrate change: %iPPS\n", 1000/PKTRATE_CAP);
2475 		packetrate_cap = PKTRATE_CAP;
2476 	}
2477 
2478 	/* local triggers for decoupling framerate from packet rate  */
2479 	render_trigger = 0;
2480 	packet_trigger = 0;
2481 
2482 	if ( cl_timedemo->integer == 1 )
2483 	{ /* accumulate timed demo statistics, free run both packet and render */
2484 		/* setting render_trigger to 1 forces timedemo_start to be set if it
2485 		 * hasn't been already. It also forces cl.timedemo_frames to be
2486 		 * incremented.
2487 		 */
2488 		render_trigger = 1;
2489 		packet_trigger = 1;
2490 	}
2491 	else
2492 	{ /* normal operation. */
2493 		/* Sometimes, the packetrate_cap can be "in phase" with
2494 		 *  the frame rate affecting the average packets-per-server-frame.
2495 		 *  A little jitter in the framerate_cap counteracts that.
2496 		 */
2497 		if ( render_timer >= (framerate_cap + frcjitter[frcjitter_ix]) )
2498 		{
2499 			if ( ++frcjitter_ix > 3 ) frcjitter_ix = 0;
2500 			render_trigger = 1;
2501 		}
2502 		if ( packetrate_cap == -1 )
2503 		{ // flagged to run same as framerate_cap
2504 			packet_trigger = render_trigger;
2505 		}
2506 		else if ( packet_timer >= packetrate_cap )
2507 		{ // normal packet trigger
2508 			packet_trigger = 1;
2509 		}
2510 		else if ( packet_delay > 0 )
2511 		{ // packet sent in previous loop was delayed
2512 			if ( packet_timer >= PKTRATE_EARLY )
2513 			{ // should be ok to send a packet early
2514 				/* idea is to try to maintain a steady number of
2515 				 * client-to-server packets per server frame.
2516 				 * If render is triggered, it is good to poll input and
2517 				 *  send a packet to avoid more delay.
2518 				 * If adding the delay to the timer reaches the cap then
2519 				 *  try to catch up
2520 				 * Otherwise, do nothing, the next loop should occur soon.
2521 				 */
2522 				if ( render_trigger
2523 					|| ((packet_timer + packet_delay) >= packetrate_cap) )
2524 				{
2525 					packet_trigger = 1;
2526 				}
2527 			}
2528 		}
2529 	}
2530 
2531 	if ( packet_trigger || send_packet_now || cls.download)
2532 	{
2533 		send_packet_now = false; // used during downloads
2534 
2535 		if ( packetrate_cap > 0 && packet_timer > packetrate_cap )
2536 		{ // difference between cap and timer, a delayed packet
2537 			packet_delay = packet_timer - packetrate_cap;
2538 		}
2539 		else
2540 		{
2541 			packet_delay = 0;
2542 		}
2543 
2544 		render_counter = 0; // for counting renders since last packet
2545 
2546 		/* let the mouse activate or deactivate */
2547 		IN_Frame();
2548 
2549 		/*
2550 		 * calculate frametime in seconds for packet procedures
2551 		 * cls.frametime is source for the cmd.msecs byte
2552 		 *  in the client-to-server move message.
2553 		 */
2554 		cls.frametime  = ((float)packet_timer) / 1000.0f;
2555 		if ( cls.frametime >= 0.250f )
2556 		{ /* very long delay */
2557 			/*
2558 			 * server checks for cmd.msecs to be <= 250
2559 			 */
2560 			Com_DPrintf("CL_Frame(): cls.frametime clamped from %0.8f to 0.24999\n",
2561 					cls.frametime );
2562 			cls.frametime = 0.24999f ;
2563 			/*
2564 			 * try to throttle the video frame rate by overriding the
2565 			 * render trigger.
2566 			 */
2567 			render_trigger = false;
2568 			render_timer = 0;
2569 		}
2570 
2571 		/* process server-to-client packets */
2572 		CL_ReadPackets();
2573 
2574 		/* execute pending commands */
2575 		Cbuf_Execute();
2576 
2577 		/* run cURL downloads */
2578 		CL_HttpDownloadThink();
2579 
2580 		/*
2581 		 * system dependent keyboard and mouse input event polling
2582 		 * accumulate keyboard and mouse events
2583 		 */
2584 		Sys_SendKeyEvents();
2585 
2586 		/* joystick input. may or may not be working. */
2587 		IN_Commands();
2588 
2589 		/* execute pending commands */
2590 		Cbuf_Execute();
2591 
2592 		/*
2593 		 * send client commands to server
2594 		 * these are construced from accumulated keyboard and mouse events,
2595 		 * which are then reset
2596 		 */
2597 		CL_SendCmd();
2598 
2599 		/* clear various cvars unless single player */
2600 		CL_FixCvarCheats ();
2601 
2602 		/* resend a connection request if necessary */
2603 		CL_CheckForResend();
2604 
2605 		/*
2606 		 * predict movement for un-acked client-to-server packets
2607 		 * [The Quake trick that keeps players view smooth in on-line play.]
2608 		 */
2609 		CL_PredictMovement();
2610 
2611 		if (speedometer && speedometer->cvar->integer) {
2612 	        speedometer->counter = sqrt(
2613 	            cl.predicted_velocity[0]*cl.predicted_velocity[0]+
2614 	            cl.predicted_velocity[1]*cl.predicted_velocity[1]
2615 	        );
2616 	        if (speedometer->counter > cl_speedrecord->value) {
2617 	        	Cvar_SetValue ("cl_speedrecord", speedometer->counter);
2618 	        	if (speedometer->counter > cl_alltimespeedrecord->value)
2619 	        		Cvar_SetValue ("cl_alltimespeedrecord", speedometer->counter);
2620 	        }
2621 	    }
2622 
2623 	    if (accelerometer && accelerometer->cvar->integer) {
2624 	    	static float old_vel;
2625 	    	float new_vel;
2626 	    	new_vel = sqrt(
2627 	            cl.predicted_velocity[0]*cl.predicted_velocity[0]+
2628 	            cl.predicted_velocity[1]*cl.predicted_velocity[1]
2629 	        );
2630 	        accelerometer->counter += new_vel-old_vel;
2631 	        old_vel = new_vel;
2632 	    }
2633 
2634 		/* retrigger packet send timer */
2635 		packet_timer = 0;
2636 	}
2637 
2638 	/*
2639 	 * refresh can occur on different frames than client-to-server messages.
2640 	 *  when packet rate limiting is in effect
2641 	 */
2642 	if ( render_trigger )
2643 	{
2644 		++render_counter; // counting renders since last packet
2645 
2646 		if (!packet_trigger && cl_test->integer) //return cl_test - this was causing major issues with menu mouse in windows build
2647 		{
2648 			/*
2649 			 * system dependent keyboard and mouse input event polling
2650 			 * accumulate keyboard and mouse events
2651 			 */
2652 			cls.frametime  = ((float)packet_timer) / 1000.0f;
2653 			Sys_SendKeyEvents();
2654 			/*
2655 			 * update view angles based on accumulated keyboard and mouse
2656 			 * events, which are *not* reset
2657 			 */
2658 			IN_Move(NULL);
2659 		}
2660 
2661 		/*
2662 		 * calculate cls.frametime in seconds for render procedures.
2663 		 *
2664 		 * May not need to clamp for rendering.
2665 		 * Only would affect things if framerate went below 4 FPS.
2666 		 *
2667 		 * Using a simple lowpass filter, to smooth out irregular timing.
2668 		 */
2669 		cls.frametime = (float)(render_timer) / 1000.0f;
2670 		r_frametime = (r_frametime + cls.frametime + cls.frametime) / 3.0f;
2671 		cls.frametime = r_frametime;
2672 
2673 		//  Update the display
2674 		VID_CheckChanges();
2675 		if ( !cl.refresh_prepped && cls.state == ca_active )
2676 		{ // re-initialize video configuration
2677 			CL_PrepRefresh();
2678 		}
2679 		else
2680 		{ // regular screen update
2681 			if ( host_speeds->integer )
2682 				time_before_ref = Sys_Milliseconds(); // TODO: obsolete test?
2683 			SCR_UpdateScreen();
2684 			if ( host_speeds->integer )
2685 				time_after_ref = Sys_Milliseconds();
2686 		}
2687 
2688 		// check for flag and update music src if possesed or lost
2689 		CL_CheckFlagStatus();
2690 
2691 		// update audio.
2692 		S_Update( cl.refdef.vieworg, cl.v_forward, cl.v_right, cl.v_up );
2693 
2694 		// advance local effects for next frame
2695 		CL_RunDLights();
2696 		CL_RunLightStyles();
2697 		SCR_RunConsole ();
2698 
2699 		++cls.framecount; // does not appear to be used anywhere
2700 
2701 		/* developer test for observing timers */
2702 		// Com_DPrintf("rt: %i cft: %f\n", render_timer, cls.frametime );
2703 
2704 		// retrigger render timing
2705 		render_timer = 0;
2706 
2707 #if 0
2708 		/* TODO: Check if this still works and/or is useful.
2709 		 */
2710 		if ( log_stats->value )
2711 		{
2712 			if ( cls.state == ca_active )
2713 			{
2714 				if ( !lasttimecalled )
2715 				{
2716 					lasttimecalled = Sys_Milliseconds();
2717 					if ( log_stats_file )
2718 						fprintf( log_stats_file, "0\n" );
2719 				}
2720 				else
2721 				{
2722 					int now = Sys_Milliseconds();
2723 
2724 					if ( log_stats_file )
2725 						fprintf( log_stats_file, "%d\n", now - lasttimecalled );
2726 					lasttimecalled = now;
2727 				}
2728 			}
2729 		}
2730 #endif
2731 
2732 	}
2733 
2734 }
2735 
2736 //============================================================================
2737 
2738 /*
2739 ====================
2740 CL_Init
2741 ====================
2742 */
CL_Init(void)2743 void CL_Init (void)
2744 {
2745 	if (dedicated->integer)
2746 		return;		// nothing running on the client
2747 
2748 	// Initialise fonts
2749 	CL_gameFont = &_CL_gameFont;
2750 	FNT_AutoInit( CL_gameFont , "freesans" , 0 , 65 , 8 , 48 );
2751 	CL_gameFont->faceVar = Cvar_Get( "fnt_game" , "orbitron" , CVAR_ARCHIVE );
2752 	CL_gameFont->sizeVar = Cvar_Get( "fnt_game_size" , "0" , CVAR_ARCHIVE );
2753 	FNT_AutoRegister( CL_gameFont );
2754 
2755 	CL_centerFont = &_CL_centerFont;
2756 	FNT_AutoInit( CL_centerFont , "freesans" , 0 , 45 , 16 , 64 );
2757 	CL_centerFont->faceVar = CL_gameFont->faceVar;
2758 	CL_centerFont->sizeVar = Cvar_Get( "fnt_center_size" , "0" , CVAR_ARCHIVE );
2759 	FNT_AutoRegister( CL_centerFont );
2760 
2761 	CL_consoleFont = &_CL_consoleFont;
2762 	FNT_AutoInit( CL_consoleFont , "freesans" , 0 , 52 , 8 , 48 );
2763 	CL_consoleFont->faceVar = Cvar_Get( "fnt_console" , "freemono" , CVAR_ARCHIVE );
2764 	CL_consoleFont->sizeVar = Cvar_Get( "fnt_console_size" , "0" , CVAR_ARCHIVE );
2765 	FNT_AutoRegister( CL_consoleFont );
2766 
2767 	CL_menuFont = &_CL_menuFont;
2768 	FNT_AutoInit( CL_menuFont , "freesans" , 0 , 48 , 8 , 48 );
2769 	CL_menuFont->faceVar = Cvar_Get( "fnt_menu" , "freesans" , CVAR_ARCHIVE );
2770 	CL_menuFont->sizeVar = Cvar_Get( "fnt_menu_size" , "0" , CVAR_ARCHIVE );
2771 	FNT_AutoRegister( CL_menuFont );
2772 
2773 	// all archived variables will now be loaded
2774 
2775 	CON_Initialise( );
2776 
2777 	VID_Init ();
2778 	S_Init ();
2779 
2780 	V_Init ();
2781 
2782 	net_message.data = net_message_buffer;
2783 	net_message.maxsize = sizeof(net_message_buffer);
2784 
2785 	M_Init ();
2786 
2787 	SCR_Init ();
2788 	cls.disable_screen = true;	// don't draw yet
2789 
2790 	CL_InitLocal ();
2791 	IN_Init ();
2792 
2793 	FS_ExecAutoexec (); // add commands from autoexec.cfg
2794 	Cbuf_Execute ();
2795 
2796 	if ( name && name->string[0] )
2797 	{
2798 		ValidatePlayerName( name->string, (strlen(name->string)+1) );
2799 	}
2800 }
2801 
2802 
2803 /*
2804 ===============
2805 CL_Shutdown
2806 
2807 FIXME: this is a callback from Sys_Quit and Com_Error.  It would be better
2808 to run quit through here before the final handoff to the sys code.
2809 ===============
2810 */
CL_Shutdown(void)2811 void CL_Shutdown(void)
2812 {
2813 	static qboolean isdown = false;
2814 
2815 	if (isdown)
2816 	{
2817 		printf ("recursive shutdown\n");
2818 		return;
2819 	}
2820 	isdown = true;
2821 
2822 	STATS_Logout();
2823 
2824 	CL_IRCInitiateShutdown();
2825 	CL_ShutdownHttpDownload();
2826 	CL_WriteConfiguration ();
2827 	CL_WriteProfile();
2828 
2829 	S_Shutdown();
2830 	IN_Shutdown ();
2831 	VID_Shutdown();
2832 	CL_IRCWaitShutdown( );
2833 
2834 	NET_Shutdown();
2835 
2836 	RS_FreeAllScripts();
2837 }
2838 
2839 
2840