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