]> icculus.org git repositories - divverent/darkplaces.git/blob - cl_parse.c
Added sv_maxrate cvar to server setup menu.
[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
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\n", 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], true);
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, 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         {
480                 Con_DPrintf("CL_ValidateState: colormap (%i) > cl.maxclients (%i)", s->colormap, cl.maxclients);
481                 s->colormap = 0;
482         }
483
484         model = cl.model_precache[s->modelindex];
485         Mod_CheckLoaded(model);
486         if (model && s->frame >= model->numframes)
487         {
488                 Con_DPrintf("CL_ValidateState: no such frame %i in \"%s\"\n", s->frame, model->name);
489                 s->frame = 0;
490         }
491         if (model && s->skin > 0 && s->skin >= model->numskins)
492         {
493                 Con_DPrintf("CL_ValidateState: no such skin %i in \"%s\"\n", s->skin, model->name);
494                 s->skin = 0;
495         }
496 }
497
498 void CL_MoveLerpEntityStates(entity_t *ent)
499 {
500         float odelta[3], adelta[3];
501         VectorSubtract(ent->state_current.origin, ent->persistent.neworigin, odelta);
502         VectorSubtract(ent->state_current.angles, ent->persistent.newangles, adelta);
503         if (!ent->state_previous.active || cls.timedemo || DotProduct(odelta, odelta) > 1000*1000 || cl_nolerp.integer)
504         {
505                 // we definitely shouldn't lerp
506                 ent->persistent.lerpdeltatime = 0;
507                 ent->persistent.lerpstarttime = cl.mtime[1];
508                 VectorCopy(ent->state_current.origin, ent->persistent.oldorigin);
509                 VectorCopy(ent->state_current.angles, ent->persistent.oldangles);
510                 VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
511                 VectorCopy(ent->state_current.angles, ent->persistent.newangles);
512         }
513         else if (ent->state_current.flags & RENDER_STEP)
514         {
515                 // monster interpolation
516                 if (DotProduct(odelta, odelta) + DotProduct(adelta, adelta) > 0.01)
517                 {
518                         ent->persistent.lerpdeltatime = bound(0, cl.mtime[1] - ent->persistent.lerpstarttime, 0.1);
519                         ent->persistent.lerpstarttime = cl.mtime[1];
520                         VectorCopy(ent->persistent.neworigin, ent->persistent.oldorigin);
521                         VectorCopy(ent->persistent.newangles, ent->persistent.oldangles);
522                         VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
523                         VectorCopy(ent->state_current.angles, ent->persistent.newangles);
524                 }
525         }
526         else
527         {
528                 // not a monster
529                 ent->persistent.lerpstarttime = cl.mtime[1];
530                 // no lerp if it's singleplayer
531                 if (cl.islocalgame)
532                         ent->persistent.lerpdeltatime = 0;
533                 else
534                         ent->persistent.lerpdeltatime = cl.mtime[0] - cl.mtime[1];
535                 VectorCopy(ent->persistent.neworigin, ent->persistent.oldorigin);
536                 VectorCopy(ent->persistent.newangles, ent->persistent.oldangles);
537                 VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
538                 VectorCopy(ent->state_current.angles, ent->persistent.newangles);
539         }
540 }
541
542 /*
543 ==================
544 CL_ParseUpdate
545
546 Parse an entity update message from the server
547 If an entities model or origin changes from frame to frame, it must be
548 relinked.  Other attributes can change without relinking.
549 ==================
550 */
551 void CL_ParseUpdate (int bits)
552 {
553         int num;
554         entity_t *ent;
555         entity_state_t new;
556
557         if (bits & U_MOREBITS)
558                 bits |= (MSG_ReadByte()<<8);
559         if ((bits & U_EXTEND1) && cl.protocol != PROTOCOL_NEHAHRAMOVIE)
560         {
561                 bits |= MSG_ReadByte() << 16;
562                 if (bits & U_EXTEND2)
563                         bits |= MSG_ReadByte() << 24;
564         }
565
566         if (bits & U_LONGENTITY)
567                 num = (unsigned) MSG_ReadShort ();
568         else
569                 num = (unsigned) MSG_ReadByte ();
570
571         if (num >= MAX_EDICTS)
572                 Host_Error("CL_ParseUpdate: entity number (%i) >= MAX_EDICTS (%i)\n", num, MAX_EDICTS);
573         if (num < 1)
574                 Host_Error("CL_ParseUpdate: invalid entity number (%i)\n", num);
575
576         ent = cl_entities + num;
577
578         // note: this inherits the 'active' state of the baseline chosen
579         // (state_baseline is always active, state_current may not be active if
580         // the entity was missing in the last frame)
581         if (bits & U_DELTA)
582                 new = ent->state_current;
583         else
584         {
585                 new = ent->state_baseline;
586                 new.active = true;
587         }
588
589         new.number = num;
590         new.time = cl.mtime[0];
591         new.flags = 0;
592         if (bits & U_MODEL)             new.modelindex = (new.modelindex & 0xFF00) | MSG_ReadByte();
593         if (bits & U_FRAME)             new.frame = (new.frame & 0xFF00) | MSG_ReadByte();
594         if (bits & U_COLORMAP)  new.colormap = MSG_ReadByte();
595         if (bits & U_SKIN)              new.skin = MSG_ReadByte();
596         if (bits & U_EFFECTS)   new.effects = (new.effects & 0xFF00) | MSG_ReadByte();
597         if (bits & U_ORIGIN1)   new.origin[0] = MSG_ReadCoord();
598         if (bits & U_ANGLE1)    new.angles[0] = MSG_ReadAngle();
599         if (bits & U_ORIGIN2)   new.origin[1] = MSG_ReadCoord();
600         if (bits & U_ANGLE2)    new.angles[1] = MSG_ReadAngle();
601         if (bits & U_ORIGIN3)   new.origin[2] = MSG_ReadCoord();
602         if (bits & U_ANGLE3)    new.angles[2] = MSG_ReadAngle();
603         if (bits & U_STEP)              new.flags |= RENDER_STEP;
604         if (bits & U_ALPHA)             new.alpha = MSG_ReadByte();
605         if (bits & U_SCALE)             new.scale = MSG_ReadByte();
606         if (bits & U_EFFECTS2)  new.effects = (new.effects & 0x00FF) | (MSG_ReadByte() << 8);
607         if (bits & U_GLOWSIZE)  new.glowsize = MSG_ReadByte();
608         if (bits & U_GLOWCOLOR) new.glowcolor = MSG_ReadByte();
609         // apparently the dpcrush demo uses this (unintended, and it uses white anyway)
610         if (bits & U_COLORMOD)  MSG_ReadByte();
611         if (bits & U_GLOWTRAIL) new.flags |= RENDER_GLOWTRAIL;
612         if (bits & U_FRAME2)    new.frame = (new.frame & 0x00FF) | (MSG_ReadByte() << 8);
613         if (bits & U_MODEL2)    new.modelindex = (new.modelindex & 0x00FF) | (MSG_ReadByte() << 8);
614         if (bits & U_VIEWMODEL) new.flags |= RENDER_VIEWMODEL;
615         if (bits & U_EXTERIORMODEL)     new.flags |= RENDER_EXTERIORMODEL;
616
617         // LordHavoc: to allow playback of the Nehahra movie
618         if (cl.protocol == PROTOCOL_NEHAHRAMOVIE && (bits & U_EXTEND1))
619         {
620                 // LordHavoc: evil format
621                 int i = MSG_ReadFloat();
622                 int j = MSG_ReadFloat() * 255.0f;
623                 if (i == 2)
624                 {
625                         i = MSG_ReadFloat();
626                         if (i)
627                                 new.effects |= EF_FULLBRIGHT;
628                 }
629                 if (j < 0)
630                         new.alpha = 0;
631                 else if (j == 0 || j >= 255)
632                         new.alpha = 255;
633                 else
634                         new.alpha = j;
635         }
636
637         if (new.active)
638                 CL_ValidateState(&new);
639
640         ent->state_previous = ent->state_current;
641         ent->state_current = new;
642         if (ent->state_current.active)
643         {
644                 CL_MoveLerpEntityStates(ent);
645                 cl_entities_active[ent->state_current.number] = true;
646                 // mark as visible (no kill this frame)
647                 entlife[ent->state_current.number] = 2;
648         }
649 }
650
651 static entity_frame_t entityframe;
652 extern mempool_t *cl_entities_mempool;
653 void CL_ReadEntityFrame(void)
654 {
655         if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
656         {
657                 int i;
658                 entity_t *ent;
659                 EntityFrame_Read(&cl.entitydatabase);
660                 EntityFrame_FetchFrame(&cl.entitydatabase, EntityFrame_MostRecentlyRecievedFrameNum(&cl.entitydatabase), &entityframe);
661                 for (i = 0;i < entityframe.numentities;i++)
662                 {
663                         // copy the states
664                         ent = &cl_entities[entityframe.entitydata[i].number];
665                         ent->state_previous = ent->state_current;
666                         ent->state_current = entityframe.entitydata[i];
667                         CL_MoveLerpEntityStates(ent);
668                         // the entity lives again...
669                         entlife[ent->state_current.number] = 2;
670                         cl_entities_active[ent->state_current.number] = true;
671                 }
672         }
673         else
674         {
675                 if (!cl.entitydatabase4)
676                         cl.entitydatabase4 = EntityFrame4_AllocDatabase(cl_entities_mempool);
677                 EntityFrame4_CL_ReadFrame(cl.entitydatabase4);
678         }
679 }
680
681 void CL_EntityUpdateSetup(void)
682 {
683 }
684
685 void CL_EntityUpdateEnd(void)
686 {
687         if (cl.protocol == PROTOCOL_QUAKE || cl.protocol == PROTOCOL_NEHAHRAMOVIE || cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
688         {
689                 int i;
690                 // disable entities that disappeared this frame
691                 for (i = 1;i < MAX_EDICTS;i++)
692                 {
693                         // clear only the entities that were active last frame but not this
694                         // frame, don't waste time clearing all entities (which would cause
695                         // cache misses)
696                         if (entlife[i])
697                         {
698                                 entlife[i]--;
699                                 if (!entlife[i])
700                                         cl_entities[i].state_previous.active = cl_entities[i].state_current.active = 0;
701                         }
702                 }
703         }
704 }
705
706 /*
707 ==================
708 CL_ParseBaseline
709 ==================
710 */
711 void CL_ParseBaseline (entity_t *ent, int large)
712 {
713         int i;
714
715         ClearStateToDefault(&ent->state_baseline);
716         ent->state_baseline.active = true;
717         if (large)
718         {
719                 ent->state_baseline.modelindex = (unsigned short) MSG_ReadShort ();
720                 ent->state_baseline.frame = (unsigned short) MSG_ReadShort ();
721         }
722         else
723         {
724                 ent->state_baseline.modelindex = MSG_ReadByte ();
725                 ent->state_baseline.frame = MSG_ReadByte ();
726         }
727         ent->state_baseline.colormap = MSG_ReadByte();
728         ent->state_baseline.skin = MSG_ReadByte();
729         for (i = 0;i < 3;i++)
730         {
731                 ent->state_baseline.origin[i] = MSG_ReadCoord ();
732                 ent->state_baseline.angles[i] = MSG_ReadAngle ();
733         }
734         CL_ValidateState(&ent->state_baseline);
735         ent->state_previous = ent->state_current = ent->state_baseline;
736 }
737
738
739 /*
740 ==================
741 CL_ParseClientdata
742
743 Server information pertaining to this client only
744 ==================
745 */
746 void CL_ParseClientdata (int bits)
747 {
748         int i, j;
749
750         bits &= 0xFFFF;
751         if (bits & SU_EXTEND1)
752                 bits |= (MSG_ReadByte() << 16);
753         if (bits & SU_EXTEND2)
754                 bits |= (MSG_ReadByte() << 24);
755
756         if (bits & SU_VIEWHEIGHT)
757                 cl.viewheight = MSG_ReadChar ();
758         else
759                 cl.viewheight = DEFAULT_VIEWHEIGHT;
760
761         if (bits & SU_IDEALPITCH)
762                 cl.idealpitch = MSG_ReadChar ();
763         else
764                 cl.idealpitch = 0;
765
766         VectorCopy (cl.mvelocity[0], cl.mvelocity[1]);
767         if (cl.protocol == PROTOCOL_DARKPLACES5)
768         {
769                 for (i = 0;i < 3;i++)
770                 {
771                         if (bits & (SU_PUNCH1<<i) )
772                                 cl.punchangle[i] = MSG_ReadPreciseAngle();
773                         else
774                                 cl.punchangle[i] = 0;
775                         if (bits & (SU_PUNCHVEC1<<i))
776                                 cl.punchvector[i] = MSG_ReadFloat();
777                         else
778                                 cl.punchvector[i] = 0;
779                         if (bits & (SU_VELOCITY1<<i) )
780                                 cl.mvelocity[0][i] = MSG_ReadFloat();
781                         else
782                                 cl.mvelocity[0][i] = 0;
783                 }
784         }
785         else
786         {
787                 for (i = 0;i < 3;i++)
788                 {
789                         if (bits & (SU_PUNCH1<<i) )
790                         {
791                                 if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
792                                         cl.punchangle[i] = MSG_ReadPreciseAngle();
793                                 else
794                                         cl.punchangle[i] = MSG_ReadChar();
795                         }
796                         else
797                                 cl.punchangle[i] = 0;
798                         if (bits & (SU_PUNCHVEC1<<i))
799                                 cl.punchvector[i] = MSG_ReadCoord();
800                         else
801                                 cl.punchvector[i] = 0;
802                         if (bits & (SU_VELOCITY1<<i) )
803                                 cl.mvelocity[0][i] = MSG_ReadChar()*16;
804                         else
805                                 cl.mvelocity[0][i] = 0;
806                 }
807         }
808
809         i = MSG_ReadLong ();
810         if (cl.items != i)
811         {       // set flash times
812                 for (j=0 ; j<32 ; j++)
813                         if ( (i & (1<<j)) && !(cl.items & (1<<j)))
814                                 cl.item_gettime[j] = cl.time;
815                 cl.items = i;
816         }
817
818         cl.onground = (bits & SU_ONGROUND) != 0;
819         cl.inwater = (bits & SU_INWATER) != 0;
820
821         cl.stats[STAT_WEAPONFRAME] = (bits & SU_WEAPONFRAME) ? MSG_ReadByte() : 0;
822         cl.stats[STAT_ARMOR] = (bits & SU_ARMOR) ? MSG_ReadByte() : 0;
823         cl.stats[STAT_WEAPON] = (bits & SU_WEAPON) ? MSG_ReadByte() : 0;
824         cl.stats[STAT_HEALTH] = MSG_ReadShort();
825         cl.stats[STAT_AMMO] = MSG_ReadByte();
826
827         cl.stats[STAT_SHELLS] = MSG_ReadByte();
828         cl.stats[STAT_NAILS] = MSG_ReadByte();
829         cl.stats[STAT_ROCKETS] = MSG_ReadByte();
830         cl.stats[STAT_CELLS] = MSG_ReadByte();
831
832         i = MSG_ReadByte ();
833
834         if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
835                 i = (1<<i);
836         // GAME_NEXUIZ hud needs weapon change time
837         // GAME_NEXUIZ uses a bit number as it's STAT_ACTIVEWEAPON, not a bitfield
838         // like other modes
839         if (cl.stats[STAT_ACTIVEWEAPON] != i)
840                 cl.weapontime = cl.time;
841         cl.stats[STAT_ACTIVEWEAPON] = i;
842
843         cl.viewzoomold = cl.viewzoomnew; // for interpolation
844         if (bits & SU_VIEWZOOM)
845         {
846                 i = MSG_ReadByte();
847                 if (i < 2)
848                         i = 2;
849                 cl.viewzoomnew = (float) i * (1.0f / 255.0f);
850         }
851         else
852                 cl.viewzoomnew = 1;
853
854 }
855
856 /*
857 =====================
858 CL_ParseStatic
859 =====================
860 */
861 void CL_ParseStatic (int large)
862 {
863         entity_t *ent;
864
865         if (cl_num_static_entities >= cl_max_static_entities)
866                 Host_Error ("Too many static entities");
867         ent = &cl_static_entities[cl_num_static_entities++];
868         CL_ParseBaseline (ent, large);
869
870 // copy it to the current state
871         ent->render.model = cl.model_precache[ent->state_baseline.modelindex];
872         ent->render.frame = ent->render.frame1 = ent->render.frame2 = ent->state_baseline.frame;
873         ent->render.framelerp = 0;
874         // make torchs play out of sync
875         ent->render.frame1time = ent->render.frame2time = lhrandom(-10, -1);
876         ent->render.colormap = -1; // no special coloring
877         ent->render.skinnum = ent->state_baseline.skin;
878         ent->render.effects = ent->state_baseline.effects;
879         ent->render.alpha = 1;
880         //ent->render.scale = 1;
881
882         //VectorCopy (ent->state_baseline.origin, ent->render.origin);
883         //VectorCopy (ent->state_baseline.angles, ent->render.angles);
884
885         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);
886         Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix);
887         CL_BoundingBoxForEntity(&ent->render);
888
889         // This is definitely cheating...
890         if (ent->render.model == NULL)
891                 cl_num_static_entities--;
892 }
893
894 /*
895 ===================
896 CL_ParseStaticSound
897 ===================
898 */
899 void CL_ParseStaticSound (int large)
900 {
901         vec3_t          org;
902         int                     sound_num, vol, atten;
903
904         MSG_ReadVector(org);
905         if (large)
906                 sound_num = (unsigned short) MSG_ReadShort ();
907         else
908                 sound_num = MSG_ReadByte ();
909         vol = MSG_ReadByte ();
910         atten = MSG_ReadByte ();
911
912         S_StaticSound (cl.sound_precache[sound_num], org, vol, atten);
913 }
914
915 void CL_ParseEffect (void)
916 {
917         vec3_t          org;
918         int                     modelindex, startframe, framecount, framerate;
919
920         MSG_ReadVector(org);
921         modelindex = MSG_ReadByte ();
922         startframe = MSG_ReadByte ();
923         framecount = MSG_ReadByte ();
924         framerate = MSG_ReadByte ();
925
926         CL_Effect(org, modelindex, startframe, framecount, framerate);
927 }
928
929 void CL_ParseEffect2 (void)
930 {
931         vec3_t          org;
932         int                     modelindex, startframe, framecount, framerate;
933
934         MSG_ReadVector(org);
935         modelindex = MSG_ReadShort ();
936         startframe = MSG_ReadShort ();
937         framecount = MSG_ReadByte ();
938         framerate = MSG_ReadByte ();
939
940         CL_Effect(org, modelindex, startframe, framecount, framerate);
941 }
942
943 model_t *cl_model_bolt = NULL;
944 model_t *cl_model_bolt2 = NULL;
945 model_t *cl_model_bolt3 = NULL;
946 model_t *cl_model_beam = NULL;
947
948 sfx_t *cl_sfx_wizhit;
949 sfx_t *cl_sfx_knighthit;
950 sfx_t *cl_sfx_tink1;
951 sfx_t *cl_sfx_ric1;
952 sfx_t *cl_sfx_ric2;
953 sfx_t *cl_sfx_ric3;
954 sfx_t *cl_sfx_r_exp3;
955
956 /*
957 =================
958 CL_ParseTEnt
959 =================
960 */
961 void CL_InitTEnts (void)
962 {
963         cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav", false, true);
964         cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav", false, true);
965         cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav", false, true);
966         cl_sfx_ric1 = S_PrecacheSound ("weapons/ric1.wav", false, true);
967         cl_sfx_ric2 = S_PrecacheSound ("weapons/ric2.wav", false, true);
968         cl_sfx_ric3 = S_PrecacheSound ("weapons/ric3.wav", false, true);
969         cl_sfx_r_exp3 = S_PrecacheSound ("weapons/r_exp3.wav", false, true);
970 }
971
972 void CL_ParseBeam (model_t *m, int lightning)
973 {
974         int i, ent;
975         vec3_t start, end;
976         beam_t *b;
977
978         ent = MSG_ReadShort ();
979         MSG_ReadVector(start);
980         MSG_ReadVector(end);
981
982         if (ent >= MAX_EDICTS)
983         {
984                 Con_Printf("CL_ParseBeam: invalid entity number %i\n", ent);
985                 ent = 0;
986         }
987
988         // override any beam with the same entity
989         for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
990         {
991                 if (b->entity == ent)
992                 {
993                         //b->entity = ent;
994                         b->lightning = lightning;
995                         b->relativestartvalid = (ent && cl_entities[ent].state_current.active) ? 2 : 0;
996                         b->model = m;
997                         b->endtime = cl.time + 0.2;
998                         VectorCopy (start, b->start);
999                         VectorCopy (end, b->end);
1000                         return;
1001                 }
1002         }
1003
1004         // find a free beam
1005         for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
1006         {
1007                 if (!b->model || b->endtime < cl.time)
1008                 {
1009                         b->entity = ent;
1010                         b->lightning = lightning;
1011                         b->relativestartvalid = (ent && cl_entities[ent].state_current.active) ? 2 : 0;
1012                         b->model = m;
1013                         b->endtime = cl.time + 0.2;
1014                         VectorCopy (start, b->start);
1015                         VectorCopy (end, b->end);
1016                         return;
1017                 }
1018         }
1019         Con_Print("beam list overflow!\n");
1020 }
1021
1022 void CL_ParseTempEntity(void)
1023 {
1024         int type;
1025         vec3_t pos;
1026         vec3_t dir;
1027         vec3_t pos2;
1028         vec3_t color;
1029         int rnd;
1030         int colorStart, colorLength, count;
1031         float velspeed, radius;
1032         qbyte *tempcolor;
1033         matrix4x4_t tempmatrix;
1034
1035         type = MSG_ReadByte();
1036         switch (type)
1037         {
1038         case TE_WIZSPIKE:
1039                 // spike hitting wall
1040                 MSG_ReadVector(pos);
1041                 CL_FindNonSolidLocation(pos, pos, 4);
1042                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1043                 CL_AllocDlight(NULL, &tempmatrix, 100, 0.12f, 0.50f, 0.12f, 500, 0.2, 0, 0, false, 1);
1044                 CL_RunParticleEffect(pos, vec3_origin, 20, 30);
1045                 S_StartSound(-1, 0, cl_sfx_wizhit, pos, 1, 1);
1046                 break;
1047
1048         case TE_KNIGHTSPIKE:
1049                 // spike hitting wall
1050                 MSG_ReadVector(pos);
1051                 CL_FindNonSolidLocation(pos, pos, 4);
1052                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1053                 CL_AllocDlight(NULL, &tempmatrix, 100, 0.50f, 0.30f, 0.10f, 500, 0.2, 0, 0, false, 1);
1054                 CL_RunParticleEffect(pos, vec3_origin, 226, 20);
1055                 S_StartSound(-1, 0, cl_sfx_knighthit, pos, 1, 1);
1056                 break;
1057
1058         case TE_SPIKE:
1059                 // spike hitting wall
1060                 MSG_ReadVector(pos);
1061                 CL_FindNonSolidLocation(pos, pos, 4);
1062                 // LordHavoc: changed to spark shower
1063                 CL_SparkShower(pos, vec3_origin, 15);
1064                 if (rand() % 5)
1065                         S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1066                 else
1067                 {
1068                         rnd = rand() & 3;
1069                         if (rnd == 1)
1070                                 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1071                         else if (rnd == 2)
1072                                 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1073                         else
1074                                 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1075                 }
1076                 break;
1077         case TE_SPIKEQUAD:
1078                 // quad spike hitting wall
1079                 MSG_ReadVector(pos);
1080                 CL_FindNonSolidLocation(pos, pos, 4);
1081                 // LordHavoc: changed to spark shower
1082                 CL_SparkShower(pos, vec3_origin, 15);
1083                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1084                 CL_AllocDlight(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, 0, true, 1);
1085                 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1086                 if (rand() % 5)
1087                         S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1088                 else
1089                 {
1090                         rnd = rand() & 3;
1091                         if (rnd == 1)
1092                                 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1093                         else if (rnd == 2)
1094                                 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1095                         else
1096                                 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1097                 }
1098                 break;
1099         case TE_SUPERSPIKE:
1100                 // super spike hitting wall
1101                 MSG_ReadVector(pos);
1102                 CL_FindNonSolidLocation(pos, pos, 4);
1103                 // LordHavoc: changed to dust shower
1104                 CL_SparkShower(pos, vec3_origin, 30);
1105                 if (rand() % 5)
1106                         S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1107                 else
1108                 {
1109                         rnd = rand() & 3;
1110                         if (rnd == 1)
1111                                 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1112                         else if (rnd == 2)
1113                                 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1114                         else
1115                                 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1116                 }
1117                 break;
1118         case TE_SUPERSPIKEQUAD:
1119                 // quad super spike hitting wall
1120                 MSG_ReadVector(pos);
1121                 CL_FindNonSolidLocation(pos, pos, 4);
1122                 // LordHavoc: changed to dust shower
1123                 CL_SparkShower(pos, vec3_origin, 30);
1124                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1125                 CL_AllocDlight(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, 0, true, 1);
1126                 if (rand() % 5)
1127                         S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1128                 else
1129                 {
1130                         rnd = rand() & 3;
1131                         if (rnd == 1)
1132                                 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1133                         else if (rnd == 2)
1134                                 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1135                         else
1136                                 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1137                 }
1138                 break;
1139                 // LordHavoc: added for improved blood splatters
1140         case TE_BLOOD:
1141                 // blood puff
1142                 MSG_ReadVector(pos);
1143                 CL_FindNonSolidLocation(pos, pos, 4);
1144                 dir[0] = MSG_ReadChar();
1145                 dir[1] = MSG_ReadChar();
1146                 dir[2] = MSG_ReadChar();
1147                 count = MSG_ReadByte();
1148                 CL_BloodPuff(pos, dir, count);
1149                 break;
1150         case TE_SPARK:
1151                 // spark shower
1152                 MSG_ReadVector(pos);
1153                 CL_FindNonSolidLocation(pos, pos, 4);
1154                 dir[0] = MSG_ReadChar();
1155                 dir[1] = MSG_ReadChar();
1156                 dir[2] = MSG_ReadChar();
1157                 count = MSG_ReadByte();
1158                 CL_SparkShower(pos, dir, count);
1159                 break;
1160         case TE_PLASMABURN:
1161                 MSG_ReadVector(pos);
1162                 CL_FindNonSolidLocation(pos, pos, 4);
1163                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1164                 CL_AllocDlight(NULL, &tempmatrix, 200, 1, 1, 1, 1000, 0.2, 0, 0, true, 1);
1165                 CL_PlasmaBurn(pos);
1166                 break;
1167                 // LordHavoc: added for improved gore
1168         case TE_BLOODSHOWER:
1169                 // vaporized body
1170                 MSG_ReadVector(pos); // mins
1171                 MSG_ReadVector(pos2); // maxs
1172                 velspeed = MSG_ReadCoord(); // speed
1173                 count = MSG_ReadShort(); // number of particles
1174                 CL_BloodShower(pos, pos2, velspeed, count);
1175                 break;
1176         case TE_PARTICLECUBE:
1177                 // general purpose particle effect
1178                 MSG_ReadVector(pos); // mins
1179                 MSG_ReadVector(pos2); // maxs
1180                 MSG_ReadVector(dir); // dir
1181                 count = MSG_ReadShort(); // number of particles
1182                 colorStart = MSG_ReadByte(); // color
1183                 colorLength = MSG_ReadByte(); // gravity (1 or 0)
1184                 velspeed = MSG_ReadCoord(); // randomvel
1185                 CL_ParticleCube(pos, pos2, dir, count, colorStart, colorLength, velspeed);
1186                 break;
1187
1188         case TE_PARTICLERAIN:
1189                 // general purpose particle effect
1190                 MSG_ReadVector(pos); // mins
1191                 MSG_ReadVector(pos2); // maxs
1192                 MSG_ReadVector(dir); // dir
1193                 count = MSG_ReadShort(); // number of particles
1194                 colorStart = MSG_ReadByte(); // color
1195                 CL_ParticleRain(pos, pos2, dir, count, colorStart, 0);
1196                 break;
1197
1198         case TE_PARTICLESNOW:
1199                 // general purpose particle effect
1200                 MSG_ReadVector(pos); // mins
1201                 MSG_ReadVector(pos2); // maxs
1202                 MSG_ReadVector(dir); // dir
1203                 count = MSG_ReadShort(); // number of particles
1204                 colorStart = MSG_ReadByte(); // color
1205                 CL_ParticleRain(pos, pos2, dir, count, colorStart, 1);
1206                 break;
1207
1208         case TE_GUNSHOT:
1209                 // bullet hitting wall
1210                 MSG_ReadVector(pos);
1211                 CL_FindNonSolidLocation(pos, pos, 4);
1212                 // LordHavoc: changed to dust shower
1213                 CL_SparkShower(pos, vec3_origin, 15);
1214                 break;
1215
1216         case TE_GUNSHOTQUAD:
1217                 // quad bullet hitting wall
1218                 MSG_ReadVector(pos);
1219                 CL_FindNonSolidLocation(pos, pos, 4);
1220                 CL_SparkShower(pos, vec3_origin, 15);
1221                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1222                 CL_AllocDlight(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, 0, true, 1);
1223                 break;
1224
1225         case TE_EXPLOSION:
1226                 // rocket explosion
1227                 MSG_ReadVector(pos);
1228                 CL_FindNonSolidLocation(pos, pos, 10);
1229                 CL_ParticleExplosion(pos);
1230                 // LordHavoc: boosted color from 1.0, 0.8, 0.4 to 1.25, 1.0, 0.5
1231                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1232                 CL_AllocDlight(NULL, &tempmatrix, 350, 4.0f, 2.0f, 0.50f, 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_EXPLOSIONQUAD:
1237                 // quad rocket explosion
1238                 MSG_ReadVector(pos);
1239                 CL_FindNonSolidLocation(pos, pos, 10);
1240                 CL_ParticleExplosion(pos);
1241                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1242                 CL_AllocDlight(NULL, &tempmatrix, 350, 2.5f, 2.0f, 4.0f, 700, 0.5, 0, 0, true, 1);
1243                 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1244                 break;
1245
1246         case TE_EXPLOSION3:
1247                 // Nehahra movie colored lighting explosion
1248                 MSG_ReadVector(pos);
1249                 CL_FindNonSolidLocation(pos, pos, 10);
1250                 CL_ParticleExplosion(pos);
1251                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1252                 color[0] = MSG_ReadCoord() * (2.0f / 1.0f);
1253                 color[1] = MSG_ReadCoord() * (2.0f / 1.0f);
1254                 color[2] = MSG_ReadCoord() * (2.0f / 1.0f);
1255                 CL_AllocDlight(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, 0, true, 1);  
1256                 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1257                 break;
1258
1259         case TE_EXPLOSIONRGB:
1260                 // colored lighting explosion
1261                 MSG_ReadVector(pos);
1262                 CL_FindNonSolidLocation(pos, pos, 10);
1263                 CL_ParticleExplosion(pos);
1264                 color[0] = MSG_ReadByte() * (2.0f / 255.0f);
1265                 color[1] = MSG_ReadByte() * (2.0f / 255.0f);
1266                 color[2] = MSG_ReadByte() * (2.0f / 255.0f);
1267                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1268                 CL_AllocDlight(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, 0, true, 1);
1269                 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1270                 break;
1271
1272         case TE_TAREXPLOSION:
1273                 // tarbaby explosion
1274                 MSG_ReadVector(pos);
1275                 CL_FindNonSolidLocation(pos, pos, 10);
1276                 CL_BlobExplosion(pos);
1277
1278                 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1279                 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1280                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1281                 CL_AllocDlight(NULL, &tempmatrix, 600, 1.6f, 0.8f, 2.0f, 1200, 0.5, 0, 0, true, 1);
1282                 break;
1283
1284         case TE_SMALLFLASH:
1285                 MSG_ReadVector(pos);
1286                 CL_FindNonSolidLocation(pos, pos, 10);
1287                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1288                 CL_AllocDlight(NULL, &tempmatrix, 200, 2, 2, 2, 1000, 0.2, 0, 0, true, 1);
1289                 break;
1290
1291         case TE_CUSTOMFLASH:
1292                 MSG_ReadVector(pos);
1293                 CL_FindNonSolidLocation(pos, pos, 4);
1294                 radius = MSG_ReadByte() * 8;
1295                 velspeed = (MSG_ReadByte() + 1) * (1.0 / 256.0);
1296                 color[0] = MSG_ReadByte() * (2.0f / 255.0f);
1297                 color[1] = MSG_ReadByte() * (2.0f / 255.0f);
1298                 color[2] = MSG_ReadByte() * (2.0f / 255.0f);
1299                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1300                 CL_AllocDlight(NULL, &tempmatrix, radius, color[0], color[1], color[2], radius / velspeed, velspeed, 0, 0, true, 1);
1301                 break;
1302
1303         case TE_FLAMEJET:
1304                 MSG_ReadVector(pos);
1305                 MSG_ReadVector(dir);
1306                 count = MSG_ReadByte();
1307                 CL_Flames(pos, dir, count);
1308                 break;
1309
1310         case TE_LIGHTNING1:
1311                 // lightning bolts
1312                 if (!cl_model_bolt)
1313                         cl_model_bolt = Mod_ForName("progs/bolt.mdl", false, false, false);
1314                 CL_ParseBeam(cl_model_bolt, true);
1315                 break;
1316
1317         case TE_LIGHTNING2:
1318                 // lightning bolts
1319                 if (!cl_model_bolt2)
1320                         cl_model_bolt2 = Mod_ForName("progs/bolt2.mdl", false, false, false);
1321                 CL_ParseBeam(cl_model_bolt2, true);
1322                 break;
1323
1324         case TE_LIGHTNING3:
1325                 // lightning bolts
1326                 if (!cl_model_bolt3)
1327                         cl_model_bolt3 = Mod_ForName("progs/bolt3.mdl", true, false, false);
1328                 CL_ParseBeam(cl_model_bolt3, false);
1329                 break;
1330
1331 // PGM 01/21/97
1332         case TE_BEAM:
1333                 // grappling hook beam
1334                 if (!cl_model_beam)
1335                         cl_model_beam = Mod_ForName("progs/beam.mdl", true, false, false);
1336                 CL_ParseBeam(cl_model_beam, false);
1337                 break;
1338 // PGM 01/21/97
1339
1340 // LordHavoc: for compatibility with the Nehahra movie...
1341         case TE_LIGHTNING4NEH:
1342                 CL_ParseBeam(Mod_ForName(MSG_ReadString(), true, false, false), false);
1343                 break;
1344
1345         case TE_LAVASPLASH:
1346                 MSG_ReadVector(pos);
1347                 CL_LavaSplash(pos);
1348                 break;
1349
1350         case TE_TELEPORT:
1351                 MSG_ReadVector(pos);
1352                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1353                 CL_AllocDlight(NULL, &tempmatrix, 500, 1.0f, 1.0f, 1.0f, 1500, 99.0f, 0, 0, true, 1);
1354 //              CL_TeleportSplash(pos);
1355                 break;
1356
1357         case TE_EXPLOSION2:
1358                 // color mapped explosion
1359                 MSG_ReadVector(pos);
1360                 CL_FindNonSolidLocation(pos, pos, 10);
1361                 colorStart = MSG_ReadByte();
1362                 colorLength = MSG_ReadByte();
1363                 CL_ParticleExplosion2(pos, colorStart, colorLength);
1364                 tempcolor = (qbyte *)&palette_complete[(rand()%colorLength) + colorStart];
1365                 color[0] = tempcolor[0] * (2.0f / 255.0f);
1366                 color[1] = tempcolor[1] * (2.0f / 255.0f);
1367                 color[2] = tempcolor[2] * (2.0f / 255.0f);
1368                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1369                 CL_AllocDlight(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, 0, true, 1);
1370                 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1371                 break;
1372
1373         case TE_TEI_G3:
1374                 MSG_ReadVector(pos);
1375                 MSG_ReadVector(pos2);
1376                 MSG_ReadVector(dir);
1377                 CL_BeamParticle(pos, pos2, 12, 1, 0.3, 0.1, 1, 1);
1378                 CL_BeamParticle(pos, pos2, 5, 1, 0.9, 0.3, 1, 1);
1379                 break;
1380
1381         case TE_TEI_SMOKE:
1382                 MSG_ReadVector(pos);
1383                 MSG_ReadVector(dir);
1384                 count = MSG_ReadByte();
1385                 CL_FindNonSolidLocation(pos, pos, 4);
1386                 CL_Tei_Smoke(pos, dir, count);
1387                 break;
1388
1389         case TE_TEI_BIGEXPLOSION:
1390                 MSG_ReadVector(pos);
1391                 CL_FindNonSolidLocation(pos, pos, 10);
1392                 CL_ParticleExplosion(pos);
1393                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1394                 CL_AllocDlight(NULL, &tempmatrix, 500, 2.5f, 2.0f, 1.0f, 500, 9999, 0, 0, true, 1);
1395                 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1396                 break;
1397
1398         case TE_TEI_PLASMAHIT:
1399                 MSG_ReadVector(pos);
1400                 MSG_ReadVector(dir);
1401                 count = MSG_ReadByte();
1402                 CL_FindNonSolidLocation(pos, pos, 5);
1403                 CL_Tei_PlasmaHit(pos, dir, count);
1404                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1405                 CL_AllocDlight(NULL, &tempmatrix, 500, 0.6, 1.2, 2.0f, 2000, 9999, 0, 0, true, 1);
1406                 break;
1407
1408         default:
1409                 Host_Error("CL_ParseTempEntity: bad type %d (hex %02X)", type, type);
1410         }
1411 }
1412
1413 #define SHOWNET(x) if(cl_shownet.integer==2)Con_Printf("%3i:%s\n", msg_readcount-1, x);
1414
1415 static qbyte cgamenetbuffer[65536];
1416
1417 /*
1418 =====================
1419 CL_ParseServerMessage
1420 =====================
1421 */
1422 int parsingerror = false;
1423 void CL_ParseServerMessage(void)
1424 {
1425         int                     cmd;
1426         int                     i, entitiesupdated;
1427         qbyte           cmdlog[32];
1428         char            *cmdlogname[32], *temp;
1429         int                     cmdindex, cmdcount = 0;
1430
1431         if (cls.demorecording)
1432                 CL_WriteDemoMessage ();
1433
1434         cl.last_received_message = realtime;
1435
1436 //
1437 // if recording demos, copy the message out
1438 //
1439         if (cl_shownet.integer == 1)
1440                 Con_Printf("%f %i\n", realtime, net_message.cursize);
1441         else if (cl_shownet.integer == 2)
1442                 Con_Print("------------------\n");
1443
1444         cl.onground = false;    // unless the server says otherwise
1445 //
1446 // parse the message
1447 //
1448         //MSG_BeginReading ();
1449
1450         entitiesupdated = false;
1451
1452         parsingerror = true;
1453
1454         while (1)
1455         {
1456                 if (msg_badread)
1457                         Host_Error ("CL_ParseServerMessage: Bad server message");
1458
1459                 cmd = MSG_ReadByte ();
1460
1461                 if (cmd == -1)
1462                 {
1463                         SHOWNET("END OF MESSAGE");
1464                         break;          // end of message
1465                 }
1466
1467                 cmdindex = cmdcount & 31;
1468                 cmdcount++;
1469                 cmdlog[cmdindex] = cmd;
1470
1471                 // if the high bit of the command byte is set, it is a fast update
1472                 if (cmd & 128)
1473                 {
1474                         // 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)
1475                         temp = "entity";
1476                         cmdlogname[cmdindex] = temp;
1477                         SHOWNET("fast update");
1478                         if (cls.signon == SIGNONS - 1)
1479                         {
1480                                 // first update is the final signon stage
1481                                 cls.signon = SIGNONS;
1482                                 CL_SignonReply ();
1483                         }
1484                         CL_ParseUpdate (cmd&127);
1485                         continue;
1486                 }
1487
1488                 SHOWNET(svc_strings[cmd]);
1489                 cmdlogname[cmdindex] = svc_strings[cmd];
1490                 if (!cmdlogname[cmdindex])
1491                 {
1492                         // 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)
1493                         temp = "<unknown>";
1494                         cmdlogname[cmdindex] = temp;
1495                 }
1496
1497                 // other commands
1498                 switch (cmd)
1499                 {
1500                 default:
1501                         {
1502                                 char description[32*64], temp[64];
1503                                 int count;
1504                                 strcpy (description, "packet dump: ");
1505                                 i = cmdcount - 32;
1506                                 if (i < 0)
1507                                         i = 0;
1508                                 count = cmdcount - i;
1509                                 i &= 31;
1510                                 while(count > 0)
1511                                 {
1512                                         snprintf (temp, sizeof (temp), "%3i:%s ", cmdlog[i], cmdlogname[i]);
1513                                         strlcat (description, temp, sizeof (description));
1514                                         count--;
1515                                         i++;
1516                                         i &= 31;
1517                                 }
1518                                 description[strlen(description)-1] = '\n'; // replace the last space with a newline
1519                                 Con_Print(description);
1520                                 Host_Error ("CL_ParseServerMessage: Illegible server message\n");
1521                         }
1522                         break;
1523
1524                 case svc_nop:
1525                         if (cls.signon < SIGNONS)
1526                                 Con_Print("<-- server to client keepalive\n");
1527                         break;
1528
1529                 case svc_time:
1530                         if (!entitiesupdated)
1531                         {
1532                                 // this is a new frame, we'll be seeing entities,
1533                                 // so prepare for entity updates
1534                                 CL_EntityUpdateSetup();
1535                                 entitiesupdated = true;
1536                         }
1537                         cl.mtime[1] = cl.mtime[0];
1538                         cl.mtime[0] = MSG_ReadFloat ();
1539                         break;
1540
1541                 case svc_clientdata:
1542                         i = MSG_ReadShort ();
1543                         CL_ParseClientdata (i);
1544                         break;
1545
1546                 case svc_version:
1547                         i = MSG_ReadLong ();
1548                         // hack for unmarked Nehahra movie demos which had a custom protocol
1549                         if (i == PROTOCOL_QUAKE && cls.demoplayback && demo_nehahra.integer)
1550                                 i = PROTOCOL_NEHAHRAMOVIE;
1551                         if (i != PROTOCOL_QUAKE && i != PROTOCOL_DARKPLACES1 && i != PROTOCOL_DARKPLACES2 && i != PROTOCOL_DARKPLACES3 && i != PROTOCOL_DARKPLACES4 && i != PROTOCOL_DARKPLACES5 && i != PROTOCOL_NEHAHRAMOVIE)
1552                                 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);
1553                         cl.protocol = i;
1554                         break;
1555
1556                 case svc_disconnect:
1557                         Con_Printf ("Server disconnected\n");
1558                         if (cls.demonum != -1)
1559                                 CL_NextDemo ();
1560                         else
1561                                 CL_Disconnect ();
1562                         break;
1563
1564                 case svc_print:
1565                         Con_Print(MSG_ReadString());
1566                         break;
1567
1568                 case svc_centerprint:
1569                         SCR_CenterPrint(MSG_ReadString ());
1570                         break;
1571
1572                 case svc_stufftext:
1573                         Cbuf_AddText (MSG_ReadString ());
1574                         break;
1575
1576                 case svc_damage:
1577                         V_ParseDamage ();
1578                         break;
1579
1580                 case svc_serverinfo:
1581                         CL_ParseServerInfo ();
1582                         break;
1583
1584                 case svc_setangle:
1585                         for (i=0 ; i<3 ; i++)
1586                                 cl.viewangles[i] = MSG_ReadAngle ();
1587                         break;
1588
1589                 case svc_setview:
1590                         cl.viewentity = (unsigned short)MSG_ReadShort ();
1591                         if (cl.viewentity >= MAX_EDICTS)
1592                                 Host_Error("svc_setview >= MAX_EDICTS\n");
1593                         // LordHavoc: assume first setview recieved is the real player entity
1594                         if (!cl.playerentity)
1595                                 cl.playerentity = cl.viewentity;
1596                         break;
1597
1598                 case svc_lightstyle:
1599                         i = MSG_ReadByte ();
1600                         if (i >= MAX_LIGHTSTYLES)
1601                                 Host_Error ("svc_lightstyle >= MAX_LIGHTSTYLES");
1602                         strlcpy (cl_lightstyle[i].map,  MSG_ReadString(), sizeof (cl_lightstyle[i].map));
1603                         cl_lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
1604                         cl_lightstyle[i].length = strlen(cl_lightstyle[i].map);
1605                         break;
1606
1607                 case svc_sound:
1608                         CL_ParseStartSoundPacket(false);
1609                         break;
1610
1611                 case svc_sound2:
1612                         CL_ParseStartSoundPacket(true);
1613                         break;
1614
1615                 case svc_stopsound:
1616                         i = MSG_ReadShort();
1617                         S_StopSound(i>>3, i&7);
1618                         break;
1619
1620                 case svc_updatename:
1621                         i = MSG_ReadByte ();
1622                         if (i >= cl.maxclients)
1623                                 Host_Error ("CL_ParseServerMessage: svc_updatename >= cl.maxclients");
1624                         strlcpy (cl.scores[i].name, MSG_ReadString (), sizeof (cl.scores[i].name));
1625                         break;
1626
1627                 case svc_updatefrags:
1628                         i = MSG_ReadByte ();
1629                         if (i >= cl.maxclients)
1630                                 Host_Error ("CL_ParseServerMessage: svc_updatefrags >= cl.maxclients");
1631                         cl.scores[i].frags = MSG_ReadShort ();
1632                         break;
1633
1634                 case svc_updatecolors:
1635                         i = MSG_ReadByte ();
1636                         if (i >= cl.maxclients)
1637                                 Host_Error ("CL_ParseServerMessage: svc_updatecolors >= cl.maxclients");
1638                         cl.scores[i].colors = MSG_ReadByte ();
1639                         break;
1640
1641                 case svc_particle:
1642                         CL_ParseParticleEffect ();
1643                         break;
1644
1645                 case svc_effect:
1646                         CL_ParseEffect ();
1647                         break;
1648
1649                 case svc_effect2:
1650                         CL_ParseEffect2 ();
1651                         break;
1652
1653                 case svc_spawnbaseline:
1654                         i = MSG_ReadShort ();
1655                         if (i < 0 || i >= MAX_EDICTS)
1656                                 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i);
1657                         CL_ParseBaseline (cl_entities + i, false);
1658                         break;
1659                 case svc_spawnbaseline2:
1660                         i = MSG_ReadShort ();
1661                         if (i < 0 || i >= MAX_EDICTS)
1662                                 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline2: invalid entity number %i", i);
1663                         CL_ParseBaseline (cl_entities + i, true);
1664                         break;
1665                 case svc_spawnstatic:
1666                         CL_ParseStatic (false);
1667                         break;
1668                 case svc_spawnstatic2:
1669                         CL_ParseStatic (true);
1670                         break;
1671                 case svc_temp_entity:
1672                         CL_ParseTempEntity ();
1673                         break;
1674
1675                 case svc_setpause:
1676                         cl.paused = MSG_ReadByte ();
1677                         if (cl.paused)
1678                         {
1679                                 CDAudio_Pause ();
1680                                 S_PauseGameSounds ();
1681                         }
1682                         else
1683                         {
1684                                 CDAudio_Resume ();
1685                                 S_ResumeGameSounds ();
1686                         }
1687                         break;
1688
1689                 case svc_signonnum:
1690                         i = MSG_ReadByte ();
1691                         if (i <= cls.signon)
1692                                 Host_Error ("Received signon %i when at %i", i, cls.signon);
1693                         cls.signon = i;
1694                         CL_SignonReply ();
1695                         break;
1696
1697                 case svc_killedmonster:
1698                         cl.stats[STAT_MONSTERS]++;
1699                         break;
1700
1701                 case svc_foundsecret:
1702                         cl.stats[STAT_SECRETS]++;
1703                         break;
1704
1705                 case svc_updatestat:
1706                         i = MSG_ReadByte ();
1707                         if (i < 0 || i >= MAX_CL_STATS)
1708                                 Host_Error ("svc_updatestat: %i is invalid", i);
1709                         cl.stats[i] = MSG_ReadLong ();
1710                         break;
1711
1712                 case svc_spawnstaticsound:
1713                         CL_ParseStaticSound (false);
1714                         break;
1715
1716                 case svc_spawnstaticsound2:
1717                         CL_ParseStaticSound (true);
1718                         break;
1719
1720                 case svc_cdtrack:
1721                         cl.cdtrack = MSG_ReadByte ();
1722                         cl.looptrack = MSG_ReadByte ();
1723                         if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )
1724                                 CDAudio_Play ((qbyte)cls.forcetrack, true);
1725                         else
1726                                 CDAudio_Play ((qbyte)cl.cdtrack, true);
1727                         break;
1728
1729                 case svc_intermission:
1730                         cl.intermission = 1;
1731                         cl.completed_time = cl.time;
1732                         break;
1733
1734                 case svc_finale:
1735                         cl.intermission = 2;
1736                         cl.completed_time = cl.time;
1737                         SCR_CenterPrint(MSG_ReadString ());
1738                         break;
1739
1740                 case svc_cutscene:
1741                         cl.intermission = 3;
1742                         cl.completed_time = cl.time;
1743                         SCR_CenterPrint(MSG_ReadString ());
1744                         break;
1745
1746                 case svc_sellscreen:
1747                         Cmd_ExecuteString ("help", src_command);
1748                         break;
1749                 case svc_hidelmp:
1750                         if (gamemode == GAME_TENEBRAE)
1751                         {
1752                                 // repeating particle effect
1753                                 MSG_ReadCoord();
1754                                 MSG_ReadCoord();
1755                                 MSG_ReadCoord();
1756                                 MSG_ReadCoord();
1757                                 MSG_ReadCoord();
1758                                 MSG_ReadCoord();
1759                                 MSG_ReadByte();
1760                                 MSG_ReadLong();
1761                                 MSG_ReadLong();
1762                                 MSG_ReadString();
1763                         }
1764                         else
1765                                 SHOWLMP_decodehide();
1766                         break;
1767                 case svc_showlmp:
1768                         if (gamemode == GAME_TENEBRAE)
1769                         {
1770                                 // particle effect
1771                                 MSG_ReadCoord();
1772                                 MSG_ReadCoord();
1773                                 MSG_ReadCoord();
1774                                 MSG_ReadByte();
1775                                 MSG_ReadString();
1776                         }
1777                         else
1778                                 SHOWLMP_decodeshow();
1779                         break;
1780                 case svc_skybox:
1781                         R_SetSkyBox(MSG_ReadString());
1782                         break;
1783                 case svc_cgame:
1784                         {
1785                                 int length;
1786                                 length = (int) ((unsigned short) MSG_ReadShort());
1787                                 for (i = 0;i < length;i++)
1788                                         cgamenetbuffer[i] = MSG_ReadByte();
1789                                 if (!msg_badread)
1790                                         CL_CGVM_ParseNetwork(cgamenetbuffer, length);
1791                         }
1792                         break;
1793                 case svc_entities:
1794                         if (cls.signon == SIGNONS - 1)
1795                         {
1796                                 // first update is the final signon stage
1797                                 cls.signon = SIGNONS;
1798                                 CL_SignonReply ();
1799                         }
1800                         CL_ReadEntityFrame();
1801                         break;
1802                 }
1803         }
1804
1805         if (entitiesupdated)
1806                 CL_EntityUpdateEnd();
1807
1808         parsingerror = false;
1809 }
1810
1811 void CL_Parse_DumpPacket(void)
1812 {
1813         if (!parsingerror)
1814                 return;
1815         Con_Print("Packet dump:\n");
1816         SZ_HexDumpToConsole(&net_message);
1817         parsingerror = false;
1818 }
1819
1820 void CL_Parse_Init(void)
1821 {
1822         // LordHavoc: added demo_nehahra cvar
1823         cl_scores_mempool = Mem_AllocPool("client player info");
1824         Cvar_RegisterVariable (&demo_nehahra);
1825         if (gamemode == GAME_NEHAHRA)
1826                 Cvar_SetValue("demo_nehahra", 1);
1827         Cvar_RegisterVariable(&developer_networkentities);
1828 }