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