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