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