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