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