• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 const 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_serverinfo",		// [long] version
40 						// [string] signon string
41 						// [string]..[0]model cache [string]...[0]sounds cache
42 						// [string]..[0]item cache
43 	"svc_lightstyle",		// [byte] [string]
44 	"svc_updatename",		// [byte] [string]
45 	"svc_updatefrags",	// [byte] [short]
46 	"svc_clientdata",		// <shortbits + data>
47 	"svc_stopsound",		// <see code>
48 	"svc_updatecolors",	// [byte] [byte]
49 	"svc_particle",		// [vec3] <variable>
50 	"svc_damage",			// [byte] impact [byte] blood [vec3] from
51 
52 	"svc_spawnstatic",
53 	"OBSOLETE svc_spawnbinary",
54 	"svc_spawnbaseline",
55 
56 	"svc_temp_entity",		// <variable>
57 	"svc_setpause",
58 	"svc_signonnum",
59 	"svc_centerprint",
60 	"svc_killedmonster",
61 	"svc_foundsecret",
62 	"svc_spawnstaticsound",
63 	"svc_intermission",
64 	"svc_finale",			// [string] music [string] text
65 	"svc_cdtrack",			// [byte] track [byte] looptrack
66 	"svc_sellscreen",
67 	"svc_cutscene"
68 };
69 
70 //=============================================================================
71 
72 /*
73 ===============
74 CL_EntityNum
75 
76 This error checks and tracks the total number of entities
77 ===============
78 */
CL_EntityNum(int num)79 entity_t	*CL_EntityNum (int num)
80 {
81 	if (num >= cl.num_entities)
82 	{
83 		if (num >= MAX_EDICTS)
84 			Host_Error ("CL_EntityNum: %i is an invalid number",num);
85 		while (cl.num_entities<=num)
86 		{
87 			cl_entities[cl.num_entities].colormap = vid.colormap;
88 			cl.num_entities++;
89 		}
90 	}
91 
92 	return &cl_entities[num];
93 }
94 
95 
96 /*
97 ==================
98 CL_ParseStartSoundPacket
99 ==================
100 */
CL_ParseStartSoundPacket(void)101 void CL_ParseStartSoundPacket(void)
102 {
103     vec3_t  pos;
104     int 	channel, ent;
105     int 	sound_num;
106     int 	volume;
107     int 	field_mask;
108     float 	attenuation;
109  	int		i;
110 
111     field_mask = MSG_ReadByte();
112 
113     if (field_mask & SND_VOLUME)
114 		volume = MSG_ReadByte ();
115 	else
116 		volume = DEFAULT_SOUND_PACKET_VOLUME;
117 
118     if (field_mask & SND_ATTENUATION)
119 		attenuation = MSG_ReadByte () / 64.0;
120 	else
121 		attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;
122 
123 	channel = MSG_ReadShort ();
124 	sound_num = MSG_ReadByte ();
125 
126 	ent = channel >> 3;
127 	channel &= 7;
128 
129 	if (ent > MAX_EDICTS)
130 		Host_Error ("CL_ParseStartSoundPacket: ent = %i", ent);
131 
132 	for (i=0 ; i<3 ; i++)
133 		pos[i] = MSG_ReadCoord ();
134 
135     S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation);
136 }
137 
138 /*
139 ==================
140 CL_KeepaliveMessage
141 
142 When the client is taking a long time to load stuff, send keepalive messages
143 so the server doesn't disconnect.
144 ==================
145 */
CL_KeepaliveMessage(void)146 void CL_KeepaliveMessage (void)
147 {
148 	float	time;
149 	static float lastmsg;
150 	int		ret;
151 	sizebuf_t	old;
152 	byte		olddata[8192];
153 
154 	if (sv.active)
155 		return;		// no need if server is local
156 	if (cls.demoplayback)
157 		return;
158 
159 // read messages from server, should just be nops
160 	old = net_message;
161 	memcpy (olddata, net_message.data, net_message.cursize);
162 
163 	do
164 	{
165 		ret = CL_GetMessage ();
166 		switch (ret)
167 		{
168 		default:
169 			Host_Error ("CL_KeepaliveMessage: CL_GetMessage failed");
170 		case 0:
171 			break;	// nothing waiting
172 		case 1:
173 			Host_Error ("CL_KeepaliveMessage: received a message");
174 			break;
175 		case 2:
176 			if (MSG_ReadByte() != svc_nop)
177 				Host_Error ("CL_KeepaliveMessage: datagram wasn't a nop");
178 			break;
179 		}
180 	} while (ret);
181 
182 	net_message = old;
183 	memcpy (net_message.data, olddata, net_message.cursize);
184 
185 // check time
186 	time = Sys_FloatTime ();
187 	if (time - lastmsg < 5)
188 		return;
189 	lastmsg = time;
190 
191 // write out a nop
192 	Con_Printf ("--> client to server keepalive\n");
193 
194 	MSG_WriteByte (&cls.message, clc_nop);
195 	NET_SendMessage (cls.netcon, &cls.message);
196 	SZ_Clear (&cls.message);
197 }
198 
199 /*
200 ==================
201 CL_ParseServerInfo
202 ==================
203 */
CL_ParseServerInfo(void)204 void CL_ParseServerInfo (void)
205 {
206 	char	*str;
207 	int		i;
208 	int		nummodels, numsounds;
209 	char	model_precache[MAX_MODELS][MAX_QPATH];
210 	char	sound_precache[MAX_SOUNDS][MAX_QPATH];
211 
212 	Con_DPrintf ("Serverinfo packet received.\n");
213 //
214 // wipe the client_state_t struct
215 //
216 	CL_ClearState ();
217 
218 // parse protocol version number
219 	i = MSG_ReadLong ();
220 	if (i != PROTOCOL_VERSION)
221 	{
222 		Con_Printf ("Server returned version %i, not %i", i, PROTOCOL_VERSION);
223 		return;
224 	}
225 
226 // parse maxclients
227 	cl.maxclients = MSG_ReadByte ();
228 	if (cl.maxclients < 1 || cl.maxclients > MAX_SCOREBOARD)
229 	{
230 		Con_Printf("Bad maxclients (%u) from server\n", cl.maxclients);
231 		return;
232 	}
233 	cl.scores = (scoreboard_t*) Hunk_AllocName (cl.maxclients*sizeof(*cl.scores), "scores");
234 
235 // parse gametype
236 	cl.gametype = MSG_ReadByte ();
237 
238 // parse signon message
239 	str = MSG_ReadString ();
240 	strncpy (cl.levelname, str, sizeof(cl.levelname)-1);
241 
242 // seperate the printfs so the server message can have a color
243 	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");
244 	Con_Printf ("%c%s\n", 2, str);
245 
246 //
247 // first we go through and touch all of the precache data that still
248 // happens to be in the cache, so precaching something else doesn't
249 // needlessly purge it
250 //
251 
252 // precache models
253 	memset (cl.model_precache, 0, sizeof(cl.model_precache));
254 	for (nummodels=1 ; ; nummodels++)
255 	{
256 		str = MSG_ReadString ();
257 		if (!str[0])
258 			break;
259 		if (nummodels==MAX_MODELS)
260 		{
261 			Con_Printf ("Server sent too many model precaches\n");
262 			return;
263 		}
264 		strcpy (model_precache[nummodels], str);
265 		Mod_TouchModel (str);
266 	}
267 
268 // precache sounds
269 	memset (cl.sound_precache, 0, sizeof(cl.sound_precache));
270 	for (numsounds=1 ; ; numsounds++)
271 	{
272 		str = MSG_ReadString ();
273 		if (!str[0])
274 			break;
275 		if (numsounds==MAX_SOUNDS)
276 		{
277 			Con_Printf ("Server sent too many sound precaches\n");
278 			return;
279 		}
280 		strcpy (sound_precache[numsounds], str);
281 		S_TouchSound (str);
282 	}
283 
284 //
285 // now we try to load everything else until a cache allocation fails
286 //
287 
288 	for (i=1 ; i<nummodels ; i++)
289 	{
290 		cl.model_precache[i] = Mod_ForName (model_precache[i], false);
291 		if (cl.model_precache[i] == NULL)
292 		{
293 			Con_Printf("Model %s not found\n", model_precache[i]);
294 			return;
295 		}
296 		CL_KeepaliveMessage ();
297 	}
298 
299 	S_BeginPrecaching ();
300 	for (i=1 ; i<numsounds ; i++)
301 	{
302 		cl.sound_precache[i] = S_PrecacheSound (sound_precache[i]);
303 		CL_KeepaliveMessage ();
304 	}
305 	S_EndPrecaching ();
306 
307 
308 // local state
309 	cl_entities[0].model = cl.worldmodel = cl.model_precache[1];
310 
311 	R_NewMap ();
312 
313 	Hunk_Check ();		// make sure nothing is hurt
314 
315 	noclip_anglehack = false;		// noclip is turned off at start
316 }
317 
318 
319 /*
320 ==================
321 CL_ParseUpdate
322 
323 Parse an entity update message from the server
324 If an entities model or origin changes from frame to frame, it must be
325 relinked.  Other attributes can change without relinking.
326 ==================
327 */
328 int	bitcounts[16];
329 
CL_ParseUpdate(int bits)330 void CL_ParseUpdate (int bits)
331 {
332 	int			i;
333 	model_t		*model;
334 	int			modnum;
335 	qboolean	forcelink;
336 	entity_t	*ent;
337 	int			num;
338 	int			skin;
339 
340 	if (cls.signon == SIGNONS - 1)
341 	{	// first update is the final signon stage
342 		cls.signon = SIGNONS;
343 		CL_SignonReply ();
344 	}
345 
346 	if (bits & U_MOREBITS)
347 	{
348 		i = MSG_ReadByte ();
349 		bits |= (i<<8);
350 	}
351 
352 	if (bits & U_LONGENTITY)
353 		num = MSG_ReadShort ();
354 	else
355 		num = MSG_ReadByte ();
356 
357 	ent = CL_EntityNum (num);
358 
359 for (i=0 ; i<16 ; i++)
360 if (bits&(1<<i))
361 	bitcounts[i]++;
362 
363 	if (ent->msgtime != cl.mtime[1])
364 		forcelink = true;	// no previous frame to lerp from
365 	else
366 		forcelink = false;
367 
368 	ent->msgtime = cl.mtime[0];
369 
370 	if (bits & U_MODEL)
371 	{
372 		modnum = MSG_ReadByte ();
373 		if (modnum >= MAX_MODELS)
374 			Host_Error ("CL_ParseModel: bad modnum");
375 	}
376 	else
377 		modnum = ent->baseline.modelindex;
378 
379 	model = cl.model_precache[modnum];
380 	if (model != ent->model)
381 	{
382 		ent->model = model;
383 	// automatic animation (torches, etc) can be either all together
384 	// or randomized
385 		if (model)
386 		{
387 			if (model->synctype == ST_RAND)
388 				ent->syncbase = (float)(rand()&0x7fff) / 0x7fff;
389 			else
390 				ent->syncbase = 0.0;
391 		}
392 		else
393 			forcelink = true;	// hack to make null model players work
394 #ifdef GLQUAKE
395 		if (num > 0 && num <= cl.maxclients)
396 			R_TranslatePlayerSkin (num - 1);
397 #endif
398 	}
399 
400 	if (bits & U_FRAME)
401 		ent->frame = MSG_ReadByte ();
402 	else
403 		ent->frame = ent->baseline.frame;
404 
405 	if (bits & U_COLORMAP)
406 		i = MSG_ReadByte();
407 	else
408 		i = ent->baseline.colormap;
409 	if (!i)
410 		ent->colormap = vid.colormap;
411 	else
412 	{
413 		if (i > cl.maxclients)
414 			Sys_Error ("i >= cl.maxclients");
415 		ent->colormap = cl.scores[i-1].translations;
416 	}
417 
418 #ifdef GLQUAKE
419 	if (bits & U_SKIN)
420 		skin = MSG_ReadByte();
421 	else
422 		skin = ent->baseline.skin;
423 	if (skin != ent->skinnum) {
424 		ent->skinnum = skin;
425 		if (num > 0 && num <= cl.maxclients)
426 			R_TranslatePlayerSkin (num - 1);
427 	}
428 
429 #else
430 
431 	if (bits & U_SKIN)
432 		ent->skinnum = MSG_ReadByte();
433 	else
434 		ent->skinnum = ent->baseline.skin;
435 #endif
436 
437 	if (bits & U_EFFECTS)
438 		ent->effects = MSG_ReadByte();
439 	else
440 		ent->effects = ent->baseline.effects;
441 
442 // shift the known values for interpolation
443 	VectorCopy (ent->msg_origins[0], ent->msg_origins[1]);
444 	VectorCopy (ent->msg_angles[0], ent->msg_angles[1]);
445 
446 	if (bits & U_ORIGIN1)
447 		ent->msg_origins[0][0] = MSG_ReadCoord ();
448 	else
449 		ent->msg_origins[0][0] = ent->baseline.origin[0];
450 	if (bits & U_ANGLE1)
451 		ent->msg_angles[0][0] = MSG_ReadAngle();
452 	else
453 		ent->msg_angles[0][0] = ent->baseline.angles[0];
454 
455 	if (bits & U_ORIGIN2)
456 		ent->msg_origins[0][1] = MSG_ReadCoord ();
457 	else
458 		ent->msg_origins[0][1] = ent->baseline.origin[1];
459 	if (bits & U_ANGLE2)
460 		ent->msg_angles[0][1] = MSG_ReadAngle();
461 	else
462 		ent->msg_angles[0][1] = ent->baseline.angles[1];
463 
464 	if (bits & U_ORIGIN3)
465 		ent->msg_origins[0][2] = MSG_ReadCoord ();
466 	else
467 		ent->msg_origins[0][2] = ent->baseline.origin[2];
468 	if (bits & U_ANGLE3)
469 		ent->msg_angles[0][2] = MSG_ReadAngle();
470 	else
471 		ent->msg_angles[0][2] = ent->baseline.angles[2];
472 
473 	if ( bits & U_NOLERP )
474 		ent->forcelink = true;
475 
476 	if ( forcelink )
477 	{	// didn't have an update last message
478 		VectorCopy (ent->msg_origins[0], ent->msg_origins[1]);
479 		VectorCopy (ent->msg_origins[0], ent->origin);
480 		VectorCopy (ent->msg_angles[0], ent->msg_angles[1]);
481 		VectorCopy (ent->msg_angles[0], ent->angles);
482 		ent->forcelink = true;
483 	}
484 }
485 
486 /*
487 ==================
488 CL_ParseBaseline
489 ==================
490 */
CL_ParseBaseline(entity_t * ent)491 void CL_ParseBaseline (entity_t *ent)
492 {
493 	int			i;
494 
495 	ent->baseline.modelindex = MSG_ReadByte ();
496 	ent->baseline.frame = MSG_ReadByte ();
497 	ent->baseline.colormap = MSG_ReadByte();
498 	ent->baseline.skin = MSG_ReadByte();
499 	for (i=0 ; i<3 ; i++)
500 	{
501 		ent->baseline.origin[i] = MSG_ReadCoord ();
502 		ent->baseline.angles[i] = MSG_ReadAngle ();
503 	}
504 }
505 
506 
507 /*
508 ==================
509 CL_ParseClientdata
510 
511 Server information pertaining to this client only
512 ==================
513 */
CL_ParseClientdata(int bits)514 void CL_ParseClientdata (int bits)
515 {
516 	int		i, j;
517 
518 	if (bits & SU_VIEWHEIGHT)
519 		cl.viewheight = MSG_ReadChar ();
520 	else
521 		cl.viewheight = DEFAULT_VIEWHEIGHT;
522 
523 	if (bits & SU_IDEALPITCH)
524 		cl.idealpitch = MSG_ReadChar ();
525 	else
526 		cl.idealpitch = 0;
527 
528 	VectorCopy (cl.mvelocity[0], cl.mvelocity[1]);
529 	for (i=0 ; i<3 ; i++)
530 	{
531 		if (bits & (SU_PUNCH1<<i) )
532 			cl.punchangle[i] = MSG_ReadChar();
533 		else
534 			cl.punchangle[i] = 0;
535 		if (bits & (SU_VELOCITY1<<i) )
536 			cl.mvelocity[0][i] = MSG_ReadChar()*16;
537 		else
538 			cl.mvelocity[0][i] = 0;
539 	}
540 
541 // [always sent]	if (bits & SU_ITEMS)
542 		i = MSG_ReadLong ();
543 
544 	if (cl.items != i)
545 	{	// set flash times
546 		Sbar_Changed ();
547 		for (j=0 ; j<32 ; j++)
548 			if ( (i & (1<<j)) && !(cl.items & (1<<j)))
549 				cl.item_gettime[j] = cl.time;
550 		cl.items = i;
551 	}
552 
553 	cl.onground = (bits & SU_ONGROUND) != 0;
554 	cl.inwater = (bits & SU_INWATER) != 0;
555 
556 	if (bits & SU_WEAPONFRAME)
557 		cl.stats[STAT_WEAPONFRAME] = MSG_ReadByte ();
558 	else
559 		cl.stats[STAT_WEAPONFRAME] = 0;
560 
561 	if (bits & SU_ARMOR)
562 		i = MSG_ReadByte ();
563 	else
564 		i = 0;
565 	if (cl.stats[STAT_ARMOR] != i)
566 	{
567 		cl.stats[STAT_ARMOR] = i;
568 		Sbar_Changed ();
569 	}
570 
571 	if (bits & SU_WEAPON)
572 		i = MSG_ReadByte ();
573 	else
574 		i = 0;
575 	if (cl.stats[STAT_WEAPON] != i)
576 	{
577 		cl.stats[STAT_WEAPON] = i;
578 		Sbar_Changed ();
579 	}
580 
581 	i = MSG_ReadShort ();
582 	if (cl.stats[STAT_HEALTH] != i)
583 	{
584 		cl.stats[STAT_HEALTH] = i;
585 		Sbar_Changed ();
586 	}
587 
588 	i = MSG_ReadByte ();
589 	if (cl.stats[STAT_AMMO] != i)
590 	{
591 		cl.stats[STAT_AMMO] = i;
592 		Sbar_Changed ();
593 	}
594 
595 	for (i=0 ; i<4 ; i++)
596 	{
597 		j = MSG_ReadByte ();
598 		if (cl.stats[STAT_SHELLS+i] != j)
599 		{
600 			cl.stats[STAT_SHELLS+i] = j;
601 			Sbar_Changed ();
602 		}
603 	}
604 
605 	i = MSG_ReadByte ();
606 
607 	if (standard_quake)
608 	{
609 		if (cl.stats[STAT_ACTIVEWEAPON] != i)
610 		{
611 			cl.stats[STAT_ACTIVEWEAPON] = i;
612 			Sbar_Changed ();
613 		}
614 	}
615 	else
616 	{
617 		if (cl.stats[STAT_ACTIVEWEAPON] != (1<<i))
618 		{
619 			cl.stats[STAT_ACTIVEWEAPON] = (1<<i);
620 			Sbar_Changed ();
621 		}
622 	}
623 }
624 
625 /*
626 =====================
627 CL_NewTranslation
628 =====================
629 */
CL_NewTranslation(int slot)630 void CL_NewTranslation (int slot)
631 {
632 	int		i, j;
633 	int		top, bottom;
634 	byte	*dest, *source;
635 
636 	if (slot > cl.maxclients)
637 		Sys_Error ("CL_NewTranslation: slot > cl.maxclients");
638 	dest = cl.scores[slot].translations;
639 	source = vid.colormap;
640 	memcpy (dest, vid.colormap, sizeof(cl.scores[slot].translations));
641 	top = cl.scores[slot].colors & 0xf0;
642 	bottom = (cl.scores[slot].colors &15)<<4;
643 #ifdef GLQUAKE
644 	R_TranslatePlayerSkin (slot);
645 #endif
646 
647 	for (i=0 ; i<VID_GRADES ; i++, dest += 256, source+=256)
648 	{
649 		if (top < 128)	// the artists made some backwards ranges.  sigh.
650 			memcpy (dest + TOP_RANGE, source + top, 16);
651 		else
652 			for (j=0 ; j<16 ; j++)
653 				dest[TOP_RANGE+j] = source[top+15-j];
654 
655 		if (bottom < 128)
656 			memcpy (dest + BOTTOM_RANGE, source + bottom, 16);
657 		else
658 			for (j=0 ; j<16 ; j++)
659 				dest[BOTTOM_RANGE+j] = source[bottom+15-j];
660 	}
661 }
662 
663 /*
664 =====================
665 CL_ParseStatic
666 =====================
667 */
CL_ParseStatic(void)668 void CL_ParseStatic (void)
669 {
670 	entity_t *ent;
671 	int		i;
672 
673 	i = cl.num_statics;
674 	if (i >= MAX_STATIC_ENTITIES)
675 		Host_Error ("Too many static entities");
676 	ent = &cl_static_entities[i];
677 	cl.num_statics++;
678 	CL_ParseBaseline (ent);
679 
680 // copy it to the current state
681 	ent->model = cl.model_precache[ent->baseline.modelindex];
682 	ent->frame = ent->baseline.frame;
683 	ent->colormap = vid.colormap;
684 	ent->skinnum = ent->baseline.skin;
685 	ent->effects = ent->baseline.effects;
686 
687 	VectorCopy (ent->baseline.origin, ent->origin);
688 	VectorCopy (ent->baseline.angles, ent->angles);
689 	R_AddEfrags (ent);
690 }
691 
692 /*
693 ===================
694 CL_ParseStaticSound
695 ===================
696 */
CL_ParseStaticSound(void)697 void CL_ParseStaticSound (void)
698 {
699 	vec3_t		org;
700 	int			sound_num, vol, atten;
701 	int			i;
702 
703 	for (i=0 ; i<3 ; i++)
704 		org[i] = MSG_ReadCoord ();
705 	sound_num = MSG_ReadByte ();
706 	vol = MSG_ReadByte ();
707 	atten = MSG_ReadByte ();
708 
709 	S_StaticSound (cl.sound_precache[sound_num], org, vol, atten);
710 }
711 
712 
713 #define SHOWNET(x) if(cl_shownet.value==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x);
714 
715 /*
716 =====================
717 CL_ParseServerMessage
718 =====================
719 */
CL_ParseServerMessage(void)720 void CL_ParseServerMessage (void)
721 {
722 	int			cmd;
723 	int			i;
724 
725 //
726 // if recording demos, copy the message out
727 //
728 	if (cl_shownet.value == 1)
729 		Con_Printf ("%i ",net_message.cursize);
730 	else if (cl_shownet.value == 2)
731 		Con_Printf ("------------------\n");
732 
733 	cl.onground = false;	// unless the server says otherwise
734 //
735 // parse the message
736 //
737 	MSG_BeginReading ();
738 
739 	while (1)
740 	{
741 		if (msg_badread)
742 			Host_Error ("CL_ParseServerMessage: Bad server message");
743 
744 		cmd = MSG_ReadByte ();
745 
746 		if (cmd == -1)
747 		{
748 			SHOWNET("END OF MESSAGE");
749 			return;		// end of message
750 		}
751 
752 	// if the high bit of the command byte is set, it is a fast update
753 		if (cmd & 128)
754 		{
755 			SHOWNET("fast update");
756 			CL_ParseUpdate (cmd&127);
757 			continue;
758 		}
759 
760 		SHOWNET(svc_strings[cmd]);
761 
762 	// other commands
763 		switch (cmd)
764 		{
765 		default:
766 			Host_Error ("CL_ParseServerMessage: Illegible server message\n");
767 			break;
768 
769 		case svc_nop:
770 //			Con_Printf ("svc_nop\n");
771 			break;
772 
773 		case svc_time:
774 			cl.mtime[1] = cl.mtime[0];
775 			cl.mtime[0] = MSG_ReadFloat ();
776 			break;
777 
778 		case svc_clientdata:
779 			i = MSG_ReadShort ();
780 			CL_ParseClientdata (i);
781 			break;
782 
783 		case svc_version:
784 			i = MSG_ReadLong ();
785 			if (i != PROTOCOL_VERSION)
786 				Host_Error ("CL_ParseServerMessage: Server is protocol %i instead of %i\n", i, PROTOCOL_VERSION);
787 			break;
788 
789 		case svc_disconnect:
790 			Host_EndGame ("Server disconnected\n");
791 
792 		case svc_print:
793 			Con_Printf ("%s", MSG_ReadString ());
794 			break;
795 
796 		case svc_centerprint:
797 			SCR_CenterPrint (MSG_ReadString ());
798 			break;
799 
800 		case svc_stufftext:
801 			Cbuf_AddText (MSG_ReadString ());
802 			break;
803 
804 		case svc_damage:
805 			V_ParseDamage ();
806 			break;
807 
808 		case svc_serverinfo:
809 			CL_ParseServerInfo ();
810 			vid.recalc_refdef = true;	// leave intermission full screen
811 			break;
812 
813 		case svc_setangle:
814 			for (i=0 ; i<3 ; i++)
815 				cl.viewangles[i] = MSG_ReadAngle ();
816 			break;
817 
818 		case svc_setview:
819 			cl.viewentity = MSG_ReadShort ();
820 			break;
821 
822 		case svc_lightstyle:
823 			i = MSG_ReadByte ();
824 			if (i >= MAX_LIGHTSTYLES)
825 				Sys_Error ("svc_lightstyle > MAX_LIGHTSTYLES");
826 			Q_strcpy (cl_lightstyle[i].map,  MSG_ReadString());
827 			cl_lightstyle[i].length = Q_strlen(cl_lightstyle[i].map);
828 			break;
829 
830 		case svc_sound:
831 			CL_ParseStartSoundPacket();
832 			break;
833 
834 		case svc_stopsound:
835 			i = MSG_ReadShort();
836 			S_StopSound(i>>3, i&7);
837 			break;
838 
839 		case svc_updatename:
840 			Sbar_Changed ();
841 			i = MSG_ReadByte ();
842 			if (i >= cl.maxclients)
843 				Host_Error ("CL_ParseServerMessage: svc_updatename > MAX_SCOREBOARD");
844 			strcpy (cl.scores[i].name, MSG_ReadString ());
845 			break;
846 
847 		case svc_updatefrags:
848 			Sbar_Changed ();
849 			i = MSG_ReadByte ();
850 			if (i >= cl.maxclients)
851 				Host_Error ("CL_ParseServerMessage: svc_updatefrags > MAX_SCOREBOARD");
852 			cl.scores[i].frags = MSG_ReadShort ();
853 			break;
854 
855 		case svc_updatecolors:
856 			Sbar_Changed ();
857 			i = MSG_ReadByte ();
858 			if (i >= cl.maxclients)
859 				Host_Error ("CL_ParseServerMessage: svc_updatecolors > MAX_SCOREBOARD");
860 			cl.scores[i].colors = MSG_ReadByte ();
861 			CL_NewTranslation (i);
862 			break;
863 
864 		case svc_particle:
865 			R_ParseParticleEffect ();
866 			break;
867 
868 		case svc_spawnbaseline:
869 			i = MSG_ReadShort ();
870 			// must use CL_EntityNum() to force cl.num_entities up
871 			CL_ParseBaseline (CL_EntityNum(i));
872 			break;
873 		case svc_spawnstatic:
874 			CL_ParseStatic ();
875 			break;
876 		case svc_temp_entity:
877 			CL_ParseTEnt ();
878 			break;
879 
880 		case svc_setpause:
881 			{
882 				cl.paused = MSG_ReadByte ();
883 
884 				if (cl.paused)
885 				{
886 					CDAudio_Pause ();
887 #ifdef _WIN32
888 					VID_HandlePause (true);
889 #endif
890 				}
891 				else
892 				{
893 					CDAudio_Resume ();
894 #ifdef _WIN32
895 					VID_HandlePause (false);
896 #endif
897 				}
898 			}
899 			break;
900 
901 		case svc_signonnum:
902 			i = MSG_ReadByte ();
903 			if (i <= cls.signon)
904 				Host_Error ("Received signon %i when at %i", i, cls.signon);
905 			cls.signon = i;
906 			CL_SignonReply ();
907 			break;
908 
909 		case svc_killedmonster:
910 			cl.stats[STAT_MONSTERS]++;
911 			break;
912 
913 		case svc_foundsecret:
914 			cl.stats[STAT_SECRETS]++;
915 			break;
916 
917 		case svc_updatestat:
918 			i = MSG_ReadByte ();
919 			if (i < 0 || i >= MAX_CL_STATS)
920 				Sys_Error ("svc_updatestat: %i is invalid", i);
921 			cl.stats[i] = MSG_ReadLong ();;
922 			break;
923 
924 		case svc_spawnstaticsound:
925 			CL_ParseStaticSound ();
926 			break;
927 
928 		case svc_cdtrack:
929 			cl.cdtrack = MSG_ReadByte ();
930 			cl.looptrack = MSG_ReadByte ();
931 			if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )
932 				CDAudio_Play ((byte)cls.forcetrack, true);
933 			else
934 				CDAudio_Play ((byte)cl.cdtrack, true);
935 			break;
936 
937 		case svc_intermission:
938 			cl.intermission = 1;
939 			cl.completed_time = (int) cl.time;
940 			vid.recalc_refdef = true;	// go to full screen
941 			break;
942 
943 		case svc_finale:
944 			cl.intermission = 2;
945 			cl.completed_time = (int) cl.time;
946 			vid.recalc_refdef = true;	// go to full screen
947 			SCR_CenterPrint (MSG_ReadString ());
948 			break;
949 
950 		case svc_cutscene:
951 			cl.intermission = 3;
952 			cl.completed_time = (int) cl.time;
953 			vid.recalc_refdef = true;	// go to full screen
954 			SCR_CenterPrint (MSG_ReadString ());
955 			break;
956 
957 		case svc_sellscreen:
958 			Cmd_ExecuteString2 ("help", src_command);
959 			break;
960 		}
961 	}
962 }
963 
964