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