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