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