1 /*
2 * cl_parse.c -- parse a message received from the server
3 * $Id: cl_parse.c 5977 2017-09-17 08:01:41Z sezero $
4 *
5 * Copyright (C) 1996-1997 Id Software, Inc.
6 * Copyright (C) 1997-1998 Raven Software Corp.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or (at
11 * your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 *
17 * See the GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #include "quakedef.h"
25 #include "bgmusic.h"
26 #include "cdaudio.h"
27 #include "r_shared.h"
28
29 static const char *svc_strings[] =
30 {
31 "svc_bad",
32 "svc_nop",
33 "svc_disconnect",
34 "svc_updatestat",
35 "svc_version", // [long] server version
36 "svc_setview", // [short] entity number
37 "svc_sound", // <see code>
38 "svc_time", // [float] server time
39 "svc_print", // [string] null terminated string
40 "svc_stufftext", // [string] stuffed into client's console buffer
41 // the string should be \n terminated
42 "svc_setangle", // [vec3] set the view angle to this absolute value
43
44 "svc_serverdata", // [long] version ...
45 "svc_lightstyle", // [byte] [string]
46 "svc_updatename", // [byte] [string]
47 "svc_updatefrags", // [byte] [short]
48 "svc_clientdata", // <shortbits + data>
49 "svc_stopsound", // <see code>
50 "svc_updatecolors", // [byte] [byte]
51 "svc_particle", // [vec3] <variable>
52 "svc_damage", // [byte] impact [byte] blood [vec3] from
53
54 "svc_spawnstatic",
55 "OBSOLETE svc_spawnbinary",
56 "svc_spawnbaseline",
57
58 "svc_temp_entity", // <variable>
59 "svc_setpause",
60 "svc_signonnum",
61 "svc_centerprint",
62 "svc_killedmonster",
63 "svc_foundsecret",
64 "svc_spawnstaticsound",
65 "svc_intermission",
66 "svc_finale",
67
68 "svc_cdtrack",
69 "svc_sellscreen",
70
71 "svc_smallkick",
72 "svc_bigkick",
73
74 "svc_updateping",
75 "svc_updateentertime",
76
77 "svc_updatestatlong",
78 "svc_muzzleflash",
79 "svc_updateuserinfo",
80 "svc_download",
81 "svc_playerinfo",
82 "svc_nails",
83 "svc_choke",
84 "svc_modellist",
85 "svc_soundlist",
86 "svc_packetentities",
87 "svc_deltapacketentities",
88 "svc_maxspeed",
89 "svc_entgravity",
90
91 "svc_plaque",
92 "svc_particle_explosion",
93 "svc_set_view_tint",
94 "svc_start_effect",
95 "svc_end_effect",
96 "svc_set_view_flags",
97 "svc_clear_view_flags",
98 "svc_update_inv",
99 "svc_particle2",
100 "svc_particle3",
101 "svc_particle4",
102 "svc_turn_effect",
103 "svc_update_effect",
104 "svc_multieffect",
105 "svc_midi_name",
106 "svc_raineffect",
107 "svc_packmissile",
108
109 "svc_indexed_print",
110 "svc_targetupdate",
111 "svc_name_print",
112 "svc_sound_update_pos",
113 "svc_update_piv",
114 "svc_player_sound",
115 "svc_updatepclass",
116 "svc_updatedminfo", // [byte] [short] [byte]
117 "svc_updatesiegeinfo", // [byte] [byte]
118 "svc_updatesiegeteam", // [byte] [byte]
119 "svc_updatesiegelosses",// [byte] [byte]
120 "svc_haskey", // [byte] [byte]
121 "svc_nonehaskey", // [byte]
122 "svc_isdoc", // [byte] [byte]
123 "svc_nodoc", // [byte]
124 "svc_playerskipped" // [byte]
125 "NEW PROTOCOL",
126 "NEW PROTOCOL",
127 "NEW PROTOCOL",
128 "NEW PROTOCOL"
129 };
130 #define NUM_SVC_STRINGS (sizeof(svc_strings) / sizeof(svc_strings[0]))
131
132 int parsecountmod;
133 double parsecounttime;
134
135 qmodel_t *player_models[MAX_PLAYER_CLASS];
136
137 int cl_spikeindex, cl_playerindex[MAX_PLAYER_CLASS], cl_flagindex;
138 int cl_ballindex, cl_missilestarindex, cl_ravenindex, cl_raven2index;
139
140
141 //=============================================================================
142
143
144 /*
145 ===============
146 CL_CheckOrDownloadFile
147
148 Returns true if the file exists, otherwise it attempts
149 to start a download from the server.
150 ===============
151 */
CL_CheckOrDownloadFile(const char * filename)152 qboolean CL_CheckOrDownloadFile (const char *filename)
153 {
154 if (strstr (filename, ".."))
155 {
156 Con_Printf ("Refusing to download a path with ..\n");
157 return true;
158 }
159
160 if (FS_FileExists(filename, NULL))
161 { // it exists, no need to download
162 return true;
163 }
164
165 //ZOID - can't download when recording
166 if (cls.demorecording)
167 {
168 Con_Printf("Unable to download %s in record mode.\n", cls.downloadname);
169 return true;
170 }
171 //ZOID - can't download when playback
172 if (cls.demoplayback)
173 return true;
174
175 q_strlcpy (cls.downloadname, filename, MAX_OSPATH);
176 Con_Printf ("Downloading %s...\n", cls.downloadname);
177
178 // download to a temp name, and only rename
179 // to the real name when done, so if interrupted
180 // a runt file wont be left
181 COM_StripExtension (cls.downloadname, cls.downloadtempname, sizeof(cls.downloadtempname));
182 q_strlcat (cls.downloadtempname, ".tmp", sizeof(cls.downloadtempname));
183
184 MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
185 MSG_WriteString (&cls.netchan.message, va("download %s", cls.downloadname));
186
187 cls.downloadnumber++;
188
189 return false;
190 }
191
192 /*
193 =================
194 Model_NextDownload
195 =================
196 */
Model_NextDownload(void)197 static void Model_NextDownload (void)
198 {
199 const char *s;
200 int i;
201
202 if (cls.downloadnumber == 0)
203 {
204 Con_Printf ("Checking models...\n");
205 cls.downloadnumber = 1;
206 }
207
208 cls.downloadtype = dl_model;
209 for ( ; cl.model_name[cls.downloadnumber][0] ; cls.downloadnumber++)
210 {
211 s = cl.model_name[cls.downloadnumber];
212 if (s[0] == '*')
213 continue; // inline brush model
214 if (!CL_CheckOrDownloadFile(s))
215 return; // started a download
216 }
217
218 for (i = 1; i < MAX_MODELS; i++)
219 {
220 if (!cl.model_name[i][0])
221 break;
222 cl.model_precache[i] = Mod_ForName (cl.model_name[i], false);
223 if (!cl.model_precache[i])
224 {
225 Con_Printf ("\nThe required model file '%s' could not be found or downloaded.\n\n", cl.model_name[i]);
226 Con_Printf ("You may need to download or purchase a %s client "
227 "pack in order to play on this server.\n\n", fs_gamedir_nopath);
228 CL_Disconnect ();
229 return;
230 }
231 }
232
233 // copy the naked name of the map file to the cl structure
234 COM_FileBase (cl.model_name[1], cl.mapname, sizeof(cl.mapname));
235
236 // all done
237 cl.worldmodel = cl.model_precache[1];
238 R_NewMap ();
239
240 Host_LoadStrings();
241
242 Hunk_Check (); // make sure nothing is hurt
243
244 // done with modellist, request first of static signon messages
245 MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
246 MSG_WriteString (&cls.netchan.message, va("prespawn %i", cl.servercount));
247 }
248
249 /*
250 =================
251 Sound_NextDownload
252 =================
253 */
Sound_NextDownload(void)254 static void Sound_NextDownload (void)
255 {
256 const char *s;
257 int i;
258
259 if (cls.downloadnumber == 0)
260 {
261 Con_Printf ("Checking sounds...\n");
262 cls.downloadnumber = 1;
263 }
264
265 cls.downloadtype = dl_sound;
266 for ( ; cl.sound_name[cls.downloadnumber][0] ; cls.downloadnumber++)
267 {
268 s = cl.sound_name[cls.downloadnumber];
269 if (!CL_CheckOrDownloadFile(va("sound/%s",s)))
270 return; // started a download
271 }
272
273 for (i = 1; i < MAX_SOUNDS; i++)
274 {
275 if (!cl.sound_name[i][0])
276 break;
277 cl.sound_precache[i] = S_PrecacheSound (cl.sound_name[i]);
278 }
279
280 // done with sounds, request models now
281 MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
282 MSG_WriteString (&cls.netchan.message, va("modellist %i", cl.servercount));
283 }
284
285
286 /*
287 ======================
288 CL_RequestNextDownload
289 ======================
290 */
CL_RequestNextDownload(void)291 static void CL_RequestNextDownload (void)
292 {
293 switch (cls.downloadtype)
294 {
295 case dl_single:
296 break;
297 case dl_skin:
298 Skin_NextDownload ();
299 break;
300 case dl_model:
301 Model_NextDownload ();
302 break;
303 case dl_sound:
304 Sound_NextDownload ();
305 break;
306 case dl_none:
307 default:
308 Con_DPrintf("Unknown download type.\n");
309 }
310 }
311
312 /*
313 =====================
314 CL_ParseDownload
315
316 A download message has been received from the server
317 =====================
318 */
CL_ParseDownload(void)319 static void CL_ParseDownload (void)
320 {
321 int size, percent;
322 char name[MAX_OSPATH];
323
324 // read the data
325 size = MSG_ReadShort ();
326 percent = MSG_ReadByte ();
327
328 if (cls.demoplayback)
329 {
330 if (size > 0)
331 msg_readcount += size;
332 return; // not in demo playback
333 }
334
335 if (size == -1)
336 {
337 Con_Printf ("File not found.\n");
338 if (cls.download)
339 {
340 Con_Printf ("cls.download shouldn't have been set\n");
341 fclose (cls.download);
342 cls.download = NULL;
343 }
344 CL_RequestNextDownload ();
345 return;
346 }
347
348 // open the file if not opened yet
349 if (!cls.download)
350 {
351 FS_MakePath_BUF (FS_USERDIR, NULL, name, sizeof(name), cls.downloadtempname);
352 if ( FS_CreatePath(name) )
353 {
354 msg_readcount += size;
355 Con_Printf ("Unable to create directory for downloading %s\n", cls.downloadtempname);
356 CL_RequestNextDownload ();
357 return;
358 }
359
360 cls.download = fopen (name, "wb");
361 if (!cls.download)
362 {
363 msg_readcount += size;
364 Con_Printf ("Failed to open %s\n", cls.downloadtempname);
365 CL_RequestNextDownload ();
366 return;
367 }
368 }
369
370 fwrite (net_message.data + msg_readcount, 1, size, cls.download);
371 msg_readcount += size;
372
373 if (percent != 100)
374 {
375 // request next block
376 cls.downloadpercent = percent;
377
378 MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
379 SZ_Print (&cls.netchan.message, "nextdl");
380 }
381 else
382 {
383 // rename the temp file to it's final name
384 char oldn[MAX_OSPATH];
385 char newn[MAX_OSPATH];
386
387 fclose (cls.download);
388 cls.download = NULL;
389 cls.downloadpercent = 0;
390
391 FS_MakePath_BUF (FS_USERDIR, NULL, oldn, sizeof(oldn), cls.downloadtempname);
392 FS_MakePath_BUF (FS_USERDIR, NULL, newn, sizeof(newn), cls.downloadname);
393 if (Sys_rename(oldn, newn) != 0)
394 Con_Printf ("failed to rename.\n");
395
396 // get another file if needed
397 CL_RequestNextDownload ();
398 }
399 }
400
401
402 /*
403 =====================================================================
404
405 SERVER CONNECTING MESSAGES
406
407 =====================================================================
408 */
409
410 /*
411 ==================
412 CL_ParseServerData
413 ==================
414 */
CL_ParseServerData(void)415 static void CL_ParseServerData (void)
416 {
417 const char *str;
418
419 Con_DPrintf ("Serverdata packet received.\n");
420
421 //
422 // wipe the client_state_t struct
423 //
424 CL_ClearState ();
425
426 // CL_ClearState() clears the cl structure already,
427 // so no need zero'ing the sound/model list arrays.
428 //memset (cl.sound_precache, 0, sizeof(cl.sound_precache));
429 //memset (cl.model_precache, 0, sizeof(cl.model_precache));
430 cl_playerindex[0] = -1;
431 cl_playerindex[1] = -1;
432 cl_playerindex[2] = -1;
433 cl_playerindex[3] = -1;
434 cl_playerindex[4] = -1;
435 cl_playerindex[5] = -1;//mg-siege
436 cl_spikeindex = -1;
437 cl_flagindex = -1;
438 cl_ballindex = -1;
439 cl_missilestarindex = -1;
440 cl_ravenindex = -1;
441 cl_raven2index = -1;
442
443 // parse protocol version number
444 cl.protocol = MSG_ReadLong ();
445 switch (cl.protocol) {
446 case OLD_PROTOCOL_VERSION:
447 case PROTOCOL_VERSION:
448 case PROTOCOL_VERSION_EXT:
449 Con_Printf ("Server using protocol %i\n", cl.protocol);
450 break;
451 default:
452 Host_EndGame ("Server returned unsupported protocol %i", cl.protocol);
453 }
454
455 cl.servercount = MSG_ReadLong ();
456
457 // game directory
458 str = MSG_ReadString ();
459
460 if (q_strcasecmp(fs_gamedir_nopath, str))
461 {
462 Con_Printf("Server set the gamedir to %s\n", str);
463
464 // save current config
465 Host_WriteConfiguration ("config.cfg");
466
467 // set the new gamedir and userdir
468 FS_Gamedir(str);
469
470 // ZOID - run autoexec.cfg in the gamedir if it exists
471 if (FS_FileInGamedir("config.cfg"))
472 {
473 // remove any weird mod specific key bindings / aliases
474 Cbuf_AddText("unbindall\n");
475 Cbuf_AddText("unaliasall\n");
476 Cbuf_AddText("exec autoexec.cfg\n");
477 Cbuf_AddText("exec config.cfg\n");
478 }
479 // gamespy crap
480 if (FS_FileInGamedir("frontend.cfg"))
481 Cbuf_AddText("exec frontend.cfg\n");
482
483 Cbuf_Execute ();
484
485 // re-init draw
486 Draw_ReInit ();
487 }
488
489 // parse player slot, high bit means spectator
490 cl.playernum = MSG_ReadByte ();
491 if (cl.playernum & 128)
492 {
493 cl.spectator = true;
494 cl.playernum &= ~128;
495 }
496
497 // get the full level name
498 str = MSG_ReadString ();
499 q_strlcpy (cl.levelname, str, sizeof(cl.levelname));
500
501 // get the movevars
502 if (cl.protocol >= PROTOCOL_VERSION)
503 {
504 movevars.gravity = MSG_ReadFloat();
505 movevars.stopspeed = MSG_ReadFloat();
506 movevars.maxspeed = MSG_ReadFloat();
507 movevars.spectatormaxspeed = MSG_ReadFloat();
508 movevars.accelerate = MSG_ReadFloat();
509 movevars.airaccelerate = MSG_ReadFloat();
510 movevars.wateraccelerate = MSG_ReadFloat();
511 movevars.friction = MSG_ReadFloat();
512 movevars.waterfriction = MSG_ReadFloat();
513 movevars.entgravity = MSG_ReadFloat();
514 }
515 else
516 {
517 movevars.gravity = 800;
518 movevars.stopspeed = 100;
519 movevars.maxspeed = 320;
520 movevars.spectatormaxspeed = 500;
521 movevars.accelerate = 10;
522 movevars.airaccelerate = 0.7;
523 movevars.wateraccelerate = 10;
524 movevars.friction = 6;
525 movevars.waterfriction = 1;
526 movevars.entgravity = 1.0;
527 }
528
529 // seperate the printfs so the server message can have a color
530 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");
531 Con_Printf ("%c%s\n", 2, str);
532
533 // ask for the sound list next
534 MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
535 MSG_WriteString (&cls.netchan.message, va("soundlist %i", cl.servercount));
536
537 // now waiting for downloads, etc
538 cls.state = ca_onserver;
539 cl_keyholder = -1;
540 cl_doc = -1;
541 }
542
CL_ParseSoundlistChunks(void)543 static void CL_ParseSoundlistChunks (void) /* from QW */
544 {
545 int numsounds, n;
546 const char *str;
547
548 // precache sounds
549 numsounds = MSG_ReadLong ();
550
551 for (;;) {
552 str = MSG_ReadString ();
553 if (!str[0])
554 break;
555 numsounds++;
556 if (numsounds >= MAX_SOUNDS)
557 Host_Error ("Server sent too many sound_precache");
558 strcpy (cl.sound_name[numsounds], str);
559 }
560
561 n = MSG_ReadLong ();
562 if (n)
563 {
564 if (!cls.demoplayback) {
565 MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
566 MSG_WriteString (&cls.netchan.message,
567 va ("soundlist %i %i", cl.servercount, n));
568 }
569 return;
570 }
571
572 cls.downloadnumber = 0;
573 cls.downloadtype = dl_sound;
574 Sound_NextDownload ();
575 }
576
577 /*
578 ==================
579 CL_ParseSoundlist
580 ==================
581 */
CL_ParseSoundlist(void)582 static void CL_ParseSoundlist (void)
583 {
584 int numsounds;
585 const char *str;
586
587 // precache sounds
588 for (numsounds = 1 ; ; numsounds++)
589 {
590 str = MSG_ReadString ();
591 if (!str[0])
592 break;
593 if (numsounds == MAX_SOUNDS)
594 Host_EndGame ("Server sent too many sound_precache");
595 q_strlcpy (cl.sound_name[numsounds], str, MAX_QPATH);
596 }
597
598 cls.downloadnumber = 0;
599 cls.downloadtype = dl_sound;
600 Sound_NextDownload ();
601 }
602
CL_ParseModellistChunks(void)603 static void CL_ParseModellistChunks (void) /* from QW */
604 {
605 int nummodels, n;
606 const char *str;
607
608 // precache models and note certain default indexes
609 nummodels = MSG_ReadLong ();
610
611 for (;;)
612 {
613 str = MSG_ReadString ();
614 if (!str[0])
615 break;
616
617 nummodels++;
618 if (nummodels >= MAX_MODELS)
619 Host_EndGame ("Server sent too many model_precache");
620
621 q_strlcpy (cl.model_name[nummodels], str, MAX_QPATH);
622
623 if (!strcmp(cl.model_name[nummodels],"progs/spike.mdl"))
624 cl_spikeindex = nummodels;
625 if (!strcmp(cl.model_name[nummodels],"models/paladin.mdl"))
626 cl_playerindex[0] = nummodels;
627 if (!strcmp(cl.model_name[nummodels],"models/crusader.mdl"))
628 cl_playerindex[1] = nummodels;
629 if (!strcmp(cl.model_name[nummodels],"models/necro.mdl"))
630 cl_playerindex[2] = nummodels;
631 if (!strcmp(cl.model_name[nummodels],"models/assassin.mdl"))
632 cl_playerindex[3] = nummodels;
633 if (!strcmp(cl.model_name[nummodels],"models/succubus.mdl"))
634 cl_playerindex[4] = nummodels;
635 if (!strcmp(cl.model_name[nummodels],"models/hank.mdl"))
636 cl_playerindex[5] = nummodels;//mg-siege
637 if (!strcmp(cl.model_name[nummodels],"progs/flag.mdl"))
638 cl_flagindex = nummodels;
639 if (!strcmp(cl.model_name[nummodels],"models/ball.mdl"))
640 cl_ballindex = nummodels;
641 if (!strcmp(cl.model_name[nummodels],"models/newmmis.mdl"))
642 cl_missilestarindex = nummodels;
643 if (!strcmp(cl.model_name[nummodels],"models/ravproj.mdl"))
644 cl_ravenindex = nummodels;
645 if (!strcmp(cl.model_name[nummodels],"models/vindsht1.mdl"))
646 cl_raven2index = nummodels;
647 }
648
649 player_models[0] = (qmodel_t *)Mod_FindName ("models/paladin.mdl");
650 player_models[1] = !(gameflags & GAME_OLD_DEMO) ? (qmodel_t *)Mod_FindName ("models/crusader.mdl") : NULL;
651 player_models[2] = !(gameflags & GAME_OLD_DEMO) ? (qmodel_t *)Mod_FindName ("models/necro.mdl") : NULL;
652 player_models[3] = (qmodel_t *)Mod_FindName ("models/assassin.mdl");
653 player_models[4] = (qmodel_t *)Mod_FindName ("models/succubus.mdl");
654 player_models[5] = (qmodel_t *)Mod_FindName ("models/hank.mdl");//siege
655
656 n = MSG_ReadLong ();
657 if (n)
658 {
659 if (!cls.demoplayback) {
660 MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
661 MSG_WriteString (&cls.netchan.message,
662 va ("modellist %i %i", cl.servercount, n));
663 }
664 return;
665 }
666
667 cls.downloadnumber = 0;
668 cls.downloadtype = dl_model;
669 Model_NextDownload ();
670 }
671
672 /*
673 ==================
674 CL_ParseModellist
675 ==================
676 */
CL_ParseModellist(void)677 static void CL_ParseModellist (void)
678 {
679 int nummodels;
680 const char *str;
681
682 // precache models and note certain default indexes
683 for (nummodels = 1 ; ; nummodels++)
684 {
685 str = MSG_ReadString ();
686 if (!str[0])
687 break;
688 if (nummodels == MAX_MODELS)
689 Host_EndGame ("Server sent too many model_precache");
690 q_strlcpy (cl.model_name[nummodels], str, MAX_QPATH);
691
692 if (!strcmp(cl.model_name[nummodels],"progs/spike.mdl"))
693 cl_spikeindex = nummodels;
694 if (!strcmp(cl.model_name[nummodels],"models/paladin.mdl"))
695 cl_playerindex[0] = nummodels;
696 if (!strcmp(cl.model_name[nummodels],"models/crusader.mdl"))
697 cl_playerindex[1] = nummodels;
698 if (!strcmp(cl.model_name[nummodels],"models/necro.mdl"))
699 cl_playerindex[2] = nummodels;
700 if (!strcmp(cl.model_name[nummodels],"models/assassin.mdl"))
701 cl_playerindex[3] = nummodels;
702 if (!strcmp(cl.model_name[nummodels],"models/succubus.mdl"))
703 cl_playerindex[4] = nummodels;
704 if (!strcmp(cl.model_name[nummodels],"models/hank.mdl"))
705 cl_playerindex[5] = nummodels;//mg-siege
706 if (!strcmp(cl.model_name[nummodels],"progs/flag.mdl"))
707 cl_flagindex = nummodels;
708 if (!strcmp(cl.model_name[nummodels],"models/ball.mdl"))
709 cl_ballindex = nummodels;
710 if (!strcmp(cl.model_name[nummodels],"models/newmmis.mdl"))
711 cl_missilestarindex = nummodels;
712 if (!strcmp(cl.model_name[nummodels],"models/ravproj.mdl"))
713 cl_ravenindex = nummodels;
714 if (!strcmp(cl.model_name[nummodels],"models/vindsht1.mdl"))
715 cl_raven2index = nummodels;
716 }
717
718 player_models[0] = (qmodel_t *)Mod_FindName ("models/paladin.mdl");
719 player_models[1] = !(gameflags & GAME_OLD_DEMO) ? (qmodel_t *)Mod_FindName ("models/crusader.mdl") : NULL;
720 player_models[2] = !(gameflags & GAME_OLD_DEMO) ? (qmodel_t *)Mod_FindName ("models/necro.mdl") : NULL;
721 player_models[3] = (qmodel_t *)Mod_FindName ("models/assassin.mdl");
722 player_models[4] = (qmodel_t *)Mod_FindName ("models/succubus.mdl");
723 player_models[5] = (qmodel_t *)Mod_FindName ("models/hank.mdl");//siege
724
725 cls.downloadnumber = 0;
726 cls.downloadtype = dl_model;
727 Model_NextDownload ();
728 }
729
730 /*
731 ==================
732 CL_ParseBaseline
733 ==================
734 */
CL_ParseBaseline(entity_state_t * es)735 static void CL_ParseBaseline (entity_state_t *es)
736 {
737 int i;
738
739 es->modelindex = MSG_ReadShort ();
740 es->frame = MSG_ReadByte ();
741 es->colormap = MSG_ReadByte();
742 es->skinnum = MSG_ReadByte();
743 es->scale = MSG_ReadByte();
744 es->drawflags = MSG_ReadByte();
745 es->abslight = MSG_ReadByte();
746
747 for (i = 0; i < 3; i++)
748 {
749 es->origin[i] = MSG_ReadCoord ();
750 es->angles[i] = MSG_ReadAngle ();
751 }
752 }
753
754
755 /*
756 =====================
757 CL_ParseStatic
758
759 Static entities are non-interactive world objects
760 like torches
761 =====================
762 */
CL_ParseStatic(void)763 static void CL_ParseStatic (void)
764 {
765 entity_t *ent;
766 int i;
767 entity_state_t es;
768
769 CL_ParseBaseline (&es);
770
771 i = cl.num_statics;
772 if (i >= MAX_STATIC_ENTITIES)
773 Host_EndGame ("Too many static entities");
774 ent = &cl_static_entities[i];
775 cl.num_statics++;
776
777 // copy it to the current state
778 ent->model = cl.model_precache[es.modelindex];
779 ent->frame = es.frame;
780 ent->colormap = vid.colormap;
781 ent->skinnum = es.skinnum;
782 ent->scale = es.scale;
783 ent->drawflags = es.drawflags;
784 ent->abslight = es.abslight;
785
786 VectorCopy (es.origin, ent->origin);
787 VectorCopy (es.angles, ent->angles);
788
789 R_AddEfrags (ent);
790 }
791
792 /*
793 ===================
794 CL_ParseStaticSound
795 ===================
796 */
CL_ParseStaticSound(void)797 static void CL_ParseStaticSound (void)
798 {
799 vec3_t org;
800 int sound_num, vol, atten;
801 int i;
802
803 for (i = 0; i < 3; i++)
804 org[i] = MSG_ReadCoord ();
805 sound_num = MSG_ReadByte ();
806 vol = MSG_ReadByte ();
807 atten = MSG_ReadByte ();
808
809 S_StaticSound (cl.sound_precache[sound_num], org, vol, atten);
810 }
811
812
813 /*
814 =====================================================================
815
816 ACTION MESSAGES
817
818 =====================================================================
819 */
820
821 /*
822 ==================
823 CL_ParseStartSoundPacket
824 ==================
825 */
CL_ParseStartSoundPacket(void)826 static void CL_ParseStartSoundPacket(void)
827 {
828 vec3_t pos;
829 int channel, ent;
830 int sound_num, volume;
831 float attenuation;
832 int i;
833
834 channel = MSG_ReadShort();
835
836 if (channel & SND_VOLUME)
837 volume = MSG_ReadByte ();
838 else volume = DEFAULT_SOUND_PACKET_VOLUME;
839
840 if (channel & SND_ATTENUATION)
841 attenuation = MSG_ReadByte () / 32.0;
842 else attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;
843
844 sound_num = MSG_ReadByte ();
845
846 for (i = 0; i < 3; i++)
847 pos[i] = MSG_ReadCoord ();
848
849 ent = (channel>>3)&1023;
850 channel &= 7;
851
852 if (ent > MAX_EDICTS)
853 Host_EndGame ("%s: ent = %i", __thisfunc__, ent);
854
855 S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation);
856 }
857
858
859 /*
860 ==================
861 CL_ParseClientdata
862
863 Server information pertaining to this client only, sent every frame
864 ==================
865 */
CL_ParseClientdata(void)866 static void CL_ParseClientdata (void)
867 {
868 int i;
869 float latency;
870 frame_t *frame;
871
872 // calculate simulated time of message
873
874 i = cls.netchan.incoming_acknowledged;
875 cl.parsecount = i;
876 i &= UPDATE_MASK;
877 parsecountmod = i;
878 frame = &cl.frames[i];
879 parsecounttime = cl.frames[i].senttime;
880
881 frame->receivedtime = realtime;
882
883 // calculate latency
884 latency = frame->receivedtime - frame->senttime;
885
886 if (latency < 0 || latency > 1.0)
887 {
888 // Con_Printf ("Odd latency: %5.2f\n", latency);
889 }
890 else
891 {
892 // drift the average latency towards the observed latency
893 if (latency < cls.latency)
894 cls.latency = latency;
895 else cls.latency += 0.001; // drift up, so correction are needed
896 }
897 }
898
899 /*
900 =====================
901 CL_NewTranslation
902 =====================
903 */
CL_NewTranslation(int slot)904 static void CL_NewTranslation (int slot)
905 {
906 #ifdef GLQUAKE
907 if (slot >= MAX_CLIENTS)
908 Sys_Error ("%s: slot > MAX_CLIENTS", __thisfunc__);
909
910 R_TranslatePlayerSkin(slot);
911 #else
912
913 int i, j;
914 int top, bottom;
915 byte *dest, *source, *sourceA, *sourceB, *colorA, *colorB;
916 player_info_t *player;
917
918 if (slot >= MAX_CLIENTS)
919 Sys_Error ("%s: slot > MAX_CLIENTS", __thisfunc__);
920
921 player = &cl.players[slot];
922 if (!player->playerclass)
923 return;
924
925 dest = player->translations;
926 source = vid.colormap;
927 memcpy (dest, vid.colormap, sizeof(player->translations));
928
929 top = player->topcolor;
930 if (top > 10 || top < 0)
931 top = 10;
932 bottom = player->bottomcolor;
933 if (bottom > 10 || bottom < 0)
934 bottom = 10;
935 top -= 1;
936 bottom -= 1;
937
938 for (i = 0; i < VID_GRADES; i++, dest += 256, source += 256)
939 {
940 colorA = playerTranslation + 256 + color_offsets[(int)player->playerclass-1];
941 colorB = colorA + 256;
942 sourceA = colorB + 256 + (top * 256);
943 sourceB = colorB + 256 + (bottom * 256);
944 for (j = 0; j < 256; j++, colorA++, colorB++, sourceA++, sourceB++)
945 {
946 if (top >= 0 && (*colorA != 255))
947 dest[j] = source[*sourceA];
948 if (bottom >= 0 && (*colorB != 255))
949 dest[j] = source[*sourceB];
950 }
951 }
952 #endif
953 }
954
955 /*
956 ==============
957 CL_UpdateUserinfo
958 ==============
959 */
CL_UpdateUserinfo(void)960 static void CL_UpdateUserinfo (void)
961 {
962 int slot;
963 player_info_t *player;
964
965 slot = MSG_ReadByte ();
966 if (slot >= MAX_CLIENTS)
967 Host_EndGame ("%s: svc_updateuserinfo > MAX_CLIENTS", __thisfunc__);
968
969 player = &cl.players[slot];
970 player->userid = MSG_ReadLong ();
971 q_strlcpy (player->userinfo, MSG_ReadString(), sizeof(player->userinfo));
972
973 q_strlcpy (player->name, Info_ValueForKey (player->userinfo, "name"), sizeof(player->name));
974 player->topcolor = atoi(Info_ValueForKey (player->userinfo, "topcolor"));
975 player->bottomcolor = atoi(Info_ValueForKey (player->userinfo, "bottomcolor"));
976 if (Info_ValueForKey (player->userinfo, "*spectator")[0])
977 player->spectator = true;
978 else player->spectator = false;
979
980 if (cls.state == ca_active)
981 Skin_Find (player);
982
983 player->playerclass = atoi(Info_ValueForKey (player->userinfo, "playerclass"));
984 /*
985 if (cl.playernum == slot && player->playerclass != playerclass.integer)
986 Cvar_SetValue ("playerclass",player->playerclass);
987 */
988 Sbar_Changed ();
989 player->Translated = false;
990 CL_NewTranslation (slot);
991 }
992
993
994 /*
995 =====================
996 CL_SetStat
997 =====================
998 */
CL_SetStat(int idx,int value)999 static void CL_SetStat (int idx, int value)
1000 {
1001 int j;
1002
1003 if (idx < 0 || idx >= MAX_CL_STATS)
1004 Sys_Error ("%s: %i is invalid", __thisfunc__, idx);
1005
1006 Sbar_Changed ();
1007
1008 if (idx == STAT_ITEMS)
1009 { // set flash times
1010 Sbar_Changed ();
1011 for (j = 0; j < 32; j++)
1012 if ((value & (1<<j)) && !(cl.stats[idx] & (1<<j)))
1013 cl.item_gettime[j] = cl.time;
1014 }
1015
1016 cl.stats[idx] = value;
1017 }
1018
1019 /*
1020 ==============
1021 CL_MuzzleFlash
1022 ==============
1023 */
CL_MuzzleFlash(void)1024 static void CL_MuzzleFlash (void)
1025 {
1026 vec3_t fv, rv, uv;
1027 dlight_t *dl;
1028 int i;
1029 player_state_t *pl;
1030
1031 i = MSG_ReadShort ();
1032
1033 if ((unsigned int)(i - 1) >= MAX_CLIENTS)
1034 return;
1035 #ifdef GLQUAKE
1036 // don't draw our own muzzle flash in gl if flashblending
1037 if (i - 1 == cl.playernum && gl_flashblend.integer)
1038 return;
1039 #endif
1040 pl = &cl.frames[parsecountmod].playerstate[i-1];
1041
1042 dl = CL_AllocDlight (i);
1043 VectorCopy (pl->origin, dl->origin);
1044 AngleVectors (pl->viewangles, fv, rv, uv);
1045
1046 VectorMA (dl->origin, 18, fv, dl->origin);
1047 dl->radius = 200 + (rand() & 31);
1048 dl->minlight = 32;
1049 dl->die = cl.time + 0.1;
1050 dl->color[0] = 0.2;
1051 dl->color[1] = 0.1;
1052 dl->color[2] = 0.05;
1053 dl->color[3] = 0.7;
1054 }
1055
CL_Plaque(void)1056 static void CL_Plaque(void)
1057 {
1058 int idx;
1059
1060 idx = MSG_ReadShort ();
1061
1062 if (idx > 0 && idx <= host_string_count)
1063 SCR_SetPlaqueMessage (Host_GetString(idx - 1));
1064 else SCR_SetPlaqueMessage ("");
1065 }
1066
CL_IndexedPrint(void)1067 static void CL_IndexedPrint(void)
1068 {
1069 int idx, i;
1070
1071 i = MSG_ReadByte ();
1072 if (i == PRINT_CHAT)
1073 {
1074 S_LocalSound ("misc/talk.wav");
1075 con_ormask = 256;
1076 }
1077
1078 idx = MSG_ReadShort ();
1079 if (idx > 0 && idx <= host_string_count)
1080 Con_Printf ("%s", Host_GetString(idx - 1));
1081
1082 con_ormask = 0;
1083 }
1084
CL_NamePrint(void)1085 static void CL_NamePrint(void)
1086 {
1087 int idx, i;
1088
1089 i = MSG_ReadByte ();
1090 if (i == PRINT_CHAT)
1091 {
1092 S_LocalSound ("misc/talk.wav");
1093 con_ormask = 256;
1094 }
1095
1096 idx = MSG_ReadByte ();
1097 if (idx >= 0 && idx < MAX_CLIENTS)
1098 Con_Printf ("%s", cl.players[idx].name);
1099
1100 con_ormask = 0;
1101 }
1102
CL_ParticleExplosion(void)1103 static void CL_ParticleExplosion(void)
1104 {
1105 vec3_t org;
1106 short color, radius, counter;
1107
1108 org[0] = MSG_ReadCoord();
1109 org[1] = MSG_ReadCoord();
1110 org[2] = MSG_ReadCoord();
1111 color = MSG_ReadShort();
1112 radius = MSG_ReadShort();
1113 counter = MSG_ReadShort();
1114
1115 R_ColoredParticleExplosion(org,color,radius,counter);
1116 }
1117
1118 #if 0 /* for debugging. from fteqw. */
1119 static void CL_DumpPacket (void)
1120 {
1121 int i, pos;
1122 char *packet = net_message.data;
1123
1124 Con_Printf("%s, BEGIN:\n", __thisfunc__);
1125 pos = 0;
1126 while (pos < net_message.cursize)
1127 {
1128 Con_Printf("%5i ", pos);
1129 for (i = 0; i < 16; i++)
1130 {
1131 if (pos >= net_message.cursize)
1132 Con_Printf(" X ");
1133 else Con_Printf("%2x ", (unsigned char)packet[pos]);
1134 pos++;
1135 }
1136 pos -= 16;
1137 for (i = 0; i < 16; i++)
1138 {
1139 if (pos >= net_message.cursize)
1140 Con_Printf("X");
1141 else if (packet[pos] == 0)
1142 Con_Printf(".");
1143 else Con_Printf("%c", (unsigned char)packet[pos]);
1144 pos++;
1145 }
1146 Con_Printf("\n");
1147 }
1148
1149 Con_Printf("%s, --- END ---\n", __thisfunc__);
1150 }
1151 #endif /* CL_DumpPacket */
1152
1153 #define SHOWNET(S) \
1154 do { \
1155 if (cl_shownet.integer == 2) \
1156 Con_Printf ("%3i:%s\n", msg_readcount-1, (S)); \
1157 } while (0)
1158
1159 /*
1160 =====================
1161 CL_ParseServerMessage
1162 =====================
1163 */
1164 //static int received_framecount;
1165 int LastServerMessageSize = 0;
1166
CL_ParseServerMessage(void)1167 void CL_ParseServerMessage (void)
1168 {
1169 int cmd;
1170 const char *s;
1171 int i, j;
1172 unsigned int sc1, sc2;
1173 byte test;
1174 char temp[100];
1175 vec3_t pos;
1176
1177 LastServerMessageSize += net_message.cursize;
1178
1179 // received_framecount = host_framecount;
1180 cl.last_servermessage = realtime;
1181 CL_ClearProjectiles ();
1182 CL_ClearMissiles ();
1183 v_targDist = 0; // This clears out the target field on each netupdate;
1184 // it won't be drawn unless another update comes...
1185
1186 // if recording demos, copy the message out
1187 if (cl_shownet.integer == 1)
1188 Con_Printf ("%i ",net_message.cursize);
1189 else if (cl_shownet.integer == 2)
1190 Con_Printf ("------------------\n");
1191
1192 CL_ParseClientdata ();
1193
1194 // parse the message
1195 while (1)
1196 {
1197 if (msg_badread)
1198 {
1199 Host_EndGame ("%s: Bad server message", __thisfunc__);
1200 break;
1201 }
1202
1203 cmd = MSG_ReadByte ();
1204 if (cmd == -1)
1205 {
1206 msg_readcount++; // so the EOM showner has the right value
1207 SHOWNET("END OF MESSAGE");
1208 break;
1209 }
1210 if (cmd < (int)NUM_SVC_STRINGS) {
1211 SHOWNET(svc_strings[cmd]);
1212 }
1213
1214 // other commands
1215 switch (cmd)
1216 {
1217 default:
1218 // CL_DumpPacket ();
1219 Host_EndGame ("%s: Illegible server message %d", __thisfunc__, cmd);
1220 break;
1221
1222 case svc_nop:
1223 // Con_Printf ("svc_nop\n");
1224 break;
1225
1226 case svc_disconnect:
1227 Host_EndGame ("Server disconnected\n");
1228 break;
1229
1230 case svc_print:
1231 i = MSG_ReadByte ();
1232 if (i == PRINT_CHAT)
1233 {
1234 S_LocalSound ("misc/talk.wav");
1235 con_ormask = 256;
1236 }
1237 else if (i >= PRINT_SOUND)
1238 {
1239 if (talksounds.integer)
1240 {
1241 q_snprintf (temp, sizeof(temp), "taunt/taunt%.3d.wav", i - PRINT_SOUND + 1);
1242 S_LocalSound (temp);
1243 con_ormask = 256;
1244 }
1245 else
1246 {
1247 MSG_ReadString();
1248 break;
1249 }
1250 }
1251 Con_Printf ("%s", MSG_ReadString ());
1252 con_ormask = 0;
1253 break;
1254
1255 case svc_centerprint:
1256 SCR_CenterPrint (MSG_ReadString ());
1257 break;
1258
1259 case svc_stufftext:
1260 s = MSG_ReadString ();
1261 Con_DPrintf ("stufftext: %s\n", s);
1262 Cbuf_AddText (s);
1263 break;
1264
1265 case svc_damage:
1266 V_ParseDamage ();
1267 break;
1268
1269 case svc_serverdata:
1270 Cbuf_Execute (); // make sure any stuffed commands are done
1271 CL_ParseServerData ();
1272 vid.recalc_refdef = true; // leave full screen intermission
1273 break;
1274
1275 case svc_setangle:
1276 for (i = 0; i < 3; i++)
1277 cl.viewangles[i] = MSG_ReadAngle ();
1278 // cl.viewangles[PITCH] = cl.viewangles[ROLL] = 0;
1279 break;
1280
1281 case svc_lightstyle:
1282 i = MSG_ReadByte ();
1283 if (i >= MAX_LIGHTSTYLES)
1284 Sys_Error ("svc_lightstyle > MAX_LIGHTSTYLES");
1285 q_strlcpy (cl_lightstyle[i].map, MSG_ReadString(), MAX_STYLESTRING);
1286 cl_lightstyle[i].length = strlen(cl_lightstyle[i].map);
1287 break;
1288
1289 case svc_sound:
1290 CL_ParseStartSoundPacket();
1291 break;
1292
1293 case svc_sound_update_pos:
1294 { // FIXME: put a field on the entity that lists the channels
1295 // it should update when it moves- if a certain flag
1296 // is on the ent, this update_channels field could
1297 // be set automatically by each sound and stopSound
1298 // called for this ent?
1299 int channel, ent_num;
1300
1301 channel = MSG_ReadShort ();
1302
1303 ent_num = channel >> 3;
1304 channel &= 7;
1305
1306 if (ent_num > MAX_EDICTS)
1307 Host_Error ("svc_sound_update_pos: ent = %i", ent_num);
1308
1309 for (i = 0; i < 3; i++)
1310 pos[i] = MSG_ReadCoord ();
1311
1312 S_UpdateSoundPos (ent_num, channel, pos);
1313 } break;
1314
1315 case svc_stopsound:
1316 i = MSG_ReadShort();
1317 S_StopSound(i>>3, i&7);
1318 break;
1319
1320 case svc_updatefrags:
1321 Sbar_Changed ();
1322 i = MSG_ReadByte ();
1323 if (i >= MAX_CLIENTS)
1324 Host_EndGame ("%s: svc_updatefrags > MAX_CLIENTS", __thisfunc__);
1325 cl.players[i].frags = MSG_ReadShort ();
1326 break;
1327
1328 case svc_updateping:
1329 i = MSG_ReadByte ();
1330 if (i >= MAX_CLIENTS)
1331 Host_EndGame ("%s: svc_updateping > MAX_CLIENTS", __thisfunc__);
1332 cl.players[i].ping = MSG_ReadShort ();
1333 break;
1334
1335 case svc_updateentertime:
1336 // time is sent over as seconds ago
1337 i = MSG_ReadByte ();
1338 if (i >= MAX_CLIENTS)
1339 Host_EndGame ("%s: svc_updateentertime > MAX_CLIENTS", __thisfunc__);
1340 cl.players[i].entertime = realtime - MSG_ReadFloat ();
1341 break;
1342
1343 case svc_updatepclass:
1344 // playerclass has changed for this dude
1345 i = MSG_ReadByte ();
1346 if (i >= MAX_CLIENTS)
1347 Host_EndGame ("%s: svc_updatepclass > MAX_CLIENTS", __thisfunc__);
1348 cl.players[i].playerclass = MSG_ReadByte ();
1349 cl.players[i].level = cl.players[i].playerclass&31;
1350 cl.players[i].playerclass = cl.players[i].playerclass>>5;
1351 break;
1352
1353 case svc_updatedminfo:
1354 // This dude killed someone, update his frags and level
1355 i = MSG_ReadByte ();
1356 if (i >= MAX_CLIENTS)
1357 Host_EndGame ("%s: svc_updatedminfo > MAX_CLIENTS", __thisfunc__);
1358 cl.players[i].frags = MSG_ReadShort ();
1359 cl.players[i].playerclass = MSG_ReadByte ();
1360 cl.players[i].level = cl.players[i].playerclass&31;
1361 cl.players[i].playerclass = cl.players[i].playerclass>>5;
1362 break;
1363
1364 case svc_updatesiegelosses:
1365 // This dude killed someone, update his frags and level
1366 defLosses = MSG_ReadByte ();
1367 attLosses = MSG_ReadByte ();
1368 break;
1369
1370 case svc_updatesiegeteam:
1371 // This dude killed someone, update his frags and level
1372 i = MSG_ReadByte ();
1373 if (i >= MAX_CLIENTS)
1374 Host_EndGame ("%s: svc_updatesiegeteam > MAX_CLIENTS", __thisfunc__);
1375 cl.players[i].siege_team = MSG_ReadByte ();
1376 break;
1377
1378 case svc_updatesiegeinfo:
1379 // We are on a siege server, set cl_siege
1380 cl_siege = true;
1381 cl_timelimit = MSG_ReadByte () * 60;
1382 cl_fraglimit = MSG_ReadByte ();
1383 break;
1384
1385 case svc_haskey:
1386 cl_keyholder = MSG_ReadShort() - 1;
1387 break;
1388
1389 case svc_isdoc:
1390 cl_doc = MSG_ReadShort() - 1;
1391 break;
1392
1393 case svc_nonehaskey:
1394 cl_keyholder = -1;
1395 break;
1396
1397 case svc_nodoc:
1398 cl_doc = -1;
1399 break;
1400
1401 case svc_time:
1402 cl_server_time_offset = ((int)MSG_ReadFloat()) - cl.time;
1403 break;
1404
1405 case svc_spawnbaseline:
1406 i = MSG_ReadShort ();
1407 CL_ParseBaseline (&cl_baselines[i]);
1408 break;
1409 case svc_spawnstatic:
1410 CL_ParseStatic ();
1411 break;
1412 case svc_temp_entity:
1413 CL_ParseTEnt ();
1414 break;
1415
1416 case svc_killedmonster:
1417 cl.stats[STAT_MONSTERS]++;
1418 break;
1419
1420 case svc_foundsecret:
1421 cl.stats[STAT_SECRETS]++;
1422 break;
1423
1424 case svc_updatestat:
1425 i = MSG_ReadByte ();
1426 j = MSG_ReadByte ();
1427 CL_SetStat (i, j);
1428 break;
1429 case svc_updatestatlong:
1430 i = MSG_ReadByte ();
1431 j = MSG_ReadLong ();
1432 CL_SetStat (i, j);
1433 break;
1434
1435 case svc_spawnstaticsound:
1436 CL_ParseStaticSound ();
1437 break;
1438
1439 case svc_cdtrack:
1440 cl.cdtrack = MSG_ReadByte ();
1441 if (q_strcasecmp(bgmtype.string,"cd") != 0)
1442 CDAudio_Stop ();
1443 else CDAudio_Play ((byte)cl.cdtrack, true);
1444 break;
1445
1446 case svc_midi_name:
1447 q_strlcpy (cl.midi_name, MSG_ReadString(), sizeof(cl.midi_name));
1448 if (q_strcasecmp(bgmtype.string,"midi") != 0)
1449 BGM_Stop();
1450 else BGM_PlayMIDIorMusic(cl.midi_name);
1451 break;
1452
1453 case svc_intermission:
1454 /*
1455 if (cl_siege) {//MG
1456 */
1457 CL_SetupIntermission (MSG_ReadByte());
1458 vid.recalc_refdef = true; // go to full screen
1459 break;
1460 /*
1461 } else { // Old Quake way- won't work
1462 cl.intermission = 1;
1463 cl.completed_time = realtime;
1464 vid.recalc_refdef = true; // go to full screen
1465 for (i = 0; i < 3; i++)
1466 cl.simorg[i] = MSG_ReadCoord ();
1467 for (i = 0; i < 3; i++)
1468 cl.simangles[i] = MSG_ReadAngle ();
1469 VectorClear (cl.simvel);
1470 break;
1471 }
1472 */
1473 case svc_finale:
1474 cl.intermission = 2;
1475 cl.completed_time = realtime;
1476 vid.recalc_refdef = true; // go to full screen
1477 SCR_CenterPrint (MSG_ReadString ());
1478 break;
1479
1480 case svc_sellscreen:
1481 Cmd_ExecuteString ("help", src_command);
1482 break;
1483
1484 case svc_smallkick:
1485 cl.punchangle = -2;
1486 break;
1487 case svc_bigkick:
1488 cl.punchangle = -4;
1489 break;
1490
1491 case svc_muzzleflash:
1492 CL_MuzzleFlash ();
1493 break;
1494
1495 case svc_updateuserinfo:
1496 CL_UpdateUserinfo ();
1497 break;
1498
1499 case svc_download:
1500 CL_ParseDownload ();
1501 break;
1502
1503 case svc_playerinfo:
1504 CL_ParsePlayerinfo ();
1505 break;
1506
1507 case svc_playerskipped:
1508 CL_SavePlayer ();
1509 break;
1510
1511 case svc_nails:
1512 CL_ParseProjectiles ();
1513 break;
1514
1515 case svc_packmissile:
1516 CL_ParsePackMissiles ();
1517 break;
1518
1519 case svc_chokecount: // some preceding packets were choked
1520 i = MSG_ReadByte ();
1521 for (j = 0; j < i; j++)
1522 cl.frames[ (cls.netchan.incoming_acknowledged-1-j)&UPDATE_MASK ].receivedtime = -2;
1523 break;
1524
1525 case svc_modellist:
1526 if (cl.protocol >= PROTOCOL_VERSION_EXT) /* from QW */
1527 {
1528 CL_ParseModellistChunks ();
1529 break;
1530 }
1531 CL_ParseModellist ();
1532 break;
1533
1534 case svc_soundlist:
1535 if (cl.protocol >= PROTOCOL_VERSION_EXT) /* from QW */
1536 {
1537 CL_ParseSoundlistChunks ();
1538 break;
1539 }
1540 CL_ParseSoundlist ();
1541 break;
1542
1543 case svc_packetentities:
1544 CL_ParsePacketEntities (false);
1545 break;
1546
1547 case svc_deltapacketentities:
1548 CL_ParsePacketEntities (true);
1549 break;
1550
1551 case svc_maxspeed :
1552 movevars.maxspeed = MSG_ReadFloat();
1553 break;
1554
1555 case svc_entgravity :
1556 movevars.entgravity = MSG_ReadFloat();
1557 break;
1558
1559 case svc_plaque:
1560 CL_Plaque();
1561 break;
1562
1563 case svc_indexed_print:
1564 CL_IndexedPrint();
1565 break;
1566
1567 case svc_name_print:
1568 CL_NamePrint();
1569 break;
1570
1571 case svc_particle_explosion:
1572 CL_ParticleExplosion();
1573 break;
1574
1575 case svc_set_view_tint:
1576 i = MSG_ReadByte();
1577 // cl.viewent.colorshade = i;
1578 break;
1579
1580 case svc_start_effect:
1581 CL_ParseEffect();
1582 break;
1583
1584 case svc_end_effect:
1585 CL_EndEffect();
1586 break;
1587
1588 case svc_set_view_flags:
1589 cl.viewent.drawflags |= MSG_ReadByte();
1590 break;
1591
1592 case svc_clear_view_flags:
1593 cl.viewent.drawflags &= ~MSG_ReadByte();
1594 break;
1595
1596 case svc_update_inv:
1597 sc1 = sc2 = 0;
1598
1599 test = MSG_ReadByte();
1600 if (test & 1)
1601 sc1 |= ((int)MSG_ReadByte());
1602 if (test & 2)
1603 sc1 |= ((int)MSG_ReadByte())<<8;
1604 if (test & 4)
1605 sc1 |= ((int)MSG_ReadByte())<<16;
1606 if (test & 8)
1607 sc1 |= ((int)MSG_ReadByte())<<24;
1608 if (test & 16)
1609 sc2 |= ((int)MSG_ReadByte());
1610 if (test & 32)
1611 sc2 |= ((int)MSG_ReadByte())<<8;
1612 if (test & 64)
1613 sc2 |= ((int)MSG_ReadByte())<<16;
1614 if (test & 128)
1615 sc2 |= ((int)MSG_ReadByte())<<24;
1616
1617 if (sc1 & SC1_HEALTH)
1618 cl.v.health = MSG_ReadShort();
1619 if (sc1 & SC1_LEVEL)
1620 cl.v.level = MSG_ReadByte();
1621 if (sc1 & SC1_INTELLIGENCE)
1622 cl.v.intelligence = MSG_ReadByte();
1623 if (sc1 & SC1_WISDOM)
1624 cl.v.wisdom = MSG_ReadByte();
1625 if (sc1 & SC1_STRENGTH)
1626 cl.v.strength = MSG_ReadByte();
1627 if (sc1 & SC1_DEXTERITY)
1628 cl.v.dexterity = MSG_ReadByte();
1629 // if (sc1 & SC1_WEAPON)
1630 // cl.v.weapon = MSG_ReadByte();
1631 if (sc1 & SC1_TELEPORT_TIME)
1632 {
1633 // Con_Printf("Teleport_time>time, got bit\n");
1634 cl.v.teleport_time = realtime + 2; // can't airmove for 2s
1635 }
1636
1637 if (sc1 & SC1_BLUEMANA)
1638 cl.v.bluemana = MSG_ReadByte();
1639 if (sc1 & SC1_GREENMANA)
1640 cl.v.greenmana = MSG_ReadByte();
1641 if (sc1 & SC1_EXPERIENCE)
1642 cl.v.experience = MSG_ReadLong();
1643 if (sc1 & SC1_CNT_TORCH)
1644 cl.v.cnt_torch = MSG_ReadByte();
1645 if (sc1 & SC1_CNT_H_BOOST)
1646 cl.v.cnt_h_boost = MSG_ReadByte();
1647 if (sc1 & SC1_CNT_SH_BOOST)
1648 cl.v.cnt_sh_boost = MSG_ReadByte();
1649 if (sc1 & SC1_CNT_MANA_BOOST)
1650 cl.v.cnt_mana_boost = MSG_ReadByte();
1651 if (sc1 & SC1_CNT_TELEPORT)
1652 cl.v.cnt_teleport = MSG_ReadByte();
1653 if (sc1 & SC1_CNT_TOME)
1654 cl.v.cnt_tome = MSG_ReadByte();
1655 if (sc1 & SC1_CNT_SUMMON)
1656 cl.v.cnt_summon = MSG_ReadByte();
1657 if (sc1 & SC1_CNT_INVISIBILITY)
1658 cl.v.cnt_invisibility = MSG_ReadByte();
1659 if (sc1 & SC1_CNT_GLYPH)
1660 cl.v.cnt_glyph = MSG_ReadByte();
1661 if (sc1 & SC1_CNT_HASTE)
1662 cl.v.cnt_haste = MSG_ReadByte();
1663 if (sc1 & SC1_CNT_BLAST)
1664 cl.v.cnt_blast = MSG_ReadByte();
1665 if (sc1 & SC1_CNT_POLYMORPH)
1666 cl.v.cnt_polymorph = MSG_ReadByte();
1667 if (sc1 & SC1_CNT_FLIGHT)
1668 cl.v.cnt_flight = MSG_ReadByte();
1669 if (sc1 & SC1_CNT_CUBEOFFORCE)
1670 cl.v.cnt_cubeofforce = MSG_ReadByte();
1671 if (sc1 & SC1_CNT_INVINCIBILITY)
1672 cl.v.cnt_invincibility = MSG_ReadByte();
1673 if (sc1 & SC1_ARTIFACT_ACTIVE)
1674 cl.v.artifact_active = MSG_ReadByte();
1675 if (sc1 & SC1_ARTIFACT_LOW)
1676 cl.v.artifact_low = MSG_ReadByte();
1677 if (sc1 & SC1_MOVETYPE)
1678 cl.v.movetype = MSG_ReadByte();
1679 if (sc1 & SC1_CAMERAMODE)
1680 cl.v.cameramode = MSG_ReadByte();
1681 if (sc1 & SC1_HASTED)
1682 cl.v.hasted = MSG_ReadFloat();
1683 if (sc1 & SC1_INVENTORY)
1684 cl.v.inventory = MSG_ReadByte();
1685 if (sc1 & SC1_RINGS_ACTIVE)
1686 cl.v.rings_active = MSG_ReadByte();
1687
1688 if (sc2 & SC2_RINGS_LOW)
1689 cl.v.rings_low = MSG_ReadByte();
1690 if (sc2 & SC2_AMULET)
1691 cl.v.armor_amulet = MSG_ReadByte();
1692 if (sc2 & SC2_BRACER)
1693 cl.v.armor_bracer = MSG_ReadByte();
1694 if (sc2 & SC2_BREASTPLATE)
1695 cl.v.armor_breastplate = MSG_ReadByte();
1696 if (sc2 & SC2_HELMET)
1697 cl.v.armor_helmet = MSG_ReadByte();
1698 if (sc2 & SC2_FLIGHT_T)
1699 cl.v.ring_flight = MSG_ReadByte();
1700 if (sc2 & SC2_WATER_T)
1701 cl.v.ring_water = MSG_ReadByte();
1702 if (sc2 & SC2_TURNING_T)
1703 cl.v.ring_turning = MSG_ReadByte();
1704 if (sc2 & SC2_REGEN_T)
1705 cl.v.ring_regeneration = MSG_ReadByte();
1706 // if (sc2 & SC2_HASTE_T)
1707 // cl.v.haste_time = MSG_ReadFloat();
1708 // if (sc2 & SC2_TOME_T)
1709 // cl.v.tome_time = MSG_ReadFloat();
1710 if (sc2 & SC2_PUZZLE1)
1711 q_snprintf(cl.puzzle_pieces[0], sizeof(cl.puzzle_pieces[0]), "%.9s", MSG_ReadString());
1712 if (sc2 & SC2_PUZZLE2)
1713 q_snprintf(cl.puzzle_pieces[1], sizeof(cl.puzzle_pieces[0]), "%.9s", MSG_ReadString());
1714 if (sc2 & SC2_PUZZLE3)
1715 q_snprintf(cl.puzzle_pieces[2], sizeof(cl.puzzle_pieces[0]), "%.9s", MSG_ReadString());
1716 if (sc2 & SC2_PUZZLE4)
1717 q_snprintf(cl.puzzle_pieces[3], sizeof(cl.puzzle_pieces[0]), "%.9s", MSG_ReadString());
1718 if (sc2 & SC2_PUZZLE5)
1719 q_snprintf(cl.puzzle_pieces[4], sizeof(cl.puzzle_pieces[0]), "%.9s", MSG_ReadString());
1720 if (sc2 & SC2_PUZZLE6)
1721 q_snprintf(cl.puzzle_pieces[5], sizeof(cl.puzzle_pieces[0]), "%.9s", MSG_ReadString());
1722 if (sc2 & SC2_PUZZLE7)
1723 q_snprintf(cl.puzzle_pieces[6], sizeof(cl.puzzle_pieces[0]), "%.9s", MSG_ReadString());
1724 if (sc2 & SC2_PUZZLE8)
1725 q_snprintf(cl.puzzle_pieces[7], sizeof(cl.puzzle_pieces[0]), "%.9s", MSG_ReadString());
1726 if (sc2 & SC2_MAXHEALTH)
1727 cl.v.max_health = MSG_ReadShort();
1728 if (sc2 & SC2_MAXMANA)
1729 cl.v.max_mana = MSG_ReadByte();
1730 if (sc2 & SC2_FLAGS)
1731 cl.v.flags = MSG_ReadFloat();
1732
1733 if ((sc1 & SC1_STAT_BAR) || (sc2 & SC2_STAT_BAR))
1734 Sbar_Changed();
1735
1736 if ((sc1 & SC1_INV) || (sc2 & SC2_INV))
1737 SB_InvChanged();
1738 break;
1739
1740 case svc_particle:
1741 R_ParseParticleEffect ();
1742 break;
1743 case svc_particle2:
1744 R_ParseParticleEffect2 ();
1745 break;
1746 case svc_particle3:
1747 R_ParseParticleEffect3 ();
1748 break;
1749 case svc_particle4:
1750 R_ParseParticleEffect4 ();
1751 break;
1752 case svc_turn_effect:
1753 CL_TurnEffect ();
1754 break;
1755 case svc_update_effect:
1756 CL_ReviseEffect();
1757 break;
1758
1759 case svc_multieffect:
1760 CL_ParseMultiEffect();
1761 break;
1762
1763 case svc_raineffect:
1764 R_ParseRainEffect();
1765 break;
1766
1767 case svc_targetupdate:
1768 V_ParseTarget();
1769 break;
1770
1771 case svc_update_piv:
1772 cl.PIV = MSG_ReadLong();
1773 break;
1774
1775 case svc_player_sound:
1776 test = MSG_ReadByte();
1777 pos[0] = MSG_ReadCoord();
1778 pos[1] = MSG_ReadCoord();
1779 pos[2] = MSG_ReadCoord();
1780 i = MSG_ReadShort ();
1781 S_StartSound(test, 1, cl.sound_precache[i], pos, 1.0, 1.0);
1782 break;
1783 }
1784 }
1785
1786 CL_SetSolidEntities ();
1787 }
1788
1789