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