]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - cl_parse.c
added loading of .ent files if found (overriding entities in bsp)
[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         Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, 0, 0, 0, 0, 0, 0, 1);
455         Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix);
456         CL_BoundingBoxForEntity(&ent->render);
457         // clear entlife array
458         memset(entlife, 0, MAX_EDICTS);
459
460         cl_num_entities = 1;
461
462         R_NewMap ();
463         CL_CGVM_Start();
464
465         // noclip is turned off at start
466         noclip_anglehack = false;
467
468         // check memory integrity
469         Mem_CheckSentinelsGlobal();
470 }
471
472 void CL_ValidateState(entity_state_t *s)
473 {
474         model_t *model;
475
476         if (!s->active)
477                 return;
478
479         if (s->modelindex >= MAX_MODELS)
480                 Host_Error("CL_ValidateState: modelindex (%i) >= MAX_MODELS (%i)\n", s->modelindex, MAX_MODELS);
481
482         // colormap is client index + 1
483         if (s->colormap > cl.maxclients)
484                 Host_Error ("CL_ValidateState: colormap (%i) > cl.maxclients (%i)", s->colormap, cl.maxclients);
485
486         model = cl.model_precache[s->modelindex];
487         Mod_CheckLoaded(model);
488         if (model && s->frame >= model->numframes)
489         {
490                 Con_DPrintf("CL_ValidateState: no such frame %i in \"%s\"\n", s->frame, model->name);
491                 s->frame = 0;
492         }
493         if (model && s->skin > 0 && s->skin >= model->numskins)
494         {
495                 Con_DPrintf("CL_ValidateState: no such skin %i in \"%s\"\n", s->skin, model->name);
496                 s->skin = 0;
497         }
498 }
499
500 void CL_MoveLerpEntityStates(entity_t *ent)
501 {
502         float odelta[3], adelta[3];
503         VectorSubtract(ent->state_current.origin, ent->persistent.neworigin, odelta);
504         VectorSubtract(ent->state_current.angles, ent->persistent.newangles, adelta);
505         if (!ent->state_previous.active || cls.timedemo || DotProduct(odelta, odelta) > 1000*1000 || cl_nolerp.integer)
506         {
507                 // we definitely shouldn't lerp
508                 ent->persistent.lerpdeltatime = 0;
509                 ent->persistent.lerpstarttime = cl.mtime[1];
510                 VectorCopy(ent->state_current.origin, ent->persistent.oldorigin);
511                 VectorCopy(ent->state_current.angles, ent->persistent.oldangles);
512                 VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
513                 VectorCopy(ent->state_current.angles, ent->persistent.newangles);
514         }
515         else if (ent->state_current.flags & RENDER_STEP)
516         {
517                 // monster interpolation
518                 if (DotProduct(odelta, odelta) + DotProduct(adelta, adelta) > 0.01)
519                 {
520                         ent->persistent.lerpdeltatime = bound(0, cl.mtime[1] - ent->persistent.lerpstarttime, 0.1);
521                         ent->persistent.lerpstarttime = cl.mtime[1];
522                         VectorCopy(ent->persistent.neworigin, ent->persistent.oldorigin);
523                         VectorCopy(ent->persistent.newangles, ent->persistent.oldangles);
524                         VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
525                         VectorCopy(ent->state_current.angles, ent->persistent.newangles);
526                 }
527         }
528         else
529         {
530                 // not a monster
531                 ent->persistent.lerpstarttime = cl.mtime[1];
532                 // no lerp if it's singleplayer
533                 if (sv.active && svs.maxclients == 1 && !ent->state_current.flags & RENDER_STEP)
534                         ent->persistent.lerpdeltatime = 0;
535                 else
536                         ent->persistent.lerpdeltatime = cl.mtime[0] - cl.mtime[1];
537                 VectorCopy(ent->persistent.neworigin, ent->persistent.oldorigin);
538                 VectorCopy(ent->persistent.newangles, ent->persistent.oldangles);
539                 VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
540                 VectorCopy(ent->state_current.angles, ent->persistent.newangles);
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
853         //VectorCopy (ent->state_baseline.origin, ent->render.origin);
854         //VectorCopy (ent->state_baseline.angles, ent->render.angles);
855
856         Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, ent->state_baseline.origin[0], ent->state_baseline.origin[1], ent->state_baseline.origin[2], ent->state_baseline.angles[0], ent->state_baseline.angles[1], ent->state_baseline.angles[2], 1);
857         Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix);
858         CL_BoundingBoxForEntity(&ent->render);
859
860         // This is definitely cheating...
861         if (ent->render.model == NULL)
862                 cl_num_static_entities--;
863 }
864
865 /*
866 ===================
867 CL_ParseStaticSound
868 ===================
869 */
870 void CL_ParseStaticSound (int large)
871 {
872         vec3_t          org;
873         int                     sound_num, vol, atten;
874
875         MSG_ReadVector(org);
876         if (large)
877                 sound_num = (unsigned short) MSG_ReadShort ();
878         else
879                 sound_num = MSG_ReadByte ();
880         vol = MSG_ReadByte ();
881         atten = MSG_ReadByte ();
882
883         S_StaticSound (cl.sound_precache[sound_num], org, vol, atten);
884 }
885
886 void CL_ParseEffect (void)
887 {
888         vec3_t          org;
889         int                     modelindex, startframe, framecount, framerate;
890
891         MSG_ReadVector(org);
892         modelindex = MSG_ReadByte ();
893         startframe = MSG_ReadByte ();
894         framecount = MSG_ReadByte ();
895         framerate = MSG_ReadByte ();
896
897         CL_Effect(org, modelindex, startframe, framecount, framerate);
898 }
899
900 void CL_ParseEffect2 (void)
901 {
902         vec3_t          org;
903         int                     modelindex, startframe, framecount, framerate;
904
905         MSG_ReadVector(org);
906         modelindex = MSG_ReadShort ();
907         startframe = MSG_ReadShort ();
908         framecount = MSG_ReadByte ();
909         framerate = MSG_ReadByte ();
910
911         CL_Effect(org, modelindex, startframe, framecount, framerate);
912 }
913
914 model_t *cl_model_bolt = NULL;
915 model_t *cl_model_bolt2 = NULL;
916 model_t *cl_model_bolt3 = NULL;
917 model_t *cl_model_beam = NULL;
918
919 sfx_t *cl_sfx_wizhit;
920 sfx_t *cl_sfx_knighthit;
921 sfx_t *cl_sfx_tink1;
922 sfx_t *cl_sfx_ric1;
923 sfx_t *cl_sfx_ric2;
924 sfx_t *cl_sfx_ric3;
925 sfx_t *cl_sfx_r_exp3;
926
927 /*
928 =================
929 CL_ParseTEnt
930 =================
931 */
932 void CL_InitTEnts (void)
933 {
934         cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav", false);
935         cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav", false);
936         cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav", false);
937         cl_sfx_ric1 = S_PrecacheSound ("weapons/ric1.wav", false);
938         cl_sfx_ric2 = S_PrecacheSound ("weapons/ric2.wav", false);
939         cl_sfx_ric3 = S_PrecacheSound ("weapons/ric3.wav", false);
940         cl_sfx_r_exp3 = S_PrecacheSound ("weapons/r_exp3.wav", false);
941 }
942
943 void CL_ParseBeam (model_t *m, int lightning)
944 {
945         int i, ent;
946         vec3_t start, end;
947         beam_t *b;
948
949         ent = MSG_ReadShort ();
950         MSG_ReadVector(start);
951         MSG_ReadVector(end);
952
953         if (ent >= MAX_EDICTS)
954         {
955                 Con_Printf("CL_ParseBeam: invalid entity number %i\n", ent);
956                 ent = 0;
957         }
958
959         // override any beam with the same entity
960         for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
961         {
962                 if (b->entity == ent)
963                 {
964                         //b->entity = ent;
965                         b->lightning = lightning;
966                         b->relativestartvalid = (ent && cl_entities[ent].state_current.active) ? 2 : 0;
967                         b->model = m;
968                         b->endtime = cl.time + 0.2;
969                         VectorCopy (start, b->start);
970                         VectorCopy (end, b->end);
971                         return;
972                 }
973         }
974
975         // find a free beam
976         for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
977         {
978                 if (!b->model || b->endtime < cl.time)
979                 {
980                         b->entity = ent;
981                         b->lightning = lightning;
982                         b->relativestartvalid = (ent && cl_entities[ent].state_current.active) ? 2 : 0;
983                         b->model = m;
984                         b->endtime = cl.time + 0.2;
985                         VectorCopy (start, b->start);
986                         VectorCopy (end, b->end);
987                         return;
988                 }
989         }
990         Con_Printf ("beam list overflow!\n");
991 }
992
993 void CL_ParseTempEntity (void)
994 {
995         int type;
996         vec3_t pos;
997         vec3_t dir;
998         vec3_t pos2;
999         vec3_t color;
1000         int rnd;
1001         int colorStart, colorLength, count;
1002         float velspeed, radius;
1003         qbyte *tempcolor;
1004
1005         type = MSG_ReadByte ();
1006         switch (type)
1007         {
1008         case TE_WIZSPIKE:
1009                 // spike hitting wall
1010                 MSG_ReadVector(pos);
1011                 Mod_FindNonSolidLocation(pos, pos, cl.worldmodel, 4);
1012                 CL_AllocDlight (NULL, pos, 50, 0.25f, 1.00f, 0.25f, 250, 0.2);
1013                 CL_RunParticleEffect (pos, vec3_origin, 20, 30);
1014                 S_StartSound (-1, 0, cl_sfx_wizhit, pos, 1, 1);
1015                 break;
1016
1017         case TE_KNIGHTSPIKE:
1018                 // spike hitting wall
1019                 MSG_ReadVector(pos);
1020                 Mod_FindNonSolidLocation(pos, pos, cl.worldmodel, 4);
1021                 CL_AllocDlight (NULL, pos, 50, 1.0f, 0.60f, 0.20f, 250, 0.2);
1022                 CL_RunParticleEffect (pos, vec3_origin, 226, 20);
1023                 S_StartSound (-1, 0, cl_sfx_knighthit, pos, 1, 1);
1024                 break;
1025
1026         case TE_SPIKE:
1027                 // spike hitting wall
1028                 MSG_ReadVector(pos);
1029                 Mod_FindNonSolidLocation(pos, pos, cl.worldmodel, 4);
1030                 // LordHavoc: changed to spark shower
1031                 CL_SparkShower(pos, vec3_origin, 15);
1032                 if ( rand() % 5 )
1033                         S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
1034                 else
1035                 {
1036                         rnd = rand() & 3;
1037                         if (rnd == 1)
1038                                 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
1039                         else if (rnd == 2)
1040                                 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
1041                         else
1042                                 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
1043                 }
1044                 break;
1045         case TE_SPIKEQUAD:
1046                 // quad spike hitting wall
1047                 MSG_ReadVector(pos);
1048                 Mod_FindNonSolidLocation(pos, pos, cl.worldmodel, 4);
1049                 // LordHavoc: changed to spark shower
1050                 CL_SparkShower(pos, vec3_origin, 15);
1051                 CL_AllocDlight (NULL, pos, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2);
1052                 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1053                 if ( rand() % 5 )
1054                         S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
1055                 else
1056                 {
1057                         rnd = rand() & 3;
1058                         if (rnd == 1)
1059                                 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
1060                         else if (rnd == 2)
1061                                 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
1062                         else
1063                                 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
1064                 }
1065                 break;
1066         case TE_SUPERSPIKE:
1067                 // super spike hitting wall
1068                 MSG_ReadVector(pos);
1069                 Mod_FindNonSolidLocation(pos, pos, cl.worldmodel, 4);
1070                 // LordHavoc: changed to dust shower
1071                 CL_SparkShower(pos, vec3_origin, 30);
1072                 if ( rand() % 5 )
1073                         S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
1074                 else
1075                 {
1076                         rnd = rand() & 3;
1077                         if (rnd == 1)
1078                                 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
1079                         else if (rnd == 2)
1080                                 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
1081                         else
1082                                 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
1083                 }
1084                 break;
1085         case TE_SUPERSPIKEQUAD:
1086                 // quad super spike hitting wall
1087                 MSG_ReadVector(pos);
1088                 Mod_FindNonSolidLocation(pos, pos, cl.worldmodel, 4);
1089                 // LordHavoc: changed to dust shower
1090                 CL_SparkShower(pos, vec3_origin, 30);
1091                 CL_AllocDlight (NULL, pos, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2);
1092                 if ( rand() % 5 )
1093                         S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
1094                 else
1095                 {
1096                         rnd = rand() & 3;
1097                         if (rnd == 1)
1098                                 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
1099                         else if (rnd == 2)
1100                                 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
1101                         else
1102                                 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
1103                 }
1104                 break;
1105                 // LordHavoc: added for improved blood splatters
1106         case TE_BLOOD:
1107                 // blood puff
1108                 MSG_ReadVector(pos);
1109                 Mod_FindNonSolidLocation(pos, pos, cl.worldmodel, 4);
1110                 dir[0] = MSG_ReadChar ();
1111                 dir[1] = MSG_ReadChar ();
1112                 dir[2] = MSG_ReadChar ();
1113                 count = MSG_ReadByte ();
1114                 CL_BloodPuff(pos, dir, count);
1115                 break;
1116         case TE_BLOOD2:
1117                 // blood puff
1118                 MSG_ReadVector(pos);
1119                 Mod_FindNonSolidLocation(pos, pos, cl.worldmodel, 4);
1120                 CL_BloodPuff(pos, vec3_origin, 10);
1121                 break;
1122         case TE_SPARK:
1123                 // spark shower
1124                 MSG_ReadVector(pos);
1125                 Mod_FindNonSolidLocation(pos, pos, cl.worldmodel, 4);
1126                 dir[0] = MSG_ReadChar ();
1127                 dir[1] = MSG_ReadChar ();
1128                 dir[2] = MSG_ReadChar ();
1129                 count = MSG_ReadByte ();
1130                 CL_SparkShower(pos, dir, count);
1131                 break;
1132         case TE_PLASMABURN:
1133                 MSG_ReadVector(pos);
1134                 Mod_FindNonSolidLocation(pos, pos, cl.worldmodel, 4);
1135                 CL_AllocDlight (NULL, pos, 200, 1, 1, 1, 1000, 0.2);
1136                 CL_PlasmaBurn(pos);
1137                 break;
1138                 // LordHavoc: added for improved gore
1139         case TE_BLOODSHOWER:
1140                 // vaporized body
1141                 MSG_ReadVector(pos); // mins
1142                 MSG_ReadVector(pos2); // maxs
1143                 velspeed = MSG_ReadCoord (); // speed
1144                 count = MSG_ReadShort (); // number of particles
1145                 CL_BloodShower(pos, pos2, velspeed, count);
1146                 break;
1147         case TE_PARTICLECUBE:
1148                 // general purpose particle effect
1149                 MSG_ReadVector(pos); // mins
1150                 MSG_ReadVector(pos2); // maxs
1151                 MSG_ReadVector(dir); // dir
1152                 count = MSG_ReadShort (); // number of particles
1153                 colorStart = MSG_ReadByte (); // color
1154                 colorLength = MSG_ReadByte (); // gravity (1 or 0)
1155                 velspeed = MSG_ReadCoord (); // randomvel
1156                 CL_ParticleCube(pos, pos2, dir, count, colorStart, colorLength, velspeed);
1157                 break;
1158
1159         case TE_PARTICLERAIN:
1160                 // general purpose particle effect
1161                 MSG_ReadVector(pos); // mins
1162                 MSG_ReadVector(pos2); // maxs
1163                 MSG_ReadVector(dir); // dir
1164                 count = MSG_ReadShort (); // number of particles
1165                 colorStart = MSG_ReadByte (); // color
1166                 CL_ParticleRain(pos, pos2, dir, count, colorStart, 0);
1167                 break;
1168
1169         case TE_PARTICLESNOW:
1170                 // general purpose particle effect
1171                 MSG_ReadVector(pos); // mins
1172                 MSG_ReadVector(pos2); // maxs
1173                 MSG_ReadVector(dir); // dir
1174                 count = MSG_ReadShort (); // number of particles
1175                 colorStart = MSG_ReadByte (); // color
1176                 CL_ParticleRain(pos, pos2, dir, count, colorStart, 1);
1177                 break;
1178
1179         case TE_GUNSHOT:
1180                 // bullet hitting wall
1181                 MSG_ReadVector(pos);
1182                 Mod_FindNonSolidLocation(pos, pos, cl.worldmodel, 4);
1183                 // LordHavoc: changed to dust shower
1184                 CL_SparkShower(pos, vec3_origin, 15);
1185                 break;
1186
1187         case TE_GUNSHOTQUAD:
1188                 // quad bullet hitting wall
1189                 MSG_ReadVector(pos);
1190                 Mod_FindNonSolidLocation(pos, pos, cl.worldmodel, 4);
1191                 CL_SparkShower(pos, vec3_origin, 15);
1192                 CL_AllocDlight (NULL, pos, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2);
1193                 break;
1194
1195         case TE_EXPLOSION:
1196                 // rocket explosion
1197                 MSG_ReadVector(pos);
1198                 Mod_FindNonSolidLocation(pos, pos, cl.worldmodel, 10);
1199                 CL_ParticleExplosion (pos);
1200                 // LordHavoc: boosted color from 1.0, 0.8, 0.4 to 1.25, 1.0, 0.5
1201                 CL_AllocDlight (NULL, pos, 350, 1.25f, 1.0f, 0.5f, 700, 0.5);
1202                 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1203                 break;
1204
1205         case TE_EXPLOSIONQUAD:
1206                 // quad rocket explosion
1207                 MSG_ReadVector(pos);
1208                 Mod_FindNonSolidLocation(pos, pos, cl.worldmodel, 10);
1209                 CL_ParticleExplosion (pos);
1210                 CL_AllocDlight (NULL, pos, 600, 0.5f, 0.4f, 1.0f, 1200, 0.5);
1211                 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1212                 break;
1213
1214         case TE_EXPLOSION3:
1215                 // Nehahra movie colored lighting explosion
1216                 MSG_ReadVector(pos);
1217                 Mod_FindNonSolidLocation(pos, pos, cl.worldmodel, 10);
1218                 CL_ParticleExplosion (pos);
1219                 CL_AllocDlight (NULL, pos, 350, MSG_ReadCoord(), MSG_ReadCoord(), MSG_ReadCoord(), 700, 0.5);
1220                 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1221                 break;
1222
1223         case TE_EXPLOSIONRGB:
1224                 // colored lighting explosion
1225                 MSG_ReadVector(pos);
1226                 Mod_FindNonSolidLocation(pos, pos, cl.worldmodel, 10);
1227                 CL_ParticleExplosion (pos);
1228                 color[0] = MSG_ReadByte() * (1.0 / 255.0);
1229                 color[1] = MSG_ReadByte() * (1.0 / 255.0);
1230                 color[2] = MSG_ReadByte() * (1.0 / 255.0);
1231                 CL_AllocDlight (NULL, pos, 350, color[0], color[1], color[2], 700, 0.5);
1232                 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1233                 break;
1234
1235         case TE_TAREXPLOSION:
1236                 // tarbaby explosion
1237                 MSG_ReadVector(pos);
1238                 Mod_FindNonSolidLocation(pos, pos, cl.worldmodel, 10);
1239                 CL_BlobExplosion (pos);
1240
1241                 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1242                 CL_AllocDlight (NULL, pos, 600, 0.8f, 0.4f, 1.0f, 1200, 0.5);
1243                 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1244                 break;
1245
1246         case TE_SMALLFLASH:
1247                 MSG_ReadVector(pos);
1248                 Mod_FindNonSolidLocation(pos, pos, cl.worldmodel, 10);
1249                 CL_AllocDlight (NULL, pos, 200, 1, 1, 1, 1000, 0.2);
1250                 break;
1251
1252         case TE_CUSTOMFLASH:
1253                 MSG_ReadVector(pos);
1254                 Mod_FindNonSolidLocation(pos, pos, cl.worldmodel, 4);
1255                 radius = MSG_ReadByte() * 8;
1256                 velspeed = (MSG_ReadByte() + 1) * (1.0 / 256.0);
1257                 color[0] = MSG_ReadByte() * (1.0 / 255.0);
1258                 color[1] = MSG_ReadByte() * (1.0 / 255.0);
1259                 color[2] = MSG_ReadByte() * (1.0 / 255.0);
1260                 CL_AllocDlight (NULL, pos, radius, color[0], color[1], color[2], radius / velspeed, velspeed);
1261                 break;
1262
1263         case TE_FLAMEJET:
1264                 MSG_ReadVector(pos);
1265                 MSG_ReadVector(dir);
1266                 count = MSG_ReadByte();
1267                 CL_Flames(pos, dir, count);
1268                 break;
1269
1270         case TE_LIGHTNING1:
1271                 // lightning bolts
1272                 if (!cl_model_bolt)
1273                         cl_model_bolt = Mod_ForName("progs/bolt.mdl", true, false, false);
1274                 CL_ParseBeam (cl_model_bolt, true);
1275                 break;
1276
1277         case TE_LIGHTNING2:
1278                 // lightning bolts
1279                 if (!cl_model_bolt2)
1280                         cl_model_bolt2 = Mod_ForName("progs/bolt2.mdl", true, false, false);
1281                 CL_ParseBeam (cl_model_bolt2, true);
1282                 break;
1283
1284         case TE_LIGHTNING3:
1285                 // lightning bolts
1286                 if (!cl_model_bolt3)
1287                         cl_model_bolt3 = Mod_ForName("progs/bolt3.mdl", true, false, false);
1288                 CL_ParseBeam (cl_model_bolt3, false);
1289                 break;
1290
1291 // PGM 01/21/97
1292         case TE_BEAM:
1293                 // grappling hook beam
1294                 if (!cl_model_beam)
1295                         cl_model_beam = Mod_ForName("progs/beam.mdl", true, false, false);
1296                 CL_ParseBeam (cl_model_beam, false);
1297                 break;
1298 // PGM 01/21/97
1299
1300 // LordHavoc: for compatibility with the Nehahra movie...
1301         case TE_LIGHTNING4NEH:
1302                 CL_ParseBeam (Mod_ForName(MSG_ReadString(), true, false, false), false);
1303                 break;
1304
1305         case TE_LAVASPLASH:
1306                 pos[0] = MSG_ReadCoord ();
1307                 pos[1] = MSG_ReadCoord ();
1308                 pos[2] = MSG_ReadCoord ();
1309                 CL_LavaSplash (pos);
1310                 break;
1311
1312         case TE_TELEPORT:
1313                 pos[0] = MSG_ReadCoord ();
1314                 pos[1] = MSG_ReadCoord ();
1315                 pos[2] = MSG_ReadCoord ();
1316                 CL_AllocDlight (NULL, pos, 500, 1.0f, 1.0f, 1.0f, 1500, 99.0f);
1317 //              CL_TeleportSplash (pos);
1318                 break;
1319
1320         case TE_EXPLOSION2:
1321                 // color mapped explosion
1322                 MSG_ReadVector(pos);
1323                 Mod_FindNonSolidLocation(pos, pos, cl.worldmodel, 10);
1324                 colorStart = MSG_ReadByte ();
1325                 colorLength = MSG_ReadByte ();
1326                 CL_ParticleExplosion2 (pos, colorStart, colorLength);
1327                 tempcolor = (qbyte *)&palette_complete[(rand()%colorLength) + colorStart];
1328                 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);
1329                 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1330                 break;
1331
1332         case TE_TEI_G3:
1333                 MSG_ReadVector(pos);
1334                 MSG_ReadVector(pos2);
1335                 MSG_ReadVector(dir);
1336                 CL_BeamParticle(pos, pos2, 12, 1, 0.3, 0.1, 1, 1);
1337                 CL_BeamParticle(pos, pos2, 5, 1, 0.9, 0.3, 1, 1);
1338                 break;
1339
1340         case TE_TEI_SMOKE:
1341                 MSG_ReadVector(pos);
1342                 MSG_ReadVector(dir);
1343                 count = MSG_ReadByte ();
1344                 Mod_FindNonSolidLocation(pos, pos, cl.worldmodel, 4);
1345                 CL_Tei_Smoke(pos, dir, count);
1346                 break;
1347
1348         case TE_TEI_BIGEXPLOSION:
1349                 MSG_ReadVector(pos);
1350                 Mod_FindNonSolidLocation(pos, pos, cl.worldmodel, 10);
1351                 CL_ParticleExplosion (pos);
1352                 CL_AllocDlight (NULL, pos, 500, 1.25f, 1.0f, 0.5f, 500, 9999);
1353                 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1354                 break;
1355
1356         case TE_TEI_PLASMAHIT:
1357                 MSG_ReadVector(pos);
1358                 MSG_ReadVector(dir);
1359                 count = MSG_ReadByte ();
1360                 Mod_FindNonSolidLocation(pos, pos, cl.worldmodel, 5);
1361                 CL_Tei_PlasmaHit(pos, dir, count);
1362                 CL_AllocDlight (NULL, pos, 500, 0.3, 0.6, 1.0f, 2000, 9999);
1363                 break;
1364
1365         default:
1366                 Host_Error ("CL_ParseTempEntity: bad type %d (hex %02X)", type, type);
1367         }
1368 }
1369
1370 #define SHOWNET(x) if(cl_shownet.integer==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x);
1371
1372 static qbyte cgamenetbuffer[65536];
1373
1374 /*
1375 =====================
1376 CL_ParseServerMessage
1377 =====================
1378 */
1379 int parsingerror = false;
1380 void CL_ParseServerMessage (void)
1381 {
1382         int                     cmd;
1383         int                     i, entitiesupdated;
1384         qbyte           cmdlog[32];
1385         char            *cmdlogname[32], *temp;
1386         int                     cmdindex, cmdcount = 0;
1387
1388 //
1389 // if recording demos, copy the message out
1390 //
1391         if (cl_shownet.integer == 1)
1392                 Con_Printf ("%i ",net_message.cursize);
1393         else if (cl_shownet.integer == 2)
1394                 Con_Printf ("------------------\n");
1395
1396         cl.onground = false;    // unless the server says otherwise
1397 //
1398 // parse the message
1399 //
1400         MSG_BeginReading ();
1401
1402         entitiesupdated = false;
1403
1404         parsingerror = true;
1405
1406         while (1)
1407         {
1408                 if (msg_badread)
1409                         Host_Error ("CL_ParseServerMessage: Bad server message");
1410
1411                 cmd = MSG_ReadByte ();
1412
1413                 if (cmd == -1)
1414                 {
1415                         SHOWNET("END OF MESSAGE");
1416                         break;          // end of message
1417                 }
1418
1419                 cmdindex = cmdcount & 31;
1420                 cmdcount++;
1421                 cmdlog[cmdindex] = cmd;
1422
1423                 // if the high bit of the command byte is set, it is a fast update
1424                 if (cmd & 128)
1425                 {
1426                         // 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)
1427                         temp = "entity";
1428                         cmdlogname[cmdindex] = temp;
1429                         SHOWNET("fast update");
1430                         if (cls.signon == SIGNONS - 1)
1431                         {
1432                                 // first update is the final signon stage
1433                                 cls.signon = SIGNONS;
1434                                 CL_SignonReply ();
1435                         }
1436                         CL_ParseUpdate (cmd&127);
1437                         continue;
1438                 }
1439
1440                 SHOWNET(svc_strings[cmd]);
1441                 cmdlogname[cmdindex] = svc_strings[cmd];
1442                 if (!cmdlogname[cmdindex])
1443                 {
1444                         // 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)
1445                         temp = "<unknown>";
1446                         cmdlogname[cmdindex] = temp;
1447                 }
1448
1449                 // other commands
1450                 switch (cmd)
1451                 {
1452                 default:
1453                         {
1454                                 char description[32*64], temp[64];
1455                                 int count;
1456                                 strcpy(description, "packet dump: ");
1457                                 i = cmdcount - 32;
1458                                 if (i < 0)
1459                                         i = 0;
1460                                 count = cmdcount - i;
1461                                 i &= 31;
1462                                 while(count > 0)
1463                                 {
1464                                         sprintf(temp, "%3i:%s ", cmdlog[i], cmdlogname[i]);
1465                                         strcat(description, temp);
1466                                         count--;
1467                                         i++;
1468                                         i &= 31;
1469                                 }
1470                                 description[strlen(description)-1] = '\n'; // replace the last space with a newline
1471                                 Con_Printf("%s", description);
1472                                 Host_Error ("CL_ParseServerMessage: Illegible server message\n");
1473                         }
1474                         break;
1475
1476                 case svc_nop:
1477                         break;
1478
1479                 case svc_time:
1480                         if (!entitiesupdated)
1481                         {
1482                                 // this is a new frame, we'll be seeing entities,
1483                                 // so prepare for entity updates
1484                                 CL_EntityUpdateSetup();
1485                                 entitiesupdated = true;
1486                         }
1487                         cl.mtime[1] = cl.mtime[0];
1488                         cl.mtime[0] = MSG_ReadFloat ();
1489                         break;
1490
1491                 case svc_clientdata:
1492                         i = MSG_ReadShort ();
1493                         CL_ParseClientdata (i);
1494                         break;
1495
1496                 case svc_version:
1497                         i = MSG_ReadLong ();
1498                         if (i != PROTOCOL_VERSION && i != DPPROTOCOL_VERSION1 && i != DPPROTOCOL_VERSION2 && i != DPPROTOCOL_VERSION3 && i != 250)
1499                                 Host_Error ("CL_ParseServerMessage: Server is protocol %i, not %i, %i, %i or %i", i, DPPROTOCOL_VERSION1, DPPROTOCOL_VERSION2, DPPROTOCOL_VERSION3, PROTOCOL_VERSION);
1500                         Nehahrademcompatibility = false;
1501                         if (i == 250)
1502                                 Nehahrademcompatibility = true;
1503                         if (cls.demoplayback && demo_nehahra.integer)
1504                                 Nehahrademcompatibility = true;
1505                         dpprotocol = i;
1506                         if (dpprotocol != DPPROTOCOL_VERSION1 && dpprotocol != DPPROTOCOL_VERSION2 && dpprotocol != DPPROTOCOL_VERSION3)
1507                                 dpprotocol = 0;
1508                         break;
1509
1510                 case svc_disconnect:
1511                         Host_EndGame ("Server disconnected\n");
1512
1513                 case svc_print:
1514                         Con_Printf ("%s", MSG_ReadString ());
1515                         break;
1516
1517                 case svc_centerprint:
1518                         SCR_CenterPrint (MSG_ReadString ());
1519                         break;
1520
1521                 case svc_stufftext:
1522                         Cbuf_AddText (MSG_ReadString ());
1523                         break;
1524
1525                 case svc_damage:
1526                         V_ParseDamage ();
1527                         break;
1528
1529                 case svc_serverinfo:
1530                         CL_ParseServerInfo ();
1531                         break;
1532
1533                 case svc_setangle:
1534                         for (i=0 ; i<3 ; i++)
1535                                 cl.viewangles[i] = MSG_ReadAngle ();
1536                         break;
1537
1538                 case svc_setview:
1539                         cl.viewentity = MSG_ReadShort ();
1540                         // LordHavoc: assume first setview recieved is the real player entity
1541                         if (!cl.playerentity)
1542                                 cl.playerentity = cl.viewentity;
1543                         break;
1544
1545                 case svc_lightstyle:
1546                         i = MSG_ReadByte ();
1547                         if (i >= MAX_LIGHTSTYLES)
1548                                 Host_Error ("svc_lightstyle >= MAX_LIGHTSTYLES");
1549                         strncpy (cl_lightstyle[i].map,  MSG_ReadString(), MAX_STYLESTRING - 1);
1550                         cl_lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
1551                         cl_lightstyle[i].length = strlen(cl_lightstyle[i].map);
1552                         break;
1553
1554                 case svc_sound:
1555                         CL_ParseStartSoundPacket(false);
1556                         break;
1557
1558                 case svc_sound2:
1559                         CL_ParseStartSoundPacket(true);
1560                         break;
1561
1562                 case svc_stopsound:
1563                         i = MSG_ReadShort();
1564                         S_StopSound(i>>3, i&7);
1565                         break;
1566
1567                 case svc_updatename:
1568                         i = MSG_ReadByte ();
1569                         if (i >= cl.maxclients)
1570                                 Host_Error ("CL_ParseServerMessage: svc_updatename >= cl.maxclients");
1571                         strcpy (cl.scores[i].name, MSG_ReadString ());
1572                         break;
1573
1574                 case svc_updatefrags:
1575                         i = MSG_ReadByte ();
1576                         if (i >= cl.maxclients)
1577                                 Host_Error ("CL_ParseServerMessage: svc_updatefrags >= cl.maxclients");
1578                         cl.scores[i].frags = MSG_ReadShort ();
1579                         break;
1580
1581                 case svc_updatecolors:
1582                         i = MSG_ReadByte ();
1583                         if (i >= cl.maxclients)
1584                                 Host_Error ("CL_ParseServerMessage: svc_updatecolors >= cl.maxclients");
1585                         cl.scores[i].colors = MSG_ReadByte ();
1586                         break;
1587
1588                 case svc_particle:
1589                         CL_ParseParticleEffect ();
1590                         break;
1591
1592                 case svc_effect:
1593                         CL_ParseEffect ();
1594                         break;
1595
1596                 case svc_effect2:
1597                         CL_ParseEffect2 ();
1598                         break;
1599
1600                 case svc_spawnbaseline:
1601                         i = MSG_ReadShort ();
1602                         if (i < 0 || i >= MAX_EDICTS)
1603                                 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i);
1604                         CL_ParseBaseline (cl_entities + i, false);
1605                         break;
1606                 case svc_spawnbaseline2:
1607                         i = MSG_ReadShort ();
1608                         if (i < 0 || i >= MAX_EDICTS)
1609                                 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline2: invalid entity number %i", i);
1610                         CL_ParseBaseline (cl_entities + i, true);
1611                         break;
1612                 case svc_spawnstatic:
1613                         CL_ParseStatic (false);
1614                         break;
1615                 case svc_spawnstatic2:
1616                         CL_ParseStatic (true);
1617                         break;
1618                 case svc_temp_entity:
1619                         CL_ParseTempEntity ();
1620                         break;
1621
1622                 case svc_setpause:
1623                         cl.paused = MSG_ReadByte ();
1624                         if (cl.paused)
1625                                 CDAudio_Pause ();
1626                         else
1627                                 CDAudio_Resume ();
1628                         break;
1629
1630                 case svc_signonnum:
1631                         i = MSG_ReadByte ();
1632                         if (i <= cls.signon)
1633                                 Host_Error ("Received signon %i when at %i", i, cls.signon);
1634                         cls.signon = i;
1635                         CL_SignonReply ();
1636                         break;
1637
1638                 case svc_killedmonster:
1639                         cl.stats[STAT_MONSTERS]++;
1640                         break;
1641
1642                 case svc_foundsecret:
1643                         cl.stats[STAT_SECRETS]++;
1644                         break;
1645
1646                 case svc_updatestat:
1647                         i = MSG_ReadByte ();
1648                         if (i < 0 || i >= MAX_CL_STATS)
1649                                 Host_Error ("svc_updatestat: %i is invalid", i);
1650                         cl.stats[i] = MSG_ReadLong ();
1651                         break;
1652
1653                 case svc_spawnstaticsound:
1654                         CL_ParseStaticSound (false);
1655                         break;
1656
1657                 case svc_spawnstaticsound2:
1658                         CL_ParseStaticSound (true);
1659                         break;
1660
1661                 case svc_cdtrack:
1662                         cl.cdtrack = MSG_ReadByte ();
1663                         cl.looptrack = MSG_ReadByte ();
1664                         if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )
1665                                 CDAudio_Play ((qbyte)cls.forcetrack, true);
1666                         else
1667                                 CDAudio_Play ((qbyte)cl.cdtrack, true);
1668                         break;
1669
1670                 case svc_intermission:
1671                         cl.intermission = 1;
1672                         cl.completed_time = cl.time;
1673                         break;
1674
1675                 case svc_finale:
1676                         cl.intermission = 2;
1677                         cl.completed_time = cl.time;
1678                         SCR_CenterPrint (MSG_ReadString ());
1679                         break;
1680
1681                 case svc_cutscene:
1682                         cl.intermission = 3;
1683                         cl.completed_time = cl.time;
1684                         SCR_CenterPrint (MSG_ReadString ());
1685                         break;
1686
1687                 case svc_sellscreen:
1688                         Cmd_ExecuteString ("help", src_command);
1689                         break;
1690                 case svc_hidelmp:
1691                         SHOWLMP_decodehide();
1692                         break;
1693                 case svc_showlmp:
1694                         SHOWLMP_decodeshow();
1695                         break;
1696                 case svc_skybox:
1697                         R_SetSkyBox(MSG_ReadString());
1698                         break;
1699                 case svc_cgame:
1700                         {
1701                                 int length;
1702                                 length = (int) ((unsigned short) MSG_ReadShort());
1703                                 for (i = 0;i < length;i++)
1704                                         cgamenetbuffer[i] = MSG_ReadByte();
1705                                 if (!msg_badread)
1706                                         CL_CGVM_ParseNetwork(cgamenetbuffer, length);
1707                         }
1708                         break;
1709                 case svc_entities:
1710                         if (cls.signon == SIGNONS - 1)
1711                         {
1712                                 // first update is the final signon stage
1713                                 cls.signon = SIGNONS;
1714                                 CL_SignonReply ();
1715                         }
1716                         CL_ReadEntityFrame();
1717                         break;
1718                 }
1719         }
1720
1721         if (entitiesupdated)
1722                 CL_EntityUpdateEnd();
1723
1724         parsingerror = false;
1725 }
1726
1727 void CL_Parse_DumpPacket(void)
1728 {
1729         if (!parsingerror)
1730                 return;
1731         Con_Printf("Packet dump:\n");
1732         SZ_HexDumpToConsole(&net_message);
1733         parsingerror = false;
1734 }
1735
1736 void CL_Parse_Init(void)
1737 {
1738         // LordHavoc: added demo_nehahra cvar
1739         Cvar_RegisterVariable (&demo_nehahra);
1740         if (gamemode == GAME_NEHAHRA)
1741                 Cvar_SetValue("demo_nehahra", 1);
1742 }