]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - cl_parse.c
tiny cleanup to RotatePointAroundVector (uses a VectorCopy instead of 3 lines)
[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         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)
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         // override any beam with the same entity
943         for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
944         {
945                 if (b->entity == ent)
946                 {
947                         //b->entity = ent;
948                         b->model = m;
949                         b->endtime = cl.time + 0.2;
950                         VectorCopy (start, b->start);
951                         VectorCopy (end, b->end);
952                         return;
953                 }
954         }
955
956         // find a free beam
957         for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
958         {
959                 if (!b->model || b->endtime < cl.time)
960                 {
961                         b->entity = ent;
962                         b->model = m;
963                         b->endtime = cl.time + 0.2;
964                         VectorCopy (start, b->start);
965                         VectorCopy (end, b->end);
966                         return;
967                 }
968         }
969         Con_Printf ("beam list overflow!\n");
970 }
971
972 void CL_ParseTempEntity (void)
973 {
974         int type;
975         vec3_t pos;
976         vec3_t dir;
977         vec3_t pos2;
978         vec3_t color;
979         int rnd;
980         int colorStart, colorLength, count;
981         float velspeed, radius;
982         qbyte *tempcolor;
983
984         type = MSG_ReadByte ();
985         switch (type)
986         {
987         case TE_WIZSPIKE:
988                 // spike hitting wall
989                 MSG_ReadVector(pos);
990                 Mod_FindNonSolidLocation(pos, cl.worldmodel);
991                 CL_RunParticleEffect (pos, vec3_origin, 20, 30);
992                 S_StartSound (-1, 0, cl_sfx_wizhit, pos, 1, 1);
993                 break;
994
995         case TE_KNIGHTSPIKE:
996                 // spike hitting wall
997                 MSG_ReadVector(pos);
998                 Mod_FindNonSolidLocation(pos, cl.worldmodel);
999                 CL_RunParticleEffect (pos, vec3_origin, 226, 20);
1000                 S_StartSound (-1, 0, cl_sfx_knighthit, pos, 1, 1);
1001                 break;
1002
1003         case TE_SPIKE:
1004                 // spike hitting wall
1005                 MSG_ReadVector(pos);
1006                 Mod_FindNonSolidLocation(pos, cl.worldmodel);
1007                 // LordHavoc: changed to spark shower
1008                 CL_SparkShower(pos, vec3_origin, 15);
1009                 if ( rand() % 5 )
1010                         S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
1011                 else
1012                 {
1013                         rnd = rand() & 3;
1014                         if (rnd == 1)
1015                                 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
1016                         else if (rnd == 2)
1017                                 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
1018                         else
1019                                 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
1020                 }
1021                 break;
1022         case TE_SPIKEQUAD:
1023                 // quad spike hitting wall
1024                 MSG_ReadVector(pos);
1025                 Mod_FindNonSolidLocation(pos, cl.worldmodel);
1026                 // LordHavoc: changed to spark shower
1027                 CL_SparkShower(pos, vec3_origin, 15);
1028                 CL_AllocDlight (NULL, pos, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2);
1029                 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
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_SUPERSPIKE:
1044                 // super spike hitting wall
1045                 MSG_ReadVector(pos);
1046                 Mod_FindNonSolidLocation(pos, cl.worldmodel);
1047                 // LordHavoc: changed to dust shower
1048                 CL_SparkShower(pos, vec3_origin, 30);
1049                 if ( rand() % 5 )
1050                         S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
1051                 else
1052                 {
1053                         rnd = rand() & 3;
1054                         if (rnd == 1)
1055                                 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
1056                         else if (rnd == 2)
1057                                 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
1058                         else
1059                                 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
1060                 }
1061                 break;
1062         case TE_SUPERSPIKEQUAD:
1063                 // quad super spike hitting wall
1064                 MSG_ReadVector(pos);
1065                 Mod_FindNonSolidLocation(pos, cl.worldmodel);
1066                 // LordHavoc: changed to dust shower
1067                 CL_SparkShower(pos, vec3_origin, 30);
1068                 CL_AllocDlight (NULL, pos, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2);
1069                 if ( rand() % 5 )
1070                         S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
1071                 else
1072                 {
1073                         rnd = rand() & 3;
1074                         if (rnd == 1)
1075                                 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
1076                         else if (rnd == 2)
1077                                 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
1078                         else
1079                                 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
1080                 }
1081                 break;
1082                 // LordHavoc: added for improved blood splatters
1083         case TE_BLOOD:
1084                 // blood puff
1085                 MSG_ReadVector(pos);
1086                 dir[0] = MSG_ReadChar ();
1087                 dir[1] = MSG_ReadChar ();
1088                 dir[2] = MSG_ReadChar ();
1089                 count = MSG_ReadByte ();
1090                 CL_BloodPuff(pos, dir, count);
1091                 break;
1092         case TE_BLOOD2:
1093                 // blood puff
1094                 MSG_ReadVector(pos);
1095                 CL_BloodPuff(pos, vec3_origin, 10);
1096                 break;
1097         case TE_SPARK:
1098                 // spark shower
1099                 MSG_ReadVector(pos);
1100                 dir[0] = MSG_ReadChar ();
1101                 dir[1] = MSG_ReadChar ();
1102                 dir[2] = MSG_ReadChar ();
1103                 count = MSG_ReadByte ();
1104                 Mod_FindNonSolidLocation(pos, cl.worldmodel);
1105                 CL_SparkShower(pos, dir, count);
1106                 break;
1107         case TE_PLASMABURN:
1108                 MSG_ReadVector(pos);
1109                 Mod_FindNonSolidLocation(pos, cl.worldmodel);
1110                 CL_AllocDlight (NULL, pos, 200, 1, 1, 1, 1000, 0.2);
1111                 CL_PlasmaBurn(pos);
1112                 break;
1113                 // LordHavoc: added for improved gore
1114         case TE_BLOODSHOWER:
1115                 // vaporized body
1116                 MSG_ReadVector(pos); // mins
1117                 MSG_ReadVector(pos2); // maxs
1118                 velspeed = MSG_ReadCoord (); // speed
1119                 count = MSG_ReadShort (); // number of particles
1120                 CL_BloodShower(pos, pos2, velspeed, count);
1121                 break;
1122         case TE_PARTICLECUBE:
1123                 // general purpose particle effect
1124                 MSG_ReadVector(pos); // mins
1125                 MSG_ReadVector(pos2); // maxs
1126                 MSG_ReadVector(dir); // dir
1127                 count = MSG_ReadShort (); // number of particles
1128                 colorStart = MSG_ReadByte (); // color
1129                 colorLength = MSG_ReadByte (); // gravity (1 or 0)
1130                 velspeed = MSG_ReadCoord (); // randomvel
1131                 CL_ParticleCube(pos, pos2, dir, count, colorStart, colorLength, velspeed);
1132                 break;
1133
1134         case TE_PARTICLERAIN:
1135                 // general purpose particle effect
1136                 MSG_ReadVector(pos); // mins
1137                 MSG_ReadVector(pos2); // maxs
1138                 MSG_ReadVector(dir); // dir
1139                 count = MSG_ReadShort (); // number of particles
1140                 colorStart = MSG_ReadByte (); // color
1141                 CL_ParticleRain(pos, pos2, dir, count, colorStart, 0);
1142                 break;
1143
1144         case TE_PARTICLESNOW:
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, 1);
1152                 break;
1153
1154         case TE_GUNSHOT:
1155                 // bullet hitting wall
1156                 MSG_ReadVector(pos);
1157                 Mod_FindNonSolidLocation(pos, cl.worldmodel);
1158                 // LordHavoc: changed to dust shower
1159                 CL_SparkShower(pos, vec3_origin, 15);
1160                 break;
1161
1162         case TE_GUNSHOTQUAD:
1163                 // quad bullet hitting wall
1164                 MSG_ReadVector(pos);
1165                 Mod_FindNonSolidLocation(pos, cl.worldmodel);
1166                 CL_SparkShower(pos, vec3_origin, 15);
1167                 CL_AllocDlight (NULL, pos, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2);
1168                 break;
1169
1170         case TE_EXPLOSION:
1171                 // rocket explosion
1172                 MSG_ReadVector(pos);
1173                 Mod_FindNonSolidLocation(pos, cl.worldmodel);
1174                 CL_ParticleExplosion (pos);
1175                 // LordHavoc: boosted color from 1.0, 0.8, 0.4 to 1.25, 1.0, 0.5
1176                 CL_AllocDlight (NULL, pos, 350, 1.25f, 1.0f, 0.5f, 700, 0.5);
1177                 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1178                 break;
1179
1180         case TE_EXPLOSIONQUAD:
1181                 // quad rocket explosion
1182                 MSG_ReadVector(pos);
1183                 Mod_FindNonSolidLocation(pos, cl.worldmodel);
1184                 CL_ParticleExplosion (pos);
1185                 CL_AllocDlight (NULL, pos, 600, 0.5f, 0.4f, 1.0f, 1200, 0.5);
1186                 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1187                 break;
1188
1189         case TE_EXPLOSION3:
1190                 // Nehahra movie colored lighting explosion
1191                 MSG_ReadVector(pos);
1192                 Mod_FindNonSolidLocation(pos, cl.worldmodel);
1193                 CL_ParticleExplosion (pos);
1194                 CL_AllocDlight (NULL, pos, 350, MSG_ReadCoord(), MSG_ReadCoord(), MSG_ReadCoord(), 700, 0.5);
1195                 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1196                 break;
1197
1198         case TE_EXPLOSIONRGB:
1199                 // colored lighting explosion
1200                 MSG_ReadVector(pos);
1201                 Mod_FindNonSolidLocation(pos, cl.worldmodel);
1202                 CL_ParticleExplosion (pos);
1203                 color[0] = MSG_ReadByte() * (1.0 / 255.0);
1204                 color[1] = MSG_ReadByte() * (1.0 / 255.0);
1205                 color[2] = MSG_ReadByte() * (1.0 / 255.0);
1206                 CL_AllocDlight (NULL, pos, 350, color[0], color[1], color[2], 700, 0.5);
1207                 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1208                 break;
1209
1210         case TE_TAREXPLOSION:
1211                 // tarbaby explosion
1212                 MSG_ReadVector(pos);
1213                 Mod_FindNonSolidLocation(pos, cl.worldmodel);
1214                 CL_BlobExplosion (pos);
1215
1216                 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1217                 CL_AllocDlight (NULL, pos, 600, 0.8f, 0.4f, 1.0f, 1200, 0.5);
1218                 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1219                 break;
1220
1221         case TE_SMALLFLASH:
1222                 MSG_ReadVector(pos);
1223                 Mod_FindNonSolidLocation(pos, cl.worldmodel);
1224                 CL_AllocDlight (NULL, pos, 200, 1, 1, 1, 1000, 0.2);
1225                 break;
1226
1227         case TE_CUSTOMFLASH:
1228                 MSG_ReadVector(pos);
1229                 Mod_FindNonSolidLocation(pos, cl.worldmodel);
1230                 radius = MSG_ReadByte() * 8;
1231                 velspeed = (MSG_ReadByte() + 1) * (1.0 / 256.0);
1232                 color[0] = MSG_ReadByte() * (1.0 / 255.0);
1233                 color[1] = MSG_ReadByte() * (1.0 / 255.0);
1234                 color[2] = MSG_ReadByte() * (1.0 / 255.0);
1235                 CL_AllocDlight (NULL, pos, radius, color[0], color[1], color[2], radius / velspeed, velspeed);
1236                 break;
1237
1238         case TE_FLAMEJET:
1239                 MSG_ReadVector(pos);
1240                 MSG_ReadVector(dir);
1241                 count = MSG_ReadByte();
1242                 CL_Flames(pos, dir, count);
1243                 break;
1244
1245         case TE_LIGHTNING1:
1246                 // lightning bolts
1247                 if (!cl_model_bolt)
1248                         cl_model_bolt = Mod_ForName("progs/bolt.mdl", true, false, false);
1249                 CL_ParseBeam (cl_model_bolt);
1250                 break;
1251
1252         case TE_LIGHTNING2:
1253                 // lightning bolts
1254                 if (!cl_model_bolt2)
1255                         cl_model_bolt2 = Mod_ForName("progs/bolt2.mdl", true, false, false);
1256                 CL_ParseBeam (cl_model_bolt2);
1257                 break;
1258
1259         case TE_LIGHTNING3:
1260                 // lightning bolts
1261                 if (!cl_model_bolt3)
1262                         cl_model_bolt3 = Mod_ForName("progs/bolt3.mdl", true, false, false);
1263                 CL_ParseBeam (cl_model_bolt3);
1264                 break;
1265
1266 // PGM 01/21/97
1267         case TE_BEAM:
1268                 // grappling hook beam
1269                 if (!cl_model_beam)
1270                         cl_model_beam = Mod_ForName("progs/beam.mdl", true, false, false);
1271                 CL_ParseBeam (cl_model_beam);
1272                 break;
1273 // PGM 01/21/97
1274
1275 // LordHavoc: for compatibility with the Nehahra movie...
1276         case TE_LIGHTNING4NEH:
1277                 CL_ParseBeam (Mod_ForName(MSG_ReadString(), true, false, false));
1278                 break;
1279
1280         case TE_LAVASPLASH:
1281                 pos[0] = MSG_ReadCoord ();
1282                 pos[1] = MSG_ReadCoord ();
1283                 pos[2] = MSG_ReadCoord ();
1284                 CL_LavaSplash (pos);
1285                 break;
1286
1287         case TE_TELEPORT:
1288                 pos[0] = MSG_ReadCoord ();
1289                 pos[1] = MSG_ReadCoord ();
1290                 pos[2] = MSG_ReadCoord ();
1291                 CL_AllocDlight (NULL, pos, 1000, 1.25f, 1.25f, 1.25f, 3000, 99.0f);
1292 //              CL_TeleportSplash (pos);
1293                 break;
1294
1295         case TE_EXPLOSION2:
1296                 // color mapped explosion
1297                 MSG_ReadVector(pos);
1298                 Mod_FindNonSolidLocation(pos, cl.worldmodel);
1299                 colorStart = MSG_ReadByte ();
1300                 colorLength = MSG_ReadByte ();
1301                 CL_ParticleExplosion2 (pos, colorStart, colorLength);
1302                 tempcolor = (qbyte *)&palette_complete[(rand()%colorLength) + colorStart];
1303                 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);
1304                 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1305                 break;
1306
1307         case TE_TEI_G3:
1308                 MSG_ReadVector(pos);
1309                 MSG_ReadVector(pos2);
1310                 MSG_ReadVector(dir);
1311                 CL_BeamParticle(pos, pos2, 12, 1, 0.3, 0.1, 1, 1);
1312                 CL_BeamParticle(pos, pos2, 5, 1, 0.9, 0.3, 1, 1);
1313                 break;
1314
1315         case TE_TEI_SMOKE:
1316                 MSG_ReadVector(pos);
1317                 MSG_ReadVector(dir);
1318                 count = MSG_ReadByte ();
1319                 Mod_FindNonSolidLocation(pos, cl.worldmodel);
1320                 CL_Tei_Smoke(pos, dir, count);
1321                 break;
1322
1323         case TE_TEI_BIGEXPLOSION:
1324                 MSG_ReadVector(pos);
1325                 Mod_FindNonSolidLocation(pos, cl.worldmodel);
1326                 CL_ParticleExplosion (pos);
1327                 CL_AllocDlight (NULL, pos, 500, 1.25f, 1.0f, 0.5f, 500, 9999);
1328                 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1329                 break;
1330
1331         case TE_TEI_PLASMAHIT:
1332                 MSG_ReadVector(pos);
1333                 MSG_ReadVector(dir);
1334                 count = MSG_ReadByte ();
1335                 Mod_FindNonSolidLocation(pos, cl.worldmodel);
1336                 CL_Tei_PlasmaHit(pos, dir, count);
1337                 CL_AllocDlight (NULL, pos, 500, 0.3, 0.6, 1.0f, 2000, 9999);
1338                 break;
1339
1340         default:
1341                 Host_Error ("CL_ParseTempEntity: bad type %d (hex %02X)", type, type);
1342         }
1343 }
1344
1345 #define SHOWNET(x) if(cl_shownet.integer==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x);
1346
1347 static qbyte cgamenetbuffer[65536];
1348
1349 /*
1350 =====================
1351 CL_ParseServerMessage
1352 =====================
1353 */
1354 int parsingerror = false;
1355 void CL_ParseServerMessage (void)
1356 {
1357         int                     cmd;
1358         int                     i, entitiesupdated;
1359         qbyte           cmdlog[32];
1360         char            *cmdlogname[32], *temp;
1361         int                     cmdindex, cmdcount = 0;
1362
1363 //
1364 // if recording demos, copy the message out
1365 //
1366         if (cl_shownet.integer == 1)
1367                 Con_Printf ("%i ",net_message.cursize);
1368         else if (cl_shownet.integer == 2)
1369                 Con_Printf ("------------------\n");
1370
1371         cl.onground = false;    // unless the server says otherwise
1372 //
1373 // parse the message
1374 //
1375         MSG_BeginReading ();
1376
1377         entitiesupdated = false;
1378
1379         parsingerror = true;
1380
1381         while (1)
1382         {
1383                 if (msg_badread)
1384                         Host_Error ("CL_ParseServerMessage: Bad server message");
1385
1386                 cmd = MSG_ReadByte ();
1387
1388                 if (cmd == -1)
1389                 {
1390                         SHOWNET("END OF MESSAGE");
1391                         break;          // end of message
1392                 }
1393
1394                 cmdindex = cmdcount & 31;
1395                 cmdcount++;
1396                 cmdlog[cmdindex] = cmd;
1397
1398                 // if the high bit of the command byte is set, it is a fast update
1399                 if (cmd & 128)
1400                 {
1401                         // 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)
1402                         temp = "entity";
1403                         cmdlogname[cmdindex] = temp;
1404                         SHOWNET("fast update");
1405                         if (cls.signon == SIGNONS - 1)
1406                         {
1407                                 // first update is the final signon stage
1408                                 cls.signon = SIGNONS;
1409                                 CL_SignonReply ();
1410                         }
1411                         CL_ParseUpdate (cmd&127);
1412                         continue;
1413                 }
1414
1415                 SHOWNET(svc_strings[cmd]);
1416                 cmdlogname[cmdindex] = svc_strings[cmd];
1417                 if (!cmdlogname[cmdindex])
1418                 {
1419                         // 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)
1420                         temp = "<unknown>";
1421                         cmdlogname[cmdindex] = temp;
1422                 }
1423
1424                 // other commands
1425                 switch (cmd)
1426                 {
1427                 default:
1428                         {
1429                                 char description[32*64], temp[64];
1430                                 int count;
1431                                 strcpy(description, "packet dump: ");
1432                                 i = cmdcount - 32;
1433                                 if (i < 0)
1434                                         i = 0;
1435                                 count = cmdcount - i;
1436                                 i &= 31;
1437                                 while(count > 0)
1438                                 {
1439                                         sprintf(temp, "%3i:%s ", cmdlog[i], cmdlogname[i]);
1440                                         strcat(description, temp);
1441                                         count--;
1442                                         i++;
1443                                         i &= 31;
1444                                 }
1445                                 description[strlen(description)-1] = '\n'; // replace the last space with a newline
1446                                 Con_Printf("%s", description);
1447                                 Host_Error ("CL_ParseServerMessage: Illegible server message\n");
1448                         }
1449                         break;
1450
1451                 case svc_nop:
1452                         break;
1453
1454                 case svc_time:
1455                         if (!entitiesupdated)
1456                         {
1457                                 // this is a new frame, we'll be seeing entities,
1458                                 // so prepare for entity updates
1459                                 CL_EntityUpdateSetup();
1460                                 entitiesupdated = true;
1461                         }
1462                         cl.mtime[1] = cl.mtime[0];
1463                         cl.mtime[0] = MSG_ReadFloat ();
1464                         break;
1465
1466                 case svc_clientdata:
1467                         i = MSG_ReadShort ();
1468                         CL_ParseClientdata (i);
1469                         break;
1470
1471                 case svc_version:
1472                         i = MSG_ReadLong ();
1473                         if (i != PROTOCOL_VERSION && i != DPPROTOCOL_VERSION1 && i != DPPROTOCOL_VERSION2 && i != DPPROTOCOL_VERSION3 && i != 250)
1474                                 Host_Error ("CL_ParseServerMessage: Server is protocol %i, not %i, %i, %i or %i", i, DPPROTOCOL_VERSION1, DPPROTOCOL_VERSION2, DPPROTOCOL_VERSION3, PROTOCOL_VERSION);
1475                         Nehahrademcompatibility = false;
1476                         if (i == 250)
1477                                 Nehahrademcompatibility = true;
1478                         if (cls.demoplayback && demo_nehahra.integer)
1479                                 Nehahrademcompatibility = true;
1480                         dpprotocol = i;
1481                         if (dpprotocol != DPPROTOCOL_VERSION1 && dpprotocol != DPPROTOCOL_VERSION2 && dpprotocol != DPPROTOCOL_VERSION3)
1482                                 dpprotocol = 0;
1483                         break;
1484
1485                 case svc_disconnect:
1486                         Host_EndGame ("Server disconnected\n");
1487
1488                 case svc_print:
1489                         Con_Printf ("%s", MSG_ReadString ());
1490                         break;
1491
1492                 case svc_centerprint:
1493                         SCR_CenterPrint (MSG_ReadString ());
1494                         break;
1495
1496                 case svc_stufftext:
1497                         Cbuf_AddText (MSG_ReadString ());
1498                         break;
1499
1500                 case svc_damage:
1501                         V_ParseDamage ();
1502                         break;
1503
1504                 case svc_serverinfo:
1505                         CL_ParseServerInfo ();
1506                         break;
1507
1508                 case svc_setangle:
1509                         for (i=0 ; i<3 ; i++)
1510                                 cl.viewangles[i] = MSG_ReadAngle ();
1511                         break;
1512
1513                 case svc_setview:
1514                         cl.viewentity = MSG_ReadShort ();
1515                         // LordHavoc: assume first setview recieved is the real player entity
1516                         if (!cl.playerentity)
1517                                 cl.playerentity = cl.viewentity;
1518                         break;
1519
1520                 case svc_lightstyle:
1521                         i = MSG_ReadByte ();
1522                         if (i >= MAX_LIGHTSTYLES)
1523                                 Host_Error ("svc_lightstyle >= MAX_LIGHTSTYLES");
1524                         strncpy (cl_lightstyle[i].map,  MSG_ReadString(), MAX_STYLESTRING - 1);
1525                         cl_lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
1526                         cl_lightstyle[i].length = strlen(cl_lightstyle[i].map);
1527                         break;
1528
1529                 case svc_sound:
1530                         CL_ParseStartSoundPacket(false);
1531                         break;
1532
1533                 case svc_sound2:
1534                         CL_ParseStartSoundPacket(true);
1535                         break;
1536
1537                 case svc_stopsound:
1538                         i = MSG_ReadShort();
1539                         S_StopSound(i>>3, i&7);
1540                         break;
1541
1542                 case svc_updatename:
1543                         i = MSG_ReadByte ();
1544                         if (i >= cl.maxclients)
1545                                 Host_Error ("CL_ParseServerMessage: svc_updatename >= cl.maxclients");
1546                         strcpy (cl.scores[i].name, MSG_ReadString ());
1547                         break;
1548
1549                 case svc_updatefrags:
1550                         i = MSG_ReadByte ();
1551                         if (i >= cl.maxclients)
1552                                 Host_Error ("CL_ParseServerMessage: svc_updatefrags >= cl.maxclients");
1553                         cl.scores[i].frags = MSG_ReadShort ();
1554                         break;
1555
1556                 case svc_updatecolors:
1557                         i = MSG_ReadByte ();
1558                         if (i >= cl.maxclients)
1559                                 Host_Error ("CL_ParseServerMessage: svc_updatecolors >= cl.maxclients");
1560                         cl.scores[i].colors = MSG_ReadByte ();
1561                         // update our color cvar if our color changed
1562                         if (i == cl.playerentity - 1)
1563                                 Cvar_SetValue ("_cl_color", cl.scores[i].colors);
1564                         break;
1565
1566                 case svc_particle:
1567                         CL_ParseParticleEffect ();
1568                         break;
1569
1570                 case svc_effect:
1571                         CL_ParseEffect ();
1572                         break;
1573
1574                 case svc_effect2:
1575                         CL_ParseEffect2 ();
1576                         break;
1577
1578                 case svc_spawnbaseline:
1579                         i = MSG_ReadShort ();
1580                         if (i < 0 || i >= MAX_EDICTS)
1581                                 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i);
1582                         CL_ParseBaseline (cl_entities + i, false);
1583                         break;
1584                 case svc_spawnbaseline2:
1585                         i = MSG_ReadShort ();
1586                         if (i < 0 || i >= MAX_EDICTS)
1587                                 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline2: invalid entity number %i", i);
1588                         CL_ParseBaseline (cl_entities + i, true);
1589                         break;
1590                 case svc_spawnstatic:
1591                         CL_ParseStatic (false);
1592                         break;
1593                 case svc_spawnstatic2:
1594                         CL_ParseStatic (true);
1595                         break;
1596                 case svc_temp_entity:
1597                         CL_ParseTempEntity ();
1598                         break;
1599
1600                 case svc_setpause:
1601                         cl.paused = MSG_ReadByte ();
1602                         if (cl.paused)
1603                                 CDAudio_Pause ();
1604                         else
1605                                 CDAudio_Resume ();
1606                         break;
1607
1608                 case svc_signonnum:
1609                         i = MSG_ReadByte ();
1610                         if (i <= cls.signon)
1611                                 Host_Error ("Received signon %i when at %i", i, cls.signon);
1612                         cls.signon = i;
1613                         CL_SignonReply ();
1614                         break;
1615
1616                 case svc_killedmonster:
1617                         cl.stats[STAT_MONSTERS]++;
1618                         break;
1619
1620                 case svc_foundsecret:
1621                         cl.stats[STAT_SECRETS]++;
1622                         break;
1623
1624                 case svc_updatestat:
1625                         i = MSG_ReadByte ();
1626                         if (i < 0 || i >= MAX_CL_STATS)
1627                                 Host_Error ("svc_updatestat: %i is invalid", i);
1628                         cl.stats[i] = MSG_ReadLong ();
1629                         break;
1630
1631                 case svc_spawnstaticsound:
1632                         CL_ParseStaticSound (false);
1633                         break;
1634
1635                 case svc_spawnstaticsound2:
1636                         CL_ParseStaticSound (true);
1637                         break;
1638
1639                 case svc_cdtrack:
1640                         cl.cdtrack = MSG_ReadByte ();
1641                         cl.looptrack = MSG_ReadByte ();
1642                         if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )
1643                                 CDAudio_Play ((qbyte)cls.forcetrack, true);
1644                         else
1645                                 CDAudio_Play ((qbyte)cl.cdtrack, true);
1646                         break;
1647
1648                 case svc_intermission:
1649                         cl.intermission = 1;
1650                         cl.completed_time = cl.time;
1651                         break;
1652
1653                 case svc_finale:
1654                         cl.intermission = 2;
1655                         cl.completed_time = cl.time;
1656                         SCR_CenterPrint (MSG_ReadString ());
1657                         break;
1658
1659                 case svc_cutscene:
1660                         cl.intermission = 3;
1661                         cl.completed_time = cl.time;
1662                         SCR_CenterPrint (MSG_ReadString ());
1663                         break;
1664
1665                 case svc_sellscreen:
1666                         Cmd_ExecuteString ("help", src_command);
1667                         break;
1668                 case svc_hidelmp:
1669                         SHOWLMP_decodehide();
1670                         break;
1671                 case svc_showlmp:
1672                         SHOWLMP_decodeshow();
1673                         break;
1674                 case svc_skybox:
1675                         R_SetSkyBox(MSG_ReadString());
1676                         break;
1677                 case svc_cgame:
1678                         {
1679                                 int length;
1680                                 length = (int) ((unsigned short) MSG_ReadShort());
1681                                 for (i = 0;i < length;i++)
1682                                         cgamenetbuffer[i] = MSG_ReadByte();
1683                                 if (!msg_badread)
1684                                         CL_CGVM_ParseNetwork(cgamenetbuffer, length);
1685                         }
1686                         break;
1687                 case svc_entities:
1688                         if (cls.signon == SIGNONS - 1)
1689                         {
1690                                 // first update is the final signon stage
1691                                 cls.signon = SIGNONS;
1692                                 CL_SignonReply ();
1693                         }
1694                         CL_ReadEntityFrame();
1695                         break;
1696                 }
1697         }
1698
1699         if (entitiesupdated)
1700                 CL_EntityUpdateEnd();
1701
1702         parsingerror = false;
1703 }
1704
1705 void CL_Parse_DumpPacket(void)
1706 {
1707         if (!parsingerror)
1708                 return;
1709         Con_Printf("Packet dump:\n");
1710         SZ_HexDumpToConsole(&net_message);
1711         parsingerror = false;
1712 }
1713
1714 void CL_Parse_Init(void)
1715 {
1716         // LordHavoc: added demo_nehahra cvar
1717         Cvar_RegisterVariable (&demo_nehahra);
1718         if (gamemode == GAME_NEHAHRA)
1719                 Cvar_SetValue("demo_nehahra", 1);
1720 }