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