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