]> icculus.org git repositories - divverent/darkplaces.git/blob - cl_parse.c
got rid of buildnumber.c and buildnum program, now uses builddate.c (touched each...
[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         CL_CGVM_Start();
485
486         Mem_CheckSentinelsGlobal();
487
488         noclip_anglehack = false;               // noclip is turned off at start
489 }
490
491 void CL_ValidateState(entity_state_t *s)
492 {
493         model_t *model;
494
495         if (!s->active)
496                 return;
497
498         if (s->modelindex >= MAX_MODELS)
499                 Host_Error("CL_ValidateState: modelindex (%i) >= MAX_MODELS (%i)\n", s->modelindex, MAX_MODELS);
500
501         // colormap is client index + 1
502         if (s->colormap > cl.maxclients)
503                 Host_Error ("CL_ValidateState: colormap (%i) > cl.maxclients (%i)", s->colormap, cl.maxclients);
504
505         model = cl.model_precache[s->modelindex];
506         Mod_CheckLoaded(model);
507         if (model && s->frame >= model->numframes)
508         {
509                 Con_Printf("CL_ValidateState: no such frame %i in \"%s\"\n", s->frame, model->name);
510                 s->frame = 0;
511         }
512         if (model && s->skin > 0 && s->skin >= model->numskins)
513         {
514                 Con_Printf("CL_ValidateState: no such skin %i in \"%s\"\n", s->skin, model->name);
515                 s->skin = 0;
516         }
517 }
518
519 /*
520 ==================
521 CL_ParseUpdate
522
523 Parse an entity update message from the server
524 If an entities model or origin changes from frame to frame, it must be
525 relinked.  Other attributes can change without relinking.
526 ==================
527 */
528 byte entkill[MAX_EDICTS];
529 int bitprofile[32], bitprofilecount = 0;
530 void CL_ParseUpdate (int bits)
531 {
532         int i, num, deltadie;
533         entity_t *ent;
534         entity_state_t new;
535
536         if (cls.signon == SIGNONS - 1)
537         {       // first update is the final signon stage
538                 cls.signon = SIGNONS;
539                 CL_SignonReply ();
540         }
541
542         if (bits & U_MOREBITS)
543                 bits |= (MSG_ReadByte()<<8);
544         if ((bits & U_EXTEND1) && (!Nehahrademcompatibility))
545         {
546                 bits |= MSG_ReadByte() << 16;
547                 if (bits & U_EXTEND2)
548                         bits |= MSG_ReadByte() << 24;
549         }
550
551         if (bits & U_LONGENTITY)
552                 num = (unsigned) MSG_ReadShort ();
553         else
554                 num = (unsigned) MSG_ReadByte ();
555
556         if (num >= MAX_EDICTS)
557                 Host_Error("CL_ParseUpdate: entity number (%i) >= MAX_EDICTS (%i)\n", num, MAX_EDICTS);
558         if (num < 1)
559                 Host_Error("CL_ParseUpdate: invalid entity number (%i)\n", num);
560
561         // mark as visible (no kill)
562         entkill[num] = 0;
563
564         ent = CL_EntityNum (num);
565
566         for (i = 0;i < 32;i++)
567                 if (bits & (1 << i))
568                         bitprofile[i]++;
569         bitprofilecount++;
570
571         deltadie = false;
572         if (bits & U_DELTA)
573         {
574                 new = ent->state_current;
575                 if (!new.active)
576                         deltadie = true; // was not present in previous frame, leave hidden until next full update
577         }
578         else
579                 new = ent->state_baseline;
580
581         new.time = cl.mtime[0];
582
583         new.flags = 0;
584         new.active = true;
585         if (bits & U_MODEL)             new.modelindex = (new.modelindex & 0xFF00) | MSG_ReadByte();
586         if (bits & U_FRAME)             new.frame = (new.frame & 0xFF00) | MSG_ReadByte();
587         if (bits & U_COLORMAP)  new.colormap = MSG_ReadByte();
588         if (bits & U_SKIN)              new.skin = MSG_ReadByte();
589         if (bits & U_EFFECTS)   new.effects = (new.effects & 0xFF00) | MSG_ReadByte();
590         if (bits & U_ORIGIN1)   new.origin[0] = MSG_ReadCoord();
591         if (bits & U_ANGLE1)    new.angles[0] = MSG_ReadAngle();
592         if (bits & U_ORIGIN2)   new.origin[1] = MSG_ReadCoord();
593         if (bits & U_ANGLE2)    new.angles[1] = MSG_ReadAngle();
594         if (bits & U_ORIGIN3)   new.origin[2] = MSG_ReadCoord();
595         if (bits & U_ANGLE3)    new.angles[2] = MSG_ReadAngle();
596         if (bits & U_STEP)              new.flags |= RENDER_STEP;
597         if (bits & U_ALPHA)             new.alpha = MSG_ReadByte();
598         if (bits & U_SCALE)             new.scale = MSG_ReadByte();
599         if (bits & U_EFFECTS2)  new.effects = (new.effects & 0x00FF) | (MSG_ReadByte() << 8);
600         if (bits & U_GLOWSIZE)  new.glowsize = MSG_ReadByte();
601         if (bits & U_GLOWCOLOR) new.glowcolor = MSG_ReadByte();
602 #if 0
603         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);}
604 #else
605         // apparently the dpcrush demo uses this (unintended, and it uses white anyway)
606         if (bits & U_COLORMOD)  MSG_ReadByte();
607 #endif
608         if (bits & U_GLOWTRAIL) new.flags |= RENDER_GLOWTRAIL;
609         if (bits & U_FRAME2)    new.frame = (new.frame & 0x00FF) | (MSG_ReadByte() << 8);
610         if (bits & U_MODEL2)    new.modelindex = (new.modelindex & 0x00FF) | (MSG_ReadByte() << 8);
611         if (bits & U_VIEWMODEL) new.flags |= RENDER_VIEWMODEL;
612         if (bits & U_EXTERIORMODEL)     new.flags |= RENDER_EXTERIORMODEL;
613
614         // LordHavoc: to allow playback of the Nehahra movie
615         if (Nehahrademcompatibility && (bits & U_EXTEND1))
616         {
617                 // LordHavoc: evil format
618                 int i = MSG_ReadFloat();
619                 int j = MSG_ReadFloat() * 255.0f;
620                 if (i == 2)
621                 {
622                         if (MSG_ReadFloat())
623                                 new.effects |= EF_FULLBRIGHT;
624                 }
625                 if (j < 0)
626                         new.alpha = 0;
627                 else if (j == 0 || j >= 255)
628                         new.alpha = 255;
629                 else
630                         new.alpha = j;
631         }
632
633         if (deltadie)
634         {
635                 // hide the entity
636                 new.active = false;
637         }
638         else
639                 CL_ValidateState(&new);
640
641         if (new.flags & RENDER_STEP) // FIXME: rename this flag?
642         {
643                 // make time identical for memcmp
644                 new.time = ent->state_current.time;
645                 if (memcmp(&new, &ent->state_current, sizeof(entity_state_t)))
646                 {
647                         // state has changed
648                         ent->state_previous = ent->state_current;
649                         ent->state_current = new;
650                         // assume 10fps animation
651                         ent->state_previous.time = cl.mtime[0];
652                         ent->state_current.time = cl.mtime[0] + 0.1; //ent->state_previous.time + 0.1;
653                 }
654         }
655         else
656         {
657                 ent->state_previous = ent->state_current;
658                 ent->state_current = new;
659         }
660 }
661
662 char *bitprofilenames[32] =
663 {
664         "U_MOREBITS",
665         "U_ORIGIN1",
666         "U_ORIGIN2",
667         "U_ORIGIN3",
668         "U_ANGLE2",
669         "U_STEP",
670         "U_FRAME",
671         "U_SIGNAL",
672         "U_ANGLE1",
673         "U_ANGLE3",
674         "U_MODEL",
675         "U_COLORMAP",
676         "U_SKIN",
677         "U_EFFECTS",
678         "U_LONGENTITY",
679         "U_EXTEND1",
680         "U_DELTA",
681         "U_ALPHA",
682         "U_SCALE",
683         "U_EFFECTS2",
684         "U_GLOWSIZE",
685         "U_GLOWCOLOR",
686         "obsolete U_COLORMOD",
687         "U_EXTEND2",
688         "U_GLOWTRAIL",
689         "U_VIEWMODEL",
690         "U_FRAME2",
691         "U_MODEL2",
692         "U_EXTERIORMODEL",
693         "U_UNUSED29",
694         "U_UNUSED30",
695         "U_EXTEND3",
696 };
697
698 void CL_BitProfile_f(void)
699 {
700         int i;
701         Con_Printf("bitprofile: %i updates\n");
702         if (bitprofilecount)
703                 for (i = 0;i < 32;i++)
704 //                      if (bitprofile[i])
705                                 Con_Printf("%s: %i %3.2f%%\n", bitprofilenames[i], bitprofile[i], bitprofile[i] * 100.0 / bitprofilecount);
706         Con_Printf("\n");
707         for (i = 0;i < 32;i++)
708                 bitprofile[i] = 0;
709         bitprofilecount = 0;
710 }
711
712 void CL_EntityUpdateSetup(void)
713 {
714         memset(entkill, 1, MAX_EDICTS);
715 }
716
717 void CL_EntityUpdateEnd(void)
718 {
719         int i;
720         for (i = 1;i < MAX_EDICTS;i++)
721                 if (entkill[i])
722                         cl_entities[i].state_previous.active = cl_entities[i].state_current.active = 0;
723 }
724
725 /*
726 ==================
727 CL_ParseBaseline
728 ==================
729 */
730 void CL_ParseBaseline (entity_t *ent, int large)
731 {
732         int i;
733
734         memset(&ent->state_baseline, 0, sizeof(entity_state_t));
735         ent->state_baseline.active = true;
736         if (large)
737         {
738                 ent->state_baseline.modelindex = (unsigned short) MSG_ReadShort ();
739                 ent->state_baseline.frame = (unsigned short) MSG_ReadShort ();
740         }
741         else
742         {
743                 ent->state_baseline.modelindex = MSG_ReadByte ();
744                 ent->state_baseline.frame = MSG_ReadByte ();
745         }
746         ent->state_baseline.colormap = MSG_ReadByte();
747         ent->state_baseline.skin = MSG_ReadByte();
748         for (i = 0;i < 3;i++)
749         {
750                 ent->state_baseline.origin[i] = MSG_ReadCoord ();
751                 ent->state_baseline.angles[i] = MSG_ReadAngle ();
752         }
753         ent->state_baseline.alpha = 255;
754         ent->state_baseline.scale = 16;
755         ent->state_baseline.glowsize = 0;
756         ent->state_baseline.glowcolor = 254;
757         ent->state_previous = ent->state_current = ent->state_baseline;
758
759         CL_ValidateState(&ent->state_baseline);
760 }
761
762
763 /*
764 ==================
765 CL_ParseClientdata
766
767 Server information pertaining to this client only
768 ==================
769 */
770 void CL_ParseClientdata (int bits)
771 {
772         int i, j;
773
774         bits &= 0xFFFF;
775         if (bits & SU_EXTEND1)
776                 bits |= (MSG_ReadByte() << 16);
777         if (bits & SU_EXTEND2)
778                 bits |= (MSG_ReadByte() << 24);
779
780         if (bits & SU_VIEWHEIGHT)
781                 cl.viewheight = MSG_ReadChar ();
782         else
783                 cl.viewheight = DEFAULT_VIEWHEIGHT;
784
785         if (bits & SU_IDEALPITCH)
786                 cl.idealpitch = MSG_ReadChar ();
787         else
788                 cl.idealpitch = 0;
789         
790         VectorCopy (cl.mvelocity[0], cl.mvelocity[1]);
791         for (i=0 ; i<3 ; i++)
792         {
793                 if (bits & (SU_PUNCH1<<i) )
794                 {
795                         if (dpprotocol)
796                                 cl.punchangle[i] = MSG_ReadPreciseAngle();
797                         else
798                                 cl.punchangle[i] = MSG_ReadChar();
799                 }
800                 else
801                         cl.punchangle[i] = 0;
802                 if (bits & (SU_PUNCHVEC1<<i))
803                         cl.punchvector[i] = MSG_ReadFloatCoord();
804                 else
805                         cl.punchvector[i] = 0;
806                 if (bits & (SU_VELOCITY1<<i) )
807                         cl.mvelocity[0][i] = MSG_ReadChar()*16;
808                 else
809                         cl.mvelocity[0][i] = 0;
810         }
811
812         i = MSG_ReadLong ();
813         if (cl.items != i)
814         {       // set flash times
815                 for (j=0 ; j<32 ; j++)
816                         if ( (i & (1<<j)) && !(cl.items & (1<<j)))
817                                 cl.item_gettime[j] = cl.time;
818                 cl.items = i;
819         }
820                 
821         cl.onground = (bits & SU_ONGROUND) != 0;
822         cl.inwater = (bits & SU_INWATER) != 0;
823
824         cl.stats[STAT_WEAPONFRAME] = (bits & SU_WEAPONFRAME) ? MSG_ReadByte() : 0;
825         cl.stats[STAT_ARMOR] = (bits & SU_ARMOR) ? MSG_ReadByte() : 0;
826         cl.stats[STAT_WEAPON] = (bits & SU_WEAPON) ? MSG_ReadByte() : 0;
827         cl.stats[STAT_HEALTH] = MSG_ReadShort();
828         cl.stats[STAT_AMMO] = MSG_ReadByte();
829
830         cl.stats[STAT_SHELLS] = MSG_ReadByte();
831         cl.stats[STAT_NAILS] = MSG_ReadByte();
832         cl.stats[STAT_ROCKETS] = MSG_ReadByte();
833         cl.stats[STAT_CELLS] = MSG_ReadByte();
834
835         i = MSG_ReadByte ();
836
837         if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
838                 cl.stats[STAT_ACTIVEWEAPON] = (1<<i);
839         else
840                 cl.stats[STAT_ACTIVEWEAPON] = i;
841 }
842
843 /*
844 =====================
845 CL_ParseStatic
846 =====================
847 */
848 void CL_ParseStatic (int large)
849 {
850         entity_t *ent;
851
852         if (cl.num_statics >= MAX_STATIC_ENTITIES)
853                 Host_Error ("Too many static entities");
854         ent = &cl_static_entities[cl.num_statics++];
855         CL_ParseBaseline (ent, large);
856
857 // copy it to the current state
858         ent->render.model = cl.model_precache[ent->state_baseline.modelindex];
859         ent->render.frame = ent->render.frame1 = ent->render.frame2 = ent->state_baseline.frame;
860         ent->render.framelerp = 0;
861         // make torchs play out of sync
862         ent->render.frame1time = ent->render.frame2time = lhrandom(-10, -1);
863         ent->render.colormap = -1; // no special coloring
864         ent->render.skinnum = ent->state_baseline.skin;
865         ent->render.effects = ent->state_baseline.effects;
866         ent->render.alpha = 1;
867         ent->render.scale = 1;
868         ent->render.alpha = 1;
869
870         VectorCopy (ent->state_baseline.origin, ent->render.origin);
871         VectorCopy (ent->state_baseline.angles, ent->render.angles);    
872 }
873
874 /*
875 ===================
876 CL_ParseStaticSound
877 ===================
878 */
879 void CL_ParseStaticSound (int large)
880 {
881         vec3_t          org;
882         int                     sound_num, vol, atten;
883
884         MSG_ReadVector(org);
885         if (large)
886                 sound_num = (unsigned short) MSG_ReadShort ();
887         else
888                 sound_num = MSG_ReadByte ();
889         vol = MSG_ReadByte ();
890         atten = MSG_ReadByte ();
891         
892         S_StaticSound (cl.sound_precache[sound_num], org, vol, atten);
893 }
894
895 void CL_ParseEffect (void)
896 {
897         vec3_t          org;
898         int                     modelindex, startframe, framecount, framerate;
899
900         MSG_ReadVector(org);
901         modelindex = MSG_ReadByte ();
902         startframe = MSG_ReadByte ();
903         framecount = MSG_ReadByte ();
904         framerate = MSG_ReadByte ();
905
906         CL_Effect(org, modelindex, startframe, framecount, framerate);
907 }
908
909 void CL_ParseEffect2 (void)
910 {
911         vec3_t          org;
912         int                     modelindex, startframe, framecount, framerate;
913
914         MSG_ReadVector(org);
915         modelindex = MSG_ReadShort ();
916         startframe = MSG_ReadShort ();
917         framecount = MSG_ReadByte ();
918         framerate = MSG_ReadByte ();
919
920         CL_Effect(org, modelindex, startframe, framecount, framerate);
921 }
922
923
924 #define SHOWNET(x) if(cl_shownet.integer==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x);
925
926 static byte cgamenetbuffer[65536];
927
928 /*
929 =====================
930 CL_ParseServerMessage
931 =====================
932 */
933 void CL_ParseServerMessage (void)
934 {
935         int                     cmd;
936         int                     i, entitiesupdated;
937         byte            cmdlog[32];
938         char            *cmdlogname[32], *temp;
939         int                     cmdindex, cmdcount = 0;
940         
941 //
942 // if recording demos, copy the message out
943 //
944         if (cl_shownet.integer == 1)
945                 Con_Printf ("%i ",net_message.cursize);
946         else if (cl_shownet.integer == 2)
947                 Con_Printf ("------------------\n");
948         
949         cl.onground = false;    // unless the server says otherwise     
950 //
951 // parse the message
952 //
953         MSG_BeginReading ();
954
955         entitiesupdated = false;
956         CL_EntityUpdateSetup();
957         
958         while (1)
959         {
960                 if (msg_badread)
961                         Host_Error ("CL_ParseServerMessage: Bad server message");
962
963                 cmd = MSG_ReadByte ();
964
965                 if (cmd == -1)
966                 {
967                         SHOWNET("END OF MESSAGE");
968                         break;          // end of message
969                 }
970
971                 cmdindex = cmdcount & 31;
972                 cmdcount++;
973                 cmdlog[cmdindex] = cmd;
974
975                 // if the high bit of the command byte is set, it is a fast update
976                 if (cmd & 128)
977                 {
978                         // 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)
979                         temp = "entity";
980                         cmdlogname[cmdindex] = temp;
981                         SHOWNET("fast update");
982                         CL_ParseUpdate (cmd&127);
983                         continue;
984                 }
985
986                 SHOWNET(svc_strings[cmd]);
987                 cmdlogname[cmdindex] = svc_strings[cmd];
988                 if (!cmdlogname[cmdindex])
989                 {
990                         // 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)
991                         temp = "<unknown>";
992                         cmdlogname[cmdindex] = temp;
993                 }
994
995                 // other commands
996                 switch (cmd)
997                 {
998                 default:
999                         {
1000                                 char description[32*64], temp[64];
1001                                 int count;
1002                                 strcpy(description, "packet dump: ");
1003                                 i = cmdcount - 32;
1004                                 if (i < 0)
1005                                         i = 0;
1006                                 count = cmdcount - i;
1007                                 i &= 31;
1008                                 while(count > 0)
1009                                 {
1010                                         sprintf(temp, "%3i:%s ", cmdlog[i], cmdlogname[i]);
1011                                         strcat(description, temp);
1012                                         count--;
1013                                         i++;
1014                                         i &= 31;
1015                                 }
1016                                 description[strlen(description)-1] = '\n'; // replace the last space with a newline
1017                                 Con_Printf("%s", description);
1018                                 Host_Error ("CL_ParseServerMessage: Illegible server message\n");
1019                         }
1020                         break;
1021
1022                 case svc_nop:
1023 //                      Con_Printf ("svc_nop\n");
1024                         break;
1025
1026                 case svc_time:
1027                         // handle old protocols which do not have entity update ranges
1028                         entitiesupdated = true;
1029                         cl.mtime[1] = cl.mtime[0];
1030                         cl.mtime[0] = MSG_ReadFloat ();
1031                         break;
1032
1033                 case svc_clientdata:
1034                         i = MSG_ReadShort ();
1035                         CL_ParseClientdata (i);
1036                         break;
1037
1038                 case svc_version:
1039                         i = MSG_ReadLong ();
1040                         if (i != PROTOCOL_VERSION && i != DPPROTOCOL_VERSION && i != 250)
1041                                 Host_Error ("CL_ParseServerMessage: Server is protocol %i, not %i or %i", i, DPPROTOCOL_VERSION, PROTOCOL_VERSION);
1042                         Nehahrademcompatibility = false;
1043                         if (i == 250)
1044                                 Nehahrademcompatibility = true;
1045                         if (cls.demoplayback && demo_nehahra.integer)
1046                                 Nehahrademcompatibility = true;
1047                         dpprotocol = i == DPPROTOCOL_VERSION;
1048                         break;
1049                         
1050                 case svc_disconnect:
1051                         Host_EndGame ("Server disconnected\n");
1052
1053                 case svc_print:
1054                         Con_Printf ("%s", MSG_ReadString ());
1055                         break;
1056
1057                 case svc_centerprint:
1058                         SCR_CenterPrint (MSG_ReadString ());
1059                         break;
1060
1061                 case svc_stufftext:
1062                         Cbuf_AddText (MSG_ReadString ());
1063                         break;
1064
1065                 case svc_damage:
1066                         V_ParseDamage ();
1067                         break;
1068
1069                 case svc_serverinfo:
1070                         CL_ParseServerInfo ();
1071 //                      vid.recalc_refdef = true;       // leave intermission full screen
1072                         break;
1073                         
1074                 case svc_setangle:
1075                         for (i=0 ; i<3 ; i++)
1076                                 cl.viewangles[i] = MSG_ReadAngle ();
1077                         break;
1078                         
1079                 case svc_setview:
1080                         cl.viewentity = MSG_ReadShort ();
1081                         break;
1082                                         
1083                 case svc_lightstyle:
1084                         i = MSG_ReadByte ();
1085                         if (i >= MAX_LIGHTSTYLES)
1086                                 Host_Error ("svc_lightstyle >= MAX_LIGHTSTYLES");
1087                         strncpy (cl_lightstyle[i].map,  MSG_ReadString(), MAX_STYLESTRING - 1);
1088                         cl_lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
1089                         cl_lightstyle[i].length = strlen(cl_lightstyle[i].map);
1090                         break;
1091
1092                 case svc_sound:
1093                         CL_ParseStartSoundPacket(false);
1094                         break;
1095
1096                 case svc_sound2:
1097                         CL_ParseStartSoundPacket(true);
1098                         break;
1099
1100                 case svc_stopsound:
1101                         i = MSG_ReadShort();
1102                         S_StopSound(i>>3, i&7);
1103                         break;
1104
1105                 case svc_updatename:
1106                         i = MSG_ReadByte ();
1107                         if (i >= cl.maxclients)
1108                                 Host_Error ("CL_ParseServerMessage: svc_updatename >= MAX_SCOREBOARD");
1109                         strcpy (cl.scores[i].name, MSG_ReadString ());
1110                         break;
1111
1112                 case svc_updatefrags:
1113                         i = MSG_ReadByte ();
1114                         if (i >= cl.maxclients)
1115                                 Host_Error ("CL_ParseServerMessage: svc_updatefrags >= MAX_SCOREBOARD");
1116                         cl.scores[i].frags = MSG_ReadShort ();
1117                         break;                  
1118
1119                 case svc_updatecolors:
1120                         i = MSG_ReadByte ();
1121                         if (i >= cl.maxclients)
1122                                 Host_Error ("CL_ParseServerMessage: svc_updatecolors >= MAX_SCOREBOARD");
1123                         cl.scores[i].colors = MSG_ReadByte ();
1124                         break;
1125                         
1126                 case svc_particle:
1127                         CL_ParseParticleEffect ();
1128                         break;
1129
1130                 case svc_effect:
1131                         CL_ParseEffect ();
1132                         break;
1133
1134                 case svc_effect2:
1135                         CL_ParseEffect2 ();
1136                         break;
1137
1138                 case svc_spawnbaseline:
1139                         i = MSG_ReadShort ();
1140                         // must use CL_EntityNum() to force cl.num_entities up
1141                         CL_ParseBaseline (CL_EntityNum(i), false);
1142                         break;
1143                 case svc_spawnbaseline2:
1144                         i = MSG_ReadShort ();
1145                         // must use CL_EntityNum() to force cl.num_entities up
1146                         CL_ParseBaseline (CL_EntityNum(i), true);
1147                         break;
1148                 case svc_spawnstatic:
1149                         CL_ParseStatic (false);
1150                         break;
1151                 case svc_spawnstatic2:
1152                         CL_ParseStatic (true);
1153                         break;
1154                 case svc_temp_entity:
1155                         CL_ParseTEnt ();
1156                         break;
1157
1158                 case svc_setpause:
1159                         cl.paused = MSG_ReadByte ();
1160                         if (cl.paused)
1161                                 CDAudio_Pause ();
1162                         else
1163                                 CDAudio_Resume ();
1164                         break;
1165                         
1166                 case svc_signonnum:
1167                         i = MSG_ReadByte ();
1168                         if (i <= cls.signon)
1169                                 Host_Error ("Received signon %i when at %i", i, cls.signon);
1170                         cls.signon = i;
1171                         CL_SignonReply ();
1172                         break;
1173
1174                 case svc_killedmonster:
1175                         cl.stats[STAT_MONSTERS]++;
1176                         break;
1177
1178                 case svc_foundsecret:
1179                         cl.stats[STAT_SECRETS]++;
1180                         break;
1181
1182                 case svc_updatestat:
1183                         i = MSG_ReadByte ();
1184                         if (i < 0 || i >= MAX_CL_STATS)
1185                                 Host_Error ("svc_updatestat: %i is invalid", i);
1186                         cl.stats[i] = MSG_ReadLong ();
1187                         break;
1188
1189                 case svc_spawnstaticsound:
1190                         CL_ParseStaticSound (false);
1191                         break;
1192
1193                 case svc_spawnstaticsound2:
1194                         CL_ParseStaticSound (true);
1195                         break;
1196
1197                 case svc_cdtrack:
1198                         cl.cdtrack = MSG_ReadByte ();
1199                         cl.looptrack = MSG_ReadByte ();
1200                         if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )
1201                                 CDAudio_Play ((byte)cls.forcetrack, true);
1202                         else
1203                                 CDAudio_Play ((byte)cl.cdtrack, true);
1204                         break;
1205
1206                 case svc_intermission:
1207                         cl.intermission = 1;
1208                         cl.completed_time = cl.time;
1209 //                      vid.recalc_refdef = true;       // go to full screen
1210                         break;
1211
1212                 case svc_finale:
1213                         cl.intermission = 2;
1214                         cl.completed_time = cl.time;
1215 //                      vid.recalc_refdef = true;       // go to full screen
1216                         SCR_CenterPrint (MSG_ReadString ());
1217                         break;
1218
1219                 case svc_cutscene:
1220                         cl.intermission = 3;
1221                         cl.completed_time = cl.time;
1222 //                      vid.recalc_refdef = true;       // go to full screen
1223                         SCR_CenterPrint (MSG_ReadString ());                    
1224                         break;
1225
1226                 case svc_sellscreen:
1227                         Cmd_ExecuteString ("help", src_command);
1228                         break;
1229                 case svc_hidelmp:
1230                         SHOWLMP_decodehide();
1231                         break;
1232                 case svc_showlmp:
1233                         SHOWLMP_decodeshow();
1234                         break;
1235                 case svc_skybox:
1236                         R_SetSkyBox(MSG_ReadString());
1237                         break;
1238                 case svc_cgame:
1239                         {
1240                                 int length;
1241                                 length = (int) ((unsigned short) MSG_ReadShort());
1242                                 /*
1243                                 if (cgamenetbuffersize < length)
1244                                 {
1245                                         cgamenetbuffersize = length;
1246                                         if (cgamenetbuffer)
1247                                                 Mem_Free(cgamenetbuffer);
1248                                         cgamenetbuffer = Mem_Alloc(cgamenetbuffersize);
1249                                 }
1250                                 */
1251                                 for (i = 0;i < length;i++)
1252                                         cgamenetbuffer[i] = MSG_ReadByte();
1253                                 if (!msg_badread)
1254                                         CL_CGVM_ParseNetwork(cgamenetbuffer, length);
1255                         }
1256                         break;
1257                 }
1258         }
1259
1260         if (entitiesupdated)
1261                 CL_EntityUpdateEnd();
1262 }