]> icculus.org git repositories - divverent/darkplaces.git/blob - cl_parse.c
added coronas (glow) to dynamic lights
[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[128] =
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 [short] x [short] 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         "", // 50
84         "svc_fog", // 51
85         "svc_effect", // [vector] org [byte] modelindex [byte] startframe [byte] framecount [byte] framerate
86         "svc_effect2", // [vector] org [short] modelindex [short] startframe [byte] framecount [byte] framerate
87 };
88
89 //=============================================================================
90
91 cvar_t demo_nehahra = {0, "demo_nehahra", "0"};
92
93 void CL_Parse_Init(void)
94 {
95         // LordHavoc: added demo_nehahra cvar
96         Cvar_RegisterVariable (&demo_nehahra);
97         if (gamemode == GAME_NEHAHRA)
98                 Cvar_SetValue("demo_nehahra", 1);
99 }
100
101 qboolean Nehahrademcompatibility; // LordHavoc: to allow playback of the early Nehahra movie segments
102 qboolean dpprotocol; // LordHavoc: whether or not the current network stream is the enhanced DarkPlaces protocol
103
104 /*
105 ===============
106 CL_EntityNum
107
108 This error checks and tracks the total number of entities
109 ===============
110 */
111 entity_t        *CL_EntityNum (int num)
112 {
113         /*
114         if (num >= cl.num_entities)
115         {
116                 if (num >= MAX_EDICTS)
117                         Host_Error ("CL_EntityNum: %i is an invalid number",num);
118                 cl.num_entities = num;
119 //              while (cl.num_entities <= num)
120 //              {
121 //                      cl_entities[cl.num_entities].colormap = -1; // no special coloring
122 //                      cl.num_entities++;
123 //              }
124         }
125         */
126         if (num >= MAX_EDICTS)
127                 Host_Error ("CL_EntityNum: %i is an invalid number",num);
128                 
129         return &cl_entities[num];
130 }
131
132
133 /*
134 ==================
135 CL_ParseStartSoundPacket
136 ==================
137 */
138 void CL_ParseStartSoundPacket(int largesoundindex)
139 {
140     vec3_t  pos;
141     int         channel, ent;
142     int         sound_num;
143     int         volume;
144     int         field_mask;
145     float       attenuation;
146         int             i;
147                    
148     field_mask = MSG_ReadByte(); 
149
150     if (field_mask & SND_VOLUME)
151                 volume = MSG_ReadByte ();
152         else
153                 volume = DEFAULT_SOUND_PACKET_VOLUME;
154         
155     if (field_mask & SND_ATTENUATION)
156                 attenuation = MSG_ReadByte () / 64.0;
157         else
158                 attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;
159         
160         channel = MSG_ReadShort ();
161         if (largesoundindex)
162                 sound_num = (unsigned short) MSG_ReadShort ();
163         else
164                 sound_num = MSG_ReadByte ();
165
166         if (sound_num >= MAX_SOUNDS)
167                 Host_Error("CL_ParseStartSoundPacket: sound_num (%i) >= MAX_SOUNDS (%i)\n", sound_num, MAX_SOUNDS);
168
169         ent = channel >> 3;
170         channel &= 7;
171
172         if (ent > MAX_EDICTS)
173                 Host_Error ("CL_ParseStartSoundPacket: ent = %i", ent);
174         
175         for (i=0 ; i<3 ; i++)
176                 pos[i] = MSG_ReadCoord ();
177
178     S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation);
179 }       
180
181 /*
182 ==================
183 CL_KeepaliveMessage
184
185 When the client is taking a long time to load stuff, send keepalive messages
186 so the server doesn't disconnect.
187 ==================
188 */
189 void CL_KeepaliveMessage (void)
190 {
191         float   time;
192         static float lastmsg;
193         int             ret;
194         sizebuf_t       old;
195         byte            olddata[8192];
196         
197         if (sv.active)
198                 return;         // no need if server is local
199         if (cls.demoplayback)
200                 return;
201
202 // read messages from server, should just be nops
203         old = net_message;
204         memcpy (olddata, net_message.data, net_message.cursize);
205         
206         do
207         {
208                 ret = CL_GetMessage ();
209                 switch (ret)
210                 {
211                 default:
212                         Host_Error ("CL_KeepaliveMessage: CL_GetMessage failed");               
213                 case 0:
214                         break;  // nothing waiting
215                 case 1:
216                         Host_Error ("CL_KeepaliveMessage: received a message");
217                         break;
218                 case 2:
219                         if (MSG_ReadByte() != svc_nop)
220                                 Host_Error ("CL_KeepaliveMessage: datagram wasn't a nop");
221                         break;
222                 }
223         } while (ret);
224
225         net_message = old;
226         memcpy (net_message.data, olddata, net_message.cursize);
227
228 // check time
229         time = Sys_DoubleTime ();
230         if (time - lastmsg < 5)
231                 return;
232         lastmsg = time;
233
234 // write out a nop
235         Con_Printf ("--> client to server keepalive\n");
236
237         MSG_WriteByte (&cls.message, clc_nop);
238         NET_SendMessage (cls.netcon, &cls.message);
239         SZ_Clear (&cls.message);
240 }
241
242 void CL_ParseEntityLump(char *entdata)
243 {
244         char *data;
245         char key[128], value[4096];
246         FOG_clear(); // LordHavoc: no fog until set
247         R_SetSkyBox(""); // LordHavoc: no environment mapped sky until set
248         data = entdata;
249         if (!data)
250                 return;
251         data = COM_Parse(data);
252         if (!data)
253                 return; // error
254         if (com_token[0] != '{')
255                 return; // error
256         while (1)
257         {
258                 data = COM_Parse(data);
259                 if (!data)
260                         return; // error
261                 if (com_token[0] == '}')
262                         break; // end of worldspawn
263                 if (com_token[0] == '_')
264                         strcpy(key, com_token + 1);
265                 else
266                         strcpy(key, com_token);
267                 while (key[strlen(key)-1] == ' ') // remove trailing spaces
268                         key[strlen(key)-1] = 0;
269                 data = COM_Parse(data);
270                 if (!data)
271                         return; // error
272                 strcpy(value, com_token);
273                 if (!strcmp("sky", key))
274                         R_SetSkyBox(value);
275                 else if (!strcmp("skyname", key)) // non-standard, introduced by QuakeForge... sigh.
276                         R_SetSkyBox(value);
277                 else if (!strcmp("qlsky", key)) // non-standard, introduced by QuakeLives (EEK)
278                         R_SetSkyBox(value);
279                 else if (!strcmp("fog", key))
280                         sscanf(value, "%f %f %f %f", &fog_density, &fog_red, &fog_green, &fog_blue);
281                 else if (!strcmp("fog_density", key))
282                         fog_density = atof(value);
283                 else if (!strcmp("fog_red", key))
284                         fog_red = atof(value);
285                 else if (!strcmp("fog_green", key))
286                         fog_green = atof(value);
287                 else if (!strcmp("fog_blue", key))
288                         fog_blue = atof(value);
289         }
290 }
291
292 /*
293 =====================
294 CL_SignonReply
295
296 An svc_signonnum has been received, perform a client side setup
297 =====================
298 */
299 static void CL_SignonReply (void)
300 {
301         char    str[8192];
302
303 Con_DPrintf ("CL_SignonReply: %i\n", cls.signon);
304
305         switch (cls.signon)
306         {
307         case 1:
308                 MSG_WriteByte (&cls.message, clc_stringcmd);
309                 MSG_WriteString (&cls.message, "prespawn");
310                 break;
311
312         case 2:
313                 MSG_WriteByte (&cls.message, clc_stringcmd);
314                 MSG_WriteString (&cls.message, va("name \"%s\"\n", cl_name.string));
315
316                 MSG_WriteByte (&cls.message, clc_stringcmd);
317                 MSG_WriteString (&cls.message, va("color %i %i\n", cl_color.integer >> 4, cl_color.integer & 15));
318
319                 if (cl_pmodel.integer)
320                 {
321                         MSG_WriteByte (&cls.message, clc_stringcmd);
322                         MSG_WriteString (&cls.message, va("pmodel %i\n", cl_pmodel.integer));
323                 }
324
325                 MSG_WriteByte (&cls.message, clc_stringcmd);
326                 sprintf (str, "spawn %s", cls.spawnparms);
327                 MSG_WriteString (&cls.message, str);
328                 break;
329
330         case 3:
331                 MSG_WriteByte (&cls.message, clc_stringcmd);
332                 MSG_WriteString (&cls.message, "begin");
333                 break;
334
335         case 4:
336 //              SCR_EndLoadingPlaque ();                // allow normal screen updates
337                 Con_ClearNotify();
338                 break;
339         }
340 }
341
342 /*
343 ==================
344 CL_ParseServerInfo
345 ==================
346 */
347 void CL_ParseServerInfo (void)
348 {
349         char    *str;
350         int             i;
351         int             nummodels, numsounds;
352         char    model_precache[MAX_MODELS][MAX_QPATH];
353         char    sound_precache[MAX_SOUNDS][MAX_QPATH];
354
355         Con_DPrintf ("Serverinfo packet received.\n");
356 //
357 // wipe the client_state_t struct
358 //
359         CL_ClearState ();
360
361 // parse protocol version number
362         i = MSG_ReadLong ();
363         if (i != PROTOCOL_VERSION && i != DPPROTOCOL_VERSION && i != 250)
364         {
365                 Con_Printf ("Server returned version %i, not %i or %i", i, DPPROTOCOL_VERSION, PROTOCOL_VERSION);
366                 return;
367         }
368         Nehahrademcompatibility = false;
369         if (i == 250)
370                 Nehahrademcompatibility = true;
371         if (cls.demoplayback && demo_nehahra.integer)
372                 Nehahrademcompatibility = true;
373         dpprotocol = i == DPPROTOCOL_VERSION;
374
375 // parse maxclients
376         cl.maxclients = MSG_ReadByte ();
377         if (cl.maxclients < 1 || cl.maxclients > MAX_SCOREBOARD)
378         {
379                 Con_Printf("Bad maxclients (%u) from server\n", cl.maxclients);
380                 return;
381         }
382         cl.scores = Mem_Alloc(cl_scores_mempool, cl.maxclients*sizeof(*cl.scores));
383
384 // parse gametype
385         cl.gametype = MSG_ReadByte ();
386
387 // parse signon message
388         str = MSG_ReadString ();
389         strncpy (cl.levelname, str, sizeof(cl.levelname)-1);
390
391 // seperate the printfs so the server message can have a color
392         if (!Nehahrademcompatibility) // no messages when playing the Nehahra movie
393         {
394                 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");
395                 Con_Printf ("%c%s\n", 2, str);
396         }
397
398 //
399 // first we go through and touch all of the precache data that still
400 // happens to be in the cache, so precaching something else doesn't
401 // needlessly purge it
402 //
403
404         Mem_CheckSentinelsGlobal();
405
406         Mod_ClearUsed();
407
408 // precache models
409         memset (cl.model_precache, 0, sizeof(cl.model_precache));
410         for (nummodels=1 ; ; nummodels++)
411         {
412                 str = MSG_ReadString ();
413                 if (!str[0])
414                         break;
415                 if (nummodels==MAX_MODELS)
416                 {
417                         Host_Error ("Server sent too many model precaches\n");
418                         return;
419                 }
420                 if (strlen(str) >= MAX_QPATH)
421                         Host_Error ("Server sent a precache name of %i characters (max %i)", strlen(str), MAX_QPATH - 1);
422                 strcpy (model_precache[nummodels], str);
423                 Mod_TouchModel (str);
424         }
425
426 // precache sounds
427         memset (cl.sound_precache, 0, sizeof(cl.sound_precache));
428         for (numsounds=1 ; ; numsounds++)
429         {
430                 str = MSG_ReadString ();
431                 if (!str[0])
432                         break;
433                 if (numsounds==MAX_SOUNDS)
434                 {
435                         Host_Error ("Server sent too many sound precaches\n");
436                         return;
437                 }
438                 if (strlen(str) >= MAX_QPATH)
439                         Host_Error ("Server sent a precache name of %i characters (max %i)", strlen(str), MAX_QPATH - 1);
440                 strcpy (sound_precache[numsounds], str);
441                 S_TouchSound (str);
442         }
443
444         Mod_PurgeUnused();
445
446 //
447 // now we try to load everything else until a cache allocation fails
448 //
449
450         Mem_CheckSentinelsGlobal();
451
452         for (i=1 ; i<nummodels ; i++)
453         {
454                 // LordHavoc: i == 1 means the first model is the world model
455                 cl.model_precache[i] = Mod_ForName (model_precache[i], false, false, i == 1);
456
457                 if (cl.model_precache[i] == NULL)
458                 {
459                         Host_Error("Model %s not found\n", model_precache[i]);
460                         return;
461                 }
462                 CL_KeepaliveMessage ();
463         }
464
465         Mem_CheckSentinelsGlobal();
466
467         S_BeginPrecaching ();
468         for (i=1 ; i<numsounds ; i++)
469         {
470                 cl.sound_precache[i] = S_PrecacheSound (sound_precache[i]);
471                 CL_KeepaliveMessage ();
472         }
473         S_EndPrecaching ();
474
475 // local state
476         cl_entities[0].render.model = cl.worldmodel = cl.model_precache[1];
477         cl_entities[0].render.scale = 1;
478         cl_entities[0].render.alpha = 1;
479
480         R_NewMap ();
481
482         Mem_CheckSentinelsGlobal();
483
484         noclip_anglehack = false;               // noclip is turned off at start
485 }
486
487 void CL_ValidateState(entity_state_t *s)
488 {
489         model_t *model;
490
491         if (!s->active)
492                 return;
493
494         if (s->modelindex >= MAX_MODELS)
495                 Host_Error("CL_ValidateState: modelindex (%i) >= MAX_MODELS (%i)\n", s->modelindex, MAX_MODELS);
496
497         // colormap is client index + 1
498         if (s->colormap > cl.maxclients)
499                 Host_Error ("CL_ValidateState: colormap (%i) > cl.maxclients (%i)", s->colormap, cl.maxclients);
500
501         model = cl.model_precache[s->modelindex];
502         Mod_CheckLoaded(model);
503         if (model && s->frame >= model->numframes)
504         {
505                 Con_Printf("CL_ValidateState: no such frame %i in \"%s\"\n", s->frame, model->name);
506                 s->frame = 0;
507         }
508         if (model && s->skin > 0 && s->skin >= model->numskins)
509         {
510                 Con_Printf("CL_ValidateState: no such skin %i in \"%s\"\n", s->skin, model->name);
511                 s->skin = 0;
512         }
513 }
514
515 /*
516 ==================
517 CL_ParseUpdate
518
519 Parse an entity update message from the server
520 If an entities model or origin changes from frame to frame, it must be
521 relinked.  Other attributes can change without relinking.
522 ==================
523 */
524 byte entkill[MAX_EDICTS];
525 int bitprofile[32], bitprofilecount = 0;
526 void CL_ParseUpdate (int bits)
527 {
528         int i, num, deltadie;
529         entity_t *ent;
530         entity_state_t new;
531
532         if (cls.signon == SIGNONS - 1)
533         {       // first update is the final signon stage
534                 cls.signon = SIGNONS;
535                 CL_SignonReply ();
536         }
537
538         if (bits & U_MOREBITS)
539                 bits |= (MSG_ReadByte()<<8);
540         if ((bits & U_EXTEND1) && (!Nehahrademcompatibility))
541         {
542                 bits |= MSG_ReadByte() << 16;
543                 if (bits & U_EXTEND2)
544                         bits |= MSG_ReadByte() << 24;
545         }
546
547         if (bits & U_LONGENTITY)
548                 num = (unsigned) MSG_ReadShort ();
549         else
550                 num = (unsigned) MSG_ReadByte ();
551
552         if (num >= MAX_EDICTS)
553                 Host_Error("CL_ParseUpdate: entity number (%i) >= MAX_EDICTS (%i)\n", num, MAX_EDICTS);
554         if (num < 1)
555                 Host_Error("CL_ParseUpdate: invalid entity number (%i)\n", num);
556
557         // mark as visible (no kill)
558         entkill[num] = 0;
559
560         ent = CL_EntityNum (num);
561
562         for (i = 0;i < 32;i++)
563                 if (bits & (1 << i))
564                         bitprofile[i]++;
565         bitprofilecount++;
566
567         deltadie = false;
568         if (bits & U_DELTA)
569         {
570                 new = ent->state_current;
571                 if (!new.active)
572                         deltadie = true; // was not present in previous frame, leave hidden until next full update
573         }
574         else
575                 new = ent->state_baseline;
576
577         new.time = cl.mtime[0];
578
579         new.flags = 0;
580         new.active = true;
581         if (bits & U_MODEL)             new.modelindex = (new.modelindex & 0xFF00) | MSG_ReadByte();
582         if (bits & U_FRAME)             new.frame = (new.frame & 0xFF00) | MSG_ReadByte();
583         if (bits & U_COLORMAP)  new.colormap = MSG_ReadByte();
584         if (bits & U_SKIN)              new.skin = MSG_ReadByte();
585         if (bits & U_EFFECTS)   new.effects = (new.effects & 0xFF00) | MSG_ReadByte();
586         if (bits & U_ORIGIN1)   new.origin[0] = MSG_ReadCoord();
587         if (bits & U_ANGLE1)    new.angles[0] = MSG_ReadAngle();
588         if (bits & U_ORIGIN2)   new.origin[1] = MSG_ReadCoord();
589         if (bits & U_ANGLE2)    new.angles[1] = MSG_ReadAngle();
590         if (bits & U_ORIGIN3)   new.origin[2] = MSG_ReadCoord();
591         if (bits & U_ANGLE3)    new.angles[2] = MSG_ReadAngle();
592         if (bits & U_STEP)              new.flags |= RENDER_STEP;
593         if (bits & U_ALPHA)             new.alpha = MSG_ReadByte();
594         if (bits & U_SCALE)             new.scale = MSG_ReadByte();
595         if (bits & U_EFFECTS2)  new.effects = (new.effects & 0x00FF) | (MSG_ReadByte() << 8);
596         if (bits & U_GLOWSIZE)  new.glowsize = MSG_ReadByte();
597         if (bits & U_GLOWCOLOR) new.glowcolor = MSG_ReadByte();
598 #if 0
599         if (bits & U_COLORMOD)  {int i = MSG_ReadByte();float r = (((int) i >> 5) & 7) * 1.0 / 7, g = (((int) i >> 2) & 7) * 1.0 / 7, b = ((int) i & 3) * 1.0 / 3;Con_Printf("warning: U_COLORMOD %i (%1.2f %1.2f %1.2f) ignored\n", i, r, g, b);}
600 #else
601         // apparently the dpcrush demo uses this (unintended, and it uses white anyway)
602         if (bits & U_COLORMOD)  MSG_ReadByte();
603 #endif
604         if (bits & U_GLOWTRAIL) new.flags |= RENDER_GLOWTRAIL;
605         if (bits & U_FRAME2)    new.frame = (new.frame & 0x00FF) | (MSG_ReadByte() << 8);
606         if (bits & U_MODEL2)    new.modelindex = (new.modelindex & 0x00FF) | (MSG_ReadByte() << 8);
607         if (bits & U_VIEWMODEL) new.flags |= RENDER_VIEWMODEL;
608         if (bits & U_EXTERIORMODEL)     new.flags |= RENDER_EXTERIORMODEL;
609
610         // LordHavoc: to allow playback of the Nehahra movie
611         if (Nehahrademcompatibility && (bits & U_EXTEND1))
612         {
613                 // LordHavoc: evil format
614                 int i = MSG_ReadFloat();
615                 int j = MSG_ReadFloat() * 255.0f;
616                 if (i == 2)
617                 {
618                         if (MSG_ReadFloat())
619                                 new.effects |= EF_FULLBRIGHT;
620                 }
621                 if (j < 0)
622                         new.alpha = 0;
623                 else if (j == 0 || j >= 255)
624                         new.alpha = 255;
625                 else
626                         new.alpha = j;
627         }
628
629         if (deltadie)
630         {
631                 // hide the entity
632                 new.active = false;
633         }
634         else
635                 CL_ValidateState(&new);
636
637         if (new.flags & RENDER_STEP) // FIXME: rename this flag?
638         {
639                 // make time identical for memcmp
640                 new.time = ent->state_current.time;
641                 if (memcmp(&new, &ent->state_current, sizeof(entity_state_t)))
642                 {
643                         // state has changed
644                         ent->state_previous = ent->state_current;
645                         ent->state_current = new;
646                         // assume 10fps animation
647                         ent->state_previous.time = cl.mtime[0];
648                         ent->state_current.time = cl.mtime[0] + 0.1; //ent->state_previous.time + 0.1;
649                 }
650         }
651         else
652         {
653                 ent->state_previous = ent->state_current;
654                 ent->state_current = new;
655         }
656 }
657
658 char *bitprofilenames[32] =
659 {
660         "U_MOREBITS",
661         "U_ORIGIN1",
662         "U_ORIGIN2",
663         "U_ORIGIN3",
664         "U_ANGLE2",
665         "U_STEP",
666         "U_FRAME",
667         "U_SIGNAL",
668         "U_ANGLE1",
669         "U_ANGLE3",
670         "U_MODEL",
671         "U_COLORMAP",
672         "U_SKIN",
673         "U_EFFECTS",
674         "U_LONGENTITY",
675         "U_EXTEND1",
676         "U_DELTA",
677         "U_ALPHA",
678         "U_SCALE",
679         "U_EFFECTS2",
680         "U_GLOWSIZE",
681         "U_GLOWCOLOR",
682         "obsolete U_COLORMOD",
683         "U_EXTEND2",
684         "U_GLOWTRAIL",
685         "U_VIEWMODEL",
686         "U_FRAME2",
687         "U_MODEL2",
688         "U_EXTERIORMODEL",
689         "U_UNUSED29",
690         "U_UNUSED30",
691         "U_EXTEND3",
692 };
693
694 void CL_BitProfile_f(void)
695 {
696         int i;
697         Con_Printf("bitprofile: %i updates\n");
698         if (bitprofilecount)
699                 for (i = 0;i < 32;i++)
700 //                      if (bitprofile[i])
701                                 Con_Printf("%s: %i %3.2f%%\n", bitprofilenames[i], bitprofile[i], bitprofile[i] * 100.0 / bitprofilecount);
702         Con_Printf("\n");
703         for (i = 0;i < 32;i++)
704                 bitprofile[i] = 0;
705         bitprofilecount = 0;
706 }
707
708 void CL_EntityUpdateSetup(void)
709 {
710         memset(entkill, 1, MAX_EDICTS);
711 }
712
713 void CL_EntityUpdateEnd(void)
714 {
715         int i;
716         for (i = 1;i < MAX_EDICTS;i++)
717                 if (entkill[i])
718                         cl_entities[i].state_previous.active = cl_entities[i].state_current.active = 0;
719 }
720
721 /*
722 ==================
723 CL_ParseBaseline
724 ==================
725 */
726 void CL_ParseBaseline (entity_t *ent, int large)
727 {
728         int i;
729
730         memset(&ent->state_baseline, 0, sizeof(entity_state_t));
731         ent->state_baseline.active = true;
732         if (large)
733         {
734                 ent->state_baseline.modelindex = (unsigned short) MSG_ReadShort ();
735                 ent->state_baseline.frame = (unsigned short) MSG_ReadShort ();
736         }
737         else
738         {
739                 ent->state_baseline.modelindex = MSG_ReadByte ();
740                 ent->state_baseline.frame = MSG_ReadByte ();
741         }
742         ent->state_baseline.colormap = MSG_ReadByte();
743         ent->state_baseline.skin = MSG_ReadByte();
744         for (i = 0;i < 3;i++)
745         {
746                 ent->state_baseline.origin[i] = MSG_ReadCoord ();
747                 ent->state_baseline.angles[i] = MSG_ReadAngle ();
748         }
749         ent->state_baseline.alpha = 255;
750         ent->state_baseline.scale = 16;
751         ent->state_baseline.glowsize = 0;
752         ent->state_baseline.glowcolor = 254;
753         ent->state_previous = ent->state_current = ent->state_baseline;
754
755         CL_ValidateState(&ent->state_baseline);
756 }
757
758
759 /*
760 ==================
761 CL_ParseClientdata
762
763 Server information pertaining to this client only
764 ==================
765 */
766 void CL_ParseClientdata (int bits)
767 {
768         int i, j;
769
770         bits &= 0xFFFF;
771         if (bits & SU_EXTEND1)
772                 bits |= (MSG_ReadByte() << 16);
773         if (bits & SU_EXTEND2)
774                 bits |= (MSG_ReadByte() << 24);
775
776         if (bits & SU_VIEWHEIGHT)
777                 cl.viewheight = MSG_ReadChar ();
778         else
779                 cl.viewheight = DEFAULT_VIEWHEIGHT;
780
781         if (bits & SU_IDEALPITCH)
782                 cl.idealpitch = MSG_ReadChar ();
783         else
784                 cl.idealpitch = 0;
785         
786         VectorCopy (cl.mvelocity[0], cl.mvelocity[1]);
787         for (i=0 ; i<3 ; i++)
788         {
789                 if (bits & (SU_PUNCH1<<i) )
790                 {
791                         if (dpprotocol)
792                                 cl.punchangle[i] = MSG_ReadPreciseAngle();
793                         else
794                                 cl.punchangle[i] = MSG_ReadChar();
795                 }
796                 else
797                         cl.punchangle[i] = 0;
798                 if (bits & (SU_PUNCHVEC1<<i))
799                         cl.punchvector[i] = MSG_ReadFloatCoord();
800                 else
801                         cl.punchvector[i] = 0;
802                 if (bits & (SU_VELOCITY1<<i) )
803                         cl.mvelocity[0][i] = MSG_ReadChar()*16;
804                 else
805                         cl.mvelocity[0][i] = 0;
806         }
807
808         i = MSG_ReadLong ();
809         if (cl.items != i)
810         {       // set flash times
811                 for (j=0 ; j<32 ; j++)
812                         if ( (i & (1<<j)) && !(cl.items & (1<<j)))
813                                 cl.item_gettime[j] = cl.time;
814                 cl.items = i;
815         }
816                 
817         cl.onground = (bits & SU_ONGROUND) != 0;
818         cl.inwater = (bits & SU_INWATER) != 0;
819
820         cl.stats[STAT_WEAPONFRAME] = (bits & SU_WEAPONFRAME) ? MSG_ReadByte() : 0;
821         cl.stats[STAT_ARMOR] = (bits & SU_ARMOR) ? MSG_ReadByte() : 0;
822         cl.stats[STAT_WEAPON] = (bits & SU_WEAPON) ? MSG_ReadByte() : 0;
823         cl.stats[STAT_HEALTH] = MSG_ReadShort();
824         cl.stats[STAT_AMMO] = MSG_ReadByte();
825
826         cl.stats[STAT_SHELLS] = MSG_ReadByte();
827         cl.stats[STAT_NAILS] = MSG_ReadByte();
828         cl.stats[STAT_ROCKETS] = MSG_ReadByte();
829         cl.stats[STAT_CELLS] = MSG_ReadByte();
830
831         i = MSG_ReadByte ();
832
833         if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
834                 cl.stats[STAT_ACTIVEWEAPON] = (1<<i);
835         else
836                 cl.stats[STAT_ACTIVEWEAPON] = i;
837 }
838
839 /*
840 =====================
841 CL_ParseStatic
842 =====================
843 */
844 void CL_ParseStatic (int large)
845 {
846         entity_t *ent;
847
848         if (cl.num_statics >= MAX_STATIC_ENTITIES)
849                 Host_Error ("Too many static entities");
850         ent = &cl_static_entities[cl.num_statics++];
851         CL_ParseBaseline (ent, large);
852
853 // copy it to the current state
854         ent->render.model = cl.model_precache[ent->state_baseline.modelindex];
855         ent->render.frame = ent->render.frame1 = ent->render.frame2 = ent->state_baseline.frame;
856         ent->render.framelerp = 0;
857         // make torchs play out of sync
858         ent->render.frame1time = ent->render.frame2time = lhrandom(-10, -1);
859         ent->render.colormap = -1; // no special coloring
860         ent->render.skinnum = ent->state_baseline.skin;
861         ent->render.effects = ent->state_baseline.effects;
862         ent->render.alpha = 1;
863         ent->render.scale = 1;
864         ent->render.alpha = 1;
865
866         VectorCopy (ent->state_baseline.origin, ent->render.origin);
867         VectorCopy (ent->state_baseline.angles, ent->render.angles);    
868 }
869
870 /*
871 ===================
872 CL_ParseStaticSound
873 ===================
874 */
875 void CL_ParseStaticSound (int large)
876 {
877         vec3_t          org;
878         int                     sound_num, vol, atten;
879
880         MSG_ReadVector(org);
881         if (large)
882                 sound_num = (unsigned short) MSG_ReadShort ();
883         else
884                 sound_num = MSG_ReadByte ();
885         vol = MSG_ReadByte ();
886         atten = MSG_ReadByte ();
887         
888         S_StaticSound (cl.sound_precache[sound_num], org, vol, atten);
889 }
890
891 void CL_ParseEffect (void)
892 {
893         vec3_t          org;
894         int                     modelindex, startframe, framecount, framerate;
895
896         MSG_ReadVector(org);
897         modelindex = MSG_ReadByte ();
898         startframe = MSG_ReadByte ();
899         framecount = MSG_ReadByte ();
900         framerate = MSG_ReadByte ();
901
902         CL_Effect(org, modelindex, startframe, framecount, framerate);
903 }
904
905 void CL_ParseEffect2 (void)
906 {
907         vec3_t          org;
908         int                     modelindex, startframe, framecount, framerate;
909
910         MSG_ReadVector(org);
911         modelindex = MSG_ReadShort ();
912         startframe = MSG_ReadShort ();
913         framecount = MSG_ReadByte ();
914         framerate = MSG_ReadByte ();
915
916         CL_Effect(org, modelindex, startframe, framecount, framerate);
917 }
918
919
920 #define SHOWNET(x) if(cl_shownet.integer==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x);
921
922 /*
923 =====================
924 CL_ParseServerMessage
925 =====================
926 */
927 void CL_ParseServerMessage (void)
928 {
929         int                     cmd;
930         int                     i, entitiesupdated;
931         byte            cmdlog[32];
932         char            *cmdlogname[32], *temp;
933         int                     cmdindex, cmdcount = 0;
934         
935 //
936 // if recording demos, copy the message out
937 //
938         if (cl_shownet.integer == 1)
939                 Con_Printf ("%i ",net_message.cursize);
940         else if (cl_shownet.integer == 2)
941                 Con_Printf ("------------------\n");
942         
943         cl.onground = false;    // unless the server says otherwise     
944 //
945 // parse the message
946 //
947         MSG_BeginReading ();
948
949         entitiesupdated = false;
950         CL_EntityUpdateSetup();
951         
952         while (1)
953         {
954                 if (msg_badread)
955                         Host_Error ("CL_ParseServerMessage: Bad server message");
956
957                 cmd = MSG_ReadByte ();
958
959                 if (cmd == -1)
960                 {
961                         SHOWNET("END OF MESSAGE");
962                         break;          // end of message
963                 }
964
965                 cmdindex = cmdcount & 31;
966                 cmdcount++;
967                 cmdlog[cmdindex] = cmd;
968
969                 // if the high bit of the command byte is set, it is a fast update
970                 if (cmd & 128)
971                 {
972                         // LordHavoc: fix for bizarre problem in MSVC that I do not understand (if I assign the string pointer directly it ends up storing a NULL pointer)
973                         temp = "entity";
974                         cmdlogname[cmdindex] = temp;
975                         SHOWNET("fast update");
976                         CL_ParseUpdate (cmd&127);
977                         continue;
978                 }
979
980                 SHOWNET(svc_strings[cmd]);
981                 cmdlogname[cmdindex] = svc_strings[cmd];
982                 if (!cmdlogname[cmdindex])
983                 {
984                         // LordHavoc: fix for bizarre problem in MSVC that I do not understand (if I assign the string pointer directly it ends up storing a NULL pointer)
985                         temp = "<unknown>";
986                         cmdlogname[cmdindex] = temp;
987                 }
988         
989                 // other commands
990                 switch (cmd)
991                 {
992                 default:
993                         {
994                                 char description[32*64], temp[64];
995                                 int count;
996                                 strcpy(description, "packet dump: ");
997                                 i = cmdcount - 32;
998                                 if (i < 0)
999                                         i = 0;
1000                                 count = cmdcount - i;
1001                                 i &= 31;
1002                                 while(count > 0)
1003                                 {
1004                                         sprintf(temp, "%3i:%s ", cmdlog[i], cmdlogname[i]);
1005                                         strcat(description, temp);
1006                                         count--;
1007                                         i++;
1008                                         i &= 31;
1009                                 }
1010                                 description[strlen(description)-1] = '\n'; // replace the last space with a newline
1011                                 Con_Printf("%s", description);
1012                                 Host_Error ("CL_ParseServerMessage: Illegible server message\n");
1013                         }
1014                         break;
1015                         
1016                 case svc_nop:
1017 //                      Con_Printf ("svc_nop\n");
1018                         break;
1019                         
1020                 case svc_time:
1021                         // handle old protocols which do not have entity update ranges
1022                         entitiesupdated = true;
1023                         cl.mtime[1] = cl.mtime[0];
1024                         cl.mtime[0] = MSG_ReadFloat ();                 
1025                         break;
1026
1027                 case svc_clientdata:
1028                         i = MSG_ReadShort ();
1029                         CL_ParseClientdata (i);
1030                         break;
1031                 
1032                 case svc_version:
1033                         i = MSG_ReadLong ();
1034                         if (i != PROTOCOL_VERSION && i != DPPROTOCOL_VERSION && i != 250)
1035                                 Host_Error ("CL_ParseServerMessage: Server is protocol %i, not %i or %i", i, DPPROTOCOL_VERSION, PROTOCOL_VERSION);
1036                         Nehahrademcompatibility = false;
1037                         if (i == 250)
1038                                 Nehahrademcompatibility = true;
1039                         if (cls.demoplayback && demo_nehahra.integer)
1040                                 Nehahrademcompatibility = true;
1041                         dpprotocol = i == DPPROTOCOL_VERSION;
1042                         break;
1043                         
1044                 case svc_disconnect:
1045                         Host_EndGame ("Server disconnected\n");
1046
1047                 case svc_print:
1048                         Con_Printf ("%s", MSG_ReadString ());
1049                         break;
1050                         
1051                 case svc_centerprint:
1052                         SCR_CenterPrint (MSG_ReadString ());
1053                         break;
1054                         
1055                 case svc_stufftext:
1056                         Cbuf_AddText (MSG_ReadString ());
1057                         break;
1058
1059                 case svc_damage:
1060                         V_ParseDamage ();
1061                         break;
1062
1063                 case svc_serverinfo:
1064                         CL_ParseServerInfo ();
1065 //                      vid.recalc_refdef = true;       // leave intermission full screen
1066                         break;
1067                         
1068                 case svc_setangle:
1069                         for (i=0 ; i<3 ; i++)
1070                                 cl.viewangles[i] = MSG_ReadAngle ();
1071                         break;
1072                         
1073                 case svc_setview:
1074                         cl.viewentity = MSG_ReadShort ();
1075                         break;
1076                                         
1077                 case svc_lightstyle:
1078                         i = MSG_ReadByte ();
1079                         if (i >= MAX_LIGHTSTYLES)
1080                                 Host_Error ("svc_lightstyle >= MAX_LIGHTSTYLES");
1081                         strncpy (cl_lightstyle[i].map,  MSG_ReadString(), MAX_STYLESTRING - 1);
1082                         cl_lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
1083                         cl_lightstyle[i].length = strlen(cl_lightstyle[i].map);
1084                         break;
1085                         
1086                 case svc_sound:
1087                         CL_ParseStartSoundPacket(false);
1088                         break;
1089
1090                 case svc_sound2:
1091                         CL_ParseStartSoundPacket(true);
1092                         break;
1093
1094                 case svc_stopsound:
1095                         i = MSG_ReadShort();
1096                         S_StopSound(i>>3, i&7);
1097                         break;
1098
1099                 case svc_updatename:
1100                         i = MSG_ReadByte ();
1101                         if (i >= cl.maxclients)
1102                                 Host_Error ("CL_ParseServerMessage: svc_updatename >= MAX_SCOREBOARD");
1103                         strcpy (cl.scores[i].name, MSG_ReadString ());
1104                         break;
1105                         
1106                 case svc_updatefrags:
1107                         i = MSG_ReadByte ();
1108                         if (i >= cl.maxclients)
1109                                 Host_Error ("CL_ParseServerMessage: svc_updatefrags >= MAX_SCOREBOARD");
1110                         cl.scores[i].frags = MSG_ReadShort ();
1111                         break;                  
1112
1113                 case svc_updatecolors:
1114                         i = MSG_ReadByte ();
1115                         if (i >= cl.maxclients)
1116                                 Host_Error ("CL_ParseServerMessage: svc_updatecolors >= MAX_SCOREBOARD");
1117                         cl.scores[i].colors = MSG_ReadByte ();
1118                         break;
1119                         
1120                 case svc_particle:
1121                         CL_ParseParticleEffect ();
1122                         break;
1123
1124                 case svc_effect:
1125                         CL_ParseEffect ();
1126                         break;
1127
1128                 case svc_effect2:
1129                         CL_ParseEffect2 ();
1130                         break;
1131
1132                 case svc_spawnbaseline:
1133                         i = MSG_ReadShort ();
1134                         // must use CL_EntityNum() to force cl.num_entities up
1135                         CL_ParseBaseline (CL_EntityNum(i), false);
1136                         break;
1137                 case svc_spawnbaseline2:
1138                         i = MSG_ReadShort ();
1139                         // must use CL_EntityNum() to force cl.num_entities up
1140                         CL_ParseBaseline (CL_EntityNum(i), true);
1141                         break;
1142                 case svc_spawnstatic:
1143                         CL_ParseStatic (false);
1144                         break;
1145                 case svc_spawnstatic2:
1146                         CL_ParseStatic (true);
1147                         break;
1148                 case svc_temp_entity:
1149                         CL_ParseTEnt ();
1150                         break;
1151
1152                 case svc_setpause:
1153                         cl.paused = MSG_ReadByte ();
1154                         if (cl.paused)
1155                                 CDAudio_Pause ();
1156                         else
1157                                 CDAudio_Resume ();
1158                         break;
1159                         
1160                 case svc_signonnum:
1161                         i = MSG_ReadByte ();
1162                         if (i <= cls.signon)
1163                                 Host_Error ("Received signon %i when at %i", i, cls.signon);
1164                         cls.signon = i;
1165                         CL_SignonReply ();
1166                         break;
1167
1168                 case svc_killedmonster:
1169                         cl.stats[STAT_MONSTERS]++;
1170                         break;
1171
1172                 case svc_foundsecret:
1173                         cl.stats[STAT_SECRETS]++;
1174                         break;
1175
1176                 case svc_updatestat:
1177                         i = MSG_ReadByte ();
1178                         if (i < 0 || i >= MAX_CL_STATS)
1179                                 Host_Error ("svc_updatestat: %i is invalid", i);
1180                         cl.stats[i] = MSG_ReadLong ();
1181                         break;
1182                         
1183                 case svc_spawnstaticsound:
1184                         CL_ParseStaticSound (false);
1185                         break;
1186
1187                 case svc_spawnstaticsound2:
1188                         CL_ParseStaticSound (true);
1189                         break;
1190
1191                 case svc_cdtrack:
1192                         cl.cdtrack = MSG_ReadByte ();
1193                         cl.looptrack = MSG_ReadByte ();
1194                         if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )
1195                                 CDAudio_Play ((byte)cls.forcetrack, true);
1196                         else
1197                                 CDAudio_Play ((byte)cl.cdtrack, true);
1198                         break;
1199
1200                 case svc_intermission:
1201                         cl.intermission = 1;
1202                         cl.completed_time = cl.time;
1203 //                      vid.recalc_refdef = true;       // go to full screen
1204                         break;
1205
1206                 case svc_finale:
1207                         cl.intermission = 2;
1208                         cl.completed_time = cl.time;
1209 //                      vid.recalc_refdef = true;       // go to full screen
1210                         SCR_CenterPrint (MSG_ReadString ());
1211                         break;
1212
1213                 case svc_cutscene:
1214                         cl.intermission = 3;
1215                         cl.completed_time = cl.time;
1216 //                      vid.recalc_refdef = true;       // go to full screen
1217                         SCR_CenterPrint (MSG_ReadString ());                    
1218                         break;
1219
1220                 case svc_sellscreen:
1221                         Cmd_ExecuteString ("help", src_command);
1222                         break;
1223                 case svc_hidelmp:
1224                         SHOWLMP_decodehide();
1225                         break;
1226                 case svc_showlmp:
1227                         SHOWLMP_decodeshow();
1228                         break;
1229                 case svc_skybox:
1230                         R_SetSkyBox(MSG_ReadString());
1231                         break;
1232                 }
1233         }
1234
1235         if (entitiesupdated)
1236                 CL_EntityUpdateEnd();
1237 }