rate limited networking ("rate" command in client console, limited by sv_maxrate...
[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 #include "cl_collision.h"
24
25 char *svc_strings[128] =
26 {
27         "svc_bad",
28         "svc_nop",
29         "svc_disconnect",
30         "svc_updatestat",
31         "svc_version",          // [long] server version
32         "svc_setview",          // [short] entity number
33         "svc_sound",                    // <see code>
34         "svc_time",                     // [float] server time
35         "svc_print",                    // [string] null terminated string
36         "svc_stufftext",                // [string] stuffed into client's console buffer
37                                                 // the string should be \n terminated
38         "svc_setangle",         // [vec3] set the view angle to this absolute value
39
40         "svc_serverinfo",               // [long] version
41                                                 // [string] signon string
42                                                 // [string]..[0]model cache [string]...[0]sounds cache
43                                                 // [string]..[0]item cache
44         "svc_lightstyle",               // [byte] [string]
45         "svc_updatename",               // [byte] [string]
46         "svc_updatefrags",      // [byte] [short]
47         "svc_clientdata",               // <shortbits + data>
48         "svc_stopsound",                // <see code>
49         "svc_updatecolors",     // [byte] [byte]
50         "svc_particle",         // [vec3] <variable>
51         "svc_damage",                   // [byte] impact [byte] blood [vec3] from
52
53         "svc_spawnstatic",
54         "OBSOLETE svc_spawnbinary",
55         "svc_spawnbaseline",
56
57         "svc_temp_entity",              // <variable>
58         "svc_setpause",
59         "svc_signonnum",
60         "svc_centerprint",
61         "svc_killedmonster",
62         "svc_foundsecret",
63         "svc_spawnstaticsound",
64         "svc_intermission",
65         "svc_finale",                   // [string] music [string] text
66         "svc_cdtrack",                  // [byte] track [byte] looptrack
67         "svc_sellscreen",
68         "svc_cutscene",
69         "svc_showlmp",  // [string] iconlabel [string] lmpfile [short] x [short] y
70         "svc_hidelmp",  // [string] iconlabel
71         "svc_skybox", // [string] skyname
72         "", // 38
73         "", // 39
74         "", // 40
75         "", // 41
76         "", // 42
77         "", // 43
78         "", // 44
79         "", // 45
80         "", // 46
81         "", // 47
82         "", // 48
83         "", // 49
84         "svc_cgame", //                         50              // [short] length [bytes] data
85         "svc_unusedlh1", //                     51              // unused
86         "svc_effect", //                        52              // [vector] org [byte] modelindex [byte] startframe [byte] framecount [byte] framerate
87         "svc_effect2", //                       53              // [vector] org [short] modelindex [short] startframe [byte] framecount [byte] framerate
88         "svc_sound2", //                        54              // short soundindex instead of byte
89         "svc_spawnbaseline2", //        55              // short modelindex instead of byte
90         "svc_spawnstatic2", //          56              // short modelindex instead of byte
91         "svc_entities", //                      57              // [int] deltaframe [int] thisframe [float vector] eye [variable length] entitydata
92         "svc_unusedlh3", //                     58
93         "svc_spawnstaticsound2", //     59              // [coord3] [short] samp [byte] vol [byte] aten
94 };
95
96 //=============================================================================
97
98 cvar_t demo_nehahra = {0, "demo_nehahra", "0"};
99 cvar_t developer_networkentities = {0, "developer_networkentities", "0"};
100
101 mempool_t *cl_scores_mempool;
102
103 /*
104 ==================
105 CL_ParseStartSoundPacket
106 ==================
107 */
108 void CL_ParseStartSoundPacket(int largesoundindex)
109 {
110         vec3_t  pos;
111         int     channel, ent;
112         int     sound_num;
113         int     volume;
114         int     field_mask;
115         float   attenuation;
116         int             i;
117
118         field_mask = MSG_ReadByte();
119
120         if (field_mask & SND_VOLUME)
121                 volume = MSG_ReadByte ();
122         else
123                 volume = DEFAULT_SOUND_PACKET_VOLUME;
124
125         if (field_mask & SND_ATTENUATION)
126                 attenuation = MSG_ReadByte () / 64.0;
127         else
128                 attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;
129
130         if (field_mask & SND_LARGEENTITY)
131         {
132                 ent = (unsigned short) MSG_ReadShort ();
133                 channel = MSG_ReadByte ();
134         }
135         else
136         {
137                 channel = (unsigned short) MSG_ReadShort ();
138                 ent = channel >> 3;
139                 channel &= 7;
140         }
141
142         if (largesoundindex || field_mask & SND_LARGESOUND)
143                 sound_num = (unsigned short) MSG_ReadShort ();
144         else
145                 sound_num = MSG_ReadByte ();
146
147         if (sound_num >= MAX_SOUNDS)
148                 Host_Error("CL_ParseStartSoundPacket: sound_num (%i) >= MAX_SOUNDS (%i)\n", sound_num, MAX_SOUNDS);
149
150
151         if (ent >= MAX_EDICTS)
152                 Host_Error ("CL_ParseStartSoundPacket: ent = %i", ent);
153
154         for (i = 0;i < 3;i++)
155                 pos[i] = MSG_ReadCoord ();
156
157         S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation);
158 }
159
160 /*
161 ==================
162 CL_KeepaliveMessage
163
164 When the client is taking a long time to load stuff, send keepalive messages
165 so the server doesn't disconnect.
166 ==================
167 */
168
169 static qbyte olddata[NET_MAXMESSAGE];
170 void CL_KeepaliveMessage (void)
171 {
172         float time;
173         static float lastmsg;
174         int oldreadcount;
175         qboolean oldbadread;
176         sizebuf_t old;
177
178         // no need if server is local and definitely not if this is a demo
179         if (sv.active || cls.demoplayback)
180                 return;
181
182 // read messages from server, should just be nops
183         oldreadcount = msg_readcount;
184         oldbadread = msg_badread;
185         old = net_message;
186         memcpy(olddata, net_message.data, net_message.cursize);
187
188         NetConn_ClientFrame();
189
190         msg_readcount = oldreadcount;
191         msg_badread = oldbadread;
192         net_message = old;
193         memcpy(net_message.data, olddata, net_message.cursize);
194
195         if (cls.netcon && NetConn_CanSendMessage(cls.netcon) && (time = Sys_DoubleTime()) - lastmsg >= 5)
196         {
197                 sizebuf_t       msg;
198                 qbyte           buf[4];
199                 lastmsg = time;
200                 // write out a nop
201                 // LordHavoc: must use unreliable because reliable could kill the sigon message!
202                 Con_Printf("--> client to server keepalive\n");
203                 msg.data = buf;
204                 msg.maxsize = sizeof(buf);
205                 msg.cursize = 0;
206                 MSG_WriteChar(&msg, svc_nop);
207                 NetConn_SendUnreliableMessage(cls.netcon, &msg);
208                 // try not to utterly crush the computer with work, that's just rude
209                 Sys_Sleep(1);
210         }
211 }
212
213 void CL_ParseEntityLump(char *entdata)
214 {
215         const char *data;
216         char key[128], value[4096];
217         FOG_clear(); // LordHavoc: no fog until set
218         R_SetSkyBox(""); // LordHavoc: no environment mapped sky until set
219         data = entdata;
220         if (!data)
221                 return;
222         if (!COM_ParseToken(&data, false))
223                 return; // error
224         if (com_token[0] != '{')
225                 return; // error
226         while (1)
227         {
228                 if (!COM_ParseToken(&data, false))
229                         return; // error
230                 if (com_token[0] == '}')
231                         break; // end of worldspawn
232                 if (com_token[0] == '_')
233                         strlcpy (key, com_token + 1, sizeof (key));
234                 else
235                         strlcpy (key, com_token, sizeof (key));
236                 while (key[strlen(key)-1] == ' ') // remove trailing spaces
237                         key[strlen(key)-1] = 0;
238                 if (!COM_ParseToken(&data, false))
239                         return; // error
240                 strlcpy (value, com_token, sizeof (value));
241                 if (!strcmp("sky", key))
242                         R_SetSkyBox(value);
243                 else if (!strcmp("skyname", key)) // non-standard, introduced by QuakeForge... sigh.
244                         R_SetSkyBox(value);
245                 else if (!strcmp("qlsky", key)) // non-standard, introduced by QuakeLives (EEK)
246                         R_SetSkyBox(value);
247                 else if (!strcmp("fog", key))
248                         sscanf(value, "%f %f %f %f", &fog_density, &fog_red, &fog_green, &fog_blue);
249                 else if (!strcmp("fog_density", key))
250                         fog_density = atof(value);
251                 else if (!strcmp("fog_red", key))
252                         fog_red = atof(value);
253                 else if (!strcmp("fog_green", key))
254                         fog_green = atof(value);
255                 else if (!strcmp("fog_blue", key))
256                         fog_blue = atof(value);
257         }
258 }
259
260 /*
261 =====================
262 CL_SignonReply
263
264 An svc_signonnum has been received, perform a client side setup
265 =====================
266 */
267 static void CL_SignonReply (void)
268 {
269         //char  str[8192];
270
271 Con_DPrintf ("CL_SignonReply: %i\n", cls.signon);
272
273         switch (cls.signon)
274         {
275         case 1:
276                 MSG_WriteByte (&cls.message, clc_stringcmd);
277                 MSG_WriteString (&cls.message, "prespawn");
278                 break;
279
280         case 2:
281                 MSG_WriteByte (&cls.message, clc_stringcmd);
282                 MSG_WriteString (&cls.message, va("name \"%s\"\n", cl_name.string));
283
284                 MSG_WriteByte (&cls.message, clc_stringcmd);
285                 MSG_WriteString (&cls.message, va("color %i %i\n", cl_color.integer >> 4, cl_color.integer & 15));
286
287                 if (cl_pmodel.integer)
288                 {
289                         MSG_WriteByte (&cls.message, clc_stringcmd);
290                         MSG_WriteString (&cls.message, va("pmodel %i\n", cl_pmodel.integer));
291                 }
292
293                 MSG_WriteByte (&cls.message, clc_stringcmd);
294                 MSG_WriteString (&cls.message, va("rate %i\n", cl_rate.integer));
295
296                 MSG_WriteByte (&cls.message, clc_stringcmd);
297                 MSG_WriteString (&cls.message, "spawn");
298                 break;
299
300         case 3:
301                 MSG_WriteByte (&cls.message, clc_stringcmd);
302                 MSG_WriteString (&cls.message, "begin");
303                 break;
304
305         case 4:
306                 Con_ClearNotify();
307                 break;
308         }
309 }
310
311 /*
312 ==================
313 CL_ParseServerInfo
314 ==================
315 */
316 qbyte entlife[MAX_EDICTS];
317 // FIXME: this is a lot of memory to be keeping around, this needs to be dynamically allocated and freed
318 static char parse_model_precache[MAX_MODELS][MAX_QPATH];
319 static char parse_sound_precache[MAX_SOUNDS][MAX_QPATH];
320 void CL_ParseServerInfo (void)
321 {
322         char *str;
323         int i;
324         int nummodels, numsounds;
325         entity_t *ent;
326
327         Con_DPrintf ("Serverinfo packet received.\n");
328 //
329 // wipe the client_state_t struct
330 //
331         CL_ClearState ();
332
333 // parse protocol version number
334         i = MSG_ReadLong ();
335         // hack for unmarked Nehahra movie demos which had a custom protocol
336         if (i == PROTOCOL_QUAKE && cls.demoplayback && demo_nehahra.integer)
337                 i = PROTOCOL_NEHAHRAMOVIE;
338         if (i != PROTOCOL_QUAKE && i != PROTOCOL_DARKPLACES1 && i != PROTOCOL_DARKPLACES2 && i != PROTOCOL_DARKPLACES3 && i != PROTOCOL_DARKPLACES4 && i != PROTOCOL_NEHAHRAMOVIE)
339         {
340                 Host_Error("CL_ParseServerInfo: Server is protocol %i, not %i (Quake), %i (DP1), %i (DP2), %i (DP3), %i (DP4), or %i (Nehahra movie)", i, PROTOCOL_QUAKE, PROTOCOL_DARKPLACES1, PROTOCOL_DARKPLACES2, PROTOCOL_DARKPLACES3, PROTOCOL_DARKPLACES4, PROTOCOL_NEHAHRAMOVIE);
341                 return;
342         }
343         cl.protocol = i;
344
345 // parse maxclients
346         cl.maxclients = MSG_ReadByte ();
347         if (cl.maxclients < 1 || cl.maxclients > MAX_SCOREBOARD)
348         {
349                 Con_Printf("Bad maxclients (%u) from server\n", cl.maxclients);
350                 return;
351         }
352         Mem_EmptyPool(cl_scores_mempool);
353         cl.scores = Mem_Alloc(cl_scores_mempool, cl.maxclients*sizeof(*cl.scores));
354
355 // parse gametype
356         cl.gametype = MSG_ReadByte ();
357
358 // parse signon message
359         str = MSG_ReadString ();
360         strlcpy (cl.levelname, str, sizeof(cl.levelname));
361
362 // seperate the printfs so the server message can have a color
363         if (cl.protocol != PROTOCOL_NEHAHRAMOVIE) // no messages when playing the Nehahra movie
364         {
365                 Con_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
366                 Con_Printf("%c%s\n", 2, str);
367         }
368
369         // check memory integrity
370         Mem_CheckSentinelsGlobal();
371
372         // disable until we get textures for it
373         R_ResetSkyBox();
374
375         memset(cl.model_precache, 0, sizeof(cl.model_precache));
376         memset(cl.sound_precache, 0, sizeof(cl.sound_precache));
377
378         // parse model precache list
379         for (nummodels=1 ; ; nummodels++)
380         {
381                 str = MSG_ReadString();
382                 if (!str[0])
383                         break;
384                 if (nummodels==MAX_MODELS)
385                         Host_Error ("Server sent too many model precaches\n");
386                 if (strlen(str) >= MAX_QPATH)
387                         Host_Error ("Server sent a precache name of %i characters (max %i)", strlen(str), MAX_QPATH - 1);
388                 strlcpy (parse_model_precache[nummodels], str, sizeof (parse_model_precache[nummodels]));
389         }
390         // parse sound precache list
391         for (numsounds=1 ; ; numsounds++)
392         {
393                 str = MSG_ReadString();
394                 if (!str[0])
395                         break;
396                 if (numsounds==MAX_SOUNDS)
397                         Host_Error("Server sent too many sound precaches\n");
398                 if (strlen(str) >= MAX_QPATH)
399                         Host_Error("Server sent a precache name of %i characters (max %i)", strlen(str), MAX_QPATH - 1);
400                 strlcpy (parse_sound_precache[numsounds], str, sizeof (parse_sound_precache[numsounds]));
401         }
402
403         // touch all of the precached models that are still loaded so we can free
404         // anything that isn't needed
405         Mod_ClearUsed();
406         for (i = 1;i < nummodels;i++)
407         {
408                 CL_KeepaliveMessage();
409                 Mod_TouchModel(parse_model_precache[i]);
410         }
411         Mod_PurgeUnused();
412
413         // do the same for sounds
414         S_ClearUsed();
415         for (i = 1;i < numsounds;i++)
416         {
417                 CL_KeepaliveMessage();
418                 S_TouchSound(parse_sound_precache[i]);
419         }
420         S_PurgeUnused();
421
422         // now we try to load everything that is new
423
424         // world model
425         CL_KeepaliveMessage ();
426         cl.model_precache[1] = Mod_ForName(parse_model_precache[1], false, false, true);
427         if (cl.model_precache[1] == NULL)
428                 Con_Printf("Map %s not found\n", parse_model_precache[1]);
429
430         // normal models
431         for (i=2 ; i<nummodels ; i++)
432         {
433                 CL_KeepaliveMessage();
434                 if ((cl.model_precache[i] = Mod_ForName(parse_model_precache[i], false, false, false)) == NULL)
435                         Con_Printf("Model %s not found\n", parse_model_precache[i]);
436         }
437
438         // sounds
439         for (i=1 ; i<numsounds ; i++)
440         {
441                 CL_KeepaliveMessage();
442                 cl.sound_precache[i] = S_PrecacheSound(parse_sound_precache[i], true);
443         }
444
445         // local state
446         ent = &cl_entities[0];
447         // entire entity array was cleared, so just fill in a few fields
448         ent->state_current.active = true;
449         ent->render.model = cl.worldmodel = cl.model_precache[1];
450         //ent->render.scale = 1;
451         ent->render.alpha = 1;
452         ent->render.flags = RENDER_SHADOW;
453         Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, 0, 0, 0, 0, 0, 0, 1);
454         Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix);
455         CL_BoundingBoxForEntity(&ent->render);
456         // clear entlife array
457         memset(entlife, 0, MAX_EDICTS);
458
459         cl_num_entities = 1;
460
461         R_Modules_NewMap();
462         CL_CGVM_Start();
463
464         // noclip is turned off at start
465         noclip_anglehack = false;
466
467         // check memory integrity
468         Mem_CheckSentinelsGlobal();
469 }
470
471 void CL_ValidateState(entity_state_t *s)
472 {
473         model_t *model;
474
475         if (!s->active)
476                 return;
477
478         if (s->modelindex >= MAX_MODELS)
479                 Host_Error("CL_ValidateState: modelindex (%i) >= MAX_MODELS (%i)\n", s->modelindex, MAX_MODELS);
480
481         // colormap is client index + 1
482         if (s->colormap > cl.maxclients)
483                 Host_Error ("CL_ValidateState: colormap (%i) > cl.maxclients (%i)", s->colormap, cl.maxclients);
484
485         model = cl.model_precache[s->modelindex];
486         Mod_CheckLoaded(model);
487         if (model && s->frame >= model->numframes)
488         {
489                 Con_DPrintf("CL_ValidateState: no such frame %i in \"%s\"\n", s->frame, model->name);
490                 s->frame = 0;
491         }
492         if (model && s->skin > 0 && s->skin >= model->numskins)
493         {
494                 Con_DPrintf("CL_ValidateState: no such skin %i in \"%s\"\n", s->skin, model->name);
495                 s->skin = 0;
496         }
497 }
498
499 void CL_MoveLerpEntityStates(entity_t *ent)
500 {
501         float odelta[3], adelta[3];
502         VectorSubtract(ent->state_current.origin, ent->persistent.neworigin, odelta);
503         VectorSubtract(ent->state_current.angles, ent->persistent.newangles, adelta);
504         if (!ent->state_previous.active || cls.timedemo || DotProduct(odelta, odelta) > 1000*1000 || cl_nolerp.integer)
505         {
506                 // we definitely shouldn't lerp
507                 ent->persistent.lerpdeltatime = 0;
508                 ent->persistent.lerpstarttime = cl.mtime[1];
509                 VectorCopy(ent->state_current.origin, ent->persistent.oldorigin);
510                 VectorCopy(ent->state_current.angles, ent->persistent.oldangles);
511                 VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
512                 VectorCopy(ent->state_current.angles, ent->persistent.newangles);
513         }
514         else if (ent->state_current.flags & RENDER_STEP)
515         {
516                 // monster interpolation
517                 if (DotProduct(odelta, odelta) + DotProduct(adelta, adelta) > 0.01)
518                 {
519                         ent->persistent.lerpdeltatime = bound(0, cl.mtime[1] - ent->persistent.lerpstarttime, 0.1);
520                         ent->persistent.lerpstarttime = cl.mtime[1];
521                         VectorCopy(ent->persistent.neworigin, ent->persistent.oldorigin);
522                         VectorCopy(ent->persistent.newangles, ent->persistent.oldangles);
523                         VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
524                         VectorCopy(ent->state_current.angles, ent->persistent.newangles);
525                 }
526         }
527         else
528         {
529                 // not a monster
530                 ent->persistent.lerpstarttime = cl.mtime[1];
531                 // no lerp if it's singleplayer
532                 if (cl.islocalgame)
533                         ent->persistent.lerpdeltatime = 0;
534                 else
535                         ent->persistent.lerpdeltatime = cl.mtime[0] - cl.mtime[1];
536                 VectorCopy(ent->persistent.neworigin, ent->persistent.oldorigin);
537                 VectorCopy(ent->persistent.newangles, ent->persistent.oldangles);
538                 VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
539                 VectorCopy(ent->state_current.angles, ent->persistent.newangles);
540         }
541 }
542
543 /*
544 ==================
545 CL_ParseUpdate
546
547 Parse an entity update message from the server
548 If an entities model or origin changes from frame to frame, it must be
549 relinked.  Other attributes can change without relinking.
550 ==================
551 */
552 void CL_ParseUpdate (int bits)
553 {
554         int num;
555         entity_t *ent;
556         entity_state_t new;
557
558         if (bits & U_MOREBITS)
559                 bits |= (MSG_ReadByte()<<8);
560         if ((bits & U_EXTEND1) && cl.protocol != PROTOCOL_NEHAHRAMOVIE)
561         {
562                 bits |= MSG_ReadByte() << 16;
563                 if (bits & U_EXTEND2)
564                         bits |= MSG_ReadByte() << 24;
565         }
566
567         if (bits & U_LONGENTITY)
568                 num = (unsigned) MSG_ReadShort ();
569         else
570                 num = (unsigned) MSG_ReadByte ();
571
572         if (num >= MAX_EDICTS)
573                 Host_Error("CL_ParseUpdate: entity number (%i) >= MAX_EDICTS (%i)\n", num, MAX_EDICTS);
574         if (num < 1)
575                 Host_Error("CL_ParseUpdate: invalid entity number (%i)\n", num);
576
577         ent = cl_entities + num;
578
579         // note: this inherits the 'active' state of the baseline chosen
580         // (state_baseline is always active, state_current may not be active if
581         // the entity was missing in the last frame)
582         if (bits & U_DELTA)
583                 new = ent->state_current;
584         else
585         {
586                 new = ent->state_baseline;
587                 new.active = true;
588         }
589
590         new.number = num;
591         new.time = cl.mtime[0];
592         new.flags = 0;
593         if (bits & U_MODEL)             new.modelindex = (new.modelindex & 0xFF00) | MSG_ReadByte();
594         if (bits & U_FRAME)             new.frame = (new.frame & 0xFF00) | MSG_ReadByte();
595         if (bits & U_COLORMAP)  new.colormap = MSG_ReadByte();
596         if (bits & U_SKIN)              new.skin = MSG_ReadByte();
597         if (bits & U_EFFECTS)   new.effects = (new.effects & 0xFF00) | MSG_ReadByte();
598         if (bits & U_ORIGIN1)   new.origin[0] = MSG_ReadCoord();
599         if (bits & U_ANGLE1)    new.angles[0] = MSG_ReadAngle();
600         if (bits & U_ORIGIN2)   new.origin[1] = MSG_ReadCoord();
601         if (bits & U_ANGLE2)    new.angles[1] = MSG_ReadAngle();
602         if (bits & U_ORIGIN3)   new.origin[2] = MSG_ReadCoord();
603         if (bits & U_ANGLE3)    new.angles[2] = MSG_ReadAngle();
604         if (bits & U_STEP)              new.flags |= RENDER_STEP;
605         if (bits & U_ALPHA)             new.alpha = MSG_ReadByte();
606         if (bits & U_SCALE)             new.scale = MSG_ReadByte();
607         if (bits & U_EFFECTS2)  new.effects = (new.effects & 0x00FF) | (MSG_ReadByte() << 8);
608         if (bits & U_GLOWSIZE)  new.glowsize = MSG_ReadByte();
609         if (bits & U_GLOWCOLOR) new.glowcolor = MSG_ReadByte();
610         // apparently the dpcrush demo uses this (unintended, and it uses white anyway)
611         if (bits & U_COLORMOD)  MSG_ReadByte();
612         if (bits & U_GLOWTRAIL) new.flags |= RENDER_GLOWTRAIL;
613         if (bits & U_FRAME2)    new.frame = (new.frame & 0x00FF) | (MSG_ReadByte() << 8);
614         if (bits & U_MODEL2)    new.modelindex = (new.modelindex & 0x00FF) | (MSG_ReadByte() << 8);
615         if (bits & U_VIEWMODEL) new.flags |= RENDER_VIEWMODEL;
616         if (bits & U_EXTERIORMODEL)     new.flags |= RENDER_EXTERIORMODEL;
617
618         // LordHavoc: to allow playback of the Nehahra movie
619         if (cl.protocol == PROTOCOL_NEHAHRAMOVIE && (bits & U_EXTEND1))
620         {
621                 // LordHavoc: evil format
622                 int i = MSG_ReadFloat();
623                 int j = MSG_ReadFloat() * 255.0f;
624                 if (i == 2)
625                 {
626                         i = MSG_ReadFloat();
627                         if (i)
628                                 new.effects |= EF_FULLBRIGHT;
629                 }
630                 if (j < 0)
631                         new.alpha = 0;
632                 else if (j == 0 || j >= 255)
633                         new.alpha = 255;
634                 else
635                         new.alpha = j;
636         }
637
638         if (new.active)
639                 CL_ValidateState(&new);
640
641         ent->state_previous = ent->state_current;
642         ent->state_current = new;
643         if (ent->state_current.active)
644         {
645                 CL_MoveLerpEntityStates(ent);
646                 cl_entities_active[ent->state_current.number] = true;
647                 // mark as visible (no kill this frame)
648                 entlife[ent->state_current.number] = 2;
649         }
650 }
651
652 static entity_frame_t entityframe;
653 extern mempool_t *cl_entities_mempool;
654 void CL_ReadEntityFrame(void)
655 {
656         if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
657         {
658                 int i;
659                 entity_t *ent;
660                 EntityFrame_Read(&cl.entitydatabase);
661                 EntityFrame_FetchFrame(&cl.entitydatabase, EntityFrame_MostRecentlyRecievedFrameNum(&cl.entitydatabase), &entityframe);
662                 for (i = 0;i < entityframe.numentities;i++)
663                 {
664                         // copy the states
665                         ent = &cl_entities[entityframe.entitydata[i].number];
666                         ent->state_previous = ent->state_current;
667                         ent->state_current = entityframe.entitydata[i];
668                         CL_MoveLerpEntityStates(ent);
669                         // the entity lives again...
670                         entlife[ent->state_current.number] = 2;
671                         cl_entities_active[ent->state_current.number] = true;
672                 }
673         }
674         else
675         {
676                 if (!cl.entitydatabase4)
677                         cl.entitydatabase4 = EntityFrame4_AllocDatabase(cl_entities_mempool);
678                 EntityFrame4_CL_ReadFrame(cl.entitydatabase4);
679         }
680 }
681
682 void CL_EntityUpdateSetup(void)
683 {
684 }
685
686 void CL_EntityUpdateEnd(void)
687 {
688         if (cl.protocol == PROTOCOL_QUAKE || cl.protocol == PROTOCOL_NEHAHRAMOVIE || cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
689         {
690                 int i;
691                 // disable entities that disappeared this frame
692                 for (i = 1;i < MAX_EDICTS;i++)
693                 {
694                         // clear only the entities that were active last frame but not this
695                         // frame, don't waste time clearing all entities (which would cause
696                         // cache misses)
697                         if (entlife[i])
698                         {
699                                 entlife[i]--;
700                                 if (!entlife[i])
701                                         cl_entities[i].state_previous.active = cl_entities[i].state_current.active = 0;
702                         }
703                 }
704         }
705 }
706
707 /*
708 ==================
709 CL_ParseBaseline
710 ==================
711 */
712 void CL_ParseBaseline (entity_t *ent, int large)
713 {
714         int i;
715
716         ClearStateToDefault(&ent->state_baseline);
717         ent->state_baseline.active = true;
718         if (large)
719         {
720                 ent->state_baseline.modelindex = (unsigned short) MSG_ReadShort ();
721                 ent->state_baseline.frame = (unsigned short) MSG_ReadShort ();
722         }
723         else
724         {
725                 ent->state_baseline.modelindex = MSG_ReadByte ();
726                 ent->state_baseline.frame = MSG_ReadByte ();
727         }
728         ent->state_baseline.colormap = MSG_ReadByte();
729         ent->state_baseline.skin = MSG_ReadByte();
730         for (i = 0;i < 3;i++)
731         {
732                 ent->state_baseline.origin[i] = MSG_ReadCoord ();
733                 ent->state_baseline.angles[i] = MSG_ReadAngle ();
734         }
735         CL_ValidateState(&ent->state_baseline);
736         ent->state_previous = ent->state_current = ent->state_baseline;
737 }
738
739
740 /*
741 ==================
742 CL_ParseClientdata
743
744 Server information pertaining to this client only
745 ==================
746 */
747 void CL_ParseClientdata (int bits)
748 {
749         int i, j;
750
751         bits &= 0xFFFF;
752         if (bits & SU_EXTEND1)
753                 bits |= (MSG_ReadByte() << 16);
754         if (bits & SU_EXTEND2)
755                 bits |= (MSG_ReadByte() << 24);
756
757         if (bits & SU_VIEWHEIGHT)
758                 cl.viewheight = MSG_ReadChar ();
759         else
760                 cl.viewheight = DEFAULT_VIEWHEIGHT;
761
762         if (bits & SU_IDEALPITCH)
763                 cl.idealpitch = MSG_ReadChar ();
764         else
765                 cl.idealpitch = 0;
766
767         VectorCopy (cl.mvelocity[0], cl.mvelocity[1]);
768         for (i=0 ; i<3 ; i++)
769         {
770                 if (bits & (SU_PUNCH1<<i) )
771                 {
772                         if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4)
773                                 cl.punchangle[i] = MSG_ReadPreciseAngle();
774                         else
775                                 cl.punchangle[i] = MSG_ReadChar();
776                 }
777                 else
778                         cl.punchangle[i] = 0;
779                 if (bits & (SU_PUNCHVEC1<<i))
780                         cl.punchvector[i] = MSG_ReadCoord();
781                 else
782                         cl.punchvector[i] = 0;
783                 if (bits & (SU_VELOCITY1<<i) )
784                         cl.mvelocity[0][i] = MSG_ReadChar()*16;
785                 else
786                         cl.mvelocity[0][i] = 0;
787         }
788
789         i = MSG_ReadLong ();
790         if (cl.items != i)
791         {       // set flash times
792                 for (j=0 ; j<32 ; j++)
793                         if ( (i & (1<<j)) && !(cl.items & (1<<j)))
794                                 cl.item_gettime[j] = cl.time;
795                 cl.items = i;
796         }
797
798         cl.onground = (bits & SU_ONGROUND) != 0;
799         cl.inwater = (bits & SU_INWATER) != 0;
800
801         cl.stats[STAT_WEAPONFRAME] = (bits & SU_WEAPONFRAME) ? MSG_ReadByte() : 0;
802         cl.stats[STAT_ARMOR] = (bits & SU_ARMOR) ? MSG_ReadByte() : 0;
803         cl.stats[STAT_WEAPON] = (bits & SU_WEAPON) ? MSG_ReadByte() : 0;
804         cl.stats[STAT_HEALTH] = MSG_ReadShort();
805         cl.stats[STAT_AMMO] = MSG_ReadByte();
806
807         cl.stats[STAT_SHELLS] = MSG_ReadByte();
808         cl.stats[STAT_NAILS] = MSG_ReadByte();
809         cl.stats[STAT_ROCKETS] = MSG_ReadByte();
810         cl.stats[STAT_CELLS] = MSG_ReadByte();
811
812         i = MSG_ReadByte ();
813
814         if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
815                 i = (1<<i);
816         // GAME_NEXUIZ hud needs weapon change time
817         // GAME_NEXUIZ uses a bit number as it's STAT_ACTIVEWEAPON, not a bitfield
818         // like other modes
819         if (cl.stats[STAT_ACTIVEWEAPON] != i)
820                 cl.weapontime = cl.time;
821         cl.stats[STAT_ACTIVEWEAPON] = i;
822
823         cl.viewzoomold = cl.viewzoomnew; // for interpolation
824         if (bits & SU_VIEWZOOM)
825         {
826                 i = MSG_ReadByte();
827                 if (i < 2)
828                         i = 2;
829                 cl.viewzoomnew = (float) i * (1.0f / 255.0f);
830         }
831         else
832                 cl.viewzoomnew = 1;
833
834 }
835
836 /*
837 =====================
838 CL_ParseStatic
839 =====================
840 */
841 void CL_ParseStatic (int large)
842 {
843         entity_t *ent;
844
845         if (cl_num_static_entities >= cl_max_static_entities)
846                 Host_Error ("Too many static entities");
847         ent = &cl_static_entities[cl_num_static_entities++];
848         CL_ParseBaseline (ent, large);
849
850 // copy it to the current state
851         ent->render.model = cl.model_precache[ent->state_baseline.modelindex];
852         ent->render.frame = ent->render.frame1 = ent->render.frame2 = ent->state_baseline.frame;
853         ent->render.framelerp = 0;
854         // make torchs play out of sync
855         ent->render.frame1time = ent->render.frame2time = lhrandom(-10, -1);
856         ent->render.colormap = -1; // no special coloring
857         ent->render.skinnum = ent->state_baseline.skin;
858         ent->render.effects = ent->state_baseline.effects;
859         ent->render.alpha = 1;
860         //ent->render.scale = 1;
861
862         //VectorCopy (ent->state_baseline.origin, ent->render.origin);
863         //VectorCopy (ent->state_baseline.angles, ent->render.angles);
864
865         Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, ent->state_baseline.origin[0], ent->state_baseline.origin[1], ent->state_baseline.origin[2], ent->state_baseline.angles[0], ent->state_baseline.angles[1], ent->state_baseline.angles[2], 1);
866         Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix);
867         CL_BoundingBoxForEntity(&ent->render);
868
869         // This is definitely cheating...
870         if (ent->render.model == NULL)
871                 cl_num_static_entities--;
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 model_t *cl_model_bolt = NULL;
924 model_t *cl_model_bolt2 = NULL;
925 model_t *cl_model_bolt3 = NULL;
926 model_t *cl_model_beam = NULL;
927
928 sfx_t *cl_sfx_wizhit;
929 sfx_t *cl_sfx_knighthit;
930 sfx_t *cl_sfx_tink1;
931 sfx_t *cl_sfx_ric1;
932 sfx_t *cl_sfx_ric2;
933 sfx_t *cl_sfx_ric3;
934 sfx_t *cl_sfx_r_exp3;
935
936 /*
937 =================
938 CL_ParseTEnt
939 =================
940 */
941 void CL_InitTEnts (void)
942 {
943         cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav", false);
944         cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav", false);
945         cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav", false);
946         cl_sfx_ric1 = S_PrecacheSound ("weapons/ric1.wav", false);
947         cl_sfx_ric2 = S_PrecacheSound ("weapons/ric2.wav", false);
948         cl_sfx_ric3 = S_PrecacheSound ("weapons/ric3.wav", false);
949         cl_sfx_r_exp3 = S_PrecacheSound ("weapons/r_exp3.wav", false);
950 }
951
952 void CL_ParseBeam (model_t *m, int lightning)
953 {
954         int i, ent;
955         vec3_t start, end;
956         beam_t *b;
957
958         ent = MSG_ReadShort ();
959         MSG_ReadVector(start);
960         MSG_ReadVector(end);
961
962         if (ent >= MAX_EDICTS)
963         {
964                 Con_Printf("CL_ParseBeam: invalid entity number %i\n", ent);
965                 ent = 0;
966         }
967
968         // override any beam with the same entity
969         for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
970         {
971                 if (b->entity == ent)
972                 {
973                         //b->entity = ent;
974                         b->lightning = lightning;
975                         b->relativestartvalid = (ent && cl_entities[ent].state_current.active) ? 2 : 0;
976                         b->model = m;
977                         b->endtime = cl.time + 0.2;
978                         VectorCopy (start, b->start);
979                         VectorCopy (end, b->end);
980                         return;
981                 }
982         }
983
984         // find a free beam
985         for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
986         {
987                 if (!b->model || b->endtime < cl.time)
988                 {
989                         b->entity = ent;
990                         b->lightning = lightning;
991                         b->relativestartvalid = (ent && cl_entities[ent].state_current.active) ? 2 : 0;
992                         b->model = m;
993                         b->endtime = cl.time + 0.2;
994                         VectorCopy (start, b->start);
995                         VectorCopy (end, b->end);
996                         return;
997                 }
998         }
999         Con_Printf ("beam list overflow!\n");
1000 }
1001
1002 void CL_ParseTempEntity(void)
1003 {
1004         int type;
1005         vec3_t pos;
1006         vec3_t dir;
1007         vec3_t pos2;
1008         vec3_t color;
1009         int rnd;
1010         int colorStart, colorLength, count;
1011         float velspeed, radius;
1012         qbyte *tempcolor;
1013         matrix4x4_t tempmatrix;
1014
1015         type = MSG_ReadByte();
1016         switch (type)
1017         {
1018         case TE_WIZSPIKE:
1019                 // spike hitting wall
1020                 MSG_ReadVector(pos);
1021                 CL_FindNonSolidLocation(pos, pos, 4);
1022                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1023                 CL_AllocDlight(NULL, &tempmatrix, 150, 0.25f, 1.00f, 0.25f, 250, 0.2, 0, 0, false, 1);
1024                 CL_RunParticleEffect(pos, vec3_origin, 20, 30);
1025                 S_StartSound(-1, 0, cl_sfx_wizhit, pos, 1, 1);
1026                 break;
1027
1028         case TE_KNIGHTSPIKE:
1029                 // spike hitting wall
1030                 MSG_ReadVector(pos);
1031                 CL_FindNonSolidLocation(pos, pos, 4);
1032                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1033                 CL_AllocDlight(NULL, &tempmatrix, 150, 1.0f, 0.60f, 0.20f, 250, 0.2, 0, 0, false, 1);
1034                 CL_RunParticleEffect(pos, vec3_origin, 226, 20);
1035                 S_StartSound(-1, 0, cl_sfx_knighthit, pos, 1, 1);
1036                 break;
1037
1038         case TE_SPIKE:
1039                 // spike hitting wall
1040                 MSG_ReadVector(pos);
1041                 CL_FindNonSolidLocation(pos, pos, 4);
1042                 // LordHavoc: changed to spark shower
1043                 CL_SparkShower(pos, vec3_origin, 15);
1044                 if (rand() % 5)
1045                         S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1046                 else
1047                 {
1048                         rnd = rand() & 3;
1049                         if (rnd == 1)
1050                                 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1051                         else if (rnd == 2)
1052                                 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1053                         else
1054                                 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1055                 }
1056                 break;
1057         case TE_SPIKEQUAD:
1058                 // quad spike hitting wall
1059                 MSG_ReadVector(pos);
1060                 CL_FindNonSolidLocation(pos, pos, 4);
1061                 // LordHavoc: changed to spark shower
1062                 CL_SparkShower(pos, vec3_origin, 15);
1063                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1064                 CL_AllocDlight(NULL, &tempmatrix, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2, 0, 0, true, 1);
1065                 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1066                 if (rand() % 5)
1067                         S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1068                 else
1069                 {
1070                         rnd = rand() & 3;
1071                         if (rnd == 1)
1072                                 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1073                         else if (rnd == 2)
1074                                 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1075                         else
1076                                 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1077                 }
1078                 break;
1079         case TE_SUPERSPIKE:
1080                 // super spike hitting wall
1081                 MSG_ReadVector(pos);
1082                 CL_FindNonSolidLocation(pos, pos, 4);
1083                 // LordHavoc: changed to dust shower
1084                 CL_SparkShower(pos, vec3_origin, 30);
1085                 if (rand() % 5)
1086                         S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1087                 else
1088                 {
1089                         rnd = rand() & 3;
1090                         if (rnd == 1)
1091                                 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1092                         else if (rnd == 2)
1093                                 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1094                         else
1095                                 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1096                 }
1097                 break;
1098         case TE_SUPERSPIKEQUAD:
1099                 // quad super spike hitting wall
1100                 MSG_ReadVector(pos);
1101                 CL_FindNonSolidLocation(pos, pos, 4);
1102                 // LordHavoc: changed to dust shower
1103                 CL_SparkShower(pos, vec3_origin, 30);
1104                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1105                 CL_AllocDlight(NULL, &tempmatrix, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2, 0, 0, true, 1);
1106                 if (rand() % 5)
1107                         S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1108                 else
1109                 {
1110                         rnd = rand() & 3;
1111                         if (rnd == 1)
1112                                 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1113                         else if (rnd == 2)
1114                                 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1115                         else
1116                                 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1117                 }
1118                 break;
1119                 // LordHavoc: added for improved blood splatters
1120         case TE_BLOOD:
1121                 // blood puff
1122                 MSG_ReadVector(pos);
1123                 CL_FindNonSolidLocation(pos, pos, 4);
1124                 dir[0] = MSG_ReadChar();
1125                 dir[1] = MSG_ReadChar();
1126                 dir[2] = MSG_ReadChar();
1127                 count = MSG_ReadByte();
1128                 CL_BloodPuff(pos, dir, count);
1129                 break;
1130         case TE_SPARK:
1131                 // spark shower
1132                 MSG_ReadVector(pos);
1133                 CL_FindNonSolidLocation(pos, pos, 4);
1134                 dir[0] = MSG_ReadChar();
1135                 dir[1] = MSG_ReadChar();
1136                 dir[2] = MSG_ReadChar();
1137                 count = MSG_ReadByte();
1138                 CL_SparkShower(pos, dir, count);
1139                 break;
1140         case TE_PLASMABURN:
1141                 MSG_ReadVector(pos);
1142                 CL_FindNonSolidLocation(pos, pos, 4);
1143                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1144                 CL_AllocDlight(NULL, &tempmatrix, 200, 1, 1, 1, 1000, 0.2, 0, 0, true, 1);
1145                 CL_PlasmaBurn(pos);
1146                 break;
1147                 // LordHavoc: added for improved gore
1148         case TE_BLOODSHOWER:
1149                 // vaporized body
1150                 MSG_ReadVector(pos); // mins
1151                 MSG_ReadVector(pos2); // maxs
1152                 velspeed = MSG_ReadCoord(); // speed
1153                 count = MSG_ReadShort(); // number of particles
1154                 CL_BloodShower(pos, pos2, velspeed, count);
1155                 break;
1156         case TE_PARTICLECUBE:
1157                 // general purpose particle effect
1158                 MSG_ReadVector(pos); // mins
1159                 MSG_ReadVector(pos2); // maxs
1160                 MSG_ReadVector(dir); // dir
1161                 count = MSG_ReadShort(); // number of particles
1162                 colorStart = MSG_ReadByte(); // color
1163                 colorLength = MSG_ReadByte(); // gravity (1 or 0)
1164                 velspeed = MSG_ReadCoord(); // randomvel
1165                 CL_ParticleCube(pos, pos2, dir, count, colorStart, colorLength, velspeed);
1166                 break;
1167
1168         case TE_PARTICLERAIN:
1169                 // general purpose particle effect
1170                 MSG_ReadVector(pos); // mins
1171                 MSG_ReadVector(pos2); // maxs
1172                 MSG_ReadVector(dir); // dir
1173                 count = MSG_ReadShort(); // number of particles
1174                 colorStart = MSG_ReadByte(); // color
1175                 CL_ParticleRain(pos, pos2, dir, count, colorStart, 0);
1176                 break;
1177
1178         case TE_PARTICLESNOW:
1179                 // general purpose particle effect
1180                 MSG_ReadVector(pos); // mins
1181                 MSG_ReadVector(pos2); // maxs
1182                 MSG_ReadVector(dir); // dir
1183                 count = MSG_ReadShort(); // number of particles
1184                 colorStart = MSG_ReadByte(); // color
1185                 CL_ParticleRain(pos, pos2, dir, count, colorStart, 1);
1186                 break;
1187
1188         case TE_GUNSHOT:
1189                 // bullet hitting wall
1190                 MSG_ReadVector(pos);
1191                 CL_FindNonSolidLocation(pos, pos, 4);
1192                 // LordHavoc: changed to dust shower
1193                 CL_SparkShower(pos, vec3_origin, 15);
1194                 break;
1195
1196         case TE_GUNSHOTQUAD:
1197                 // quad bullet hitting wall
1198                 MSG_ReadVector(pos);
1199                 CL_FindNonSolidLocation(pos, pos, 4);
1200                 CL_SparkShower(pos, vec3_origin, 15);
1201                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1202                 CL_AllocDlight(NULL, &tempmatrix, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2, 0, 0, true, 1);
1203                 break;
1204
1205         case TE_EXPLOSION:
1206                 // rocket explosion
1207                 MSG_ReadVector(pos);
1208                 CL_FindNonSolidLocation(pos, pos, 10);
1209                 CL_ParticleExplosion(pos);
1210                 // LordHavoc: boosted color from 1.0, 0.8, 0.4 to 1.25, 1.0, 0.5
1211                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1212                 CL_AllocDlight(NULL, &tempmatrix, 350, 1.25f, 1.0f, 0.5f, 700, 0.5, 0, 0, true, 1);
1213                 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1214                 break;
1215
1216         case TE_EXPLOSIONQUAD:
1217                 // quad rocket explosion
1218                 MSG_ReadVector(pos);
1219                 CL_FindNonSolidLocation(pos, pos, 10);
1220                 CL_ParticleExplosion(pos);
1221                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1222                 CL_AllocDlight(NULL, &tempmatrix, 600, 0.5f, 0.4f, 1.0f, 1200, 0.5, 0, 0, true, 1);
1223                 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1224                 break;
1225
1226         case TE_EXPLOSION3:
1227                 // Nehahra movie colored lighting explosion
1228                 MSG_ReadVector(pos);
1229                 CL_FindNonSolidLocation(pos, pos, 10);
1230                 CL_ParticleExplosion(pos);
1231                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1232                 CL_AllocDlight(NULL, &tempmatrix, 350, MSG_ReadCoord(), MSG_ReadCoord(), MSG_ReadCoord(), 700, 0.5, 0, 0, true, 1);
1233                 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1234                 break;
1235
1236         case TE_EXPLOSIONRGB:
1237                 // colored lighting explosion
1238                 MSG_ReadVector(pos);
1239                 CL_FindNonSolidLocation(pos, pos, 10);
1240                 CL_ParticleExplosion(pos);
1241                 color[0] = MSG_ReadByte() * (1.0 / 255.0);
1242                 color[1] = MSG_ReadByte() * (1.0 / 255.0);
1243                 color[2] = MSG_ReadByte() * (1.0 / 255.0);
1244                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1245                 CL_AllocDlight(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, 0, true, 1);
1246                 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1247                 break;
1248
1249         case TE_TAREXPLOSION:
1250                 // tarbaby explosion
1251                 MSG_ReadVector(pos);
1252                 CL_FindNonSolidLocation(pos, pos, 10);
1253                 CL_BlobExplosion(pos);
1254
1255                 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1256                 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1257                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1258                 CL_AllocDlight(NULL, &tempmatrix, 600, 0.8f, 0.4f, 1.0f, 1200, 0.5, 0, 0, true, 1);
1259                 break;
1260
1261         case TE_SMALLFLASH:
1262                 MSG_ReadVector(pos);
1263                 CL_FindNonSolidLocation(pos, pos, 10);
1264                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1265                 CL_AllocDlight(NULL, &tempmatrix, 200, 1, 1, 1, 1000, 0.2, 0, 0, true, 1);
1266                 break;
1267
1268         case TE_CUSTOMFLASH:
1269                 MSG_ReadVector(pos);
1270                 CL_FindNonSolidLocation(pos, pos, 4);
1271                 radius = MSG_ReadByte() * 8;
1272                 velspeed = (MSG_ReadByte() + 1) * (1.0 / 256.0);
1273                 color[0] = MSG_ReadByte() * (1.0 / 255.0);
1274                 color[1] = MSG_ReadByte() * (1.0 / 255.0);
1275                 color[2] = MSG_ReadByte() * (1.0 / 255.0);
1276                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1277                 CL_AllocDlight(NULL, &tempmatrix, radius, color[0], color[1], color[2], radius / velspeed, velspeed, 0, 0, true, 1);
1278                 break;
1279
1280         case TE_FLAMEJET:
1281                 MSG_ReadVector(pos);
1282                 MSG_ReadVector(dir);
1283                 count = MSG_ReadByte();
1284                 CL_Flames(pos, dir, count);
1285                 break;
1286
1287         case TE_LIGHTNING1:
1288                 // lightning bolts
1289                 if (!cl_model_bolt)
1290                         cl_model_bolt = Mod_ForName("progs/bolt.mdl", true, false, false);
1291                 CL_ParseBeam(cl_model_bolt, true);
1292                 break;
1293
1294         case TE_LIGHTNING2:
1295                 // lightning bolts
1296                 if (!cl_model_bolt2)
1297                         cl_model_bolt2 = Mod_ForName("progs/bolt2.mdl", true, false, false);
1298                 CL_ParseBeam(cl_model_bolt2, true);
1299                 break;
1300
1301         case TE_LIGHTNING3:
1302                 // lightning bolts
1303                 if (!cl_model_bolt3)
1304                         cl_model_bolt3 = Mod_ForName("progs/bolt3.mdl", true, false, false);
1305                 CL_ParseBeam(cl_model_bolt3, false);
1306                 break;
1307
1308 // PGM 01/21/97
1309         case TE_BEAM:
1310                 // grappling hook beam
1311                 if (!cl_model_beam)
1312                         cl_model_beam = Mod_ForName("progs/beam.mdl", true, false, false);
1313                 CL_ParseBeam(cl_model_beam, false);
1314                 break;
1315 // PGM 01/21/97
1316
1317 // LordHavoc: for compatibility with the Nehahra movie...
1318         case TE_LIGHTNING4NEH:
1319                 CL_ParseBeam(Mod_ForName(MSG_ReadString(), true, false, false), false);
1320                 break;
1321
1322         case TE_LAVASPLASH:
1323                 pos[0] = MSG_ReadCoord();
1324                 pos[1] = MSG_ReadCoord();
1325                 pos[2] = MSG_ReadCoord();
1326                 CL_LavaSplash(pos);
1327                 break;
1328
1329         case TE_TELEPORT:
1330                 pos[0] = MSG_ReadCoord();
1331                 pos[1] = MSG_ReadCoord();
1332                 pos[2] = MSG_ReadCoord();
1333                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1334                 CL_AllocDlight(NULL, &tempmatrix, 500, 1.0f, 1.0f, 1.0f, 1500, 99.0f, 0, 0, true, 1);
1335 //              CL_TeleportSplash(pos);
1336                 break;
1337
1338         case TE_EXPLOSION2:
1339                 // color mapped explosion
1340                 MSG_ReadVector(pos);
1341                 CL_FindNonSolidLocation(pos, pos, 10);
1342                 colorStart = MSG_ReadByte();
1343                 colorLength = MSG_ReadByte();
1344                 CL_ParticleExplosion2(pos, colorStart, colorLength);
1345                 tempcolor = (qbyte *)&palette_complete[(rand()%colorLength) + colorStart];
1346                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1347                 CL_AllocDlight(NULL, &tempmatrix, 350, tempcolor[0] * (1.0f / 255.0f), tempcolor[1] * (1.0f / 255.0f), tempcolor[2] * (1.0f / 255.0f), 700, 0.5, 0, 0, true, 1);
1348                 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1349                 break;
1350
1351         case TE_TEI_G3:
1352                 MSG_ReadVector(pos);
1353                 MSG_ReadVector(pos2);
1354                 MSG_ReadVector(dir);
1355                 CL_BeamParticle(pos, pos2, 12, 1, 0.3, 0.1, 1, 1);
1356                 CL_BeamParticle(pos, pos2, 5, 1, 0.9, 0.3, 1, 1);
1357                 break;
1358
1359         case TE_TEI_SMOKE:
1360                 MSG_ReadVector(pos);
1361                 MSG_ReadVector(dir);
1362                 count = MSG_ReadByte();
1363                 CL_FindNonSolidLocation(pos, pos, 4);
1364                 CL_Tei_Smoke(pos, dir, count);
1365                 break;
1366
1367         case TE_TEI_BIGEXPLOSION:
1368                 MSG_ReadVector(pos);
1369                 CL_FindNonSolidLocation(pos, pos, 10);
1370                 CL_ParticleExplosion(pos);
1371                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1372                 CL_AllocDlight(NULL, &tempmatrix, 500, 1.25f, 1.0f, 0.5f, 500, 9999, 0, 0, true, 1);
1373                 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1374                 break;
1375
1376         case TE_TEI_PLASMAHIT:
1377                 MSG_ReadVector(pos);
1378                 MSG_ReadVector(dir);
1379                 count = MSG_ReadByte();
1380                 CL_FindNonSolidLocation(pos, pos, 5);
1381                 CL_Tei_PlasmaHit(pos, dir, count);
1382                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1383                 CL_AllocDlight(NULL, &tempmatrix, 500, 0.3, 0.6, 1.0f, 2000, 9999, 0, 0, true, 1);
1384                 break;
1385
1386         default:
1387                 Host_Error("CL_ParseTempEntity: bad type %d (hex %02X)", type, type);
1388         }
1389 }
1390
1391 #define SHOWNET(x) if(cl_shownet.integer==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x);
1392
1393 static qbyte cgamenetbuffer[65536];
1394
1395 /*
1396 =====================
1397 CL_ParseServerMessage
1398 =====================
1399 */
1400 int parsingerror = false;
1401 void CL_ParseServerMessage(void)
1402 {
1403         int                     cmd;
1404         int                     i, entitiesupdated;
1405         qbyte           cmdlog[32];
1406         char            *cmdlogname[32], *temp;
1407         int                     cmdindex, cmdcount = 0;
1408
1409         if (cls.demorecording)
1410                 CL_WriteDemoMessage ();
1411
1412         cl.last_received_message = realtime;
1413
1414 //
1415 // if recording demos, copy the message out
1416 //
1417         if (cl_shownet.integer == 1)
1418                 Con_Printf ("%f %i\n", realtime, net_message.cursize);
1419         else if (cl_shownet.integer == 2)
1420                 Con_Printf ("------------------\n");
1421
1422         cl.onground = false;    // unless the server says otherwise
1423 //
1424 // parse the message
1425 //
1426         //MSG_BeginReading ();
1427
1428         entitiesupdated = false;
1429
1430         parsingerror = true;
1431
1432         while (1)
1433         {
1434                 if (msg_badread)
1435                         Host_Error ("CL_ParseServerMessage: Bad server message");
1436
1437                 cmd = MSG_ReadByte ();
1438
1439                 if (cmd == -1)
1440                 {
1441                         SHOWNET("END OF MESSAGE");
1442                         break;          // end of message
1443                 }
1444
1445                 cmdindex = cmdcount & 31;
1446                 cmdcount++;
1447                 cmdlog[cmdindex] = cmd;
1448
1449                 // if the high bit of the command byte is set, it is a fast update
1450                 if (cmd & 128)
1451                 {
1452                         // 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)
1453                         temp = "entity";
1454                         cmdlogname[cmdindex] = temp;
1455                         SHOWNET("fast update");
1456                         if (cls.signon == SIGNONS - 1)
1457                         {
1458                                 // first update is the final signon stage
1459                                 cls.signon = SIGNONS;
1460                                 CL_SignonReply ();
1461                         }
1462                         CL_ParseUpdate (cmd&127);
1463                         continue;
1464                 }
1465
1466                 SHOWNET(svc_strings[cmd]);
1467                 cmdlogname[cmdindex] = svc_strings[cmd];
1468                 if (!cmdlogname[cmdindex])
1469                 {
1470                         // 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)
1471                         temp = "<unknown>";
1472                         cmdlogname[cmdindex] = temp;
1473                 }
1474
1475                 // other commands
1476                 switch (cmd)
1477                 {
1478                 default:
1479                         {
1480                                 char description[32*64], temp[64];
1481                                 int count;
1482                                 strcpy (description, "packet dump: ");
1483                                 i = cmdcount - 32;
1484                                 if (i < 0)
1485                                         i = 0;
1486                                 count = cmdcount - i;
1487                                 i &= 31;
1488                                 while(count > 0)
1489                                 {
1490                                         snprintf (temp, sizeof (temp), "%3i:%s ", cmdlog[i], cmdlogname[i]);
1491                                         strlcat (description, temp, sizeof (description));
1492                                         count--;
1493                                         i++;
1494                                         i &= 31;
1495                                 }
1496                                 description[strlen(description)-1] = '\n'; // replace the last space with a newline
1497                                 Con_Printf("%s", description);
1498                                 Host_Error ("CL_ParseServerMessage: Illegible server message\n");
1499                         }
1500                         break;
1501
1502                 case svc_nop:
1503                         if (cls.signon < SIGNONS)
1504                                 Con_Printf("<-- server to client keepalive\n");
1505                         break;
1506
1507                 case svc_time:
1508                         if (!entitiesupdated)
1509                         {
1510                                 // this is a new frame, we'll be seeing entities,
1511                                 // so prepare for entity updates
1512                                 CL_EntityUpdateSetup();
1513                                 entitiesupdated = true;
1514                         }
1515                         cl.mtime[1] = cl.mtime[0];
1516                         cl.mtime[0] = MSG_ReadFloat ();
1517                         break;
1518
1519                 case svc_clientdata:
1520                         i = MSG_ReadShort ();
1521                         CL_ParseClientdata (i);
1522                         break;
1523
1524                 case svc_version:
1525                         i = MSG_ReadLong ();
1526                         // hack for unmarked Nehahra movie demos which had a custom protocol
1527                         if (i == PROTOCOL_QUAKE && cls.demoplayback && demo_nehahra.integer)
1528                                 i = PROTOCOL_NEHAHRAMOVIE;
1529                         if (i != PROTOCOL_QUAKE && i != PROTOCOL_DARKPLACES1 && i != PROTOCOL_DARKPLACES2 && i != PROTOCOL_DARKPLACES3 && i != PROTOCOL_DARKPLACES4 && i != PROTOCOL_NEHAHRAMOVIE)
1530                                 Host_Error("CL_ParseServerMessage: Server is protocol %i, not %i (Quake), %i (DP1), %i (DP2), %i (DP3), %i (DP4), or %i (Nehahra movie)", i, PROTOCOL_QUAKE, PROTOCOL_DARKPLACES1, PROTOCOL_DARKPLACES2, PROTOCOL_DARKPLACES3, PROTOCOL_DARKPLACES4, PROTOCOL_NEHAHRAMOVIE);
1531                         cl.protocol = i;
1532                         break;
1533
1534                 case svc_disconnect:
1535                         Host_EndGame ("Server disconnected\n");
1536
1537                 case svc_print:
1538                         Con_Printf ("%s", MSG_ReadString ());
1539                         break;
1540
1541                 case svc_centerprint:
1542                         SCR_CenterPrint (MSG_ReadString ());
1543                         break;
1544
1545                 case svc_stufftext:
1546                         Cbuf_AddText (MSG_ReadString ());
1547                         break;
1548
1549                 case svc_damage:
1550                         V_ParseDamage ();
1551                         break;
1552
1553                 case svc_serverinfo:
1554                         CL_ParseServerInfo ();
1555                         break;
1556
1557                 case svc_setangle:
1558                         for (i=0 ; i<3 ; i++)
1559                                 cl.viewangles[i] = MSG_ReadAngle ();
1560                         break;
1561
1562                 case svc_setview:
1563                         cl.viewentity = (unsigned short)MSG_ReadShort ();
1564                         if (cl.viewentity >= MAX_EDICTS)
1565                                 Host_Error("svc_setview >= MAX_EDICTS\n");
1566                         // LordHavoc: assume first setview recieved is the real player entity
1567                         if (!cl.playerentity)
1568                                 cl.playerentity = cl.viewentity;
1569                         break;
1570
1571                 case svc_lightstyle:
1572                         i = MSG_ReadByte ();
1573                         if (i >= MAX_LIGHTSTYLES)
1574                                 Host_Error ("svc_lightstyle >= MAX_LIGHTSTYLES");
1575                         strlcpy (cl_lightstyle[i].map,  MSG_ReadString(), sizeof (cl_lightstyle[i].map));
1576                         cl_lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
1577                         cl_lightstyle[i].length = strlen(cl_lightstyle[i].map);
1578                         break;
1579
1580                 case svc_sound:
1581                         CL_ParseStartSoundPacket(false);
1582                         break;
1583
1584                 case svc_sound2:
1585                         CL_ParseStartSoundPacket(true);
1586                         break;
1587
1588                 case svc_stopsound:
1589                         i = MSG_ReadShort();
1590                         S_StopSound(i>>3, i&7);
1591                         break;
1592
1593                 case svc_updatename:
1594                         i = MSG_ReadByte ();
1595                         if (i >= cl.maxclients)
1596                                 Host_Error ("CL_ParseServerMessage: svc_updatename >= cl.maxclients");
1597                         strlcpy (cl.scores[i].name, MSG_ReadString (), sizeof (cl.scores[i].name));
1598                         break;
1599
1600                 case svc_updatefrags:
1601                         i = MSG_ReadByte ();
1602                         if (i >= cl.maxclients)
1603                                 Host_Error ("CL_ParseServerMessage: svc_updatefrags >= cl.maxclients");
1604                         cl.scores[i].frags = MSG_ReadShort ();
1605                         break;
1606
1607                 case svc_updatecolors:
1608                         i = MSG_ReadByte ();
1609                         if (i >= cl.maxclients)
1610                                 Host_Error ("CL_ParseServerMessage: svc_updatecolors >= cl.maxclients");
1611                         cl.scores[i].colors = MSG_ReadByte ();
1612                         break;
1613
1614                 case svc_particle:
1615                         CL_ParseParticleEffect ();
1616                         break;
1617
1618                 case svc_effect:
1619                         CL_ParseEffect ();
1620                         break;
1621
1622                 case svc_effect2:
1623                         CL_ParseEffect2 ();
1624                         break;
1625
1626                 case svc_spawnbaseline:
1627                         i = MSG_ReadShort ();
1628                         if (i < 0 || i >= MAX_EDICTS)
1629                                 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i);
1630                         CL_ParseBaseline (cl_entities + i, false);
1631                         break;
1632                 case svc_spawnbaseline2:
1633                         i = MSG_ReadShort ();
1634                         if (i < 0 || i >= MAX_EDICTS)
1635                                 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline2: invalid entity number %i", i);
1636                         CL_ParseBaseline (cl_entities + i, true);
1637                         break;
1638                 case svc_spawnstatic:
1639                         CL_ParseStatic (false);
1640                         break;
1641                 case svc_spawnstatic2:
1642                         CL_ParseStatic (true);
1643                         break;
1644                 case svc_temp_entity:
1645                         CL_ParseTempEntity ();
1646                         break;
1647
1648                 case svc_setpause:
1649                         cl.paused = MSG_ReadByte ();
1650                         if (cl.paused)
1651                                 CDAudio_Pause ();
1652                         else
1653                                 CDAudio_Resume ();
1654                         break;
1655
1656                 case svc_signonnum:
1657                         i = MSG_ReadByte ();
1658                         if (i <= cls.signon)
1659                                 Host_Error ("Received signon %i when at %i", i, cls.signon);
1660                         cls.signon = i;
1661                         CL_SignonReply ();
1662                         break;
1663
1664                 case svc_killedmonster:
1665                         cl.stats[STAT_MONSTERS]++;
1666                         break;
1667
1668                 case svc_foundsecret:
1669                         cl.stats[STAT_SECRETS]++;
1670                         break;
1671
1672                 case svc_updatestat:
1673                         i = MSG_ReadByte ();
1674                         if (i < 0 || i >= MAX_CL_STATS)
1675                                 Host_Error ("svc_updatestat: %i is invalid", i);
1676                         cl.stats[i] = MSG_ReadLong ();
1677                         break;
1678
1679                 case svc_spawnstaticsound:
1680                         CL_ParseStaticSound (false);
1681                         break;
1682
1683                 case svc_spawnstaticsound2:
1684                         CL_ParseStaticSound (true);
1685                         break;
1686
1687                 case svc_cdtrack:
1688                         cl.cdtrack = MSG_ReadByte ();
1689                         cl.looptrack = MSG_ReadByte ();
1690                         if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )
1691                                 CDAudio_Play ((qbyte)cls.forcetrack, true);
1692                         else
1693                                 CDAudio_Play ((qbyte)cl.cdtrack, true);
1694                         break;
1695
1696                 case svc_intermission:
1697                         cl.intermission = 1;
1698                         cl.completed_time = cl.time;
1699                         break;
1700
1701                 case svc_finale:
1702                         cl.intermission = 2;
1703                         cl.completed_time = cl.time;
1704                         SCR_CenterPrint (MSG_ReadString ());
1705                         break;
1706
1707                 case svc_cutscene:
1708                         cl.intermission = 3;
1709                         cl.completed_time = cl.time;
1710                         SCR_CenterPrint (MSG_ReadString ());
1711                         break;
1712
1713                 case svc_sellscreen:
1714                         Cmd_ExecuteString ("help", src_command);
1715                         break;
1716                 case svc_hidelmp:
1717                         if (gamemode == GAME_TENEBRAE)
1718                         {
1719                                 // repeating particle effect
1720                                 MSG_ReadCoord();
1721                                 MSG_ReadCoord();
1722                                 MSG_ReadCoord();
1723                                 MSG_ReadCoord();
1724                                 MSG_ReadCoord();
1725                                 MSG_ReadCoord();
1726                                 MSG_ReadByte();
1727                                 MSG_ReadLong();
1728                                 MSG_ReadLong();
1729                                 MSG_ReadString();
1730                         }
1731                         else
1732                                 SHOWLMP_decodehide();
1733                         break;
1734                 case svc_showlmp:
1735                         if (gamemode == GAME_TENEBRAE)
1736                         {
1737                                 // particle effect
1738                                 MSG_ReadCoord();
1739                                 MSG_ReadCoord();
1740                                 MSG_ReadCoord();
1741                                 MSG_ReadByte();
1742                                 MSG_ReadString();
1743                         }
1744                         else
1745                                 SHOWLMP_decodeshow();
1746                         break;
1747                 case svc_skybox:
1748                         R_SetSkyBox(MSG_ReadString());
1749                         break;
1750                 case svc_cgame:
1751                         {
1752                                 int length;
1753                                 length = (int) ((unsigned short) MSG_ReadShort());
1754                                 for (i = 0;i < length;i++)
1755                                         cgamenetbuffer[i] = MSG_ReadByte();
1756                                 if (!msg_badread)
1757                                         CL_CGVM_ParseNetwork(cgamenetbuffer, length);
1758                         }
1759                         break;
1760                 case svc_entities:
1761                         if (cls.signon == SIGNONS - 1)
1762                         {
1763                                 // first update is the final signon stage
1764                                 cls.signon = SIGNONS;
1765                                 CL_SignonReply ();
1766                         }
1767                         CL_ReadEntityFrame();
1768                         break;
1769                 }
1770         }
1771
1772         if (entitiesupdated)
1773                 CL_EntityUpdateEnd();
1774
1775         parsingerror = false;
1776 }
1777
1778 void CL_Parse_DumpPacket(void)
1779 {
1780         if (!parsingerror)
1781                 return;
1782         Con_Printf("Packet dump:\n");
1783         SZ_HexDumpToConsole(&net_message);
1784         parsingerror = false;
1785 }
1786
1787 void CL_Parse_Init(void)
1788 {
1789         // LordHavoc: added demo_nehahra cvar
1790         cl_scores_mempool = Mem_AllocPool("client player info");
1791         Cvar_RegisterVariable (&demo_nehahra);
1792         if (gamemode == GAME_NEHAHRA)
1793                 Cvar_SetValue("demo_nehahra", 1);
1794         Cvar_RegisterVariable(&developer_networkentities);
1795 }