removed no longer used static light parsing code
[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         Mem_CheckSentinelsGlobal();
409
410 // precache models
411         memset (cl.model_precache, 0, sizeof(cl.model_precache));
412         for (nummodels=1 ; ; nummodels++)
413         {
414                 str = MSG_ReadString ();
415                 if (!str[0])
416                         break;
417                 if (nummodels==MAX_MODELS)
418                 {
419                         Con_Printf ("Server sent too many model precaches\n");
420                         return;
421                 }
422                 if (strlen(str) >= MAX_QPATH)
423                         Host_Error ("Server sent a precache name of %i characters (max %i)", strlen(str), MAX_QPATH - 1);
424                 strcpy (model_precache[nummodels], str);
425                 Mod_TouchModel (str);
426         }
427
428 // precache sounds
429         memset (cl.sound_precache, 0, sizeof(cl.sound_precache));
430         for (numsounds=1 ; ; numsounds++)
431         {
432                 str = MSG_ReadString ();
433                 if (!str[0])
434                         break;
435                 if (numsounds==MAX_SOUNDS)
436                 {
437                         Con_Printf ("Server sent too many sound precaches\n");
438                         return;
439                 }
440                 if (strlen(str) >= MAX_QPATH)
441                         Host_Error ("Server sent a precache name of %i characters (max %i)", strlen(str), MAX_QPATH - 1);
442                 strcpy (sound_precache[numsounds], str);
443                 S_TouchSound (str);
444         }
445
446         Mem_CheckSentinelsGlobal();
447
448         Mod_PurgeUnused();
449
450 //
451 // now we try to load everything else until a cache allocation fails
452 //
453
454         Mem_CheckSentinelsGlobal();
455
456         for (i=1 ; i<nummodels ; i++)
457         {
458                 // LordHavoc: i == 1 means the first model is the world model
459                 cl.model_precache[i] = Mod_ForName (model_precache[i], false, true, i == 1);
460
461                 if (cl.model_precache[i] == NULL)
462                 {
463                         Con_Printf("Model %s not found\n", model_precache[i]);
464                         return;
465                 }
466                 CL_KeepaliveMessage ();
467         }
468
469         Mem_CheckSentinelsGlobal();
470
471         S_BeginPrecaching ();
472         for (i=1 ; i<numsounds ; i++)
473         {
474                 cl.sound_precache[i] = S_PrecacheSound (sound_precache[i]);
475                 CL_KeepaliveMessage ();
476         }
477         S_EndPrecaching ();
478
479 // local state
480         cl_entities[0].render.model = cl.worldmodel = cl.model_precache[1];
481         cl_entities[0].render.scale = 1;
482         cl_entities[0].render.alpha = 1;
483
484         R_NewMap ();
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 /*
927 =====================
928 CL_ParseServerMessage
929 =====================
930 */
931 void CL_ParseServerMessage (void)
932 {
933         int                     cmd;
934         int                     i, entitiesupdated;
935         byte            cmdlog[32];
936         char            *cmdlogname[32], *temp;
937         int                     cmdindex, cmdcount = 0;
938         
939 //
940 // if recording demos, copy the message out
941 //
942         if (cl_shownet.integer == 1)
943                 Con_Printf ("%i ",net_message.cursize);
944         else if (cl_shownet.integer == 2)
945                 Con_Printf ("------------------\n");
946         
947         cl.onground = false;    // unless the server says otherwise     
948 //
949 // parse the message
950 //
951         MSG_BeginReading ();
952
953         entitiesupdated = false;
954         CL_EntityUpdateSetup();
955         
956         while (1)
957         {
958                 if (msg_badread)
959                         Host_Error ("CL_ParseServerMessage: Bad server message");
960
961                 cmd = MSG_ReadByte ();
962
963                 if (cmd == -1)
964                 {
965                         SHOWNET("END OF MESSAGE");
966                         break;          // end of message
967                 }
968
969                 cmdindex = cmdcount & 31;
970                 cmdcount++;
971                 cmdlog[cmdindex] = cmd;
972
973                 // if the high bit of the command byte is set, it is a fast update
974                 if (cmd & 128)
975                 {
976                         // 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)
977                         temp = "entity";
978                         cmdlogname[cmdindex] = temp;
979                         SHOWNET("fast update");
980                         CL_ParseUpdate (cmd&127);
981                         continue;
982                 }
983
984                 SHOWNET(svc_strings[cmd]);
985                 cmdlogname[cmdindex] = svc_strings[cmd];
986                 if (!cmdlogname[cmdindex])
987                 {
988                         // 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)
989                         temp = "<unknown>";
990                         cmdlogname[cmdindex] = temp;
991                 }
992         
993                 // other commands
994                 switch (cmd)
995                 {
996                 default:
997                         {
998                                 char description[32*64], temp[64];
999                                 int count;
1000                                 strcpy(description, "packet dump: ");
1001                                 i = cmdcount - 32;
1002                                 if (i < 0)
1003                                         i = 0;
1004                                 count = cmdcount - i;
1005                                 i &= 31;
1006                                 while(count > 0)
1007                                 {
1008                                         sprintf(temp, "%3i:%s ", cmdlog[i], cmdlogname[i]);
1009                                         strcat(description, temp);
1010                                         count--;
1011                                         i++;
1012                                         i &= 31;
1013                                 }
1014                                 description[strlen(description)-1] = '\n'; // replace the last space with a newline
1015                                 Con_Printf("%s", description);
1016                                 Host_Error ("CL_ParseServerMessage: Illegible server message\n");
1017                         }
1018                         break;
1019                         
1020                 case svc_nop:
1021 //                      Con_Printf ("svc_nop\n");
1022                         break;
1023                         
1024                 case svc_time:
1025                         // handle old protocols which do not have entity update ranges
1026                         entitiesupdated = true;
1027                         cl.mtime[1] = cl.mtime[0];
1028                         cl.mtime[0] = MSG_ReadFloat ();                 
1029                         break;
1030
1031                 case svc_clientdata:
1032                         i = MSG_ReadShort ();
1033                         CL_ParseClientdata (i);
1034                         break;
1035                 
1036                 case svc_version:
1037                         i = MSG_ReadLong ();
1038                         if (i != PROTOCOL_VERSION && i != DPPROTOCOL_VERSION && i != 250)
1039                                 Host_Error ("CL_ParseServerMessage: Server is protocol %i, not %i or %i", i, DPPROTOCOL_VERSION, PROTOCOL_VERSION);
1040                         Nehahrademcompatibility = false;
1041                         if (i == 250)
1042                                 Nehahrademcompatibility = true;
1043                         if (cls.demoplayback && demo_nehahra.integer)
1044                                 Nehahrademcompatibility = true;
1045                         dpprotocol = i == DPPROTOCOL_VERSION;
1046                         break;
1047                         
1048                 case svc_disconnect:
1049                         Host_EndGame ("Server disconnected\n");
1050
1051                 case svc_print:
1052                         Con_Printf ("%s", MSG_ReadString ());
1053                         break;
1054                         
1055                 case svc_centerprint:
1056                         SCR_CenterPrint (MSG_ReadString ());
1057                         break;
1058                         
1059                 case svc_stufftext:
1060                         Cbuf_AddText (MSG_ReadString ());
1061                         break;
1062
1063                 case svc_damage:
1064                         V_ParseDamage ();
1065                         break;
1066
1067                 case svc_serverinfo:
1068                         CL_ParseServerInfo ();
1069 //                      vid.recalc_refdef = true;       // leave intermission full screen
1070                         break;
1071                         
1072                 case svc_setangle:
1073                         for (i=0 ; i<3 ; i++)
1074                                 cl.viewangles[i] = MSG_ReadAngle ();
1075                         break;
1076                         
1077                 case svc_setview:
1078                         cl.viewentity = MSG_ReadShort ();
1079                         break;
1080                                         
1081                 case svc_lightstyle:
1082                         i = MSG_ReadByte ();
1083                         if (i >= MAX_LIGHTSTYLES)
1084                                 Host_Error ("svc_lightstyle >= MAX_LIGHTSTYLES");
1085                         strncpy (cl_lightstyle[i].map,  MSG_ReadString(), MAX_STYLESTRING - 1);
1086                         cl_lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
1087                         cl_lightstyle[i].length = strlen(cl_lightstyle[i].map);
1088                         break;
1089                         
1090                 case svc_sound:
1091                         CL_ParseStartSoundPacket(false);
1092                         break;
1093
1094                 case svc_sound2:
1095                         CL_ParseStartSoundPacket(true);
1096                         break;
1097
1098                 case svc_stopsound:
1099                         i = MSG_ReadShort();
1100                         S_StopSound(i>>3, i&7);
1101                         break;
1102
1103                 case svc_updatename:
1104                         i = MSG_ReadByte ();
1105                         if (i >= cl.maxclients)
1106                                 Host_Error ("CL_ParseServerMessage: svc_updatename >= MAX_SCOREBOARD");
1107                         strcpy (cl.scores[i].name, MSG_ReadString ());
1108                         break;
1109                         
1110                 case svc_updatefrags:
1111                         i = MSG_ReadByte ();
1112                         if (i >= cl.maxclients)
1113                                 Host_Error ("CL_ParseServerMessage: svc_updatefrags >= MAX_SCOREBOARD");
1114                         cl.scores[i].frags = MSG_ReadShort ();
1115                         break;                  
1116
1117                 case svc_updatecolors:
1118                         i = MSG_ReadByte ();
1119                         if (i >= cl.maxclients)
1120                                 Host_Error ("CL_ParseServerMessage: svc_updatecolors >= MAX_SCOREBOARD");
1121                         cl.scores[i].colors = MSG_ReadByte ();
1122                         break;
1123                         
1124                 case svc_particle:
1125                         CL_ParseParticleEffect ();
1126                         break;
1127
1128                 case svc_effect:
1129                         CL_ParseEffect ();
1130                         break;
1131
1132                 case svc_effect2:
1133                         CL_ParseEffect2 ();
1134                         break;
1135
1136                 case svc_spawnbaseline:
1137                         i = MSG_ReadShort ();
1138                         // must use CL_EntityNum() to force cl.num_entities up
1139                         CL_ParseBaseline (CL_EntityNum(i), false);
1140                         break;
1141                 case svc_spawnbaseline2:
1142                         i = MSG_ReadShort ();
1143                         // must use CL_EntityNum() to force cl.num_entities up
1144                         CL_ParseBaseline (CL_EntityNum(i), true);
1145                         break;
1146                 case svc_spawnstatic:
1147                         CL_ParseStatic (false);
1148                         break;
1149                 case svc_spawnstatic2:
1150                         CL_ParseStatic (true);
1151                         break;
1152                 case svc_temp_entity:
1153                         CL_ParseTEnt ();
1154                         break;
1155
1156                 case svc_setpause:
1157                         cl.paused = MSG_ReadByte ();
1158                         if (cl.paused)
1159                                 CDAudio_Pause ();
1160                         else
1161                                 CDAudio_Resume ();
1162                         break;
1163                         
1164                 case svc_signonnum:
1165                         i = MSG_ReadByte ();
1166                         if (i <= cls.signon)
1167                                 Host_Error ("Received signon %i when at %i", i, cls.signon);
1168                         cls.signon = i;
1169                         CL_SignonReply ();
1170                         break;
1171
1172                 case svc_killedmonster:
1173                         cl.stats[STAT_MONSTERS]++;
1174                         break;
1175
1176                 case svc_foundsecret:
1177                         cl.stats[STAT_SECRETS]++;
1178                         break;
1179
1180                 case svc_updatestat:
1181                         i = MSG_ReadByte ();
1182                         if (i < 0 || i >= MAX_CL_STATS)
1183                                 Host_Error ("svc_updatestat: %i is invalid", i);
1184                         cl.stats[i] = MSG_ReadLong ();
1185                         break;
1186                         
1187                 case svc_spawnstaticsound:
1188                         CL_ParseStaticSound (false);
1189                         break;
1190
1191                 case svc_spawnstaticsound2:
1192                         CL_ParseStaticSound (true);
1193                         break;
1194
1195                 case svc_cdtrack:
1196                         cl.cdtrack = MSG_ReadByte ();
1197                         cl.looptrack = MSG_ReadByte ();
1198                         if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )
1199                                 CDAudio_Play ((byte)cls.forcetrack, true);
1200                         else
1201                                 CDAudio_Play ((byte)cl.cdtrack, true);
1202                         break;
1203
1204                 case svc_intermission:
1205                         cl.intermission = 1;
1206                         cl.completed_time = cl.time;
1207 //                      vid.recalc_refdef = true;       // go to full screen
1208                         break;
1209
1210                 case svc_finale:
1211                         cl.intermission = 2;
1212                         cl.completed_time = cl.time;
1213 //                      vid.recalc_refdef = true;       // go to full screen
1214                         SCR_CenterPrint (MSG_ReadString ());
1215                         break;
1216
1217                 case svc_cutscene:
1218                         cl.intermission = 3;
1219                         cl.completed_time = cl.time;
1220 //                      vid.recalc_refdef = true;       // go to full screen
1221                         SCR_CenterPrint (MSG_ReadString ());                    
1222                         break;
1223
1224                 case svc_sellscreen:
1225                         Cmd_ExecuteString ("help", src_command);
1226                         break;
1227                 case svc_hidelmp:
1228                         SHOWLMP_decodehide();
1229                         break;
1230                 case svc_showlmp:
1231                         SHOWLMP_decodeshow();
1232                         break;
1233                 case svc_skybox:
1234                         R_SetSkyBox(MSG_ReadString());
1235                         break;
1236                 }
1237         }
1238
1239         if (entitiesupdated)
1240                 CL_EntityUpdateEnd();
1241 }