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