]> icculus.org git repositories - divverent/darkplaces.git/blob - cl_parse.c
clean up an unnecessary snprintf
[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_Printf("--> 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_DPrintf ("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         {
364                 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");
365                 Con_Printf("%c%s\n", 2, str);
366         }
367
368         // check memory integrity
369         Mem_CheckSentinelsGlobal();
370
371         // disable until we get textures for it
372         R_ResetSkyBox();
373
374         memset(cl.model_precache, 0, sizeof(cl.model_precache));
375         memset(cl.sound_precache, 0, sizeof(cl.sound_precache));
376
377         // parse model precache list
378         for (nummodels=1 ; ; nummodels++)
379         {
380                 str = MSG_ReadString();
381                 if (!str[0])
382                         break;
383                 if (nummodels==MAX_MODELS)
384                         Host_Error ("Server sent too many model precaches\n");
385                 if (strlen(str) >= MAX_QPATH)
386                         Host_Error ("Server sent a precache name of %i characters (max %i)", strlen(str), MAX_QPATH - 1);
387                 strlcpy (parse_model_precache[nummodels], str, sizeof (parse_model_precache[nummodels]));
388         }
389         // parse sound precache list
390         for (numsounds=1 ; ; numsounds++)
391         {
392                 str = MSG_ReadString();
393                 if (!str[0])
394                         break;
395                 if (numsounds==MAX_SOUNDS)
396                         Host_Error("Server sent too many sound precaches\n");
397                 if (strlen(str) >= MAX_QPATH)
398                         Host_Error("Server sent a precache name of %i characters (max %i)", strlen(str), MAX_QPATH - 1);
399                 strlcpy (parse_sound_precache[numsounds], str, sizeof (parse_sound_precache[numsounds]));
400         }
401
402         // touch all of the precached models that are still loaded so we can free
403         // anything that isn't needed
404         Mod_ClearUsed();
405         for (i = 1;i < nummodels;i++)
406         {
407                 CL_KeepaliveMessage();
408                 Mod_TouchModel(parse_model_precache[i]);
409         }
410         Mod_PurgeUnused();
411
412         // do the same for sounds
413         S_ClearUsed();
414         for (i = 1;i < numsounds;i++)
415         {
416                 CL_KeepaliveMessage();
417                 S_TouchSound(parse_sound_precache[i]);
418         }
419         S_PurgeUnused();
420
421         // now we try to load everything that is new
422
423         // world model
424         CL_KeepaliveMessage ();
425         cl.model_precache[1] = Mod_ForName(parse_model_precache[1], false, false, true);
426         if (cl.model_precache[1] == NULL)
427                 Con_Printf("Map %s not found\n", parse_model_precache[1]);
428
429         // normal models
430         for (i=2 ; i<nummodels ; i++)
431         {
432                 CL_KeepaliveMessage();
433                 if ((cl.model_precache[i] = Mod_ForName(parse_model_precache[i], false, false, false)) == NULL)
434                         Con_Printf("Model %s not found\n", parse_model_precache[i]);
435         }
436
437         // sounds
438         for (i=1 ; i<numsounds ; i++)
439         {
440                 CL_KeepaliveMessage();
441                 cl.sound_precache[i] = S_PrecacheSound(parse_sound_precache[i], true);
442         }
443
444         // local state
445         ent = &cl_entities[0];
446         // entire entity array was cleared, so just fill in a few fields
447         ent->state_current.active = true;
448         ent->render.model = cl.worldmodel = cl.model_precache[1];
449         ent->render.scale = 1; // some of the renderer still relies on scale
450         ent->render.alpha = 1;
451         ent->render.flags = RENDER_SHADOW | RENDER_LIGHT;
452         Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, 0, 0, 0, 0, 0, 0, 1);
453         Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix);
454         CL_BoundingBoxForEntity(&ent->render);
455         // clear entlife array
456         memset(entlife, 0, MAX_EDICTS);
457
458         cl_num_entities = 1;
459
460         R_Modules_NewMap();
461         CL_CGVM_Start();
462
463         // noclip is turned off at start
464         noclip_anglehack = false;
465
466         // check memory integrity
467         Mem_CheckSentinelsGlobal();
468 }
469
470 void CL_ValidateState(entity_state_t *s)
471 {
472         model_t *model;
473
474         if (!s->active)
475                 return;
476
477         if (s->modelindex >= MAX_MODELS)
478                 Host_Error("CL_ValidateState: modelindex (%i) >= MAX_MODELS (%i)\n", s->modelindex, MAX_MODELS);
479
480         // colormap is client index + 1
481         if (s->colormap > cl.maxclients)
482                 Host_Error ("CL_ValidateState: colormap (%i) > cl.maxclients (%i)", s->colormap, cl.maxclients);
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);
964         cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav", false);
965         cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav", false);
966         cl_sfx_ric1 = S_PrecacheSound ("weapons/ric1.wav", false);
967         cl_sfx_ric2 = S_PrecacheSound ("weapons/ric2.wav", false);
968         cl_sfx_ric3 = S_PrecacheSound ("weapons/ric3.wav", false);
969         cl_sfx_r_exp3 = S_PrecacheSound ("weapons/r_exp3.wav", false);
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_Printf ("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, 150, 0.25f, 1.00f, 0.25f, 250, 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, 150, 1.0f, 0.60f, 0.20f, 250, 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, 200, 0.1f, 0.1f, 1.0f, 1000, 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, 200, 0.1f, 0.1f, 1.0f, 1000, 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, 200, 0.1f, 0.1f, 1.0f, 1000, 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, 1.25f, 1.0f, 0.5f, 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, 600, 0.5f, 0.4f, 1.0f, 1200, 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                 CL_AllocDlight(NULL, &tempmatrix, 350, MSG_ReadCoord(), MSG_ReadCoord(), MSG_ReadCoord(), 700, 0.5, 0, 0, true, 1);
1253                 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1254                 break;
1255
1256         case TE_EXPLOSIONRGB:
1257                 // colored lighting explosion
1258                 MSG_ReadVector(pos);
1259                 CL_FindNonSolidLocation(pos, pos, 10);
1260                 CL_ParticleExplosion(pos);
1261                 color[0] = MSG_ReadByte() * (1.0 / 255.0);
1262                 color[1] = MSG_ReadByte() * (1.0 / 255.0);
1263                 color[2] = MSG_ReadByte() * (1.0 / 255.0);
1264                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1265                 CL_AllocDlight(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, 0, true, 1);
1266                 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1267                 break;
1268
1269         case TE_TAREXPLOSION:
1270                 // tarbaby explosion
1271                 MSG_ReadVector(pos);
1272                 CL_FindNonSolidLocation(pos, pos, 10);
1273                 CL_BlobExplosion(pos);
1274
1275                 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1276                 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1277                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1278                 CL_AllocDlight(NULL, &tempmatrix, 600, 0.8f, 0.4f, 1.0f, 1200, 0.5, 0, 0, true, 1);
1279                 break;
1280
1281         case TE_SMALLFLASH:
1282                 MSG_ReadVector(pos);
1283                 CL_FindNonSolidLocation(pos, pos, 10);
1284                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1285                 CL_AllocDlight(NULL, &tempmatrix, 200, 1, 1, 1, 1000, 0.2, 0, 0, true, 1);
1286                 break;
1287
1288         case TE_CUSTOMFLASH:
1289                 MSG_ReadVector(pos);
1290                 CL_FindNonSolidLocation(pos, pos, 4);
1291                 radius = MSG_ReadByte() * 8;
1292                 velspeed = (MSG_ReadByte() + 1) * (1.0 / 256.0);
1293                 color[0] = MSG_ReadByte() * (1.0 / 255.0);
1294                 color[1] = MSG_ReadByte() * (1.0 / 255.0);
1295                 color[2] = MSG_ReadByte() * (1.0 / 255.0);
1296                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1297                 CL_AllocDlight(NULL, &tempmatrix, radius, color[0], color[1], color[2], radius / velspeed, velspeed, 0, 0, true, 1);
1298                 break;
1299
1300         case TE_FLAMEJET:
1301                 MSG_ReadVector(pos);
1302                 MSG_ReadVector(dir);
1303                 count = MSG_ReadByte();
1304                 CL_Flames(pos, dir, count);
1305                 break;
1306
1307         case TE_LIGHTNING1:
1308                 // lightning bolts
1309                 if (!cl_model_bolt)
1310                         cl_model_bolt = Mod_ForName("progs/bolt.mdl", true, false, false);
1311                 CL_ParseBeam(cl_model_bolt, true);
1312                 break;
1313
1314         case TE_LIGHTNING2:
1315                 // lightning bolts
1316                 if (!cl_model_bolt2)
1317                         cl_model_bolt2 = Mod_ForName("progs/bolt2.mdl", true, false, false);
1318                 CL_ParseBeam(cl_model_bolt2, true);
1319                 break;
1320
1321         case TE_LIGHTNING3:
1322                 // lightning bolts
1323                 if (!cl_model_bolt3)
1324                         cl_model_bolt3 = Mod_ForName("progs/bolt3.mdl", true, false, false);
1325                 CL_ParseBeam(cl_model_bolt3, false);
1326                 break;
1327
1328 // PGM 01/21/97
1329         case TE_BEAM:
1330                 // grappling hook beam
1331                 if (!cl_model_beam)
1332                         cl_model_beam = Mod_ForName("progs/beam.mdl", true, false, false);
1333                 CL_ParseBeam(cl_model_beam, false);
1334                 break;
1335 // PGM 01/21/97
1336
1337 // LordHavoc: for compatibility with the Nehahra movie...
1338         case TE_LIGHTNING4NEH:
1339                 CL_ParseBeam(Mod_ForName(MSG_ReadString(), true, false, false), false);
1340                 break;
1341
1342         case TE_LAVASPLASH:
1343                 MSG_ReadVector(pos);
1344                 CL_LavaSplash(pos);
1345                 break;
1346
1347         case TE_TELEPORT:
1348                 MSG_ReadVector(pos);
1349                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1350                 CL_AllocDlight(NULL, &tempmatrix, 500, 1.0f, 1.0f, 1.0f, 1500, 99.0f, 0, 0, true, 1);
1351 //              CL_TeleportSplash(pos);
1352                 break;
1353
1354         case TE_EXPLOSION2:
1355                 // color mapped explosion
1356                 MSG_ReadVector(pos);
1357                 CL_FindNonSolidLocation(pos, pos, 10);
1358                 colorStart = MSG_ReadByte();
1359                 colorLength = MSG_ReadByte();
1360                 CL_ParticleExplosion2(pos, colorStart, colorLength);
1361                 tempcolor = (qbyte *)&palette_complete[(rand()%colorLength) + colorStart];
1362                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1363                 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);
1364                 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1365                 break;
1366
1367         case TE_TEI_G3:
1368                 MSG_ReadVector(pos);
1369                 MSG_ReadVector(pos2);
1370                 MSG_ReadVector(dir);
1371                 CL_BeamParticle(pos, pos2, 12, 1, 0.3, 0.1, 1, 1);
1372                 CL_BeamParticle(pos, pos2, 5, 1, 0.9, 0.3, 1, 1);
1373                 break;
1374
1375         case TE_TEI_SMOKE:
1376                 MSG_ReadVector(pos);
1377                 MSG_ReadVector(dir);
1378                 count = MSG_ReadByte();
1379                 CL_FindNonSolidLocation(pos, pos, 4);
1380                 CL_Tei_Smoke(pos, dir, count);
1381                 break;
1382
1383         case TE_TEI_BIGEXPLOSION:
1384                 MSG_ReadVector(pos);
1385                 CL_FindNonSolidLocation(pos, pos, 10);
1386                 CL_ParticleExplosion(pos);
1387                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1388                 CL_AllocDlight(NULL, &tempmatrix, 500, 1.25f, 1.0f, 0.5f, 500, 9999, 0, 0, true, 1);
1389                 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1390                 break;
1391
1392         case TE_TEI_PLASMAHIT:
1393                 MSG_ReadVector(pos);
1394                 MSG_ReadVector(dir);
1395                 count = MSG_ReadByte();
1396                 CL_FindNonSolidLocation(pos, pos, 5);
1397                 CL_Tei_PlasmaHit(pos, dir, count);
1398                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1399                 CL_AllocDlight(NULL, &tempmatrix, 500, 0.3, 0.6, 1.0f, 2000, 9999, 0, 0, true, 1);
1400                 break;
1401
1402         default:
1403                 Host_Error("CL_ParseTempEntity: bad type %d (hex %02X)", type, type);
1404         }
1405 }
1406
1407 #define SHOWNET(x) if(cl_shownet.integer==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x);
1408
1409 static qbyte cgamenetbuffer[65536];
1410
1411 /*
1412 =====================
1413 CL_ParseServerMessage
1414 =====================
1415 */
1416 int parsingerror = false;
1417 void CL_ParseServerMessage(void)
1418 {
1419         int                     cmd;
1420         int                     i, entitiesupdated;
1421         qbyte           cmdlog[32];
1422         char            *cmdlogname[32], *temp;
1423         int                     cmdindex, cmdcount = 0;
1424
1425         if (cls.demorecording)
1426                 CL_WriteDemoMessage ();
1427
1428         cl.last_received_message = realtime;
1429
1430 //
1431 // if recording demos, copy the message out
1432 //
1433         if (cl_shownet.integer == 1)
1434                 Con_Printf ("%f %i\n", realtime, net_message.cursize);
1435         else if (cl_shownet.integer == 2)
1436                 Con_Printf ("------------------\n");
1437
1438         cl.onground = false;    // unless the server says otherwise
1439 //
1440 // parse the message
1441 //
1442         //MSG_BeginReading ();
1443
1444         entitiesupdated = false;
1445
1446         parsingerror = true;
1447
1448         while (1)
1449         {
1450                 if (msg_badread)
1451                         Host_Error ("CL_ParseServerMessage: Bad server message");
1452
1453                 cmd = MSG_ReadByte ();
1454
1455                 if (cmd == -1)
1456                 {
1457                         SHOWNET("END OF MESSAGE");
1458                         break;          // end of message
1459                 }
1460
1461                 cmdindex = cmdcount & 31;
1462                 cmdcount++;
1463                 cmdlog[cmdindex] = cmd;
1464
1465                 // if the high bit of the command byte is set, it is a fast update
1466                 if (cmd & 128)
1467                 {
1468                         // 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)
1469                         temp = "entity";
1470                         cmdlogname[cmdindex] = temp;
1471                         SHOWNET("fast update");
1472                         if (cls.signon == SIGNONS - 1)
1473                         {
1474                                 // first update is the final signon stage
1475                                 cls.signon = SIGNONS;
1476                                 CL_SignonReply ();
1477                         }
1478                         CL_ParseUpdate (cmd&127);
1479                         continue;
1480                 }
1481
1482                 SHOWNET(svc_strings[cmd]);
1483                 cmdlogname[cmdindex] = svc_strings[cmd];
1484                 if (!cmdlogname[cmdindex])
1485                 {
1486                         // 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)
1487                         temp = "<unknown>";
1488                         cmdlogname[cmdindex] = temp;
1489                 }
1490
1491                 // other commands
1492                 switch (cmd)
1493                 {
1494                 default:
1495                         {
1496                                 char description[32*64], temp[64];
1497                                 int count;
1498                                 strcpy (description, "packet dump: ");
1499                                 i = cmdcount - 32;
1500                                 if (i < 0)
1501                                         i = 0;
1502                                 count = cmdcount - i;
1503                                 i &= 31;
1504                                 while(count > 0)
1505                                 {
1506                                         snprintf (temp, sizeof (temp), "%3i:%s ", cmdlog[i], cmdlogname[i]);
1507                                         strlcat (description, temp, sizeof (description));
1508                                         count--;
1509                                         i++;
1510                                         i &= 31;
1511                                 }
1512                                 description[strlen(description)-1] = '\n'; // replace the last space with a newline
1513                                 Con_Printf("%s", description);
1514                                 Host_Error ("CL_ParseServerMessage: Illegible server message\n");
1515                         }
1516                         break;
1517
1518                 case svc_nop:
1519                         if (cls.signon < SIGNONS)
1520                                 Con_Printf("<-- server to client keepalive\n");
1521                         break;
1522
1523                 case svc_time:
1524                         if (!entitiesupdated)
1525                         {
1526                                 // this is a new frame, we'll be seeing entities,
1527                                 // so prepare for entity updates
1528                                 CL_EntityUpdateSetup();
1529                                 entitiesupdated = true;
1530                         }
1531                         cl.mtime[1] = cl.mtime[0];
1532                         cl.mtime[0] = MSG_ReadFloat ();
1533                         break;
1534
1535                 case svc_clientdata:
1536                         i = MSG_ReadShort ();
1537                         CL_ParseClientdata (i);
1538                         break;
1539
1540                 case svc_version:
1541                         i = MSG_ReadLong ();
1542                         // hack for unmarked Nehahra movie demos which had a custom protocol
1543                         if (i == PROTOCOL_QUAKE && cls.demoplayback && demo_nehahra.integer)
1544                                 i = PROTOCOL_NEHAHRAMOVIE;
1545                         if (i != PROTOCOL_QUAKE && i != PROTOCOL_DARKPLACES1 && i != PROTOCOL_DARKPLACES2 && i != PROTOCOL_DARKPLACES3 && i != PROTOCOL_DARKPLACES4 && i != PROTOCOL_DARKPLACES5 && i != PROTOCOL_NEHAHRAMOVIE)
1546                                 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);
1547                         cl.protocol = i;
1548                         break;
1549
1550                 case svc_disconnect:
1551                         Host_EndGame ("Server disconnected\n");
1552
1553                 case svc_print:
1554                         Con_Printf ("%s", MSG_ReadString ());
1555                         break;
1556
1557                 case svc_centerprint:
1558                         SCR_CenterPrint (MSG_ReadString ());
1559                         break;
1560
1561                 case svc_stufftext:
1562                         Cbuf_AddText (MSG_ReadString ());
1563                         break;
1564
1565                 case svc_damage:
1566                         V_ParseDamage ();
1567                         break;
1568
1569                 case svc_serverinfo:
1570                         CL_ParseServerInfo ();
1571                         break;
1572
1573                 case svc_setangle:
1574                         for (i=0 ; i<3 ; i++)
1575                                 cl.viewangles[i] = MSG_ReadAngle ();
1576                         break;
1577
1578                 case svc_setview:
1579                         cl.viewentity = (unsigned short)MSG_ReadShort ();
1580                         if (cl.viewentity >= MAX_EDICTS)
1581                                 Host_Error("svc_setview >= MAX_EDICTS\n");
1582                         // LordHavoc: assume first setview recieved is the real player entity
1583                         if (!cl.playerentity)
1584                                 cl.playerentity = cl.viewentity;
1585                         break;
1586
1587                 case svc_lightstyle:
1588                         i = MSG_ReadByte ();
1589                         if (i >= MAX_LIGHTSTYLES)
1590                                 Host_Error ("svc_lightstyle >= MAX_LIGHTSTYLES");
1591                         strlcpy (cl_lightstyle[i].map,  MSG_ReadString(), sizeof (cl_lightstyle[i].map));
1592                         cl_lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
1593                         cl_lightstyle[i].length = strlen(cl_lightstyle[i].map);
1594                         break;
1595
1596                 case svc_sound:
1597                         CL_ParseStartSoundPacket(false);
1598                         break;
1599
1600                 case svc_sound2:
1601                         CL_ParseStartSoundPacket(true);
1602                         break;
1603
1604                 case svc_stopsound:
1605                         i = MSG_ReadShort();
1606                         S_StopSound(i>>3, i&7);
1607                         break;
1608
1609                 case svc_updatename:
1610                         i = MSG_ReadByte ();
1611                         if (i >= cl.maxclients)
1612                                 Host_Error ("CL_ParseServerMessage: svc_updatename >= cl.maxclients");
1613                         strlcpy (cl.scores[i].name, MSG_ReadString (), sizeof (cl.scores[i].name));
1614                         break;
1615
1616                 case svc_updatefrags:
1617                         i = MSG_ReadByte ();
1618                         if (i >= cl.maxclients)
1619                                 Host_Error ("CL_ParseServerMessage: svc_updatefrags >= cl.maxclients");
1620                         cl.scores[i].frags = MSG_ReadShort ();
1621                         break;
1622
1623                 case svc_updatecolors:
1624                         i = MSG_ReadByte ();
1625                         if (i >= cl.maxclients)
1626                                 Host_Error ("CL_ParseServerMessage: svc_updatecolors >= cl.maxclients");
1627                         cl.scores[i].colors = MSG_ReadByte ();
1628                         break;
1629
1630                 case svc_particle:
1631                         CL_ParseParticleEffect ();
1632                         break;
1633
1634                 case svc_effect:
1635                         CL_ParseEffect ();
1636                         break;
1637
1638                 case svc_effect2:
1639                         CL_ParseEffect2 ();
1640                         break;
1641
1642                 case svc_spawnbaseline:
1643                         i = MSG_ReadShort ();
1644                         if (i < 0 || i >= MAX_EDICTS)
1645                                 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i);
1646                         CL_ParseBaseline (cl_entities + i, false);
1647                         break;
1648                 case svc_spawnbaseline2:
1649                         i = MSG_ReadShort ();
1650                         if (i < 0 || i >= MAX_EDICTS)
1651                                 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline2: invalid entity number %i", i);
1652                         CL_ParseBaseline (cl_entities + i, true);
1653                         break;
1654                 case svc_spawnstatic:
1655                         CL_ParseStatic (false);
1656                         break;
1657                 case svc_spawnstatic2:
1658                         CL_ParseStatic (true);
1659                         break;
1660                 case svc_temp_entity:
1661                         CL_ParseTempEntity ();
1662                         break;
1663
1664                 case svc_setpause:
1665                         cl.paused = MSG_ReadByte ();
1666                         if (cl.paused)
1667                                 CDAudio_Pause ();
1668                         else
1669                                 CDAudio_Resume ();
1670                         break;
1671
1672                 case svc_signonnum:
1673                         i = MSG_ReadByte ();
1674                         if (i <= cls.signon)
1675                                 Host_Error ("Received signon %i when at %i", i, cls.signon);
1676                         cls.signon = i;
1677                         CL_SignonReply ();
1678                         break;
1679
1680                 case svc_killedmonster:
1681                         cl.stats[STAT_MONSTERS]++;
1682                         break;
1683
1684                 case svc_foundsecret:
1685                         cl.stats[STAT_SECRETS]++;
1686                         break;
1687
1688                 case svc_updatestat:
1689                         i = MSG_ReadByte ();
1690                         if (i < 0 || i >= MAX_CL_STATS)
1691                                 Host_Error ("svc_updatestat: %i is invalid", i);
1692                         cl.stats[i] = MSG_ReadLong ();
1693                         break;
1694
1695                 case svc_spawnstaticsound:
1696                         CL_ParseStaticSound (false);
1697                         break;
1698
1699                 case svc_spawnstaticsound2:
1700                         CL_ParseStaticSound (true);
1701                         break;
1702
1703                 case svc_cdtrack:
1704                         cl.cdtrack = MSG_ReadByte ();
1705                         cl.looptrack = MSG_ReadByte ();
1706                         if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )
1707                                 CDAudio_Play ((qbyte)cls.forcetrack, true);
1708                         else
1709                                 CDAudio_Play ((qbyte)cl.cdtrack, true);
1710                         break;
1711
1712                 case svc_intermission:
1713                         cl.intermission = 1;
1714                         cl.completed_time = cl.time;
1715                         break;
1716
1717                 case svc_finale:
1718                         cl.intermission = 2;
1719                         cl.completed_time = cl.time;
1720                         SCR_CenterPrint (MSG_ReadString ());
1721                         break;
1722
1723                 case svc_cutscene:
1724                         cl.intermission = 3;
1725                         cl.completed_time = cl.time;
1726                         SCR_CenterPrint (MSG_ReadString ());
1727                         break;
1728
1729                 case svc_sellscreen:
1730                         Cmd_ExecuteString ("help", src_command);
1731                         break;
1732                 case svc_hidelmp:
1733                         if (gamemode == GAME_TENEBRAE)
1734                         {
1735                                 // repeating particle effect
1736                                 MSG_ReadCoord();
1737                                 MSG_ReadCoord();
1738                                 MSG_ReadCoord();
1739                                 MSG_ReadCoord();
1740                                 MSG_ReadCoord();
1741                                 MSG_ReadCoord();
1742                                 MSG_ReadByte();
1743                                 MSG_ReadLong();
1744                                 MSG_ReadLong();
1745                                 MSG_ReadString();
1746                         }
1747                         else
1748                                 SHOWLMP_decodehide();
1749                         break;
1750                 case svc_showlmp:
1751                         if (gamemode == GAME_TENEBRAE)
1752                         {
1753                                 // particle effect
1754                                 MSG_ReadCoord();
1755                                 MSG_ReadCoord();
1756                                 MSG_ReadCoord();
1757                                 MSG_ReadByte();
1758                                 MSG_ReadString();
1759                         }
1760                         else
1761                                 SHOWLMP_decodeshow();
1762                         break;
1763                 case svc_skybox:
1764                         R_SetSkyBox(MSG_ReadString());
1765                         break;
1766                 case svc_cgame:
1767                         {
1768                                 int length;
1769                                 length = (int) ((unsigned short) MSG_ReadShort());
1770                                 for (i = 0;i < length;i++)
1771                                         cgamenetbuffer[i] = MSG_ReadByte();
1772                                 if (!msg_badread)
1773                                         CL_CGVM_ParseNetwork(cgamenetbuffer, length);
1774                         }
1775                         break;
1776                 case svc_entities:
1777                         if (cls.signon == SIGNONS - 1)
1778                         {
1779                                 // first update is the final signon stage
1780                                 cls.signon = SIGNONS;
1781                                 CL_SignonReply ();
1782                         }
1783                         CL_ReadEntityFrame();
1784                         break;
1785                 }
1786         }
1787
1788         if (entitiesupdated)
1789                 CL_EntityUpdateEnd();
1790
1791         parsingerror = false;
1792 }
1793
1794 void CL_Parse_DumpPacket(void)
1795 {
1796         if (!parsingerror)
1797                 return;
1798         Con_Printf("Packet dump:\n");
1799         SZ_HexDumpToConsole(&net_message);
1800         parsingerror = false;
1801 }
1802
1803 void CL_Parse_Init(void)
1804 {
1805         // LordHavoc: added demo_nehahra cvar
1806         cl_scores_mempool = Mem_AllocPool("client player info");
1807         Cvar_RegisterVariable (&demo_nehahra);
1808         if (gamemode == GAME_NEHAHRA)
1809                 Cvar_SetValue("demo_nehahra", 1);
1810         Cvar_RegisterVariable(&developer_networkentities);
1811 }