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