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