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