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