1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, 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
24const 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===============
74CL_EntityNum
75
76This error checks and tracks the total number of entities
77===============
78*/
79entity_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==================
98CL_ParseStartSoundPacket
99==================
100*/
101void 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==================
140CL_KeepaliveMessage
141
142When the client is taking a long time to load stuff, send keepalive messages
143so the server doesn't disconnect.
144==================
145*/
146void 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==================
201CL_ParseServerInfo
202==================
203*/
204void 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==================
321CL_ParseUpdate
322
323Parse an entity update message from the server
324If an entities model or origin changes from frame to frame, it must be
325relinked.  Other attributes can change without relinking.
326==================
327*/
328int	bitcounts[16];
329
330void 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
359for (i=0 ; i<16 ; i++)
360if (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==================
488CL_ParseBaseline
489==================
490*/
491void 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==================
509CL_ParseClientdata
510
511Server information pertaining to this client only
512==================
513*/
514void 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=====================
627CL_NewTranslation
628=====================
629*/
630void 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=====================
665CL_ParseStatic
666=====================
667*/
668void 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===================
694CL_ParseStaticSound
695===================
696*/
697void 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=====================
717CL_ParseServerMessage
718=====================
719*/
720void 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