]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - cl_parse.c
beginnings of qw protocol support
[xonotic/darkplaces.git] / cl_parse.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // cl_parse.c  -- parse a message received from the server
21
22 #include "quakedef.h"
23 #include "cdaudio.h"
24 #include "cl_collision.h"
25 #include "csprogs.h"
26
27 char *svc_strings[128] =
28 {
29         "svc_bad",
30         "svc_nop",
31         "svc_disconnect",
32         "svc_updatestat",
33         "svc_version",          // [int] server version
34         "svc_setview",          // [short] entity number
35         "svc_sound",                    // <see code>
36         "svc_time",                     // [float] server time
37         "svc_print",                    // [string] null terminated string
38         "svc_stufftext",                // [string] stuffed into client's console buffer
39                                                 // the string should be \n terminated
40         "svc_setangle",         // [vec3] set the view angle to this absolute value
41
42         "svc_serverinfo",               // [int] version
43                                                 // [string] signon string
44                                                 // [string]..[0]model cache [string]...[0]sounds cache
45                                                 // [string]..[0]item cache
46         "svc_lightstyle",               // [byte] [string]
47         "svc_updatename",               // [byte] [string]
48         "svc_updatefrags",      // [byte] [short]
49         "svc_clientdata",               // <shortbits + data>
50         "svc_stopsound",                // <see code>
51         "svc_updatecolors",     // [byte] [byte]
52         "svc_particle",         // [vec3] <variable>
53         "svc_damage",                   // [byte] impact [byte] blood [vec3] from
54
55         "svc_spawnstatic",
56         "OBSOLETE svc_spawnbinary",
57         "svc_spawnbaseline",
58
59         "svc_temp_entity",              // <variable>
60         "svc_setpause",
61         "svc_signonnum",
62         "svc_centerprint",
63         "svc_killedmonster",
64         "svc_foundsecret",
65         "svc_spawnstaticsound",
66         "svc_intermission",
67         "svc_finale",                   // [string] music [string] text
68         "svc_cdtrack",                  // [byte] track [byte] looptrack
69         "svc_sellscreen",
70         "svc_cutscene",
71         "svc_showlmp",  // [string] iconlabel [string] lmpfile [short] x [short] y
72         "svc_hidelmp",  // [string] iconlabel
73         "svc_skybox", // [string] skyname
74         "", // 38
75         "", // 39
76         "", // 40
77         "", // 41
78         "", // 42
79         "", // 43
80         "", // 44
81         "", // 45
82         "", // 46
83         "", // 47
84         "", // 48
85         "", // 49
86         "svc_cgame", //                         50              // [short] length [bytes] data
87         "svc_updatestatubyte", //                       51              // [byte] stat [byte] value
88         "svc_effect", //                        52              // [vector] org [byte] modelindex [byte] startframe [byte] framecount [byte] framerate
89         "svc_effect2", //                       53              // [vector] org [short] modelindex [short] startframe [byte] framecount [byte] framerate
90         "svc_sound2", //                        54              // short soundindex instead of byte
91         "svc_spawnbaseline2", //        55              // short modelindex instead of byte
92         "svc_spawnstatic2", //          56              // short modelindex instead of byte
93         "svc_entities", //                      57              // [int] deltaframe [int] thisframe [float vector] eye [variable length] entitydata
94         "svc_csqcentities", //          58              // [short] entnum [variable length] entitydata ... [short] 0x0000
95         "svc_spawnstaticsound2", //     59              // [coord3] [short] samp [byte] vol [byte] aten
96 };
97
98 char *qw_svc_strings[128] =
99 {
100         "qw_svc_bad",                                   // 0
101         "qw_svc_nop",                                   // 1
102         "qw_svc_disconnect",                    // 2
103         "qw_svc_updatestat",                    // 3    // [byte] [byte]
104         "",                                                             // 4
105         "qw_svc_setview",                               // 5    // [short] entity number
106         "qw_svc_sound",                                 // 6    // <see code>
107         "",                                                             // 7
108         "qw_svc_print",                                 // 8    // [byte] id [string] null terminated string
109         "qw_svc_stufftext",                             // 9    // [string] stuffed into client's console buffer
110         "qw_svc_setangle",                              // 10   // [angle3] set the view angle to this absolute value
111         "qw_svc_serverdata",                    // 11   // [long] protocol ...
112         "qw_svc_lightstyle",                    // 12   // [byte] [string]
113         "",                                                             // 13
114         "qw_svc_updatefrags",                   // 14   // [byte] [short]
115         "",                                                             // 15
116         "qw_svc_stopsound",                             // 16   // <see code>
117         "",                                                             // 17
118         "",                                                             // 18
119         "qw_svc_damage",                                // 19
120         "qw_svc_spawnstatic",                   // 20
121         "",                                                             // 21
122         "qw_svc_spawnbaseline",                 // 22
123         "qw_svc_temp_entity",                   // 23   // variable
124         "qw_svc_setpause",                              // 24   // [byte] on / off
125         "",                                                             // 25
126         "qw_svc_centerprint",                   // 26   // [string] to put in center of the screen
127         "qw_svc_killedmonster",                 // 27
128         "qw_svc_foundsecret",                   // 28
129         "qw_svc_spawnstaticsound",              // 29   // [coord3] [byte] samp [byte] vol [byte] aten
130         "qw_svc_intermission",                  // 30           // [vec3_t] origin [vec3_t] angle
131         "qw_svc_finale",                                // 31           // [string] text
132         "qw_svc_cdtrack",                               // 32           // [byte] track
133         "qw_svc_sellscreen",                    // 33
134         "qw_svc_smallkick",                             // 34           // set client punchangle to 2
135         "qw_svc_bigkick",                               // 35           // set client punchangle to 4
136         "qw_svc_updateping",                    // 36           // [byte] [short]
137         "qw_svc_updateentertime",               // 37           // [byte] [float]
138         "qw_svc_updatestatlong",                // 38           // [byte] [long]
139         "qw_svc_muzzleflash",                   // 39           // [short] entity
140         "qw_svc_updateuserinfo",                // 40           // [byte] slot [long] uid
141         "qw_svc_download",                              // 41           // [short] size [size bytes]
142         "qw_svc_playerinfo",                    // 42           // variable
143         "qw_svc_nails",                                 // 43           // [byte] num [48 bits] xyzpy 12 12 12 4 8
144         "qw_svc_chokecount",                    // 44           // [byte] packets choked
145         "qw_svc_modellist",                             // 45           // [strings]
146         "qw_svc_soundlist",                             // 46           // [strings]
147         "qw_svc_packetentities",                // 47           // [...]
148         "qw_svc_deltapacketentities",   // 48           // [...]
149         "qw_svc_maxspeed",                              // 49           // maxspeed change, for prediction
150         "qw_svc_entgravity",                    // 50           // gravity change, for prediction
151         "qw_svc_setinfo",                               // 51           // setinfo on a client
152         "qw_svc_serverinfo",                    // 52           // serverinfo
153         "qw_svc_updatepl",                              // 53           // [byte] [byte]
154 };
155
156 //=============================================================================
157
158 cvar_t demo_nehahra = {0, "demo_nehahra", "0", "reads all quake demos as nehahra movie protocol"};
159 cvar_t developer_networkentities = {0, "developer_networkentities", "0", "prints received entities, value is 0-4 (higher for more info)"};
160
161 /*
162 ==================
163 CL_ParseStartSoundPacket
164 ==================
165 */
166 void CL_ParseStartSoundPacket(int largesoundindex)
167 {
168         vec3_t  pos;
169         int     channel, ent;
170         int     sound_num;
171         int     volume;
172         int     field_mask;
173         float   attenuation;
174
175         field_mask = MSG_ReadByte();
176
177         if (field_mask & SND_VOLUME)
178                 volume = MSG_ReadByte ();
179         else
180                 volume = DEFAULT_SOUND_PACKET_VOLUME;
181
182         if (field_mask & SND_ATTENUATION)
183                 attenuation = MSG_ReadByte () / 64.0;
184         else
185                 attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;
186
187         if (field_mask & SND_LARGEENTITY)
188         {
189                 ent = (unsigned short) MSG_ReadShort ();
190                 channel = MSG_ReadByte ();
191         }
192         else
193         {
194                 channel = (unsigned short) MSG_ReadShort ();
195                 ent = channel >> 3;
196                 channel &= 7;
197         }
198
199         if (largesoundindex || field_mask & SND_LARGESOUND)
200                 sound_num = (unsigned short) MSG_ReadShort ();
201         else
202                 sound_num = MSG_ReadByte ();
203
204         MSG_ReadVector(pos, cls.protocol);
205
206         if (sound_num >= MAX_SOUNDS)
207         {
208                 Con_Printf("CL_ParseStartSoundPacket: sound_num (%i) >= MAX_SOUNDS (%i)\n", sound_num, MAX_SOUNDS);
209                 return;
210         }
211
212         if (ent >= MAX_EDICTS)
213         {
214                 Con_Printf("CL_ParseStartSoundPacket: ent = %i", ent);
215                 return;
216         }
217
218         S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0f, attenuation);
219 }
220
221 /*
222 ==================
223 CL_KeepaliveMessage
224
225 When the client is taking a long time to load stuff, send keepalive messages
226 so the server doesn't disconnect.
227 ==================
228 */
229
230 static unsigned char olddata[NET_MAXMESSAGE];
231 void CL_KeepaliveMessage (void)
232 {
233         float time;
234         static double nextmsg = -1;
235         int oldreadcount;
236         qboolean oldbadread;
237         sizebuf_t old;
238
239         // no need if server is local and definitely not if this is a demo
240         if (sv.active || !cls.netcon || cls.protocol == PROTOCOL_QUAKEWORLD)
241                 return;
242
243 // read messages from server, should just be nops
244         oldreadcount = msg_readcount;
245         oldbadread = msg_badread;
246         old = net_message;
247         memcpy(olddata, net_message.data, net_message.cursize);
248
249         NetConn_ClientFrame();
250
251         msg_readcount = oldreadcount;
252         msg_badread = oldbadread;
253         net_message = old;
254         memcpy(net_message.data, olddata, net_message.cursize);
255
256         if (cls.netcon && (time = Sys_DoubleTime()) >= nextmsg)
257         {
258                 sizebuf_t       msg;
259                 unsigned char           buf[4];
260                 nextmsg = time + 5;
261                 // write out a nop
262                 // LordHavoc: must use unreliable because reliable could kill the sigon message!
263                 Con_Print("--> client to server keepalive\n");
264                 memset(&msg, 0, sizeof(msg));
265                 msg.data = buf;
266                 msg.maxsize = sizeof(buf);
267                 MSG_WriteChar(&msg, svc_nop);
268                 NetConn_SendUnreliableMessage(cls.netcon, &msg, cls.protocol);
269         }
270 }
271
272 void CL_ParseEntityLump(char *entdata)
273 {
274         const char *data;
275         char key[128], value[MAX_INPUTLINE];
276         FOG_clear(); // LordHavoc: no fog until set
277         // LordHavoc: default to the map's sky (q3 shader parsing sets this)
278         R_SetSkyBox(cl.worldmodel->brush.skybox);
279         data = entdata;
280         if (!data)
281                 return;
282         if (!COM_ParseToken(&data, false))
283                 return; // error
284         if (com_token[0] != '{')
285                 return; // error
286         while (1)
287         {
288                 if (!COM_ParseToken(&data, false))
289                         return; // error
290                 if (com_token[0] == '}')
291                         break; // end of worldspawn
292                 if (com_token[0] == '_')
293                         strlcpy (key, com_token + 1, sizeof (key));
294                 else
295                         strlcpy (key, com_token, sizeof (key));
296                 while (key[strlen(key)-1] == ' ') // remove trailing spaces
297                         key[strlen(key)-1] = 0;
298                 if (!COM_ParseToken(&data, false))
299                         return; // error
300                 strlcpy (value, com_token, sizeof (value));
301                 if (!strcmp("sky", key))
302                         R_SetSkyBox(value);
303                 else if (!strcmp("skyname", key)) // non-standard, introduced by QuakeForge... sigh.
304                         R_SetSkyBox(value);
305                 else if (!strcmp("qlsky", key)) // non-standard, introduced by QuakeLives (EEK)
306                         R_SetSkyBox(value);
307                 else if (!strcmp("fog", key))
308                         sscanf(value, "%f %f %f %f", &fog_density, &fog_red, &fog_green, &fog_blue);
309                 else if (!strcmp("fog_density", key))
310                         fog_density = atof(value);
311                 else if (!strcmp("fog_red", key))
312                         fog_red = atof(value);
313                 else if (!strcmp("fog_green", key))
314                         fog_green = atof(value);
315                 else if (!strcmp("fog_blue", key))
316                         fog_blue = atof(value);
317         }
318 }
319
320 /*
321 =====================
322 CL_SignonReply
323
324 An svc_signonnum has been received, perform a client side setup
325 =====================
326 */
327 static void CL_SignonReply (void)
328 {
329         Con_DPrintf("CL_SignonReply: %i\n", cls.signon);
330
331         switch (cls.signon)
332         {
333         case 1:
334                 if (cls.netcon)
335                 {
336                         MSG_WriteByte (&cls.netcon->message, clc_stringcmd);
337                         MSG_WriteString (&cls.netcon->message, "prespawn");
338                 }
339                 break;
340
341         case 2:
342                 if (cls.netcon)
343                 {
344                         MSG_WriteByte (&cls.netcon->message, clc_stringcmd);
345                         MSG_WriteString (&cls.netcon->message, va("name \"%s\"", cl_name.string));
346
347                         MSG_WriteByte (&cls.netcon->message, clc_stringcmd);
348                         MSG_WriteString (&cls.netcon->message, va("color %i %i", cl_color.integer >> 4, cl_color.integer & 15));
349
350                         if (cl_pmodel.integer)
351                         {
352                                 MSG_WriteByte (&cls.netcon->message, clc_stringcmd);
353                                 MSG_WriteString (&cls.netcon->message, va("pmodel %i", cl_pmodel.integer));
354                         }
355                         if (*cl_playermodel.string)
356                         {
357                                 MSG_WriteByte (&cls.netcon->message, clc_stringcmd);
358                                 MSG_WriteString (&cls.netcon->message, va("playermodel %s", cl_playermodel.string));
359                         }
360                         if (*cl_playerskin.string)
361                         {
362                                 MSG_WriteByte (&cls.netcon->message, clc_stringcmd);
363                                 MSG_WriteString (&cls.netcon->message, va("playerskin %s", cl_playerskin.string));
364                         }
365
366                         MSG_WriteByte (&cls.netcon->message, clc_stringcmd);
367                         MSG_WriteString (&cls.netcon->message, va("rate %i", cl_rate.integer));
368
369                         MSG_WriteByte (&cls.netcon->message, clc_stringcmd);
370                         MSG_WriteString (&cls.netcon->message, "spawn");
371                 }
372                 break;
373
374         case 3:
375                 if (cls.netcon)
376                 {
377                         MSG_WriteByte (&cls.netcon->message, clc_stringcmd);
378                         MSG_WriteString (&cls.netcon->message, "begin");
379                 }
380                 break;
381
382         case 4:
383                 Con_ClearNotify();
384                 break;
385         }
386 }
387
388 /*
389 ==================
390 CL_ParseServerInfo
391 ==================
392 */
393 // FIXME: this is a lot of memory to be keeping around, this needs to be dynamically allocated and freed
394 static char parse_model_precache[MAX_MODELS][MAX_QPATH];
395 static char parse_sound_precache[MAX_SOUNDS][MAX_QPATH];
396 void CL_ParseServerInfo (void)
397 {
398         char *str;
399         int i;
400         protocolversion_t protocol;
401         int nummodels, numsounds;
402         entity_t *ent;
403
404         Con_DPrint("Serverinfo packet received.\n");
405
406         // check memory integrity
407         Mem_CheckSentinelsGlobal();
408
409 //
410 // wipe the client_state_t struct
411 //
412         CL_ClearState ();
413
414 // parse protocol version number
415         i = MSG_ReadLong ();
416         protocol = Protocol_EnumForNumber(i);
417         if (protocol == PROTOCOL_UNKNOWN)
418         {
419                 Host_Error("CL_ParseServerInfo: Server is unrecognized protocol number (%i)", i);
420                 return;
421         }
422         // hack for unmarked Nehahra movie demos which had a custom protocol
423         if (protocol == PROTOCOL_QUAKEDP && cls.demoplayback && demo_nehahra.integer)
424                 protocol = PROTOCOL_NEHAHRAMOVIE;
425         cls.protocol = protocol;
426         Con_DPrintf("Server protocol is %s\n", Protocol_NameForEnum(cls.protocol));
427
428 // parse maxclients
429         cl.maxclients = MSG_ReadByte ();
430         if (cl.maxclients < 1 || cl.maxclients > MAX_SCOREBOARD)
431         {
432                 Host_Error("Bad maxclients (%u) from server", cl.maxclients);
433                 return;
434         }
435         cl.scores = (scoreboard_t *)Mem_Alloc(cl_mempool, cl.maxclients*sizeof(*cl.scores));
436
437 // parse gametype
438         cl.gametype = MSG_ReadByte ();
439
440 // parse signon message
441         str = MSG_ReadString ();
442         strlcpy (cl.levelname, str, sizeof(cl.levelname));
443
444 // seperate the printfs so the server message can have a color
445         if (cls.protocol != PROTOCOL_NEHAHRAMOVIE) // no messages when playing the Nehahra movie
446                 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\2%s\n", str);
447
448         // check memory integrity
449         Mem_CheckSentinelsGlobal();
450
451         S_StopAllSounds();
452         // if server is active, we already began a loading plaque
453         if (!sv.active)
454                 SCR_BeginLoadingPlaque();
455
456         // disable until we get textures for it
457         R_ResetSkyBox();
458
459         memset(cl.csqc_model_precache, 0, sizeof(cl.csqc_model_precache));      //[515]: csqc
460         memset(cl.model_precache, 0, sizeof(cl.model_precache));
461         memset(cl.sound_precache, 0, sizeof(cl.sound_precache));
462
463         // parse model precache list
464         for (nummodels=1 ; ; nummodels++)
465         {
466                 str = MSG_ReadString();
467                 if (!str[0])
468                         break;
469                 if (nummodels==MAX_MODELS)
470                         Host_Error ("Server sent too many model precaches");
471                 if (strlen(str) >= MAX_QPATH)
472                         Host_Error ("Server sent a precache name of %i characters (max %i)", strlen(str), MAX_QPATH - 1);
473                 strlcpy (parse_model_precache[nummodels], str, sizeof (parse_model_precache[nummodels]));
474         }
475         // parse sound precache list
476         for (numsounds=1 ; ; numsounds++)
477         {
478                 str = MSG_ReadString();
479                 if (!str[0])
480                         break;
481                 if (numsounds==MAX_SOUNDS)
482                         Host_Error("Server sent too many sound precaches");
483                 if (strlen(str) >= MAX_QPATH)
484                         Host_Error("Server sent a precache name of %i characters (max %i)", strlen(str), MAX_QPATH - 1);
485                 strlcpy (parse_sound_precache[numsounds], str, sizeof (parse_sound_precache[numsounds]));
486         }
487
488         // touch all of the precached models that are still loaded so we can free
489         // anything that isn't needed
490         Mod_ClearUsed();
491         for (i = 1;i < nummodels;i++)
492                 Mod_FindName(parse_model_precache[i]);
493         // precache any models used by the client (this also marks them used)
494         cl.model_bolt = Mod_ForName("progs/bolt.mdl", false, false, false);
495         cl.model_bolt2 = Mod_ForName("progs/bolt2.mdl", false, false, false);
496         cl.model_bolt3 = Mod_ForName("progs/bolt3.mdl", false, false, false);
497         cl.model_beam = Mod_ForName("progs/beam.mdl", false, false, false);
498         Mod_PurgeUnused();
499
500         // do the same for sounds
501         // FIXME: S_ServerSounds does not know about cl.sfx_ sounds
502         S_ServerSounds (parse_sound_precache, numsounds);
503
504         // precache any sounds used by the client
505         cl.sfx_wizhit = S_PrecacheSound("sound/wizard/hit.wav", false, true);
506         cl.sfx_knighthit = S_PrecacheSound("sound/hknight/hit.wav", false, true);
507         cl.sfx_tink1 = S_PrecacheSound("sound/weapons/tink1.wav", false, true);
508         cl.sfx_ric1 = S_PrecacheSound("sound/weapons/ric1.wav", false, true);
509         cl.sfx_ric2 = S_PrecacheSound("sound/weapons/ric2.wav", false, true);
510         cl.sfx_ric3 = S_PrecacheSound("sound/weapons/ric3.wav", false, true);
511         cl.sfx_r_exp3 = S_PrecacheSound("sound/weapons/r_exp3.wav", false, true);
512
513         // now we try to load everything that is new
514
515         // world model
516         CL_KeepaliveMessage ();
517         cl.model_precache[1] = Mod_ForName(parse_model_precache[1], false, false, true);
518         if (cl.model_precache[1]->Draw == NULL)
519                 Con_Printf("Map %s not found\n", parse_model_precache[1]);
520
521         // normal models
522         for (i=2 ; i<nummodels ; i++)
523         {
524                 CL_KeepaliveMessage();
525                 if ((cl.model_precache[i] = Mod_ForName(parse_model_precache[i], false, false, false))->Draw == NULL)
526                         Con_Printf("Model %s not found\n", parse_model_precache[i]);
527         }
528
529         // sounds
530         for (i=1 ; i<numsounds ; i++)
531         {
532                 CL_KeepaliveMessage();
533
534                 // Don't lock the sfx here, S_ServerSounds already did that
535                 cl.sound_precache[i] = S_PrecacheSound (parse_sound_precache[i], true, false);
536         }
537
538         // local state
539         ent = &cl_entities[0];
540         // entire entity array was cleared, so just fill in a few fields
541         ent->state_current.active = true;
542         ent->render.model = cl.worldmodel = cl.model_precache[1];
543         ent->render.scale = 1; // some of the renderer still relies on scale
544         ent->render.alpha = 1;
545         ent->render.colormap = -1; // no special coloring
546         ent->render.flags = RENDER_SHADOW | RENDER_LIGHT;
547         Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, 0, 0, 0, 0, 0, 0, 1);
548         Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix);
549         CL_BoundingBoxForEntity(&ent->render);
550
551         cl_num_entities = 1;
552
553         R_Modules_NewMap();
554         CL_CGVM_Start();
555
556         // noclip is turned off at start
557         noclip_anglehack = false;
558
559         // check memory integrity
560         Mem_CheckSentinelsGlobal();
561 }
562
563 void CL_ValidateState(entity_state_t *s)
564 {
565         model_t *model;
566
567         if (!s->active)
568                 return;
569
570         if (s->modelindex >= MAX_MODELS && (65536-s->modelindex) >= MAX_MODELS)
571                 Host_Error("CL_ValidateState: modelindex (%i) >= MAX_MODELS (%i)\n", s->modelindex, MAX_MODELS);
572
573         // colormap is client index + 1
574         if ((!s->flags & RENDER_COLORMAPPED) && s->colormap > cl.maxclients)
575         {
576                 Con_DPrintf("CL_ValidateState: colormap (%i) > cl.maxclients (%i)\n", s->colormap, cl.maxclients);
577                 s->colormap = 0;
578         }
579
580         model = cl.model_precache[s->modelindex];
581         if (model && model->type && s->frame >= model->numframes)
582         {
583                 Con_DPrintf("CL_ValidateState: no such frame %i in \"%s\" (which has %i frames)\n", s->frame, model->name, model->numframes);
584                 s->frame = 0;
585         }
586         if (model && model->type && s->skin > 0 && s->skin >= model->numskins && !(s->lightpflags & PFLAGS_FULLDYNAMIC))
587         {
588                 Con_DPrintf("CL_ValidateState: no such skin %i in \"%s\" (which has %i skins)\n", s->skin, model->name, model->numskins);
589                 s->skin = 0;
590         }
591 }
592
593 void CL_MoveLerpEntityStates(entity_t *ent)
594 {
595         float odelta[3], adelta[3];
596         CL_ValidateState(&ent->state_current);
597         VectorSubtract(ent->state_current.origin, ent->persistent.neworigin, odelta);
598         VectorSubtract(ent->state_current.angles, ent->persistent.newangles, adelta);
599         if (!ent->state_previous.active || ent->state_previous.modelindex != ent->state_current.modelindex)
600         {
601                 // reset all persistent stuff if this is a new entity
602                 ent->persistent.lerpdeltatime = 0;
603                 ent->persistent.lerpstarttime = cl.mtime[1];
604                 VectorCopy(ent->state_current.origin, ent->persistent.oldorigin);
605                 VectorCopy(ent->state_current.angles, ent->persistent.oldangles);
606                 VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
607                 VectorCopy(ent->state_current.angles, ent->persistent.newangles);
608                 // reset animation interpolation as well
609                 ent->render.frame = ent->render.frame1 = ent->render.frame2 = ent->state_current.frame;
610                 ent->render.frame1time = ent->render.frame2time = cl.time;
611                 ent->render.framelerp = 1;
612                 // reset various persistent stuff
613                 ent->persistent.muzzleflash = 0;
614                 VectorCopy(ent->state_current.origin, ent->persistent.trail_origin);
615         }
616         else if (cls.timedemo || cl_nolerp.integer || DotProduct(odelta, odelta) > 1000*1000)
617         {
618                 // don't interpolate the move
619                 ent->persistent.lerpdeltatime = 0;
620                 ent->persistent.lerpstarttime = cl.mtime[1];
621                 VectorCopy(ent->state_current.origin, ent->persistent.oldorigin);
622                 VectorCopy(ent->state_current.angles, ent->persistent.oldangles);
623                 VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
624                 VectorCopy(ent->state_current.angles, ent->persistent.newangles);
625         }
626         else if (ent->state_current.flags & RENDER_STEP)
627         {
628                 // monster interpolation
629                 if (DotProduct(odelta, odelta) + DotProduct(adelta, adelta) > 0.01)
630                 {
631                         ent->persistent.lerpdeltatime = bound(0, cl.mtime[1] - ent->persistent.lerpstarttime, 0.1);
632                         ent->persistent.lerpstarttime = cl.mtime[1];
633                         VectorCopy(ent->persistent.neworigin, ent->persistent.oldorigin);
634                         VectorCopy(ent->persistent.newangles, ent->persistent.oldangles);
635                         VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
636                         VectorCopy(ent->state_current.angles, ent->persistent.newangles);
637                 }
638         }
639         else
640         {
641                 // not a monster
642                 ent->persistent.lerpstarttime = ent->state_previous.time;
643                 // no lerp if it's singleplayer
644                 if (cl.islocalgame && !sv_fixedframeratesingleplayer.integer)
645                         ent->persistent.lerpdeltatime = 0;
646                 else
647                         ent->persistent.lerpdeltatime = bound(0, ent->state_current.time - ent->state_previous.time, 0.1);
648                 VectorCopy(ent->persistent.neworigin, ent->persistent.oldorigin);
649                 VectorCopy(ent->persistent.newangles, ent->persistent.oldangles);
650                 VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
651                 VectorCopy(ent->state_current.angles, ent->persistent.newangles);
652         }
653 }
654
655 /*
656 ==================
657 CL_ParseBaseline
658 ==================
659 */
660 void CL_ParseBaseline (entity_t *ent, int large)
661 {
662         int i;
663
664         ent->state_baseline = defaultstate;
665         // FIXME: set ent->state_baseline.number?
666         ent->state_baseline.active = true;
667         if (large)
668         {
669                 ent->state_baseline.modelindex = (unsigned short) MSG_ReadShort ();
670                 ent->state_baseline.frame = (unsigned short) MSG_ReadShort ();
671         }
672         else
673         {
674                 ent->state_baseline.modelindex = MSG_ReadByte ();
675                 ent->state_baseline.frame = MSG_ReadByte ();
676         }
677         ent->state_baseline.colormap = MSG_ReadByte();
678         ent->state_baseline.skin = MSG_ReadByte();
679         for (i = 0;i < 3;i++)
680         {
681                 ent->state_baseline.origin[i] = MSG_ReadCoord(cls.protocol);
682                 ent->state_baseline.angles[i] = MSG_ReadAngle(cls.protocol);
683         }
684         CL_ValidateState(&ent->state_baseline);
685         ent->state_previous = ent->state_current = ent->state_baseline;
686 }
687
688
689 /*
690 ==================
691 CL_ParseClientdata
692
693 Server information pertaining to this client only
694 ==================
695 */
696 void CL_ParseClientdata (void)
697 {
698         int i, j, bits;
699
700         VectorCopy (cl.mpunchangle[0], cl.mpunchangle[1]);
701         VectorCopy (cl.mpunchvector[0], cl.mpunchvector[1]);
702         VectorCopy (cl.mvelocity[0], cl.mvelocity[1]);
703         cl.mviewzoom[1] = cl.mviewzoom[0];
704
705         if (cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEDP || cls.protocol == PROTOCOL_NEHAHRAMOVIE || cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3 || cls.protocol == PROTOCOL_DARKPLACES4 || cls.protocol == PROTOCOL_DARKPLACES5)
706         {
707                 cl.stats[STAT_VIEWHEIGHT] = DEFAULT_VIEWHEIGHT;
708                 cl.stats[STAT_ITEMS] = 0;
709                 cl.stats[STAT_VIEWZOOM] = 255;
710         }
711         cl.idealpitch = 0;
712         cl.mpunchangle[0][0] = 0;
713         cl.mpunchangle[0][1] = 0;
714         cl.mpunchangle[0][2] = 0;
715         cl.mpunchvector[0][0] = 0;
716         cl.mpunchvector[0][1] = 0;
717         cl.mpunchvector[0][2] = 0;
718         cl.mvelocity[0][0] = 0;
719         cl.mvelocity[0][1] = 0;
720         cl.mvelocity[0][2] = 0;
721         cl.mviewzoom[0] = 1;
722
723         bits = (unsigned short) MSG_ReadShort ();
724         if (bits & SU_EXTEND1)
725                 bits |= (MSG_ReadByte() << 16);
726         if (bits & SU_EXTEND2)
727                 bits |= (MSG_ReadByte() << 24);
728
729         if (bits & SU_VIEWHEIGHT)
730                 cl.stats[STAT_VIEWHEIGHT] = MSG_ReadChar ();
731
732         if (bits & SU_IDEALPITCH)
733                 cl.idealpitch = MSG_ReadChar ();
734
735         for (i = 0;i < 3;i++)
736         {
737                 if (bits & (SU_PUNCH1<<i) )
738                 {
739                         if (cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEDP || cls.protocol == PROTOCOL_NEHAHRAMOVIE)
740                                 cl.mpunchangle[0][i] = MSG_ReadChar();
741                         else
742                                 cl.mpunchangle[0][i] = MSG_ReadAngle16i();
743                 }
744                 if (bits & (SU_PUNCHVEC1<<i))
745                 {
746                         if (cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3 || cls.protocol == PROTOCOL_DARKPLACES4)
747                                 cl.mpunchvector[0][i] = MSG_ReadCoord16i();
748                         else
749                                 cl.mpunchvector[0][i] = MSG_ReadCoord32f();
750                 }
751                 if (bits & (SU_VELOCITY1<<i) )
752                 {
753                         if (cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEDP || cls.protocol == PROTOCOL_NEHAHRAMOVIE || cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3 || cls.protocol == PROTOCOL_DARKPLACES4)
754                                 cl.mvelocity[0][i] = MSG_ReadChar()*16;
755                         else
756                                 cl.mvelocity[0][i] = MSG_ReadCoord32f();
757                 }
758         }
759
760         // LordHavoc: hipnotic demos don't have this bit set but should
761         if (bits & SU_ITEMS || cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEDP || cls.protocol == PROTOCOL_NEHAHRAMOVIE || cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3 || cls.protocol == PROTOCOL_DARKPLACES4 || cls.protocol == PROTOCOL_DARKPLACES5)
762                 cl.stats[STAT_ITEMS] = MSG_ReadLong ();
763
764         cl.onground = (bits & SU_ONGROUND) != 0;
765         csqc_onground = cl.onground;    //[515]: cause without this csqc will receive not right value on svc_print =/
766         cl.inwater = (bits & SU_INWATER) != 0;
767
768         if (cls.protocol == PROTOCOL_DARKPLACES5)
769         {
770                 cl.stats[STAT_WEAPONFRAME] = (bits & SU_WEAPONFRAME) ? MSG_ReadShort() : 0;
771                 cl.stats[STAT_ARMOR] = (bits & SU_ARMOR) ? MSG_ReadShort() : 0;
772                 cl.stats[STAT_WEAPON] = (bits & SU_WEAPON) ? MSG_ReadShort() : 0;
773                 cl.stats[STAT_HEALTH] = MSG_ReadShort();
774                 cl.stats[STAT_AMMO] = MSG_ReadShort();
775                 cl.stats[STAT_SHELLS] = MSG_ReadShort();
776                 cl.stats[STAT_NAILS] = MSG_ReadShort();
777                 cl.stats[STAT_ROCKETS] = MSG_ReadShort();
778                 cl.stats[STAT_CELLS] = MSG_ReadShort();
779                 cl.stats[STAT_ACTIVEWEAPON] = (unsigned short) MSG_ReadShort ();
780         }
781         else if (cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEDP || cls.protocol == PROTOCOL_NEHAHRAMOVIE || cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3 || cls.protocol == PROTOCOL_DARKPLACES4)
782         {
783                 cl.stats[STAT_WEAPONFRAME] = (bits & SU_WEAPONFRAME) ? MSG_ReadByte() : 0;
784                 cl.stats[STAT_ARMOR] = (bits & SU_ARMOR) ? MSG_ReadByte() : 0;
785                 cl.stats[STAT_WEAPON] = (bits & SU_WEAPON) ? MSG_ReadByte() : 0;
786                 cl.stats[STAT_HEALTH] = MSG_ReadShort();
787                 cl.stats[STAT_AMMO] = MSG_ReadByte();
788                 cl.stats[STAT_SHELLS] = MSG_ReadByte();
789                 cl.stats[STAT_NAILS] = MSG_ReadByte();
790                 cl.stats[STAT_ROCKETS] = MSG_ReadByte();
791                 cl.stats[STAT_CELLS] = MSG_ReadByte();
792                 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
793                         cl.stats[STAT_ACTIVEWEAPON] = (1<<MSG_ReadByte ());
794                 else
795                         cl.stats[STAT_ACTIVEWEAPON] = MSG_ReadByte ();
796         }
797
798         if (bits & SU_VIEWZOOM)
799         {
800                 if (cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3 || cls.protocol == PROTOCOL_DARKPLACES4)
801                         cl.stats[STAT_VIEWZOOM] = MSG_ReadByte();
802                 else
803                         cl.stats[STAT_VIEWZOOM] = (unsigned short) MSG_ReadShort();
804         }
805
806         // check for important changes
807
808         // set flash times
809         if (cl.olditems != cl.stats[STAT_ITEMS])
810                 for (j = 0;j < 32;j++)
811                         if ((cl.stats[STAT_ITEMS] & (1<<j)) && !(cl.olditems & (1<<j)))
812                                 cl.item_gettime[j] = cl.time;
813         cl.olditems = cl.stats[STAT_ITEMS];
814
815         // GAME_NEXUIZ hud needs weapon change time
816         if (cl.activeweapon != cl.stats[STAT_ACTIVEWEAPON])
817                 cl.weapontime = cl.time;
818         cl.activeweapon = cl.stats[STAT_ACTIVEWEAPON];
819
820         // viewzoom interpolation
821         cl.mviewzoom[0] = (float) max(cl.stats[STAT_VIEWZOOM], 2) * (1.0f / 255.0f);
822 }
823
824 /*
825 =====================
826 CL_ParseStatic
827 =====================
828 */
829 void CL_ParseStatic (int large)
830 {
831         entity_t *ent;
832
833         if (cl_num_static_entities >= cl_max_static_entities)
834                 Host_Error ("Too many static entities");
835         ent = &cl_static_entities[cl_num_static_entities++];
836         CL_ParseBaseline (ent, large);
837
838 // copy it to the current state
839         ent->render.model = cl.model_precache[ent->state_baseline.modelindex];
840         ent->render.frame = ent->render.frame1 = ent->render.frame2 = ent->state_baseline.frame;
841         ent->render.framelerp = 0;
842         // make torchs play out of sync
843         ent->render.frame1time = ent->render.frame2time = lhrandom(-10, -1);
844         ent->render.colormap = -1; // no special coloring
845         ent->render.skinnum = ent->state_baseline.skin;
846         ent->render.effects = ent->state_baseline.effects;
847         ent->render.alpha = 1;
848         //ent->render.scale = 1;
849
850         //VectorCopy (ent->state_baseline.origin, ent->render.origin);
851         //VectorCopy (ent->state_baseline.angles, ent->render.angles);
852
853         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);
854         Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix);
855         CL_BoundingBoxForEntity(&ent->render);
856
857         // This is definitely cheating...
858         if (ent->render.model == NULL)
859                 cl_num_static_entities--;
860 }
861
862 /*
863 ===================
864 CL_ParseStaticSound
865 ===================
866 */
867 void CL_ParseStaticSound (int large)
868 {
869         vec3_t          org;
870         int                     sound_num, vol, atten;
871
872         MSG_ReadVector(org, cls.protocol);
873         if (large)
874                 sound_num = (unsigned short) MSG_ReadShort ();
875         else
876                 sound_num = MSG_ReadByte ();
877         vol = MSG_ReadByte ();
878         atten = MSG_ReadByte ();
879
880         S_StaticSound (cl.sound_precache[sound_num], org, vol/255.0f, atten);
881 }
882
883 void CL_ParseEffect (void)
884 {
885         vec3_t          org;
886         int                     modelindex, startframe, framecount, framerate;
887
888         MSG_ReadVector(org, cls.protocol);
889         modelindex = MSG_ReadByte ();
890         startframe = MSG_ReadByte ();
891         framecount = MSG_ReadByte ();
892         framerate = MSG_ReadByte ();
893
894         CL_Effect(org, modelindex, startframe, framecount, framerate);
895 }
896
897 void CL_ParseEffect2 (void)
898 {
899         vec3_t          org;
900         int                     modelindex, startframe, framecount, framerate;
901
902         MSG_ReadVector(org, cls.protocol);
903         modelindex = (unsigned short) MSG_ReadShort ();
904         startframe = (unsigned short) MSG_ReadShort ();
905         framecount = MSG_ReadByte ();
906         framerate = MSG_ReadByte ();
907
908         CL_Effect(org, modelindex, startframe, framecount, framerate);
909 }
910
911 void CL_ParseBeam (model_t *m, int lightning)
912 {
913         int i, ent;
914         vec3_t start, end;
915         beam_t *b = NULL;
916
917         ent = (unsigned short) MSG_ReadShort ();
918         MSG_ReadVector(start, cls.protocol);
919         MSG_ReadVector(end, cls.protocol);
920
921         if (ent >= MAX_EDICTS)
922         {
923                 Con_Printf("CL_ParseBeam: invalid entity number %i\n", ent);
924                 ent = 0;
925         }
926
927         if (ent >= cl_max_entities)
928                 CL_ExpandEntities(ent);
929
930         // override any beam with the same entity
931         i = cl_max_beams;
932         if (ent)
933                 for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
934                         if (b->entity == ent)
935                                 break;
936         // if the entity was not found then just replace an unused beam
937         if (i == cl_max_beams)
938                 for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
939                         if (!b->model || b->endtime < cl.time)
940                                 break;
941         if (i < cl_max_beams)
942         {
943                 b->entity = ent;
944                 b->lightning = lightning;
945                 b->model = m;
946                 b->endtime = cl.time + 0.2;
947                 VectorCopy (start, b->start);
948                 VectorCopy (end, b->end);
949                 b->relativestartvalid = 0;
950                 if (ent && cl_entities[ent].state_current.active)
951                 {
952                         entity_state_t *p;
953                         matrix4x4_t matrix, imatrix;
954                         if (ent == cl.viewentity && cl.movement)
955                                 p = &cl_entities[b->entity].state_previous;
956                         else
957                                 p = &cl_entities[b->entity].state_current;
958                         // not really valid yet, we need to get the orientation now
959                         // (ParseBeam flagged this because it is received before
960                         //  entities are received, by now they have been received)
961                         // note: because players create lightning in their think
962                         // function (which occurs before movement), they actually
963                         // have some lag in it's location, so compare to the
964                         // previous player state, not the latest
965                         Matrix4x4_CreateFromQuakeEntity(&matrix, p->origin[0], p->origin[1], p->origin[2], -p->angles[0], p->angles[1], p->angles[2], 1);
966                         Matrix4x4_Invert_Simple(&imatrix, &matrix);
967                         Matrix4x4_Transform(&imatrix, b->start, b->relativestart);
968                         Matrix4x4_Transform(&imatrix, b->end, b->relativeend);
969                         b->relativestartvalid = 1;
970                 }
971         }
972         else
973                 Con_Print("beam list overflow!\n");
974 }
975
976 void CL_ParseTempEntity(void)
977 {
978         int type;
979         vec3_t pos;
980         vec3_t dir;
981         vec3_t pos2;
982         vec3_t color;
983         int rnd;
984         int colorStart, colorLength, count;
985         float velspeed, radius;
986         unsigned char *tempcolor;
987         matrix4x4_t tempmatrix;
988
989         type = MSG_ReadByte();
990         switch (type)
991         {
992         case TE_WIZSPIKE:
993                 // spike hitting wall
994                 MSG_ReadVector(pos, cls.protocol);
995                 CL_FindNonSolidLocation(pos, pos, 4);
996                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
997                 //CL_AllocDlight(NULL, &tempmatrix, 100, 0.12f, 0.50f, 0.12f, 500, 0.2, 0, -1, false, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
998                 CL_RunParticleEffect(pos, vec3_origin, 20, 30);
999                 S_StartSound(-1, 0, cl.sfx_wizhit, pos, 1, 1);
1000                 break;
1001
1002         case TE_KNIGHTSPIKE:
1003                 // spike hitting wall
1004                 MSG_ReadVector(pos, cls.protocol);
1005                 CL_FindNonSolidLocation(pos, pos, 4);
1006                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1007                 //CL_AllocDlight(NULL, &tempmatrix, 100, 0.50f, 0.30f, 0.10f, 500, 0.2, 0, -1, false, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
1008                 CL_RunParticleEffect(pos, vec3_origin, 226, 20);
1009                 S_StartSound(-1, 0, cl.sfx_knighthit, pos, 1, 1);
1010                 break;
1011
1012         case TE_SPIKE:
1013                 // spike hitting wall
1014                 MSG_ReadVector(pos, cls.protocol);
1015                 CL_FindNonSolidLocation(pos, pos, 4);
1016                 if (cl_particles_quake.integer)
1017                         CL_RunParticleEffect(pos, vec3_origin, 0, 10);
1018                 else if (cl_particles_bulletimpacts.integer)
1019                 {
1020                         CL_SparkShower(pos, vec3_origin, 15, 1);
1021                         CL_Smoke(pos, vec3_origin, 15);
1022                 }
1023                 CL_BulletMark(pos);
1024                 if (rand() % 5)
1025                         S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
1026                 else
1027                 {
1028                         rnd = rand() & 3;
1029                         if (rnd == 1)
1030                                 S_StartSound(-1, 0, cl.sfx_ric1, pos, 1, 1);
1031                         else if (rnd == 2)
1032                                 S_StartSound(-1, 0, cl.sfx_ric2, pos, 1, 1);
1033                         else
1034                                 S_StartSound(-1, 0, cl.sfx_ric3, pos, 1, 1);
1035                 }
1036                 break;
1037         case TE_SPIKEQUAD:
1038                 // quad spike hitting wall
1039                 MSG_ReadVector(pos, cls.protocol);
1040                 CL_FindNonSolidLocation(pos, pos, 4);
1041                 if (cl_particles_quake.integer)
1042                         CL_RunParticleEffect(pos, vec3_origin, 0, 10);
1043                 else if (cl_particles_bulletimpacts.integer)
1044                 {
1045                         CL_SparkShower(pos, vec3_origin, 15, 1);
1046                         CL_Smoke(pos, vec3_origin, 15);
1047                 }
1048                 CL_BulletMark(pos);
1049                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1050                 CL_AllocDlight(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
1051                 if (rand() % 5)
1052                         S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
1053                 else
1054                 {
1055                         rnd = rand() & 3;
1056                         if (rnd == 1)
1057                                 S_StartSound(-1, 0, cl.sfx_ric1, pos, 1, 1);
1058                         else if (rnd == 2)
1059                                 S_StartSound(-1, 0, cl.sfx_ric2, pos, 1, 1);
1060                         else
1061                                 S_StartSound(-1, 0, cl.sfx_ric3, pos, 1, 1);
1062                 }
1063                 break;
1064         case TE_SUPERSPIKE:
1065                 // super spike hitting wall
1066                 MSG_ReadVector(pos, cls.protocol);
1067                 CL_FindNonSolidLocation(pos, pos, 4);
1068                 if (cl_particles_quake.integer)
1069                         CL_RunParticleEffect(pos, vec3_origin, 0, 20);
1070                 else if (cl_particles_bulletimpacts.integer)
1071                 {
1072                         CL_SparkShower(pos, vec3_origin, 30, 1);
1073                         CL_Smoke(pos, vec3_origin, 30);
1074                 }
1075                 CL_BulletMark(pos);
1076                 if (rand() % 5)
1077                         S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
1078                 else
1079                 {
1080                         rnd = rand() & 3;
1081                         if (rnd == 1)
1082                                 S_StartSound(-1, 0, cl.sfx_ric1, pos, 1, 1);
1083                         else if (rnd == 2)
1084                                 S_StartSound(-1, 0, cl.sfx_ric2, pos, 1, 1);
1085                         else
1086                                 S_StartSound(-1, 0, cl.sfx_ric3, pos, 1, 1);
1087                 }
1088                 break;
1089         case TE_SUPERSPIKEQUAD:
1090                 // quad super spike hitting wall
1091                 MSG_ReadVector(pos, cls.protocol);
1092                 CL_FindNonSolidLocation(pos, pos, 4);
1093                 if (cl_particles_quake.integer)
1094                         CL_RunParticleEffect(pos, vec3_origin, 0, 20);
1095                 else if (cl_particles_bulletimpacts.integer)
1096                 {
1097                         CL_SparkShower(pos, vec3_origin, 30, 1);
1098                         CL_Smoke(pos, vec3_origin, 30);
1099                 }
1100                 CL_BulletMark(pos);
1101                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1102                 CL_AllocDlight(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
1103                 if (rand() % 5)
1104                         S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
1105                 else
1106                 {
1107                         rnd = rand() & 3;
1108                         if (rnd == 1)
1109                                 S_StartSound(-1, 0, cl.sfx_ric1, pos, 1, 1);
1110                         else if (rnd == 2)
1111                                 S_StartSound(-1, 0, cl.sfx_ric2, pos, 1, 1);
1112                         else
1113                                 S_StartSound(-1, 0, cl.sfx_ric3, pos, 1, 1);
1114                 }
1115                 break;
1116                 // LordHavoc: added for improved blood splatters
1117         case TE_BLOOD:
1118                 // blood puff
1119                 MSG_ReadVector(pos, cls.protocol);
1120                 CL_FindNonSolidLocation(pos, pos, 4);
1121                 dir[0] = MSG_ReadChar();
1122                 dir[1] = MSG_ReadChar();
1123                 dir[2] = MSG_ReadChar();
1124                 count = MSG_ReadByte();
1125                 CL_BloodPuff(pos, dir, count);
1126                 break;
1127         case TE_SPARK:
1128                 // spark shower
1129                 MSG_ReadVector(pos, cls.protocol);
1130                 CL_FindNonSolidLocation(pos, pos, 4);
1131                 dir[0] = MSG_ReadChar();
1132                 dir[1] = MSG_ReadChar();
1133                 dir[2] = MSG_ReadChar();
1134                 count = MSG_ReadByte();
1135                 CL_SparkShower(pos, dir, count, 1);
1136                 break;
1137         case TE_PLASMABURN:
1138                 MSG_ReadVector(pos, cls.protocol);
1139                 CL_FindNonSolidLocation(pos, pos, 4);
1140                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1141                 CL_AllocDlight(NULL, &tempmatrix, 200, 1, 1, 1, 1000, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
1142                 CL_PlasmaBurn(pos);
1143                 break;
1144                 // LordHavoc: added for improved gore
1145         case TE_BLOODSHOWER:
1146                 // vaporized body
1147                 MSG_ReadVector(pos, cls.protocol); // mins
1148                 MSG_ReadVector(pos2, cls.protocol); // maxs
1149                 velspeed = MSG_ReadCoord(cls.protocol); // speed
1150                 count = (unsigned short) MSG_ReadShort(); // number of particles
1151                 CL_BloodShower(pos, pos2, velspeed, count);
1152                 break;
1153         case TE_PARTICLECUBE:
1154                 // general purpose particle effect
1155                 MSG_ReadVector(pos, cls.protocol); // mins
1156                 MSG_ReadVector(pos2, cls.protocol); // maxs
1157                 MSG_ReadVector(dir, cls.protocol); // dir
1158                 count = (unsigned short) MSG_ReadShort(); // number of particles
1159                 colorStart = MSG_ReadByte(); // color
1160                 colorLength = MSG_ReadByte(); // gravity (1 or 0)
1161                 velspeed = MSG_ReadCoord(cls.protocol); // randomvel
1162                 CL_ParticleCube(pos, pos2, dir, count, colorStart, colorLength, velspeed);
1163                 break;
1164
1165         case TE_PARTICLERAIN:
1166                 // general purpose particle effect
1167                 MSG_ReadVector(pos, cls.protocol); // mins
1168                 MSG_ReadVector(pos2, cls.protocol); // maxs
1169                 MSG_ReadVector(dir, cls.protocol); // dir
1170                 count = (unsigned short) MSG_ReadShort(); // number of particles
1171                 colorStart = MSG_ReadByte(); // color
1172                 CL_ParticleRain(pos, pos2, dir, count, colorStart, 0);
1173                 break;
1174
1175         case TE_PARTICLESNOW:
1176                 // general purpose particle effect
1177                 MSG_ReadVector(pos, cls.protocol); // mins
1178                 MSG_ReadVector(pos2, cls.protocol); // maxs
1179                 MSG_ReadVector(dir, cls.protocol); // dir
1180                 count = (unsigned short) MSG_ReadShort(); // number of particles
1181                 colorStart = MSG_ReadByte(); // color
1182                 CL_ParticleRain(pos, pos2, dir, count, colorStart, 1);
1183                 break;
1184
1185         case TE_GUNSHOT:
1186                 // bullet hitting wall
1187                 MSG_ReadVector(pos, cls.protocol);
1188                 CL_FindNonSolidLocation(pos, pos, 4);
1189                 if (cl_particles_quake.integer)
1190                         CL_RunParticleEffect(pos, vec3_origin, 0, 20);
1191                 else
1192                 {
1193                         CL_SparkShower(pos, vec3_origin, 15, 1);
1194                         CL_Smoke(pos, vec3_origin, 15);
1195                 }
1196                 CL_BulletMark(pos);
1197                 break;
1198
1199         case TE_GUNSHOTQUAD:
1200                 // quad bullet hitting wall
1201                 MSG_ReadVector(pos, cls.protocol);
1202                 CL_FindNonSolidLocation(pos, pos, 4);
1203                 if (cl_particles_quake.integer)
1204                         CL_RunParticleEffect(pos, vec3_origin, 0, 20);
1205                 else
1206                 {
1207                         CL_SparkShower(pos, vec3_origin, 15, 1);
1208                         CL_Smoke(pos, vec3_origin, 15);
1209                 }
1210                 CL_BulletMark(pos);
1211                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1212                 CL_AllocDlight(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
1213                 break;
1214
1215         case TE_EXPLOSION:
1216                 // rocket explosion
1217                 MSG_ReadVector(pos, cls.protocol);
1218                 CL_FindNonSolidLocation(pos, pos, 10);
1219                 CL_ParticleExplosion(pos);
1220                 // LordHavoc: boosted color from 1.0, 0.8, 0.4 to 1.25, 1.0, 0.5
1221                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1222                 CL_AllocDlight(NULL, &tempmatrix, 350, 4.0f, 2.0f, 0.50f, 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
1223                 if (gamemode != GAME_NEXUIZ)
1224                         S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1);
1225                 break;
1226
1227         case TE_EXPLOSIONQUAD:
1228                 // quad rocket explosion
1229                 MSG_ReadVector(pos, cls.protocol);
1230                 CL_FindNonSolidLocation(pos, pos, 10);
1231                 CL_ParticleExplosion(pos);
1232                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1233                 CL_AllocDlight(NULL, &tempmatrix, 350, 2.5f, 2.0f, 4.0f, 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
1234                 if (gamemode != GAME_NEXUIZ)
1235                         S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1);
1236                 break;
1237
1238         case TE_EXPLOSION3:
1239                 // Nehahra movie colored lighting explosion
1240                 MSG_ReadVector(pos, cls.protocol);
1241                 CL_FindNonSolidLocation(pos, pos, 10);
1242                 CL_ParticleExplosion(pos);
1243                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1244                 color[0] = MSG_ReadCoord(cls.protocol) * (2.0f / 1.0f);
1245                 color[1] = MSG_ReadCoord(cls.protocol) * (2.0f / 1.0f);
1246                 color[2] = MSG_ReadCoord(cls.protocol) * (2.0f / 1.0f);
1247                 CL_AllocDlight(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
1248                 if (gamemode != GAME_NEXUIZ)
1249                         S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1);
1250                 break;
1251
1252         case TE_EXPLOSIONRGB:
1253                 // colored lighting explosion
1254                 MSG_ReadVector(pos, cls.protocol);
1255                 CL_FindNonSolidLocation(pos, pos, 10);
1256                 CL_ParticleExplosion(pos);
1257                 color[0] = MSG_ReadByte() * (2.0f / 255.0f);
1258                 color[1] = MSG_ReadByte() * (2.0f / 255.0f);
1259                 color[2] = MSG_ReadByte() * (2.0f / 255.0f);
1260                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1261                 CL_AllocDlight(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
1262                 if (gamemode != GAME_NEXUIZ)
1263                         S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1);
1264                 break;
1265
1266         case TE_TAREXPLOSION:
1267                 // tarbaby explosion
1268                 MSG_ReadVector(pos, cls.protocol);
1269                 CL_FindNonSolidLocation(pos, pos, 10);
1270                 CL_BlobExplosion(pos);
1271
1272                 if (gamemode != GAME_NEXUIZ)
1273                         S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1);
1274                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1275                 CL_AllocDlight(NULL, &tempmatrix, 600, 1.6f, 0.8f, 2.0f, 1200, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
1276                 break;
1277
1278         case TE_SMALLFLASH:
1279                 MSG_ReadVector(pos, cls.protocol);
1280                 CL_FindNonSolidLocation(pos, pos, 10);
1281                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1282                 CL_AllocDlight(NULL, &tempmatrix, 200, 2, 2, 2, 1000, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
1283                 break;
1284
1285         case TE_CUSTOMFLASH:
1286                 MSG_ReadVector(pos, cls.protocol);
1287                 CL_FindNonSolidLocation(pos, pos, 4);
1288                 radius = (MSG_ReadByte() + 1) * 8;
1289                 velspeed = (MSG_ReadByte() + 1) * (1.0 / 256.0);
1290                 color[0] = MSG_ReadByte() * (2.0f / 255.0f);
1291                 color[1] = MSG_ReadByte() * (2.0f / 255.0f);
1292                 color[2] = MSG_ReadByte() * (2.0f / 255.0f);
1293                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1294                 CL_AllocDlight(NULL, &tempmatrix, radius, color[0], color[1], color[2], radius / velspeed, velspeed, 0, -1, true, 1, 0.25, 1, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
1295                 break;
1296
1297         case TE_FLAMEJET:
1298                 MSG_ReadVector(pos, cls.protocol);
1299                 MSG_ReadVector(dir, cls.protocol);
1300                 count = MSG_ReadByte();
1301                 CL_Flames(pos, dir, count);
1302                 break;
1303
1304         case TE_LIGHTNING1:
1305                 // lightning bolts
1306                 CL_ParseBeam(cl.model_bolt, true);
1307                 break;
1308
1309         case TE_LIGHTNING2:
1310                 // lightning bolts
1311                 CL_ParseBeam(cl.model_bolt2, true);
1312                 break;
1313
1314         case TE_LIGHTNING3:
1315                 // lightning bolts
1316                 CL_ParseBeam(cl.model_bolt3, false);
1317                 break;
1318
1319 // PGM 01/21/97
1320         case TE_BEAM:
1321                 // grappling hook beam
1322                 CL_ParseBeam(cl.model_beam, false);
1323                 break;
1324 // PGM 01/21/97
1325
1326 // LordHavoc: for compatibility with the Nehahra movie...
1327         case TE_LIGHTNING4NEH:
1328                 CL_ParseBeam(Mod_ForName(MSG_ReadString(), true, false, false), false);
1329                 break;
1330
1331         case TE_LAVASPLASH:
1332                 MSG_ReadVector(pos, cls.protocol);
1333                 CL_LavaSplash(pos);
1334                 break;
1335
1336         case TE_TELEPORT:
1337                 MSG_ReadVector(pos, cls.protocol);
1338                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1339                 CL_AllocDlight(NULL, &tempmatrix, 200, 1.0f, 1.0f, 1.0f, 600, 99.0f, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
1340                 CL_TeleportSplash(pos);
1341                 break;
1342
1343         case TE_EXPLOSION2:
1344                 // color mapped explosion
1345                 MSG_ReadVector(pos, cls.protocol);
1346                 CL_FindNonSolidLocation(pos, pos, 10);
1347                 colorStart = MSG_ReadByte();
1348                 colorLength = MSG_ReadByte();
1349                 CL_ParticleExplosion2(pos, colorStart, colorLength);
1350                 tempcolor = (unsigned char *)&palette_complete[(rand()%colorLength) + colorStart];
1351                 color[0] = tempcolor[0] * (2.0f / 255.0f);
1352                 color[1] = tempcolor[1] * (2.0f / 255.0f);
1353                 color[2] = tempcolor[2] * (2.0f / 255.0f);
1354                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1355                 CL_AllocDlight(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
1356                 if (gamemode != GAME_NEXUIZ)
1357                         S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1);
1358                 break;
1359
1360         case TE_TEI_G3:
1361                 MSG_ReadVector(pos, cls.protocol);
1362                 MSG_ReadVector(pos2, cls.protocol);
1363                 MSG_ReadVector(dir, cls.protocol);
1364                 CL_BeamParticle(pos, pos2, 8, 1, 1, 1, 1, 1);
1365                 break;
1366
1367         case TE_TEI_SMOKE:
1368                 MSG_ReadVector(pos, cls.protocol);
1369                 MSG_ReadVector(dir, cls.protocol);
1370                 count = MSG_ReadByte();
1371                 CL_FindNonSolidLocation(pos, pos, 4);
1372                 CL_Tei_Smoke(pos, dir, count);
1373                 break;
1374
1375         case TE_TEI_BIGEXPLOSION:
1376                 MSG_ReadVector(pos, cls.protocol);
1377                 CL_FindNonSolidLocation(pos, pos, 10);
1378                 CL_ParticleExplosion(pos);
1379                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1380                 CL_AllocDlight(NULL, &tempmatrix, 500, 2.5f, 2.0f, 1.0f, 500, 9999, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
1381                 if (gamemode != GAME_NEXUIZ)
1382                         S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1);
1383                 break;
1384
1385         case TE_TEI_PLASMAHIT:
1386                 MSG_ReadVector(pos, cls.protocol);
1387                 MSG_ReadVector(dir, cls.protocol);
1388                 count = MSG_ReadByte();
1389                 CL_FindNonSolidLocation(pos, pos, 5);
1390                 CL_Tei_PlasmaHit(pos, dir, count);
1391                 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1392                 CL_AllocDlight(NULL, &tempmatrix, 500, 0.6, 1.2, 2.0f, 2000, 9999, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
1393                 break;
1394
1395         default:
1396                 Host_Error("CL_ParseTempEntity: bad type %d (hex %02X)", type, type);
1397         }
1398 }
1399
1400 #define SHOWNET(x) if(cl_shownet.integer==2)Con_Printf("%3i:%s\n", msg_readcount-1, x);
1401
1402 //[515]: csqc
1403 void CL_VM_Init (void);
1404 qboolean CL_VM_Parse_TempEntity (void);
1405 void CL_VM_Parse_StuffCmd (const char *msg);
1406 void CL_VM_Parse_CenterPrint (const char *msg);
1407 void CSQC_AddPrintText (const char *msg);
1408 void CSQC_ReadEntities (void);
1409 //
1410 static unsigned char cgamenetbuffer[65536];
1411
1412 /*
1413 =====================
1414 CL_ParseServerMessage
1415 =====================
1416 */
1417 int parsingerror = false;
1418 void CL_ParseServerMessage(void)
1419 {
1420         int                     cmd;
1421         int                     i;
1422         protocolversion_t protocol;
1423         unsigned char           cmdlog[32];
1424         char            *cmdlogname[32], *temp;
1425         int                     cmdindex, cmdcount = 0;
1426
1427         if (cls.demorecording)
1428                 CL_WriteDemoMessage ();
1429
1430         cl.last_received_message = realtime;
1431
1432 //
1433 // if recording demos, copy the message out
1434 //
1435         if (cl_shownet.integer == 1)
1436                 Con_Printf("%f %i\n", realtime, net_message.cursize);
1437         else if (cl_shownet.integer == 2)
1438                 Con_Print("------------------\n");
1439
1440         cl.onground = false;    // unless the server says otherwise
1441 //
1442 // parse the message
1443 //
1444         //MSG_BeginReading ();
1445
1446         parsingerror = true;
1447
1448         while (1)
1449         {
1450                 if (msg_badread)
1451                         Host_Error ("CL_ParseServerMessage: Bad server message");
1452
1453                 cmd = MSG_ReadByte ();
1454
1455                 if (cmd == -1)
1456                 {
1457                         SHOWNET("END OF MESSAGE");
1458                         break;          // end of message
1459                 }
1460
1461                 cmdindex = cmdcount & 31;
1462                 cmdcount++;
1463                 cmdlog[cmdindex] = cmd;
1464
1465                 // if the high bit of the command byte is set, it is a fast update
1466                 if (cmd & 128)
1467                 {
1468                         // 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)
1469                         temp = "entity";
1470                         cmdlogname[cmdindex] = temp;
1471                         SHOWNET("fast update");
1472                         if (cls.signon == SIGNONS - 1)
1473                         {
1474                                 // first update is the final signon stage
1475                                 cls.signon = SIGNONS;
1476                                 CL_SignonReply ();
1477                         }
1478                         EntityFrameQuake_ReadEntity (cmd&127);
1479                         continue;
1480                 }
1481
1482                 SHOWNET(svc_strings[cmd]);
1483                 cmdlogname[cmdindex] = svc_strings[cmd];
1484                 if (!cmdlogname[cmdindex])
1485                 {
1486                         // 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)
1487                         temp = "<unknown>";
1488                         cmdlogname[cmdindex] = temp;
1489                 }
1490
1491                 // other commands
1492                 switch (cmd)
1493                 {
1494                 default:
1495                         {
1496                                 char description[32*64], temp[64];
1497                                 int count;
1498                                 strcpy (description, "packet dump: ");
1499                                 i = cmdcount - 32;
1500                                 if (i < 0)
1501                                         i = 0;
1502                                 count = cmdcount - i;
1503                                 i &= 31;
1504                                 while(count > 0)
1505                                 {
1506                                         dpsnprintf (temp, sizeof (temp), "%3i:%s ", cmdlog[i], cmdlogname[i]);
1507                                         strlcat (description, temp, sizeof (description));
1508                                         count--;
1509                                         i++;
1510                                         i &= 31;
1511                                 }
1512                                 description[strlen(description)-1] = '\n'; // replace the last space with a newline
1513                                 Con_Print(description);
1514                                 Host_Error ("CL_ParseServerMessage: Illegible server message");
1515                         }
1516                         break;
1517
1518                 case svc_nop:
1519                         if (cls.signon < SIGNONS)
1520                                 Con_Print("<-- server to client keepalive\n");
1521                         break;
1522
1523                 case svc_time:
1524                         cl.mtime[1] = cl.mtime[0];
1525                         cl.mtime[0] = MSG_ReadFloat ();
1526                         cl.movement_needupdate = true;
1527                         break;
1528
1529                 case svc_clientdata:
1530                         CL_ParseClientdata();
1531                         break;
1532
1533                 case svc_version:
1534                         i = MSG_ReadLong ();
1535                         protocol = Protocol_EnumForNumber(i);
1536                         if (protocol == PROTOCOL_UNKNOWN)
1537                                 Host_Error("CL_ParseServerMessage: Server is unrecognized protocol number (%i)", i);
1538                         // hack for unmarked Nehahra movie demos which had a custom protocol
1539                         if (protocol == PROTOCOL_QUAKEDP && cls.demoplayback && demo_nehahra.integer)
1540                                 protocol = PROTOCOL_NEHAHRAMOVIE;
1541                         cls.protocol = protocol;
1542                         break;
1543
1544                 case svc_disconnect:
1545                         Con_Printf ("Server disconnected\n");
1546                         if (cls.demonum != -1)
1547                                 CL_NextDemo ();
1548                         else
1549                                 CL_Disconnect ();
1550                         break;
1551
1552                 case svc_print:
1553                         CSQC_AddPrintText(MSG_ReadString());    //[515]: csqc
1554                         break;
1555
1556                 case svc_centerprint:
1557                         CL_VM_Parse_CenterPrint(MSG_ReadString ());     //[515]: csqc
1558                         break;
1559
1560                 case svc_stufftext:
1561                         CL_VM_Parse_StuffCmd(MSG_ReadString ());        //[515]: csqc
1562                         break;
1563
1564                 case svc_damage:
1565                         V_ParseDamage ();
1566                         break;
1567
1568                 case svc_serverinfo:
1569                         CL_ParseServerInfo ();
1570                         CL_VM_Init();   //[515]: init csqc
1571                         break;
1572
1573                 case svc_setangle:
1574                         for (i=0 ; i<3 ; i++)
1575                                 cl.viewangles[i] = MSG_ReadAngle (cls.protocol);
1576                         break;
1577
1578                 case svc_setview:
1579                         cl.viewentity = (unsigned short)MSG_ReadShort ();
1580                         if (cl.viewentity >= MAX_EDICTS)
1581                                 Host_Error("svc_setview >= MAX_EDICTS");
1582                         if (cl.viewentity >= cl_max_entities)
1583                                 CL_ExpandEntities(cl.viewentity);
1584                         // LordHavoc: assume first setview recieved is the real player entity
1585                         if (!cl.playerentity)
1586                                 cl.playerentity = cl.viewentity;
1587                         break;
1588
1589                 case svc_lightstyle:
1590                         i = MSG_ReadByte ();
1591                         if (i >= cl_max_lightstyle)
1592                         {
1593                                 Con_Printf ("svc_lightstyle >= MAX_LIGHTSTYLES");
1594                                 break;
1595                         }
1596                         strlcpy (cl_lightstyle[i].map,  MSG_ReadString(), sizeof (cl_lightstyle[i].map));
1597                         cl_lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
1598                         cl_lightstyle[i].length = (int)strlen(cl_lightstyle[i].map);
1599                         break;
1600
1601                 case svc_sound:
1602                         CL_ParseStartSoundPacket(false);
1603                         break;
1604
1605                 case svc_precache:
1606                         if (cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3)
1607                         {
1608                                 // was svc_sound2 in protocols 1, 2, 3, removed in 4, 5, changed to svc_precache in 6
1609                                 CL_ParseStartSoundPacket(true);
1610                         }
1611                         else
1612                         {
1613                                 int i = (unsigned short)MSG_ReadShort();
1614                                 char *s = MSG_ReadString();
1615                                 if (i < 32768)
1616                                 {
1617                                         if (i >= 1 && i < MAX_MODELS)
1618                                         {
1619                                                 model_t *model = Mod_ForName(s, false, false, i == 1);
1620                                                 if (!model)
1621                                                         Con_Printf("svc_precache: Mod_ForName(\"%s\") failed\n", s);
1622                                                 cl.model_precache[i] = model;
1623                                         }
1624                                         else
1625                                                 Con_Printf("svc_precache: index %i outside range %i...%i\n", i, 1, MAX_MODELS);
1626                                 }
1627                                 else
1628                                 {
1629                                         i -= 32768;
1630                                         if (i >= 1 && i < MAX_SOUNDS)
1631                                         {
1632                                                 sfx_t *sfx = S_PrecacheSound (s, true, false);
1633                                                 if (!sfx && snd_initialized.integer)
1634                                                         Con_Printf("svc_precache: S_PrecacheSound(\"%s\") failed\n", s);
1635                                                 cl.sound_precache[i] = sfx;
1636                                         }
1637                                         else
1638                                                 Con_Printf("svc_precache: index %i outside range %i...%i\n", i, 1, MAX_SOUNDS);
1639                                 }
1640                         }
1641                         break;
1642
1643                 case svc_stopsound:
1644                         i = (unsigned short) MSG_ReadShort();
1645                         S_StopSound(i>>3, i&7);
1646                         break;
1647
1648                 case svc_updatename:
1649                         i = MSG_ReadByte ();
1650                         if (i >= cl.maxclients)
1651                                 Host_Error ("CL_ParseServerMessage: svc_updatename >= cl.maxclients");
1652                         strlcpy (cl.scores[i].name, MSG_ReadString (), sizeof (cl.scores[i].name));
1653                         break;
1654
1655                 case svc_updatefrags:
1656                         i = MSG_ReadByte ();
1657                         if (i >= cl.maxclients)
1658                                 Host_Error ("CL_ParseServerMessage: svc_updatefrags >= cl.maxclients");
1659                         cl.scores[i].frags = (signed short) MSG_ReadShort ();
1660                         break;
1661
1662                 case svc_updatecolors:
1663                         i = MSG_ReadByte ();
1664                         if (i >= cl.maxclients)
1665                                 Host_Error ("CL_ParseServerMessage: svc_updatecolors >= cl.maxclients");
1666                         cl.scores[i].colors = MSG_ReadByte ();
1667                         break;
1668
1669                 case svc_particle:
1670                         CL_ParseParticleEffect ();
1671                         break;
1672
1673                 case svc_effect:
1674                         CL_ParseEffect ();
1675                         break;
1676
1677                 case svc_effect2:
1678                         CL_ParseEffect2 ();
1679                         break;
1680
1681                 case svc_spawnbaseline:
1682                         i = (unsigned short) MSG_ReadShort ();
1683                         if (i < 0 || i >= MAX_EDICTS)
1684                                 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i);
1685                         if (i >= cl_max_entities)
1686                                 CL_ExpandEntities(i);
1687                         CL_ParseBaseline (cl_entities + i, false);
1688                         break;
1689                 case svc_spawnbaseline2:
1690                         i = (unsigned short) MSG_ReadShort ();
1691                         if (i < 0 || i >= MAX_EDICTS)
1692                                 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline2: invalid entity number %i", i);
1693                         if (i >= cl_max_entities)
1694                                 CL_ExpandEntities(i);
1695                         CL_ParseBaseline (cl_entities + i, true);
1696                         break;
1697                 case svc_spawnstatic:
1698                         CL_ParseStatic (false);
1699                         break;
1700                 case svc_spawnstatic2:
1701                         CL_ParseStatic (true);
1702                         break;
1703                 case svc_temp_entity:
1704                         if(!CL_VM_Parse_TempEntity())
1705                                 CL_ParseTempEntity ();
1706                         break;
1707
1708                 case svc_setpause:
1709                         cl.paused = MSG_ReadByte ();
1710                         if (cl.paused)
1711                                 CDAudio_Pause ();
1712                         else
1713                                 CDAudio_Resume ();
1714                         S_PauseGameSounds (cl.paused);
1715                         break;
1716
1717                 case svc_signonnum:
1718                         i = MSG_ReadByte ();
1719                         // LordHavoc: it's rude to kick off the client if they missed the
1720                         // reconnect somehow, so allow signon 1 even if at signon 1
1721                         if (i <= cls.signon && i != 1)
1722                                 Host_Error ("Received signon %i when at %i", i, cls.signon);
1723                         cls.signon = i;
1724                         CL_SignonReply ();
1725                         break;
1726
1727                 case svc_killedmonster:
1728                         cl.stats[STAT_MONSTERS]++;
1729                         break;
1730
1731                 case svc_foundsecret:
1732                         cl.stats[STAT_SECRETS]++;
1733                         break;
1734
1735                 case svc_updatestat:
1736                         i = MSG_ReadByte ();
1737                         if (i < 0 || i >= MAX_CL_STATS)
1738                                 Host_Error ("svc_updatestat: %i is invalid", i);
1739                         cl.stats[i] = MSG_ReadLong ();
1740                         break;
1741
1742                 case svc_updatestatubyte:
1743                         i = MSG_ReadByte ();
1744                         if (i < 0 || i >= MAX_CL_STATS)
1745                                 Host_Error ("svc_updatestat: %i is invalid", i);
1746                         cl.stats[i] = MSG_ReadByte ();
1747                         break;
1748
1749                 case svc_spawnstaticsound:
1750                         CL_ParseStaticSound (false);
1751                         break;
1752
1753                 case svc_spawnstaticsound2:
1754                         CL_ParseStaticSound (true);
1755                         break;
1756
1757                 case svc_cdtrack:
1758                         cl.cdtrack = MSG_ReadByte ();
1759                         cl.looptrack = MSG_ReadByte ();
1760                         if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )
1761                                 CDAudio_Play ((unsigned char)cls.forcetrack, true);
1762                         else
1763                                 CDAudio_Play ((unsigned char)cl.cdtrack, true);
1764                         break;
1765
1766                 case svc_intermission:
1767                         cl.intermission = 1;
1768                         cl.completed_time = cl.time;
1769                         break;
1770
1771                 case svc_finale:
1772                         cl.intermission = 2;
1773                         cl.completed_time = cl.time;
1774                         SCR_CenterPrint(MSG_ReadString ());
1775                         break;
1776
1777                 case svc_cutscene:
1778                         cl.intermission = 3;
1779                         cl.completed_time = cl.time;
1780                         SCR_CenterPrint(MSG_ReadString ());
1781                         break;
1782
1783                 case svc_sellscreen:
1784                         Cmd_ExecuteString ("help", src_command);
1785                         break;
1786                 case svc_hidelmp:
1787                         if (gamemode == GAME_TENEBRAE)
1788                         {
1789                                 // repeating particle effect
1790                                 MSG_ReadCoord(cls.protocol);
1791                                 MSG_ReadCoord(cls.protocol);
1792                                 MSG_ReadCoord(cls.protocol);
1793                                 MSG_ReadCoord(cls.protocol);
1794                                 MSG_ReadCoord(cls.protocol);
1795                                 MSG_ReadCoord(cls.protocol);
1796                                 MSG_ReadByte();
1797                                 MSG_ReadLong();
1798                                 MSG_ReadLong();
1799                                 MSG_ReadString();
1800                         }
1801                         else
1802                                 SHOWLMP_decodehide();
1803                         break;
1804                 case svc_showlmp:
1805                         if (gamemode == GAME_TENEBRAE)
1806                         {
1807                                 // particle effect
1808                                 MSG_ReadCoord(cls.protocol);
1809                                 MSG_ReadCoord(cls.protocol);
1810                                 MSG_ReadCoord(cls.protocol);
1811                                 MSG_ReadByte();
1812                                 MSG_ReadString();
1813                         }
1814                         else
1815                                 SHOWLMP_decodeshow();
1816                         break;
1817                 case svc_skybox:
1818                         R_SetSkyBox(MSG_ReadString());
1819                         break;
1820                 case svc_cgame:
1821                         {
1822                                 int length;
1823                                 length = (int) ((unsigned short) MSG_ReadShort());
1824                                 for (i = 0;i < length;i++)
1825                                         cgamenetbuffer[i] = MSG_ReadByte();
1826                                 if (!msg_badread)
1827                                         CL_CGVM_ParseNetwork(cgamenetbuffer, length);
1828                         }
1829                         break;
1830                 case svc_entities:
1831                         if (cls.signon == SIGNONS - 1)
1832                         {
1833                                 // first update is the final signon stage
1834                                 cls.signon = SIGNONS;
1835                                 CL_SignonReply ();
1836                         }
1837                         if (cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3)
1838                                 EntityFrame_CL_ReadFrame();
1839                         else if (cls.protocol == PROTOCOL_DARKPLACES4)
1840                                 EntityFrame4_CL_ReadFrame();
1841                         else
1842                                 EntityFrame5_CL_ReadFrame();
1843                         break;
1844                 case svc_csqcentities:
1845                         CSQC_ReadEntities();
1846                         break;
1847                 }
1848         }
1849
1850         EntityFrameQuake_ISeeDeadEntities();
1851
1852         parsingerror = false;
1853 }
1854
1855 void CL_Parse_DumpPacket(void)
1856 {
1857         if (!parsingerror)
1858                 return;
1859         Con_Print("Packet dump:\n");
1860         SZ_HexDumpToConsole(&net_message);
1861         parsingerror = false;
1862 }
1863
1864 void CL_Parse_Init(void)
1865 {
1866         // LordHavoc: added demo_nehahra cvar
1867         Cvar_RegisterVariable (&demo_nehahra);
1868         if (gamemode == GAME_NEHAHRA)
1869                 Cvar_SetValue("demo_nehahra", 1);
1870         Cvar_RegisterVariable(&developer_networkentities);
1871 }
1872
1873 void CL_Parse_Shutdown(void)
1874 {
1875 }