]> icculus.org git repositories - divverent/darkplaces.git/blob - cl_parse.c
moved all type-specific model fields to respective structures (alias, sprite, brush)
[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_BLOOD2:
1117                 // blood puff
1118                 MSG_ReadVector(pos);
1119                 CL_FindNonSolidLocation(pos, pos, 4);
1120                 CL_BloodPuff(pos, vec3_origin, 10);
1121                 break;
1122         case TE_SPARK:
1123                 // spark shower
1124                 MSG_ReadVector(pos);
1125                 CL_FindNonSolidLocation(pos, pos, 4);
1126                 dir[0] = MSG_ReadChar();
1127                 dir[1] = MSG_ReadChar();
1128                 dir[2] = MSG_ReadChar();
1129                 count = MSG_ReadByte();
1130                 CL_SparkShower(pos, dir, count);
1131                 break;
1132         case TE_PLASMABURN:
1133                 MSG_ReadVector(pos);
1134                 CL_FindNonSolidLocation(pos, pos, 4);
1135                 CL_AllocDlight(NULL, pos, 200, 1, 1, 1, 1000, 0.2);
1136                 CL_PlasmaBurn(pos);
1137                 break;
1138                 // LordHavoc: added for improved gore
1139         case TE_BLOODSHOWER:
1140                 // vaporized body
1141                 MSG_ReadVector(pos); // mins
1142                 MSG_ReadVector(pos2); // maxs
1143                 velspeed = MSG_ReadCoord(); // speed
1144                 count = MSG_ReadShort(); // number of particles
1145                 CL_BloodShower(pos, pos2, velspeed, count);
1146                 break;
1147         case TE_PARTICLECUBE:
1148                 // general purpose particle effect
1149                 MSG_ReadVector(pos); // mins
1150                 MSG_ReadVector(pos2); // maxs
1151                 MSG_ReadVector(dir); // dir
1152                 count = MSG_ReadShort(); // number of particles
1153                 colorStart = MSG_ReadByte(); // color
1154                 colorLength = MSG_ReadByte(); // gravity (1 or 0)
1155                 velspeed = MSG_ReadCoord(); // randomvel
1156                 CL_ParticleCube(pos, pos2, dir, count, colorStart, colorLength, velspeed);
1157                 break;
1158
1159         case TE_PARTICLERAIN:
1160                 // general purpose particle effect
1161                 MSG_ReadVector(pos); // mins
1162                 MSG_ReadVector(pos2); // maxs
1163                 MSG_ReadVector(dir); // dir
1164                 count = MSG_ReadShort(); // number of particles
1165                 colorStart = MSG_ReadByte(); // color
1166                 CL_ParticleRain(pos, pos2, dir, count, colorStart, 0);
1167                 break;
1168
1169         case TE_PARTICLESNOW:
1170                 // general purpose particle effect
1171                 MSG_ReadVector(pos); // mins
1172                 MSG_ReadVector(pos2); // maxs
1173                 MSG_ReadVector(dir); // dir
1174                 count = MSG_ReadShort(); // number of particles
1175                 colorStart = MSG_ReadByte(); // color
1176                 CL_ParticleRain(pos, pos2, dir, count, colorStart, 1);
1177                 break;
1178
1179         case TE_GUNSHOT:
1180                 // bullet hitting wall
1181                 MSG_ReadVector(pos);
1182                 CL_FindNonSolidLocation(pos, pos, 4);
1183                 // LordHavoc: changed to dust shower
1184                 CL_SparkShower(pos, vec3_origin, 15);
1185                 break;
1186
1187         case TE_GUNSHOTQUAD:
1188                 // quad bullet hitting wall
1189                 MSG_ReadVector(pos);
1190                 CL_FindNonSolidLocation(pos, pos, 4);
1191                 CL_SparkShower(pos, vec3_origin, 15);
1192                 CL_AllocDlight(NULL, pos, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2);
1193                 break;
1194
1195         case TE_EXPLOSION:
1196                 // rocket explosion
1197                 MSG_ReadVector(pos);
1198                 CL_FindNonSolidLocation(pos, pos, 10);
1199                 CL_ParticleExplosion(pos);
1200                 // LordHavoc: boosted color from 1.0, 0.8, 0.4 to 1.25, 1.0, 0.5
1201                 CL_AllocDlight(NULL, pos, 350, 1.25f, 1.0f, 0.5f, 700, 0.5);
1202                 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1203                 break;
1204
1205         case TE_EXPLOSIONQUAD:
1206                 // quad rocket explosion
1207                 MSG_ReadVector(pos);
1208                 CL_FindNonSolidLocation(pos, pos, 10);
1209                 CL_ParticleExplosion(pos);
1210                 CL_AllocDlight(NULL, pos, 600, 0.5f, 0.4f, 1.0f, 1200, 0.5);
1211                 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1212                 break;
1213
1214         case TE_EXPLOSION3:
1215                 // Nehahra movie colored lighting explosion
1216                 MSG_ReadVector(pos);
1217                 CL_FindNonSolidLocation(pos, pos, 10);
1218                 CL_ParticleExplosion(pos);
1219                 CL_AllocDlight(NULL, pos, 350, MSG_ReadCoord(), MSG_ReadCoord(), MSG_ReadCoord(), 700, 0.5);
1220                 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1221                 break;
1222
1223         case TE_EXPLOSIONRGB:
1224                 // colored lighting explosion
1225                 MSG_ReadVector(pos);
1226                 CL_FindNonSolidLocation(pos, pos, 10);
1227                 CL_ParticleExplosion(pos);
1228                 color[0] = MSG_ReadByte() * (1.0 / 255.0);
1229                 color[1] = MSG_ReadByte() * (1.0 / 255.0);
1230                 color[2] = MSG_ReadByte() * (1.0 / 255.0);
1231                 CL_AllocDlight(NULL, pos, 350, color[0], color[1], color[2], 700, 0.5);
1232                 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1233                 break;
1234
1235         case TE_TAREXPLOSION:
1236                 // tarbaby explosion
1237                 MSG_ReadVector(pos);
1238                 CL_FindNonSolidLocation(pos, pos, 10);
1239                 CL_BlobExplosion(pos);
1240
1241                 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1242                 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1243                 CL_AllocDlight(NULL, pos, 600, 0.8f, 0.4f, 1.0f, 1200, 0.5);
1244                 break;
1245
1246         case TE_SMALLFLASH:
1247                 MSG_ReadVector(pos);
1248                 CL_FindNonSolidLocation(pos, pos, 10);
1249                 CL_AllocDlight(NULL, pos, 200, 1, 1, 1, 1000, 0.2);
1250                 break;
1251
1252         case TE_CUSTOMFLASH:
1253                 MSG_ReadVector(pos);
1254                 CL_FindNonSolidLocation(pos, pos, 4);
1255                 radius = MSG_ReadByte() * 8;
1256                 velspeed = (MSG_ReadByte() + 1) * (1.0 / 256.0);
1257                 color[0] = MSG_ReadByte() * (1.0 / 255.0);
1258                 color[1] = MSG_ReadByte() * (1.0 / 255.0);
1259                 color[2] = MSG_ReadByte() * (1.0 / 255.0);
1260                 CL_AllocDlight(NULL, pos, radius, color[0], color[1], color[2], radius / velspeed, velspeed);
1261                 break;
1262
1263         case TE_FLAMEJET:
1264                 MSG_ReadVector(pos);
1265                 MSG_ReadVector(dir);
1266                 count = MSG_ReadByte();
1267                 CL_Flames(pos, dir, count);
1268                 break;
1269
1270         case TE_LIGHTNING1:
1271                 // lightning bolts
1272                 if (!cl_model_bolt)
1273                         cl_model_bolt = Mod_ForName("progs/bolt.mdl", true, false, false);
1274                 CL_ParseBeam(cl_model_bolt, true);
1275                 break;
1276
1277         case TE_LIGHTNING2:
1278                 // lightning bolts
1279                 if (!cl_model_bolt2)
1280                         cl_model_bolt2 = Mod_ForName("progs/bolt2.mdl", true, false, false);
1281                 CL_ParseBeam(cl_model_bolt2, true);
1282                 break;
1283
1284         case TE_LIGHTNING3:
1285                 // lightning bolts
1286                 if (!cl_model_bolt3)
1287                         cl_model_bolt3 = Mod_ForName("progs/bolt3.mdl", true, false, false);
1288                 CL_ParseBeam(cl_model_bolt3, false);
1289                 break;
1290
1291 // PGM 01/21/97
1292         case TE_BEAM:
1293                 // grappling hook beam
1294                 if (!cl_model_beam)
1295                         cl_model_beam = Mod_ForName("progs/beam.mdl", true, false, false);
1296                 CL_ParseBeam(cl_model_beam, false);
1297                 break;
1298 // PGM 01/21/97
1299
1300 // LordHavoc: for compatibility with the Nehahra movie...
1301         case TE_LIGHTNING4NEH:
1302                 CL_ParseBeam(Mod_ForName(MSG_ReadString(), true, false, false), false);
1303                 break;
1304
1305         case TE_LAVASPLASH:
1306                 pos[0] = MSG_ReadCoord();
1307                 pos[1] = MSG_ReadCoord();
1308                 pos[2] = MSG_ReadCoord();
1309                 CL_LavaSplash(pos);
1310                 break;
1311
1312         case TE_TELEPORT:
1313                 pos[0] = MSG_ReadCoord();
1314                 pos[1] = MSG_ReadCoord();
1315                 pos[2] = MSG_ReadCoord();
1316                 CL_AllocDlight(NULL, pos, 500, 1.0f, 1.0f, 1.0f, 1500, 99.0f);
1317 //              CL_TeleportSplash(pos);
1318                 break;
1319
1320         case TE_EXPLOSION2:
1321                 // color mapped explosion
1322                 MSG_ReadVector(pos);
1323                 CL_FindNonSolidLocation(pos, pos, 10);
1324                 colorStart = MSG_ReadByte();
1325                 colorLength = MSG_ReadByte();
1326                 CL_ParticleExplosion2(pos, colorStart, colorLength);
1327                 tempcolor = (qbyte *)&palette_complete[(rand()%colorLength) + colorStart];
1328                 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);
1329                 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1330                 break;
1331
1332         case TE_TEI_G3:
1333                 MSG_ReadVector(pos);
1334                 MSG_ReadVector(pos2);
1335                 MSG_ReadVector(dir);
1336                 CL_BeamParticle(pos, pos2, 12, 1, 0.3, 0.1, 1, 1);
1337                 CL_BeamParticle(pos, pos2, 5, 1, 0.9, 0.3, 1, 1);
1338                 break;
1339
1340         case TE_TEI_SMOKE:
1341                 MSG_ReadVector(pos);
1342                 MSG_ReadVector(dir);
1343                 count = MSG_ReadByte();
1344                 CL_FindNonSolidLocation(pos, pos, 4);
1345                 CL_Tei_Smoke(pos, dir, count);
1346                 break;
1347
1348         case TE_TEI_BIGEXPLOSION:
1349                 MSG_ReadVector(pos);
1350                 CL_FindNonSolidLocation(pos, pos, 10);
1351                 CL_ParticleExplosion(pos);
1352                 CL_AllocDlight(NULL, pos, 500, 1.25f, 1.0f, 0.5f, 500, 9999);
1353                 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1354                 break;
1355
1356         case TE_TEI_PLASMAHIT:
1357                 MSG_ReadVector(pos);
1358                 MSG_ReadVector(dir);
1359                 count = MSG_ReadByte();
1360                 CL_FindNonSolidLocation(pos, pos, 5);
1361                 CL_Tei_PlasmaHit(pos, dir, count);
1362                 CL_AllocDlight(NULL, pos, 500, 0.3, 0.6, 1.0f, 2000, 9999);
1363                 break;
1364
1365         default:
1366                 Host_Error("CL_ParseTempEntity: bad type %d (hex %02X)", type, type);
1367         }
1368 }
1369
1370 #define SHOWNET(x) if(cl_shownet.integer==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x);
1371
1372 static qbyte cgamenetbuffer[65536];
1373
1374 /*
1375 =====================
1376 CL_ParseServerMessage
1377 =====================
1378 */
1379 int parsingerror = false;
1380 void CL_ParseServerMessage(void)
1381 {
1382         int                     cmd;
1383         int                     i, entitiesupdated;
1384         qbyte           cmdlog[32];
1385         char            *cmdlogname[32], *temp;
1386         int                     cmdindex, cmdcount = 0;
1387
1388         if (cls.demorecording)
1389                 CL_WriteDemoMessage ();
1390
1391         cl.last_received_message = realtime;
1392
1393 //
1394 // if recording demos, copy the message out
1395 //
1396         if (cl_shownet.integer == 1)
1397                 Con_Printf ("%f %i\n", realtime, net_message.cursize);
1398         else if (cl_shownet.integer == 2)
1399                 Con_Printf ("------------------\n");
1400
1401         cl.onground = false;    // unless the server says otherwise
1402 //
1403 // parse the message
1404 //
1405         //MSG_BeginReading ();
1406
1407         entitiesupdated = false;
1408
1409         parsingerror = true;
1410
1411         while (1)
1412         {
1413                 if (msg_badread)
1414                         Host_Error ("CL_ParseServerMessage: Bad server message");
1415
1416                 cmd = MSG_ReadByte ();
1417
1418                 if (cmd == -1)
1419                 {
1420                         SHOWNET("END OF MESSAGE");
1421                         break;          // end of message
1422                 }
1423
1424                 cmdindex = cmdcount & 31;
1425                 cmdcount++;
1426                 cmdlog[cmdindex] = cmd;
1427
1428                 // if the high bit of the command byte is set, it is a fast update
1429                 if (cmd & 128)
1430                 {
1431                         // 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)
1432                         temp = "entity";
1433                         cmdlogname[cmdindex] = temp;
1434                         SHOWNET("fast update");
1435                         if (cls.signon == SIGNONS - 1)
1436                         {
1437                                 // first update is the final signon stage
1438                                 cls.signon = SIGNONS;
1439                                 CL_SignonReply ();
1440                         }
1441                         CL_ParseUpdate (cmd&127);
1442                         continue;
1443                 }
1444
1445                 SHOWNET(svc_strings[cmd]);
1446                 cmdlogname[cmdindex] = svc_strings[cmd];
1447                 if (!cmdlogname[cmdindex])
1448                 {
1449                         // 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)
1450                         temp = "<unknown>";
1451                         cmdlogname[cmdindex] = temp;
1452                 }
1453
1454                 // other commands
1455                 switch (cmd)
1456                 {
1457                 default:
1458                         {
1459                                 char description[32*64], temp[64];
1460                                 int count;
1461                                 strcpy(description, "packet dump: ");
1462                                 i = cmdcount - 32;
1463                                 if (i < 0)
1464                                         i = 0;
1465                                 count = cmdcount - i;
1466                                 i &= 31;
1467                                 while(count > 0)
1468                                 {
1469                                         sprintf(temp, "%3i:%s ", cmdlog[i], cmdlogname[i]);
1470                                         strcat(description, temp);
1471                                         count--;
1472                                         i++;
1473                                         i &= 31;
1474                                 }
1475                                 description[strlen(description)-1] = '\n'; // replace the last space with a newline
1476                                 Con_Printf("%s", description);
1477                                 Host_Error ("CL_ParseServerMessage: Illegible server message\n");
1478                         }
1479                         break;
1480
1481                 case svc_nop:
1482                         if (cls.signon < SIGNONS)
1483                                 Con_Printf("<-- server to client keepalive\n");
1484                         break;
1485
1486                 case svc_time:
1487                         if (!entitiesupdated)
1488                         {
1489                                 // this is a new frame, we'll be seeing entities,
1490                                 // so prepare for entity updates
1491                                 CL_EntityUpdateSetup();
1492                                 entitiesupdated = true;
1493                         }
1494                         cl.mtime[1] = cl.mtime[0];
1495                         cl.mtime[0] = MSG_ReadFloat ();
1496                         break;
1497
1498                 case svc_clientdata:
1499                         i = MSG_ReadShort ();
1500                         CL_ParseClientdata (i);
1501                         break;
1502
1503                 case svc_version:
1504                         i = MSG_ReadLong ();
1505                         if (i != PROTOCOL_VERSION && i != DPPROTOCOL_VERSION1 && i != DPPROTOCOL_VERSION2 && i != DPPROTOCOL_VERSION3 && i != 250)
1506                                 Host_Error ("CL_ParseServerMessage: Server is protocol %i, not %i, %i, %i or %i", i, DPPROTOCOL_VERSION1, DPPROTOCOL_VERSION2, DPPROTOCOL_VERSION3, PROTOCOL_VERSION);
1507                         Nehahrademcompatibility = false;
1508                         if (i == 250)
1509                                 Nehahrademcompatibility = true;
1510                         if (cls.demoplayback && demo_nehahra.integer)
1511                                 Nehahrademcompatibility = true;
1512                         dpprotocol = i;
1513                         if (dpprotocol != DPPROTOCOL_VERSION1 && dpprotocol != DPPROTOCOL_VERSION2 && dpprotocol != DPPROTOCOL_VERSION3)
1514                                 dpprotocol = 0;
1515                         break;
1516
1517                 case svc_disconnect:
1518                         Host_EndGame ("Server disconnected\n");
1519
1520                 case svc_print:
1521                         Con_Printf ("%s", MSG_ReadString ());
1522                         break;
1523
1524                 case svc_centerprint:
1525                         SCR_CenterPrint (MSG_ReadString ());
1526                         break;
1527
1528                 case svc_stufftext:
1529                         Cbuf_AddText (MSG_ReadString ());
1530                         break;
1531
1532                 case svc_damage:
1533                         V_ParseDamage ();
1534                         break;
1535
1536                 case svc_serverinfo:
1537                         CL_ParseServerInfo ();
1538                         break;
1539
1540                 case svc_setangle:
1541                         for (i=0 ; i<3 ; i++)
1542                                 cl.viewangles[i] = MSG_ReadAngle ();
1543                         break;
1544
1545                 case svc_setview:
1546                         cl.viewentity = (unsigned short)MSG_ReadShort ();
1547                         if (cl.viewentity >= MAX_EDICTS)
1548                                 Host_Error("svc_setview >= MAX_EDICTS\n");
1549                         // LordHavoc: assume first setview recieved is the real player entity
1550                         if (!cl.playerentity)
1551                                 cl.playerentity = cl.viewentity;
1552                         break;
1553
1554                 case svc_lightstyle:
1555                         i = MSG_ReadByte ();
1556                         if (i >= MAX_LIGHTSTYLES)
1557                                 Host_Error ("svc_lightstyle >= MAX_LIGHTSTYLES");
1558                         strncpy (cl_lightstyle[i].map,  MSG_ReadString(), MAX_STYLESTRING - 1);
1559                         cl_lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
1560                         cl_lightstyle[i].length = strlen(cl_lightstyle[i].map);
1561                         break;
1562
1563                 case svc_sound:
1564                         CL_ParseStartSoundPacket(false);
1565                         break;
1566
1567                 case svc_sound2:
1568                         CL_ParseStartSoundPacket(true);
1569                         break;
1570
1571                 case svc_stopsound:
1572                         i = MSG_ReadShort();
1573                         S_StopSound(i>>3, i&7);
1574                         break;
1575
1576                 case svc_updatename:
1577                         i = MSG_ReadByte ();
1578                         if (i >= cl.maxclients)
1579                                 Host_Error ("CL_ParseServerMessage: svc_updatename >= cl.maxclients");
1580                         strcpy (cl.scores[i].name, MSG_ReadString ());
1581                         break;
1582
1583                 case svc_updatefrags:
1584                         i = MSG_ReadByte ();
1585                         if (i >= cl.maxclients)
1586                                 Host_Error ("CL_ParseServerMessage: svc_updatefrags >= cl.maxclients");
1587                         cl.scores[i].frags = MSG_ReadShort ();
1588                         break;
1589
1590                 case svc_updatecolors:
1591                         i = MSG_ReadByte ();
1592                         if (i >= cl.maxclients)
1593                                 Host_Error ("CL_ParseServerMessage: svc_updatecolors >= cl.maxclients");
1594                         cl.scores[i].colors = MSG_ReadByte ();
1595                         break;
1596
1597                 case svc_particle:
1598                         CL_ParseParticleEffect ();
1599                         break;
1600
1601                 case svc_effect:
1602                         CL_ParseEffect ();
1603                         break;
1604
1605                 case svc_effect2:
1606                         CL_ParseEffect2 ();
1607                         break;
1608
1609                 case svc_spawnbaseline:
1610                         i = MSG_ReadShort ();
1611                         if (i < 0 || i >= MAX_EDICTS)
1612                                 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i);
1613                         CL_ParseBaseline (cl_entities + i, false);
1614                         break;
1615                 case svc_spawnbaseline2:
1616                         i = MSG_ReadShort ();
1617                         if (i < 0 || i >= MAX_EDICTS)
1618                                 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline2: invalid entity number %i", i);
1619                         CL_ParseBaseline (cl_entities + i, true);
1620                         break;
1621                 case svc_spawnstatic:
1622                         CL_ParseStatic (false);
1623                         break;
1624                 case svc_spawnstatic2:
1625                         CL_ParseStatic (true);
1626                         break;
1627                 case svc_temp_entity:
1628                         CL_ParseTempEntity ();
1629                         break;
1630
1631                 case svc_setpause:
1632                         cl.paused = MSG_ReadByte ();
1633                         if (cl.paused)
1634                                 CDAudio_Pause ();
1635                         else
1636                                 CDAudio_Resume ();
1637                         break;
1638
1639                 case svc_signonnum:
1640                         i = MSG_ReadByte ();
1641                         if (i <= cls.signon)
1642                                 Host_Error ("Received signon %i when at %i", i, cls.signon);
1643                         cls.signon = i;
1644                         CL_SignonReply ();
1645                         break;
1646
1647                 case svc_killedmonster:
1648                         cl.stats[STAT_MONSTERS]++;
1649                         break;
1650
1651                 case svc_foundsecret:
1652                         cl.stats[STAT_SECRETS]++;
1653                         break;
1654
1655                 case svc_updatestat:
1656                         i = MSG_ReadByte ();
1657                         if (i < 0 || i >= MAX_CL_STATS)
1658                                 Host_Error ("svc_updatestat: %i is invalid", i);
1659                         cl.stats[i] = MSG_ReadLong ();
1660                         break;
1661
1662                 case svc_spawnstaticsound:
1663                         CL_ParseStaticSound (false);
1664                         break;
1665
1666                 case svc_spawnstaticsound2:
1667                         CL_ParseStaticSound (true);
1668                         break;
1669
1670                 case svc_cdtrack:
1671                         cl.cdtrack = MSG_ReadByte ();
1672                         cl.looptrack = MSG_ReadByte ();
1673                         if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )
1674                                 CDAudio_Play ((qbyte)cls.forcetrack, true);
1675                         else
1676                                 CDAudio_Play ((qbyte)cl.cdtrack, true);
1677                         break;
1678
1679                 case svc_intermission:
1680                         cl.intermission = 1;
1681                         cl.completed_time = cl.time;
1682                         break;
1683
1684                 case svc_finale:
1685                         cl.intermission = 2;
1686                         cl.completed_time = cl.time;
1687                         SCR_CenterPrint (MSG_ReadString ());
1688                         break;
1689
1690                 case svc_cutscene:
1691                         cl.intermission = 3;
1692                         cl.completed_time = cl.time;
1693                         SCR_CenterPrint (MSG_ReadString ());
1694                         break;
1695
1696                 case svc_sellscreen:
1697                         Cmd_ExecuteString ("help", src_command);
1698                         break;
1699                 case svc_hidelmp:
1700                         SHOWLMP_decodehide();
1701                         break;
1702                 case svc_showlmp:
1703                         SHOWLMP_decodeshow();
1704                         break;
1705                 case svc_skybox:
1706                         R_SetSkyBox(MSG_ReadString());
1707                         break;
1708                 case svc_cgame:
1709                         {
1710                                 int length;
1711                                 length = (int) ((unsigned short) MSG_ReadShort());
1712                                 for (i = 0;i < length;i++)
1713                                         cgamenetbuffer[i] = MSG_ReadByte();
1714                                 if (!msg_badread)
1715                                         CL_CGVM_ParseNetwork(cgamenetbuffer, length);
1716                         }
1717                         break;
1718                 case svc_entities:
1719                         if (cls.signon == SIGNONS - 1)
1720                         {
1721                                 // first update is the final signon stage
1722                                 cls.signon = SIGNONS;
1723                                 CL_SignonReply ();
1724                         }
1725                         CL_ReadEntityFrame();
1726                         break;
1727                 }
1728         }
1729
1730         if (entitiesupdated)
1731                 CL_EntityUpdateEnd();
1732
1733         parsingerror = false;
1734 }
1735
1736 void CL_Parse_DumpPacket(void)
1737 {
1738         if (!parsingerror)
1739                 return;
1740         Con_Printf("Packet dump:\n");
1741         SZ_HexDumpToConsole(&net_message);
1742         parsingerror = false;
1743 }
1744
1745 void CL_Parse_Init(void)
1746 {
1747         // LordHavoc: added demo_nehahra cvar
1748         cl_scores_mempool = Mem_AllocPool("client player info");
1749         Cvar_RegisterVariable (&demo_nehahra);
1750         if (gamemode == GAME_NEHAHRA)
1751                 Cvar_SetValue("demo_nehahra", 1);
1752 }