Home | History | Annotate | Download | only in client
      1 /*
      2 Copyright (C) 1996-1997 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 // cl_parse.c  -- parse a message received from the server
     21 
     22 #include "quakedef.h"
     23 
     24 char *svc_strings[] =
     25 {
     26 	"svc_bad",
     27 	"svc_nop",
     28 	"svc_disconnect",
     29 	"svc_updatestat",
     30 	"svc_version",		// [long] server version
     31 	"svc_setview",		// [short] entity number
     32 	"svc_sound",			// <see code>
     33 	"svc_time",			// [float] server time
     34 	"svc_print",			// [string] null terminated string
     35 	"svc_stufftext",		// [string] stuffed into client's console buffer
     36 						// the string should be \n terminated
     37 	"svc_setangle",		// [vec3] set the view angle to this absolute value
     38 
     39 	"svc_serverdata",		// [long] version ...
     40 	"svc_lightstyle",		// [byte] [string]
     41 	"svc_updatename",		// [byte] [string]
     42 	"svc_updatefrags",	// [byte] [short]
     43 	"svc_clientdata",		// <shortbits + data>
     44 	"svc_stopsound",		// <see code>
     45 	"svc_updatecolors",	// [byte] [byte]
     46 	"svc_particle",		// [vec3] <variable>
     47 	"svc_damage",			// [byte] impact [byte] blood [vec3] from
     48 
     49 	"svc_spawnstatic",
     50 	"OBSOLETE svc_spawnbinary",
     51 	"svc_spawnbaseline",
     52 
     53 	"svc_temp_entity",		// <variable>
     54 	"svc_setpause",
     55 	"svc_signonnum",
     56 	"svc_centerprint",
     57 	"svc_killedmonster",
     58 	"svc_foundsecret",
     59 	"svc_spawnstaticsound",
     60 	"svc_intermission",
     61 	"svc_finale",
     62 
     63 	"svc_cdtrack",
     64 	"svc_sellscreen",
     65 
     66 	"svc_smallkick",
     67 	"svc_bigkick",
     68 
     69 	"svc_updateping",
     70 	"svc_updateentertime",
     71 
     72 	"svc_updatestatlong",
     73 	"svc_muzzleflash",
     74 	"svc_updateuserinfo",
     75 	"svc_download",
     76 	"svc_playerinfo",
     77 	"svc_nails",
     78 	"svc_choke",
     79 	"svc_modellist",
     80 	"svc_soundlist",
     81 	"svc_packetentities",
     82  	"svc_deltapacketentities",
     83 	"svc_maxspeed",
     84 	"svc_entgravity",
     85 
     86 	"svc_setinfo",
     87 	"svc_serverinfo",
     88 	"svc_updatepl",
     89 	"NEW PROTOCOL",
     90 	"NEW PROTOCOL",
     91 	"NEW PROTOCOL",
     92 	"NEW PROTOCOL",
     93 	"NEW PROTOCOL",
     94 	"NEW PROTOCOL",
     95 	"NEW PROTOCOL",
     96 	"NEW PROTOCOL",
     97 	"NEW PROTOCOL",
     98 	"NEW PROTOCOL",
     99 	"NEW PROTOCOL",
    100 	"NEW PROTOCOL",
    101 	"NEW PROTOCOL"
    102 };
    103 
    104 int	oldparsecountmod;
    105 int	parsecountmod;
    106 double	parsecounttime;
    107 
    108 int		cl_spikeindex, cl_playerindex, cl_flagindex;
    109 
    110 //=============================================================================
    111 
    112 int packet_latency[NET_TIMINGS];
    113 
    114 int CL_CalcNet (void)
    115 {
    116 	int		a, i;
    117 	frame_t	*frame;
    118 	int lost;
    119 	char st[80];
    120 
    121 	for (i=cls.netchan.outgoing_sequence-UPDATE_BACKUP+1
    122 		; i <= cls.netchan.outgoing_sequence
    123 		; i++)
    124 	{
    125 		frame = &cl.frames[i&UPDATE_MASK];
    126 		if (frame->receivedtime == -1)
    127 			packet_latency[i&NET_TIMINGSMASK] = 9999;	// dropped
    128 		else if (frame->receivedtime == -2)
    129 			packet_latency[i&NET_TIMINGSMASK] = 10000;	// choked
    130 		else if (frame->invalid)
    131 			packet_latency[i&NET_TIMINGSMASK] = 9998;	// invalid delta
    132 		else
    133 			packet_latency[i&NET_TIMINGSMASK] = (frame->receivedtime - frame->senttime)*20;
    134 	}
    135 
    136 	lost = 0;
    137 	for (a=0 ; a<NET_TIMINGS ; a++)
    138 	{
    139 		i = (cls.netchan.outgoing_sequence-a) & NET_TIMINGSMASK;
    140 		if (packet_latency[i] == 9999)
    141 			lost++;
    142 	}
    143 	return lost * 100 / NET_TIMINGS;
    144 }
    145 
    146 //=============================================================================
    147 
    148 /*
    149 ===============
    150 CL_CheckOrDownloadFile
    151 
    152 Returns true if the file exists, otherwise it attempts
    153 to start a download from the server.
    154 ===============
    155 */
    156 qboolean	CL_CheckOrDownloadFile (char *filename)
    157 {
    158 	FILE	*f;
    159 
    160 	if (strstr (filename, ".."))
    161 	{
    162 		Con_Printf ("Refusing to download a path with ..\n");
    163 		return true;
    164 	}
    165 
    166 	COM_FOpenFile (filename, &f);
    167 	if (f)
    168 	{	// it exists, no need to download
    169 		fclose (f);
    170 		return true;
    171 	}
    172 
    173 	//ZOID - can't download when recording
    174 	if (cls.demorecording) {
    175 		Con_Printf("Unable to download %s in record mode.\n", cls.downloadname);
    176 		return true;
    177 	}
    178 	//ZOID - can't download when playback
    179 	if (cls.demoplayback)
    180 		return true;
    181 
    182 	strcpy (cls.downloadname, filename);
    183 	Con_Printf ("Downloading %s...\n", cls.downloadname);
    184 
    185 	// download to a temp name, and only rename
    186 	// to the real name when done, so if interrupted
    187 	// a runt file wont be left
    188 	COM_StripExtension (cls.downloadname, cls.downloadtempname);
    189 	strcat (cls.downloadtempname, ".tmp");
    190 
    191 	MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
    192 	MSG_WriteString (&cls.netchan.message, va("download %s", cls.downloadname));
    193 
    194 	cls.downloadnumber++;
    195 
    196 	return false;
    197 }
    198 
    199 /*
    200 =================
    201 Model_NextDownload
    202 =================
    203 */
    204 void Model_NextDownload (void)
    205 {
    206 	char	*s;
    207 	int		i;
    208 	extern	char gamedirfile[];
    209 
    210 	if (cls.downloadnumber == 0)
    211 	{
    212 		Con_Printf ("Checking models...\n");
    213 		cls.downloadnumber = 1;
    214 	}
    215 
    216 	cls.downloadtype = dl_model;
    217 	for (
    218 		; cl.model_name[cls.downloadnumber][0]
    219 		; cls.downloadnumber++)
    220 	{
    221 		s = cl.model_name[cls.downloadnumber];
    222 		if (s[0] == '*')
    223 			continue;	// inline brush model
    224 		if (!CL_CheckOrDownloadFile(s))
    225 			return;		// started a download
    226 	}
    227 
    228 	for (i=1 ; i<MAX_MODELS ; i++)
    229 	{
    230 		if (!cl.model_name[i][0])
    231 			break;
    232 
    233 		cl.model_precache[i] = Mod_ForName (cl.model_name[i], false);
    234 
    235 		if (!cl.model_precache[i])
    236 		{
    237 			Con_Printf ("\nThe required model file '%s' could not be found or downloaded.\n\n"
    238 				, cl.model_name[i]);
    239 			Con_Printf ("You may need to download or purchase a %s client "
    240 				"pack in order to play on this server.\n\n", gamedirfile);
    241 			CL_Disconnect ();
    242 			return;
    243 		}
    244 	}
    245 
    246 	// all done
    247 	cl.worldmodel = cl.model_precache[1];
    248 	R_NewMap ();
    249 	Hunk_Check ();		// make sure nothing is hurt
    250 
    251 	// done with modellist, request first of static signon messages
    252 	MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
    253 //	MSG_WriteString (&cls.netchan.message, va("prespawn %i 0 %i", cl.servercount, cl.worldmodel->checksum2));
    254 	MSG_WriteString (&cls.netchan.message, va(prespawn_name, cl.servercount, cl.worldmodel->checksum2));
    255 }
    256 
    257 /*
    258 =================
    259 Sound_NextDownload
    260 =================
    261 */
    262 void Sound_NextDownload (void)
    263 {
    264 	char	*s;
    265 	int		i;
    266 
    267 	if (cls.downloadnumber == 0)
    268 	{
    269 		Con_Printf ("Checking sounds...\n");
    270 		cls.downloadnumber = 1;
    271 	}
    272 
    273 	cls.downloadtype = dl_sound;
    274 	for (
    275 		; cl.sound_name[cls.downloadnumber][0]
    276 		; cls.downloadnumber++)
    277 	{
    278 		s = cl.sound_name[cls.downloadnumber];
    279 		if (!CL_CheckOrDownloadFile(va("sound/%s",s)))
    280 			return;		// started a download
    281 	}
    282 
    283 	for (i=1 ; i<MAX_SOUNDS ; i++)
    284 	{
    285 		if (!cl.sound_name[i][0])
    286 			break;
    287 		cl.sound_precache[i] = S_PrecacheSound (cl.sound_name[i]);
    288 	}
    289 
    290 	// done with sounds, request models now
    291 	memset (cl.model_precache, 0, sizeof(cl.model_precache));
    292 	cl_playerindex = -1;
    293 	cl_spikeindex = -1;
    294 	cl_flagindex = -1;
    295 	MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
    296 //	MSG_WriteString (&cls.netchan.message, va("modellist %i 0", cl.servercount));
    297 	MSG_WriteString (&cls.netchan.message, va(modellist_name, cl.servercount, 0));
    298 }
    299 
    300 
    301 /*
    302 ======================
    303 CL_RequestNextDownload
    304 ======================
    305 */
    306 void CL_RequestNextDownload (void)
    307 {
    308 	switch (cls.downloadtype)
    309 	{
    310 	case dl_single:
    311 		break;
    312 	case dl_skin:
    313 		Skin_NextDownload ();
    314 		break;
    315 	case dl_model:
    316 		Model_NextDownload ();
    317 		break;
    318 	case dl_sound:
    319 		Sound_NextDownload ();
    320 		break;
    321 	case dl_none:
    322 	default:
    323 		Con_DPrintf("Unknown download type.\n");
    324 	}
    325 }
    326 
    327 /*
    328 =====================
    329 CL_ParseDownload
    330 
    331 A download message has been received from the server
    332 =====================
    333 */
    334 void CL_ParseDownload (void)
    335 {
    336 	int		size, percent;
    337 	char	name[1024];
    338 	int		r;
    339 
    340 
    341 	// read the data
    342 	size = MSG_ReadShort ();
    343 	percent = MSG_ReadByte ();
    344 
    345 	if (cls.demoplayback) {
    346 		if (size > 0)
    347 			msg_readcount += size;
    348 		return; // not in demo playback
    349 	}
    350 
    351 	if (size == -1)
    352 	{
    353 		Con_Printf ("File not found.\n");
    354 		if (cls.download)
    355 		{
    356 			Con_Printf ("cls.download shouldn't have been set\n");
    357 			fclose (cls.download);
    358 			cls.download = NULL;
    359 		}
    360 		CL_RequestNextDownload ();
    361 		return;
    362 	}
    363 
    364 	// open the file if not opened yet
    365 	if (!cls.download)
    366 	{
    367 		if (strncmp(cls.downloadtempname,"skins/",6))
    368 			sprintf (name, "%s/%s", com_gamedir, cls.downloadtempname);
    369 		else
    370 			sprintf (name, "qw/%s", cls.downloadtempname);
    371 
    372 		COM_CreatePath (name);
    373 
    374 		cls.download = fopen (name, "wb");
    375 		if (!cls.download)
    376 		{
    377 			msg_readcount += size;
    378 			Con_Printf ("Failed to open %s\n", cls.downloadtempname);
    379 			CL_RequestNextDownload ();
    380 			return;
    381 		}
    382 	}
    383 
    384 	fwrite (net_message.data + msg_readcount, 1, size, cls.download);
    385 	msg_readcount += size;
    386 
    387 	if (percent != 100)
    388 	{
    389 // change display routines by zoid
    390 		// request next block
    391 #if 0
    392 		Con_Printf (".");
    393 		if (10*(percent/10) != cls.downloadpercent)
    394 		{
    395 			cls.downloadpercent = 10*(percent/10);
    396 			Con_Printf ("%i%%", cls.downloadpercent);
    397 		}
    398 #endif
    399 		cls.downloadpercent = percent;
    400 
    401 		MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
    402 		SZ_Print (&cls.netchan.message, "nextdl");
    403 	}
    404 	else
    405 	{
    406 		char	oldn[MAX_OSPATH];
    407 		char	newn[MAX_OSPATH];
    408 
    409 #if 0
    410 		Con_Printf ("100%%\n");
    411 #endif
    412 
    413 		fclose (cls.download);
    414 
    415 		// rename the temp file to it's final name
    416 		if (strcmp(cls.downloadtempname, cls.downloadname)) {
    417 			if (strncmp(cls.downloadtempname,"skins/",6)) {
    418 				sprintf (oldn, "%s/%s", com_gamedir, cls.downloadtempname);
    419 				sprintf (newn, "%s/%s", com_gamedir, cls.downloadname);
    420 			} else {
    421 				sprintf (oldn, "qw/%s", cls.downloadtempname);
    422 				sprintf (newn, "qw/%s", cls.downloadname);
    423 			}
    424 			r = rename (oldn, newn);
    425 			if (r)
    426 				Con_Printf ("failed to rename.\n");
    427 		}
    428 
    429 		cls.download = NULL;
    430 		cls.downloadpercent = 0;
    431 
    432 		// get another file if needed
    433 
    434 		CL_RequestNextDownload ();
    435 	}
    436 }
    437 
    438 static byte *upload_data;
    439 static int upload_pos;
    440 static int upload_size;
    441 
    442 void CL_NextUpload(void)
    443 {
    444 	byte	buffer[1024];
    445 	int		r;
    446 	int		percent;
    447 	int		size;
    448 
    449 	if (!upload_data)
    450 		return;
    451 
    452 	r = upload_size - upload_pos;
    453 	if (r > 768)
    454 		r = 768;
    455 	memcpy(buffer, upload_data + upload_pos, r);
    456 	MSG_WriteByte (&cls.netchan.message, clc_upload);
    457 	MSG_WriteShort (&cls.netchan.message, r);
    458 
    459 	upload_pos += r;
    460 	size = upload_size;
    461 	if (!size)
    462 		size = 1;
    463 	percent = upload_pos*100/size;
    464 	MSG_WriteByte (&cls.netchan.message, percent);
    465 	SZ_Write (&cls.netchan.message, buffer, r);
    466 
    467 Con_DPrintf ("UPLOAD: %6d: %d written\n", upload_pos - r, r);
    468 
    469 	if (upload_pos != upload_size)
    470 		return;
    471 
    472 	Con_Printf ("Upload completed\n");
    473 
    474 	free(upload_data);
    475 	upload_data = 0;
    476 	upload_pos = upload_size = 0;
    477 }
    478 
    479 void CL_StartUpload (byte *data, int size)
    480 {
    481 	if (cls.state < ca_onserver)
    482 		return; // gotta be connected
    483 
    484 	// override
    485 	if (upload_data)
    486 		free(upload_data);
    487 
    488 Con_DPrintf("Upload starting of %d...\n", size);
    489 
    490 	upload_data = malloc(size);
    491 	memcpy(upload_data, data, size);
    492 	upload_size = size;
    493 	upload_pos = 0;
    494 
    495 	CL_NextUpload();
    496 }
    497 
    498 qboolean CL_IsUploading(void)
    499 {
    500 	if (upload_data)
    501 		return true;
    502 	return false;
    503 }
    504 
    505 void CL_StopUpload(void)
    506 {
    507 	if (upload_data)
    508 		free(upload_data);
    509 	upload_data = NULL;
    510 }
    511 
    512 /*
    513 =====================================================================
    514 
    515   SERVER CONNECTING MESSAGES
    516 
    517 =====================================================================
    518 */
    519 
    520 /*
    521 ==================
    522 CL_ParseServerData
    523 ==================
    524 */
    525 void CL_ParseServerData (void)
    526 {
    527 	char	*str;
    528 	FILE	*f;
    529 	char	fn[MAX_OSPATH];
    530 	qboolean	cflag = false;
    531 	extern	char	gamedirfile[MAX_OSPATH];
    532 	int protover;
    533 
    534 	Con_DPrintf ("Serverdata packet received.\n");
    535 //
    536 // wipe the client_state_t struct
    537 //
    538 	CL_ClearState ();
    539 
    540 // parse protocol version number
    541 // allow 2.2 and 2.29 demos to play
    542 	protover = MSG_ReadLong ();
    543 	if (protover != PROTOCOL_VERSION &&
    544 		!(cls.demoplayback && (protover == 26 || protover == 27 || protover == 28)))
    545 		Host_EndGame ("Server returned version %i, not %i\nYou probably need to upgrade.\nCheck http://www.quakeworld.net/", protover, PROTOCOL_VERSION);
    546 
    547 	cl.servercount = MSG_ReadLong ();
    548 
    549 	// game directory
    550 	str = MSG_ReadString ();
    551 
    552 	if (strcasecmp(gamedirfile, str)) {
    553 		// save current config
    554 		Host_WriteConfiguration ();
    555 		cflag = true;
    556 	}
    557 
    558 	COM_Gamedir(str);
    559 
    560 	//ZOID--run the autoexec.cfg in the gamedir
    561 	//if it exists
    562 	if (cflag) {
    563 		sprintf(fn, "%s/%s", com_gamedir, "config.cfg");
    564 		if ((f = fopen(fn, "r")) != NULL) {
    565 			fclose(f);
    566 			Cbuf_AddText ("cl_warncmd 0\n");
    567 			Cbuf_AddText("exec config.cfg\n");
    568 			Cbuf_AddText("exec frontend.cfg\n");
    569 			Cbuf_AddText ("cl_warncmd 1\n");
    570 		}
    571 	}
    572 
    573 	// parse player slot, high bit means spectator
    574 	cl.playernum = MSG_ReadByte ();
    575 	if (cl.playernum & 128)
    576 	{
    577 		cl.spectator = true;
    578 		cl.playernum &= ~128;
    579 	}
    580 
    581 	// get the full level name
    582 	str = MSG_ReadString ();
    583 	strncpy (cl.levelname, str, sizeof(cl.levelname)-1);
    584 
    585 	// get the movevars
    586 	movevars.gravity			= MSG_ReadFloat();
    587 	movevars.stopspeed          = MSG_ReadFloat();
    588 	movevars.maxspeed           = MSG_ReadFloat();
    589 	movevars.spectatormaxspeed  = MSG_ReadFloat();
    590 	movevars.accelerate         = MSG_ReadFloat();
    591 	movevars.airaccelerate      = MSG_ReadFloat();
    592 	movevars.wateraccelerate    = MSG_ReadFloat();
    593 	movevars.friction           = MSG_ReadFloat();
    594 	movevars.waterfriction      = MSG_ReadFloat();
    595 	movevars.entgravity         = MSG_ReadFloat();
    596 
    597 	// seperate the printfs so the server message can have a color
    598 	Con_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
    599 	Con_Printf ("%c%s\n", 2, str);
    600 
    601 	// ask for the sound list next
    602 	memset(cl.sound_name, 0, sizeof(cl.sound_name));
    603 	MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
    604 //	MSG_WriteString (&cls.netchan.message, va("soundlist %i 0", cl.servercount));
    605 	MSG_WriteString (&cls.netchan.message, va(soundlist_name, cl.servercount, 0));
    606 
    607 	// now waiting for downloads, etc
    608 	cls.state = ca_onserver;
    609 }
    610 
    611 /*
    612 ==================
    613 CL_ParseSoundlist
    614 ==================
    615 */
    616 void CL_ParseSoundlist (void)
    617 {
    618 	int	numsounds;
    619 	char	*str;
    620 	int n;
    621 
    622 // precache sounds
    623 //	memset (cl.sound_precache, 0, sizeof(cl.sound_precache));
    624 
    625 	numsounds = MSG_ReadByte();
    626 
    627 	for (;;) {
    628 		str = MSG_ReadString ();
    629 		if (!str[0])
    630 			break;
    631 		numsounds++;
    632 		if (numsounds == MAX_SOUNDS)
    633 			Host_EndGame ("Server sent too many sound_precache");
    634 		strcpy (cl.sound_name[numsounds], str);
    635 	}
    636 
    637 	n = MSG_ReadByte();
    638 
    639 	if (n) {
    640 		MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
    641 //		MSG_WriteString (&cls.netchan.message, va("soundlist %i %i", cl.servercount, n));
    642 		MSG_WriteString (&cls.netchan.message, va(soundlist_name, cl.servercount, n));
    643 		return;
    644 	}
    645 
    646 	cls.downloadnumber = 0;
    647 	cls.downloadtype = dl_sound;
    648 	Sound_NextDownload ();
    649 }
    650 
    651 /*
    652 ==================
    653 CL_ParseModellist
    654 ==================
    655 */
    656 void CL_ParseModellist (void)
    657 {
    658 	int	nummodels;
    659 	char	*str;
    660 	int n;
    661 
    662 // precache models and note certain default indexes
    663 	nummodels = MSG_ReadByte();
    664 
    665 	for (;;)
    666 	{
    667 		str = MSG_ReadString ();
    668 		if (!str[0])
    669 			break;
    670 		nummodels++;
    671 		if (nummodels==MAX_MODELS)
    672 			Host_EndGame ("Server sent too many model_precache");
    673 		strcpy (cl.model_name[nummodels], str);
    674 
    675 		if (!strcmp(cl.model_name[nummodels],"progs/spike.mdl"))
    676 			cl_spikeindex = nummodels;
    677 		if (!strcmp(cl.model_name[nummodels],"progs/player.mdl"))
    678 			cl_playerindex = nummodels;
    679 		if (!strcmp(cl.model_name[nummodels],"progs/flag.mdl"))
    680 			cl_flagindex = nummodels;
    681 	}
    682 
    683 	n = MSG_ReadByte();
    684 
    685 	if (n) {
    686 		MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
    687 //		MSG_WriteString (&cls.netchan.message, va("modellist %i %i", cl.servercount, n));
    688 		MSG_WriteString (&cls.netchan.message, va(modellist_name, cl.servercount, n));
    689 		return;
    690 	}
    691 
    692 	cls.downloadnumber = 0;
    693 	cls.downloadtype = dl_model;
    694 	Model_NextDownload ();
    695 }
    696 
    697 /*
    698 ==================
    699 CL_ParseBaseline
    700 ==================
    701 */
    702 void CL_ParseBaseline (entity_state_t *es)
    703 {
    704 	int			i;
    705 
    706 	es->modelindex = MSG_ReadByte ();
    707 	es->frame = MSG_ReadByte ();
    708 	es->colormap = MSG_ReadByte();
    709 	es->skinnum = MSG_ReadByte();
    710 	for (i=0 ; i<3 ; i++)
    711 	{
    712 		es->origin[i] = MSG_ReadCoord ();
    713 		es->angles[i] = MSG_ReadAngle ();
    714 	}
    715 }
    716 
    717 
    718 
    719 /*
    720 =====================
    721 CL_ParseStatic
    722 
    723 Static entities are non-interactive world objects
    724 like torches
    725 =====================
    726 */
    727 void CL_ParseStatic (void)
    728 {
    729 	entity_t *ent;
    730 	int		i;
    731 	entity_state_t	es;
    732 
    733 	CL_ParseBaseline (&es);
    734 
    735 	i = cl.num_statics;
    736 	if (i >= MAX_STATIC_ENTITIES)
    737 		Host_EndGame ("Too many static entities");
    738 	ent = &cl_static_entities[i];
    739 	cl.num_statics++;
    740 
    741 // copy it to the current state
    742 	ent->model = cl.model_precache[es.modelindex];
    743 	ent->frame = es.frame;
    744 	ent->colormap = vid.colormap;
    745 	ent->skinnum = es.skinnum;
    746 
    747 	VectorCopy (es.origin, ent->origin);
    748 	VectorCopy (es.angles, ent->angles);
    749 
    750 	R_AddEfrags (ent);
    751 }
    752 
    753 /*
    754 ===================
    755 CL_ParseStaticSound
    756 ===================
    757 */
    758 void CL_ParseStaticSound (void)
    759 {
    760 	vec3_t		org;
    761 	int			sound_num, vol, atten;
    762 	int			i;
    763 
    764 	for (i=0 ; i<3 ; i++)
    765 		org[i] = MSG_ReadCoord ();
    766 	sound_num = MSG_ReadByte ();
    767 	vol = MSG_ReadByte ();
    768 	atten = MSG_ReadByte ();
    769 
    770 	S_StaticSound (cl.sound_precache[sound_num], org, vol, atten);
    771 }
    772 
    773 
    774 
    775 /*
    776 =====================================================================
    777 
    778 ACTION MESSAGES
    779 
    780 =====================================================================
    781 */
    782 
    783 /*
    784 ==================
    785 CL_ParseStartSoundPacket
    786 ==================
    787 */
    788 void CL_ParseStartSoundPacket(void)
    789 {
    790     vec3_t  pos;
    791     int 	channel, ent;
    792     int 	sound_num;
    793     int 	volume;
    794     float 	attenuation;
    795  	int		i;
    796 
    797     channel = MSG_ReadShort();
    798 
    799     if (channel & SND_VOLUME)
    800 		volume = MSG_ReadByte ();
    801 	else
    802 		volume = DEFAULT_SOUND_PACKET_VOLUME;
    803 
    804     if (channel & SND_ATTENUATION)
    805 		attenuation = MSG_ReadByte () / 64.0;
    806 	else
    807 		attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;
    808 
    809 	sound_num = MSG_ReadByte ();
    810 
    811 	for (i=0 ; i<3 ; i++)
    812 		pos[i] = MSG_ReadCoord ();
    813 
    814 	ent = (channel>>3)&1023;
    815 	channel &= 7;
    816 
    817 	if (ent > MAX_EDICTS)
    818 		Host_EndGame ("CL_ParseStartSoundPacket: ent = %i", ent);
    819 
    820     S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation);
    821 }
    822 
    823 
    824 /*
    825 ==================
    826 CL_ParseClientdata
    827 
    828 Server information pertaining to this client only, sent every frame
    829 ==================
    830 */
    831 void CL_ParseClientdata (void)
    832 {
    833 	int				i;
    834 	float		latency;
    835 	frame_t		*frame;
    836 
    837 // calculate simulated time of message
    838 	oldparsecountmod = parsecountmod;
    839 
    840 	i = cls.netchan.incoming_acknowledged;
    841 	cl.parsecount = i;
    842 	i &= UPDATE_MASK;
    843 	parsecountmod = i;
    844 	frame = &cl.frames[i];
    845 	parsecounttime = cl.frames[i].senttime;
    846 
    847 	frame->receivedtime = realtime;
    848 
    849 // calculate latency
    850 	latency = frame->receivedtime - frame->senttime;
    851 
    852 	if (latency < 0 || latency > 1.0)
    853 	{
    854 //		Con_Printf ("Odd latency: %5.2f\n", latency);
    855 	}
    856 	else
    857 	{
    858 	// drift the average latency towards the observed latency
    859 		if (latency < cls.latency)
    860 			cls.latency = latency;
    861 		else
    862 			cls.latency += 0.001;	// drift up, so correction are needed
    863 	}
    864 }
    865 
    866 /*
    867 =====================
    868 CL_NewTranslation
    869 =====================
    870 */
    871 void CL_NewTranslation (int slot)
    872 {
    873 #ifdef GLQUAKE
    874 	if (slot > MAX_CLIENTS)
    875 		Sys_Error ("CL_NewTranslation: slot > MAX_CLIENTS");
    876 
    877 	R_TranslatePlayerSkin(slot);
    878 #else
    879 
    880 	int		i, j;
    881 	int		top, bottom;
    882 	byte	*dest, *source;
    883 	player_info_t	*player;
    884 	char s[512];
    885 
    886 	if (slot > MAX_CLIENTS)
    887 		Sys_Error ("CL_NewTranslation: slot > MAX_CLIENTS");
    888 
    889 	player = &cl.players[slot];
    890 
    891 	strcpy(s, Info_ValueForKey(player->userinfo, "skin"));
    892 	COM_StripExtension(s, s);
    893 	if (player->skin && !stricmp(s, player->skin->name))
    894 		player->skin = NULL;
    895 
    896 	if (player->_topcolor != player->topcolor ||
    897 		player->_bottomcolor != player->bottomcolor || !player->skin) {
    898 		player->_topcolor = player->topcolor;
    899 		player->_bottomcolor = player->bottomcolor;
    900 
    901 		dest = player->translations;
    902 		source = vid.colormap;
    903 		memcpy (dest, vid.colormap, sizeof(player->translations));
    904 		top = player->topcolor;
    905 		if (top > 13 || top < 0)
    906 			top = 13;
    907 		top *= 16;
    908 		bottom = player->bottomcolor;
    909 		if (bottom > 13 || bottom < 0)
    910 			bottom = 13;
    911 		bottom *= 16;
    912 
    913 		for (i=0 ; i<VID_GRADES ; i++, dest += 256, source+=256)
    914 		{
    915 			if (top < 128)	// the artists made some backwards ranges.  sigh.
    916 				memcpy (dest + TOP_RANGE, source + top, 16);
    917 			else
    918 				for (j=0 ; j<16 ; j++)
    919 					dest[TOP_RANGE+j] = source[top+15-j];
    920 
    921 			if (bottom < 128)
    922 				memcpy (dest + BOTTOM_RANGE, source + bottom, 16);
    923 			else
    924 				for (j=0 ; j<16 ; j++)
    925 					dest[BOTTOM_RANGE+j] = source[bottom+15-j];
    926 		}
    927 	}
    928 #endif
    929 }
    930 
    931 /*
    932 ==============
    933 CL_UpdateUserinfo
    934 ==============
    935 */
    936 void CL_ProcessUserInfo (int slot, player_info_t *player)
    937 {
    938 	strncpy (player->name, Info_ValueForKey (player->userinfo, "name"), sizeof(player->name)-1);
    939 	player->topcolor = atoi(Info_ValueForKey (player->userinfo, "topcolor"));
    940 	player->bottomcolor = atoi(Info_ValueForKey (player->userinfo, "bottomcolor"));
    941 	if (Info_ValueForKey (player->userinfo, "*spectator")[0])
    942 		player->spectator = true;
    943 	else
    944 		player->spectator = false;
    945 
    946 	if (cls.state == ca_active)
    947 		Skin_Find (player);
    948 
    949 	Sbar_Changed ();
    950 	CL_NewTranslation (slot);
    951 }
    952 
    953 /*
    954 ==============
    955 CL_UpdateUserinfo
    956 ==============
    957 */
    958 void CL_UpdateUserinfo (void)
    959 {
    960 	int		slot;
    961 	player_info_t	*player;
    962 
    963 	slot = MSG_ReadByte ();
    964 	if (slot >= MAX_CLIENTS)
    965 		Host_EndGame ("CL_ParseServerMessage: svc_updateuserinfo > MAX_SCOREBOARD");
    966 
    967 	player = &cl.players[slot];
    968 	player->userid = MSG_ReadLong ();
    969 	strncpy (player->userinfo, MSG_ReadString(), sizeof(player->userinfo)-1);
    970 
    971 	CL_ProcessUserInfo (slot, player);
    972 }
    973 
    974 /*
    975 ==============
    976 CL_SetInfo
    977 ==============
    978 */
    979 void CL_SetInfo (void)
    980 {
    981 	int		slot;
    982 	player_info_t	*player;
    983 	char key[MAX_MSGLEN];
    984 	char value[MAX_MSGLEN];
    985 
    986 	slot = MSG_ReadByte ();
    987 	if (slot >= MAX_CLIENTS)
    988 		Host_EndGame ("CL_ParseServerMessage: svc_setinfo > MAX_SCOREBOARD");
    989 
    990 	player = &cl.players[slot];
    991 
    992 	strncpy (key, MSG_ReadString(), sizeof(key) - 1);
    993 	key[sizeof(key) - 1] = 0;
    994 	strncpy (value, MSG_ReadString(), sizeof(value) - 1);
    995 	key[sizeof(value) - 1] = 0;
    996 
    997 	Con_DPrintf("SETINFO %s: %s=%s\n", player->name, key, value);
    998 
    999 	Info_SetValueForKey (player->userinfo, key, value, MAX_INFO_STRING);
   1000 
   1001 	CL_ProcessUserInfo (slot, player);
   1002 }
   1003 
   1004 /*
   1005 ==============
   1006 CL_ServerInfo
   1007 ==============
   1008 */
   1009 void CL_ServerInfo (void)
   1010 {
   1011 	int		slot;
   1012 	player_info_t	*player;
   1013 	char key[MAX_MSGLEN];
   1014 	char value[MAX_MSGLEN];
   1015 
   1016 	strncpy (key, MSG_ReadString(), sizeof(key) - 1);
   1017 	key[sizeof(key) - 1] = 0;
   1018 	strncpy (value, MSG_ReadString(), sizeof(value) - 1);
   1019 	key[sizeof(value) - 1] = 0;
   1020 
   1021 	Con_DPrintf("SERVERINFO: %s=%s\n", key, value);
   1022 
   1023 	Info_SetValueForKey (cl.serverinfo, key, value, MAX_SERVERINFO_STRING);
   1024 }
   1025 
   1026 /*
   1027 =====================
   1028 CL_SetStat
   1029 =====================
   1030 */
   1031 void CL_SetStat (int stat, int value)
   1032 {
   1033 	int	j;
   1034 	if (stat < 0 || stat >= MAX_CL_STATS)
   1035 		Sys_Error ("CL_SetStat: %i is invalid", stat);
   1036 
   1037 	Sbar_Changed ();
   1038 
   1039 	if (stat == STAT_ITEMS)
   1040 	{	// set flash times
   1041 		Sbar_Changed ();
   1042 		for (j=0 ; j<32 ; j++)
   1043 			if ( (value & (1<<j)) && !(cl.stats[stat] & (1<<j)))
   1044 				cl.item_gettime[j] = cl.time;
   1045 	}
   1046 
   1047 	cl.stats[stat] = value;
   1048 }
   1049 
   1050 /*
   1051 ==============
   1052 CL_MuzzleFlash
   1053 ==============
   1054 */
   1055 void CL_MuzzleFlash (void)
   1056 {
   1057 	vec3_t		fv, rv, uv;
   1058 	dlight_t	*dl;
   1059 	int			i;
   1060 	player_state_t	*pl;
   1061 
   1062 	i = MSG_ReadShort ();
   1063 
   1064 	if ((unsigned)(i-1) >= MAX_CLIENTS)
   1065 		return;
   1066 
   1067 #ifdef GLQUAKE
   1068 	// don't draw our own muzzle flash in gl if flashblending
   1069 	if (i-1 == cl.playernum && gl_flashblend.value)
   1070 		return;
   1071 #endif
   1072 
   1073 	pl = &cl.frames[parsecountmod].playerstate[i-1];
   1074 
   1075 	dl = CL_AllocDlight (i);
   1076 	VectorCopy (pl->origin,  dl->origin);
   1077 	AngleVectors (pl->viewangles, fv, rv, uv);
   1078 
   1079 	VectorMA (dl->origin, 18, fv, dl->origin);
   1080 	dl->radius = 200 + (rand()&31);
   1081 	dl->minlight = 32;
   1082 	dl->die = cl.time + 0.1;
   1083 	dl->color[0] = 0.2;
   1084 	dl->color[1] = 0.1;
   1085 	dl->color[2] = 0.05;
   1086 	dl->color[3] = 0.7;
   1087 }
   1088 
   1089 
   1090 #define SHOWNET(x) if(cl_shownet.value==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x);
   1091 /*
   1092 =====================
   1093 CL_ParseServerMessage
   1094 =====================
   1095 */
   1096 int	received_framecount;
   1097 void CL_ParseServerMessage (void)
   1098 {
   1099 	int			cmd;
   1100 	char		*s;
   1101 	int			i, j;
   1102 
   1103 	received_framecount = host_framecount;
   1104 	cl.last_servermessage = realtime;
   1105 	CL_ClearProjectiles ();
   1106 
   1107 //
   1108 // if recording demos, copy the message out
   1109 //
   1110 	if (cl_shownet.value == 1)
   1111 		Con_Printf ("%i ",net_message.cursize);
   1112 	else if (cl_shownet.value == 2)
   1113 		Con_Printf ("------------------\n");
   1114 
   1115 
   1116 	CL_ParseClientdata ();
   1117 
   1118 //
   1119 // parse the message
   1120 //
   1121 	while (1)
   1122 	{
   1123 		if (msg_badread)
   1124 		{
   1125 			Host_EndGame ("CL_ParseServerMessage: Bad server message");
   1126 			break;
   1127 		}
   1128 
   1129 		cmd = MSG_ReadByte ();
   1130 
   1131 		if (cmd == -1)
   1132 		{
   1133 			msg_readcount++;	// so the EOM showner has the right value
   1134 			SHOWNET("END OF MESSAGE");
   1135 			break;
   1136 		}
   1137 
   1138 		SHOWNET(svc_strings[cmd]);
   1139 
   1140 	// other commands
   1141 		switch (cmd)
   1142 		{
   1143 		default:
   1144 			Host_EndGame ("CL_ParseServerMessage: Illegible server message");
   1145 			break;
   1146 
   1147 		case svc_nop:
   1148 //			Con_Printf ("svc_nop\n");
   1149 			break;
   1150 
   1151 		case svc_disconnect:
   1152 			if (cls.state == ca_connected)
   1153 				Host_EndGame ("Server disconnected\n"
   1154 					"Server version may not be compatible");
   1155 			else
   1156 				Host_EndGame ("Server disconnected");
   1157 			break;
   1158 
   1159 		case svc_print:
   1160 			i = MSG_ReadByte ();
   1161 			if (i == PRINT_CHAT)
   1162 			{
   1163 				S_LocalSound ("misc/talk.wav");
   1164 				con_ormask = 128;
   1165 			}
   1166 			Con_Printf ("%s", MSG_ReadString ());
   1167 			con_ormask = 0;
   1168 			break;
   1169 
   1170 		case svc_centerprint:
   1171 			SCR_CenterPrint (MSG_ReadString ());
   1172 			break;
   1173 
   1174 		case svc_stufftext:
   1175 			s = MSG_ReadString ();
   1176 			Con_DPrintf ("stufftext: %s\n", s);
   1177 			Cbuf_AddText (s);
   1178 			break;
   1179 
   1180 		case svc_damage:
   1181 			V_ParseDamage ();
   1182 			break;
   1183 
   1184 		case svc_serverdata:
   1185 			Cbuf_Execute ();		// make sure any stuffed commands are done
   1186 			CL_ParseServerData ();
   1187 			vid.recalc_refdef = true;	// leave full screen intermission
   1188 			break;
   1189 
   1190 		case svc_setangle:
   1191 			for (i=0 ; i<3 ; i++)
   1192 				cl.viewangles[i] = MSG_ReadAngle ();
   1193 //			cl.viewangles[PITCH] = cl.viewangles[ROLL] = 0;
   1194 			break;
   1195 
   1196 		case svc_lightstyle:
   1197 			i = MSG_ReadByte ();
   1198 			if (i >= MAX_LIGHTSTYLES)
   1199 				Sys_Error ("svc_lightstyle > MAX_LIGHTSTYLES");
   1200 			Q_strcpy (cl_lightstyle[i].map,  MSG_ReadString());
   1201 			cl_lightstyle[i].length = Q_strlen(cl_lightstyle[i].map);
   1202 			break;
   1203 
   1204 		case svc_sound:
   1205 			CL_ParseStartSoundPacket();
   1206 			break;
   1207 
   1208 		case svc_stopsound:
   1209 			i = MSG_ReadShort();
   1210 			S_StopSound(i>>3, i&7);
   1211 			break;
   1212 
   1213 		case svc_updatefrags:
   1214 			Sbar_Changed ();
   1215 			i = MSG_ReadByte ();
   1216 			if (i >= MAX_CLIENTS)
   1217 				Host_EndGame ("CL_ParseServerMessage: svc_updatefrags > MAX_SCOREBOARD");
   1218 			cl.players[i].frags = MSG_ReadShort ();
   1219 			break;
   1220 
   1221 		case svc_updateping:
   1222 			i = MSG_ReadByte ();
   1223 			if (i >= MAX_CLIENTS)
   1224 				Host_EndGame ("CL_ParseServerMessage: svc_updateping > MAX_SCOREBOARD");
   1225 			cl.players[i].ping = MSG_ReadShort ();
   1226 			break;
   1227 
   1228 		case svc_updatepl:
   1229 			i = MSG_ReadByte ();
   1230 			if (i >= MAX_CLIENTS)
   1231 				Host_EndGame ("CL_ParseServerMessage: svc_updatepl > MAX_SCOREBOARD");
   1232 			cl.players[i].pl = MSG_ReadByte ();
   1233 			break;
   1234 
   1235 		case svc_updateentertime:
   1236 		// time is sent over as seconds ago
   1237 			i = MSG_ReadByte ();
   1238 			if (i >= MAX_CLIENTS)
   1239 				Host_EndGame ("CL_ParseServerMessage: svc_updateentertime > MAX_SCOREBOARD");
   1240 			cl.players[i].entertime = realtime - MSG_ReadFloat ();
   1241 			break;
   1242 
   1243 		case svc_spawnbaseline:
   1244 			i = MSG_ReadShort ();
   1245 			CL_ParseBaseline (&cl_baselines[i]);
   1246 			break;
   1247 		case svc_spawnstatic:
   1248 			CL_ParseStatic ();
   1249 			break;
   1250 		case svc_temp_entity:
   1251 			CL_ParseTEnt ();
   1252 			break;
   1253 
   1254 		case svc_killedmonster:
   1255 			cl.stats[STAT_MONSTERS]++;
   1256 			break;
   1257 
   1258 		case svc_foundsecret:
   1259 			cl.stats[STAT_SECRETS]++;
   1260 			break;
   1261 
   1262 		case svc_updatestat:
   1263 			i = MSG_ReadByte ();
   1264 			j = MSG_ReadByte ();
   1265 			CL_SetStat (i, j);
   1266 			break;
   1267 		case svc_updatestatlong:
   1268 			i = MSG_ReadByte ();
   1269 			j = MSG_ReadLong ();
   1270 			CL_SetStat (i, j);
   1271 			break;
   1272 
   1273 		case svc_spawnstaticsound:
   1274 			CL_ParseStaticSound ();
   1275 			break;
   1276 
   1277 		case svc_cdtrack:
   1278 			cl.cdtrack = MSG_ReadByte ();
   1279 			CDAudio_Play ((byte)cl.cdtrack, true);
   1280 			break;
   1281 
   1282 		case svc_intermission:
   1283 			cl.intermission = 1;
   1284 			cl.completed_time = realtime;
   1285 			vid.recalc_refdef = true;	// go to full screen
   1286 			for (i=0 ; i<3 ; i++)
   1287 				cl.simorg[i] = MSG_ReadCoord ();
   1288 			for (i=0 ; i<3 ; i++)
   1289 				cl.simangles[i] = MSG_ReadAngle ();
   1290 			VectorCopy (vec3_origin, cl.simvel);
   1291 			break;
   1292 
   1293 		case svc_finale:
   1294 			cl.intermission = 2;
   1295 			cl.completed_time = realtime;
   1296 			vid.recalc_refdef = true;	// go to full screen
   1297 			SCR_CenterPrint (MSG_ReadString ());
   1298 			break;
   1299 
   1300 		case svc_sellscreen:
   1301 			Cmd_ExecuteString ("help");
   1302 			break;
   1303 
   1304 		case svc_smallkick:
   1305 			cl.punchangle = -2;
   1306 			break;
   1307 		case svc_bigkick:
   1308 			cl.punchangle = -4;
   1309 			break;
   1310 
   1311 		case svc_muzzleflash:
   1312 			CL_MuzzleFlash ();
   1313 			break;
   1314 
   1315 		case svc_updateuserinfo:
   1316 			CL_UpdateUserinfo ();
   1317 			break;
   1318 
   1319 		case svc_setinfo:
   1320 			CL_SetInfo ();
   1321 			break;
   1322 
   1323 		case svc_serverinfo:
   1324 			CL_ServerInfo ();
   1325 			break;
   1326 
   1327 		case svc_download:
   1328 			CL_ParseDownload ();
   1329 			break;
   1330 
   1331 		case svc_playerinfo:
   1332 			CL_ParsePlayerinfo ();
   1333 			break;
   1334 
   1335 		case svc_nails:
   1336 			CL_ParseProjectiles ();
   1337 			break;
   1338 
   1339 		case svc_chokecount:		// some preceding packets were choked
   1340 			i = MSG_ReadByte ();
   1341 			for (j=0 ; j<i ; j++)
   1342 				cl.frames[ (cls.netchan.incoming_acknowledged-1-j)&UPDATE_MASK ].receivedtime = -2;
   1343 			break;
   1344 
   1345 		case svc_modellist:
   1346 			CL_ParseModellist ();
   1347 			break;
   1348 
   1349 		case svc_soundlist:
   1350 			CL_ParseSoundlist ();
   1351 			break;
   1352 
   1353 		case svc_packetentities:
   1354 			CL_ParsePacketEntities (false);
   1355 			break;
   1356 
   1357 		case svc_deltapacketentities:
   1358 			CL_ParsePacketEntities (true);
   1359 			break;
   1360 
   1361 		case svc_maxspeed :
   1362 			movevars.maxspeed = MSG_ReadFloat();
   1363 			break;
   1364 
   1365 		case svc_entgravity :
   1366 			movevars.entgravity = MSG_ReadFloat();
   1367 			break;
   1368 
   1369 		case svc_setpause:
   1370 			cl.paused = MSG_ReadByte ();
   1371 			if (cl.paused)
   1372 				CDAudio_Pause ();
   1373 			else
   1374 				CDAudio_Resume ();
   1375 			break;
   1376 
   1377 		}
   1378 	}
   1379 
   1380 	CL_SetSolidEntities ();
   1381 }
   1382 
   1383 
   1384