1 /*
2 cl_parse.c
3
4 parse a message received from the server
5
6 Copyright (C) 1996-1997 Id Software, Inc.
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but 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
20 along with this program; if not, write to:
21
22 Free Software Foundation, Inc.
23 59 Temple Place - Suite 330
24 Boston, MA 02111-1307, USA
25
26 */
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #ifdef HAVE_STRING_H
32 # include <string.h>
33 #endif
34 #ifdef HAVE_STRINGS_H
35 # include <strings.h>
36 #endif
37
38 #include "QF/cbuf.h"
39 #include "QF/cdaudio.h"
40 #include "QF/cmd.h"
41 #include "QF/console.h"
42 #include "QF/cvar.h"
43 #include "QF/dstring.h"
44 #include "QF/idparse.h"
45 #include "QF/input.h"
46 #include "QF/msg.h"
47 #include "QF/qfplist.h"
48 #include "QF/sys.h"
49 #include "QF/screen.h"
50 #include "QF/skin.h"
51 #include "QF/sound.h" // FIXME: DEFAULT_SOUND_PACKET_*
52 #include "QF/va.h"
53
54 #include "QF/plugin/vid_render.h"
55
56 #include "client.h"
57 #include "compat.h"
58 #include "host.h"
59 #include "sbar.h"
60 #include "server.h"
61 #include "game.h"
62
63 const char *svc_strings[] = {
64 "svc_bad",
65 "svc_nop",
66 "svc_disconnect",
67 "svc_updatestat",
68 "svc_version", // [long] server version
69 "svc_setview", // [short] entity number
70 "svc_sound", // <see code>
71 "svc_time", // [float] server time
72 "svc_print", // [string] null terminated string
73 "svc_stufftext", // [string] stuffed into client's console
74 // buffer the string should be \n terminated
75 "svc_setangle", // [vec3] set view angle to this absolute value
76
77 "svc_serverinfo", // [long] version
78 // [string] signon string
79 // [string]..[0]model cache
80 // [string]...[0]sounds cache
81 // [string]..[0]item cache
82 "svc_lightstyle", // [byte] [string]
83 "svc_updatename", // [byte] [string]
84 "svc_updatefrags", // [byte] [short]
85 "svc_clientdata", // <shortbits + data>
86 "svc_stopsound", // <see code>
87 "svc_updatecolors", // [byte] [byte]
88 "svc_particle", // [vec3] <variable>
89 "svc_damage", // [byte] impact [byte] blood [vec3] from
90
91 "svc_spawnstatic",
92 "OBSOLETE svc_spawnbinary",
93 "svc_spawnbaseline",
94
95 "svc_temp_entity", // <variable>
96 "svc_setpause",
97 "svc_signonnum",
98 "svc_centerprint",
99 "svc_killedmonster",
100 "svc_foundsecret",
101 "svc_spawnstaticsound",
102 "svc_intermission",
103 "svc_finale", // [string] text
104 "svc_cdtrack", // [byte] track [byte] looptrack
105 "svc_sellscreen",
106 "svc_cutscene",
107 // end of iD svc
108 // FIXME switchable extensions?
109 // protocol 666
110 "",
111 "",
112 "svc_skybox",
113 "",
114 "",
115 "svc_bf",
116 "svc_fog",
117 "svc_spawnbaseline2",
118 "svc_spawnstatic2",
119 "svc_spawnstaticsound2",
120 };
121
122 dstring_t *centerprint;
123
124 static void
CL_LoadSky(void)125 CL_LoadSky (void)
126 {
127 plitem_t *item;
128 const char *name = 0;
129
130 if (!cl.worldspawn) {
131 r_funcs->R_LoadSkys (0);
132 return;
133 }
134 if ((item = PL_ObjectForKey (cl.worldspawn, "sky")) // Q2/DarkPlaces
135 || (item = PL_ObjectForKey (cl.worldspawn, "skyname")) // old QF
136 || (item = PL_ObjectForKey (cl.worldspawn, "qlsky"))) /* QuakeLives */ {
137 name = PL_String (item);
138 }
139 r_funcs->R_LoadSkys (name);
140 }
141
142 /*
143 CL_EntityNum
144
145 This error checks and tracks the total number of entities
146 */
147 static entity_state_t *
CL_EntityNum(int num)148 CL_EntityNum (int num)
149 {
150 if (num < 0 || num >= MAX_EDICTS)
151 Host_Error ("CL_EntityNum: %i is an invalid number", num);
152 if (num >= cl.num_entities)
153 cl.num_entities = num + 1;
154
155 return &nq_entstates.baseline[num];
156 }
157
158 static void
CL_ParseStartSoundPacket(void)159 CL_ParseStartSoundPacket (void)
160 {
161 float attenuation;
162 int channel, ent, field_mask, sound_num, volume;
163 vec3_t pos;
164
165 field_mask = MSG_ReadByte (net_message);
166
167 if (field_mask & SND_VOLUME)
168 volume = MSG_ReadByte (net_message);
169 else
170 volume = DEFAULT_SOUND_PACKET_VOLUME;
171
172 if (field_mask & SND_ATTENUATION)
173 attenuation = MSG_ReadByte (net_message) / 64.0;
174 else
175 attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;
176
177 if (field_mask & SND_LARGEENTITY) {
178 ent = MSG_ReadShort (net_message);
179 channel = MSG_ReadByte (net_message);
180 } else {
181 channel = MSG_ReadShort (net_message);
182 ent = channel >> 3;
183 channel &= 7;
184 }
185
186 if (field_mask & SND_LARGESOUND)
187 sound_num = MSG_ReadShort (net_message);
188 else
189 sound_num = MSG_ReadByte (net_message);
190
191 if (sound_num >= MAX_SOUNDS)
192 Host_Error ("CL_ParseStartSoundPacket: %i > MAX_SOUNDS", sound_num);
193 if (ent > MAX_EDICTS)
194 Host_Error ("CL_ParseStartSoundPacket: ent = %i", ent);
195
196 MSG_ReadCoordV (net_message, pos);
197
198 S_StartSound (ent, channel, cl.sound_precache[sound_num], pos,
199 volume / 255.0, attenuation);
200 }
201
202 /*
203 CL_KeepaliveMessage
204
205 When the client is taking a long time to load stuff, send keepalive
206 messages so the server doesn't disconnect.
207 */
208 static void
CL_KeepaliveMessage(void)209 CL_KeepaliveMessage (void)
210 {
211 byte olddata[8192];
212 float time;
213 static float lastmsg;
214 int ret;
215 sizebuf_t old;
216
217 if (sv.active)
218 return; // no need if server is local
219 if (cls.demoplayback)
220 return;
221
222 // read messages from server, should just be nops
223 old = *net_message->message;
224 memcpy (olddata, net_message->message->data,
225 net_message->message->cursize);
226
227 do {
228 ret = CL_GetMessage ();
229 switch (ret) {
230 default:
231 Host_Error ("CL_KeepaliveMessage: CL_GetMessage failed");
232 case 0:
233 break; // nothing waiting
234 case 1:
235 Host_Error ("CL_KeepaliveMessage: received a message");
236 break;
237 case 2:
238 if (MSG_ReadByte (net_message) != svc_nop)
239 Host_Error ("CL_KeepaliveMessage: datagram wasn't a nop");
240 break;
241 }
242 } while (ret);
243
244 *net_message->message = old;
245 memcpy (net_message->message->data, olddata,
246 net_message->message->cursize);
247
248 // check time
249 time = Sys_DoubleTime ();
250 if (time - lastmsg < 5)
251 return;
252 lastmsg = time;
253
254 // write out a nop
255 Sys_Printf ("--> client to server keepalive\n");
256
257 MSG_WriteByte (&cls.message, clc_nop);
258 NET_SendMessage (cls.netcon, &cls.message);
259 SZ_Clear (&cls.message);
260 }
261
262 static void
map_cfg(const char * mapname,int all)263 map_cfg (const char *mapname, int all)
264 {
265 char *name = malloc (strlen (mapname) + 4 + 1);
266 cbuf_t *cbuf = Cbuf_New (&id_interp);
267 QFile *f;
268
269 QFS_StripExtension (mapname, name);
270 strcat (name, ".cfg");
271 QFS_FOpenFile (name, &f);
272 if (f) {
273 Qclose (f);
274 Cmd_Exec_File (cbuf, name, 1);
275 } else {
276 Cmd_Exec_File (cbuf, "maps_default.cfg", 1);
277 }
278 if (all) {
279 Cbuf_Execute_Stack (cbuf);
280 } else {
281 Cbuf_Execute_Sets (cbuf);
282 }
283 free (name);
284 Cbuf_Delete (cbuf);
285 }
286
287 static plitem_t *
map_ent(const char * mapname)288 map_ent (const char *mapname)
289 {
290 static progs_t edpr;
291 char *name = malloc (strlen (mapname) + 4 + 1);
292 char *buf;
293 plitem_t *edicts = 0;
294
295 QFS_StripExtension (mapname, name);
296 strcat (name, ".ent");
297 if ((buf = (char *) QFS_LoadFile (name, 0))) {
298 edicts = ED_Parse (&edpr, buf);
299 free (buf);
300 } else {
301 edicts = ED_Parse (&edpr, cl.model_precache[1]->entities);
302 }
303 free (name);
304 return edicts;
305 }
306
307 static void
CL_NewMap(const char * mapname)308 CL_NewMap (const char *mapname)
309 {
310 r_funcs->R_NewMap (cl.worldmodel, cl.model_precache, cl.nummodels);
311 Con_NewMap ();
312 Hunk_Check (); // make sure nothing is hurt
313 Sbar_CenterPrint (0);
314
315 if (cl.model_precache[1] && cl.model_precache[1]->entities) {
316 cl.edicts = map_ent (mapname);
317 if (cl.edicts) {
318 cl.worldspawn = PL_ObjectAtIndex (cl.edicts, 0);
319 CL_LoadSky ();
320 if (r_funcs->Fog_ParseWorldspawn)
321 r_funcs->Fog_ParseWorldspawn (cl.worldspawn);
322 }
323 }
324
325 map_cfg (mapname, 1);
326 }
327
328 static void
CL_ParseServerInfo(void)329 CL_ParseServerInfo (void)
330 {
331 char model_precache[MAX_MODELS][MAX_QPATH];
332 char sound_precache[MAX_SOUNDS][MAX_QPATH];
333 const char *str;
334 int i;
335
336 Sys_MaskPrintf (SYS_DEV, "Serverinfo packet received.\n");
337
338 S_BlockSound ();
339 S_StopAllSounds ();
340
341 // wipe the client_state_t struct
342 CL_ClearState ();
343
344 // parse protocol version number
345 i = MSG_ReadLong (net_message);
346 if (i != PROTOCOL_NETQUAKE && i!= PROTOCOL_FITZQUAKE) {
347 Host_Error ("Server returned version %i, not %i or %i\n", i,
348 PROTOCOL_NETQUAKE, PROTOCOL_FITZQUAKE);
349 goto done;
350 }
351 cl.protocol = i;
352 if (cl.protocol == PROTOCOL_FITZQUAKE)
353 write_angles = MSG_WriteAngle16V;
354 else
355 write_angles = MSG_WriteAngleV;
356 // parse maxclients
357 cl.maxclients = MSG_ReadByte (net_message);
358 if (cl.maxclients < 1 || cl.maxclients > MAX_SCOREBOARD) {
359 Sys_Printf ("Bad maxclients (%u) from server\n", cl.maxclients);
360 goto done;
361 }
362 cl.scores = Hunk_AllocName (cl.maxclients * sizeof (*cl.scores), "scores");
363 for (i = 0; i < cl.maxclients; i++) {
364 cl.scores[i].info = Info_ParseString ("name\\", 0, 0);
365 cl.scores[i].name = Info_Key (cl.scores[i].info, "name");
366 cl.scores[i].topcolor = 0;
367 cl.scores[i].bottomcolor = 0;
368 }
369
370 // parse gametype
371 cl.gametype = MSG_ReadByte (net_message);
372
373 // parse signon message
374 str = MSG_ReadString (net_message);
375 strncpy (cl.levelname, str, sizeof (cl.levelname) - 1);
376
377 // separate the printfs so the server message can have a color
378 Sys_Printf ("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36"
379 "\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n"
380 "\n");
381 Sys_Printf ("%c%s\n", 2, str);
382
383 // first we go through and touch all of the precache data that still
384 // happens to be in the cache, so precaching something else doesn't
385 // needlessly purge it
386
387 // precache models
388 memset (cl.model_precache, 0, sizeof (cl.model_precache));
389 for (cl.nummodels = 1;; cl.nummodels++) {
390 str = MSG_ReadString (net_message);
391 if (!str[0])
392 break;
393 if (cl.nummodels >= MAX_MODELS) {
394 Sys_Printf ("Server sent too many model precaches\n");
395 goto done;
396 }
397 strcpy (model_precache[cl.nummodels], str);
398 Mod_TouchModel (str);
399 }
400
401 // precache sounds
402 memset (cl.sound_precache, 0, sizeof (cl.sound_precache));
403 for (cl.numsounds = 1;; cl.numsounds++) {
404 str = MSG_ReadString (net_message);
405 if (!str[0])
406 break;
407 if (cl.numsounds >= MAX_SOUNDS) {
408 Sys_Printf ("Server sent too many sound precaches\n");
409 goto done;
410 }
411 strcpy (sound_precache[cl.numsounds], str);
412 }
413
414 // now we try to load everything else until a cache allocation fails
415 if (model_precache[1])
416 map_cfg (model_precache[1], 0);
417
418 for (i = 1; i < cl.nummodels; i++) {
419 cl.model_precache[i] = Mod_ForName (model_precache[i], false);
420 if (cl.model_precache[i] == NULL) {
421 Sys_Printf ("Model %s not found\n", model_precache[i]);
422 goto done;
423 }
424 CL_KeepaliveMessage ();
425 }
426
427 for (i = 1; i < cl.numsounds; i++) {
428 cl.sound_precache[i] = S_PrecacheSound (sound_precache[i]);
429 CL_KeepaliveMessage ();
430 }
431
432 // local state
433 cl_entities[0].model = cl.worldmodel = cl.model_precache[1];
434 if (!centerprint)
435 centerprint = dstring_newstr ();
436 else
437 dstring_clearstr (centerprint);
438 CL_NewMap (model_precache[1]);
439
440 Hunk_Check (); // make sure nothing is hurt
441
442 noclip_anglehack = false; // noclip is turned off at start
443 r_data->gravity = 800.0; // Set up gravity for renderer effects
444 done:
445 S_UnblockSound ();
446 }
447
448 int bitcounts[16];
449
450 /*
451 CL_ParseUpdate
452
453 Parse an entity update message from the server
454 If an entities model or origin changes from frame to frame, it must be
455 relinked. Other attributes can change without relinking.
456 */
457 static void
CL_ParseUpdate(int bits)458 CL_ParseUpdate (int bits)
459 {
460 entity_state_t *baseline;
461 entity_state_t *state;
462 int modnum, num, i;
463 qboolean forcelink;
464
465 if (cls.signon == so_begin) {
466 // first update is the final signon stage
467 cls.signon = so_active;
468 CL_SignonReply ();
469 }
470
471 if (bits & U_MOREBITS) {
472 i = MSG_ReadByte (net_message);
473 bits |= (i << 8);
474 }
475
476 if (cl.protocol == PROTOCOL_FITZQUAKE) {
477 if (bits & U_EXTEND1)
478 bits |= MSG_ReadByte(net_message) << 16;
479 if (bits & U_EXTEND2)
480 bits |= MSG_ReadByte(net_message) << 24;
481 }
482
483 if (bits & U_LONGENTITY)
484 num = MSG_ReadShort (net_message);
485 else
486 num = MSG_ReadByte (net_message);
487
488 baseline = CL_EntityNum (num);
489 state = &nq_entstates.frame[0 + cl.mindex][num];
490
491 for (i = 0; i < 16; i++)
492 if (bits & (1 << i))
493 bitcounts[i]++;
494
495 if (cl_msgtime[num] != cl.mtime[1])
496 forcelink = true; // no previous frame to lerp from
497 else
498 forcelink = false;
499
500 cl_msgtime[num] = cl.mtime[0];
501
502 if (bits & U_MODEL) {
503 modnum = MSG_ReadByte (net_message);
504 if (modnum >= MAX_MODELS)
505 Host_Error ("CL_ParseModel: bad modnum");
506 } else
507 modnum = baseline->modelindex;
508
509 if (bits & U_FRAME)
510 state->frame = MSG_ReadByte (net_message);
511 else
512 state->frame = baseline->frame;
513
514 if (bits & U_COLORMAP)
515 state->colormap = MSG_ReadByte (net_message);
516 else
517 state->colormap = baseline->colormap;
518 if (state->colormap > cl.maxclients)
519 Sys_Error ("colormap > cl.maxclients");
520
521 if (bits & U_SKIN)
522 state->skinnum = MSG_ReadByte (net_message);
523 else
524 state->skinnum = baseline->skinnum;
525
526 if (bits & U_EFFECTS)
527 state->effects = MSG_ReadByte (net_message);
528 else
529 state->effects = baseline->effects;
530
531 if (bits & U_ORIGIN1)
532 state->origin[0] = MSG_ReadCoord (net_message);
533 else
534 state->origin[0] = baseline->origin[0];
535 if (bits & U_ANGLE1)
536 state->angles[0] = MSG_ReadAngle (net_message);
537 else
538 state->angles[0] = baseline->angles[0];
539
540 if (bits & U_ORIGIN2)
541 state->origin[1] = MSG_ReadCoord (net_message);
542 else
543 state->origin[1] = baseline->origin[1];
544 if (bits & U_ANGLE2)
545 state->angles[1] = MSG_ReadAngle (net_message);
546 else
547 state->angles[1] = baseline->angles[1];
548
549 if (bits & U_ORIGIN3)
550 state->origin[2] = MSG_ReadCoord (net_message);
551 else
552 state->origin[2] = baseline->origin[2];
553 if (bits & U_ANGLE3)
554 state->angles[2] = MSG_ReadAngle (net_message);
555 else
556 state->angles[2] = baseline->angles[2];
557
558 // if (bits & U_STEP) //FIXME lerping (see fitzquake)
559 // forcelink = true;
560
561 if (cl.protocol == PROTOCOL_FITZQUAKE) {
562 if (bits & U_ALPHA)
563 state->alpha = MSG_ReadByte(net_message);
564 else
565 state->alpha = baseline->alpha;
566 if (bits & U_FRAME2)
567 state->frame |= MSG_ReadByte(net_message) << 8;
568 if (bits & U_MODEL2)
569 modnum |= MSG_ReadByte(net_message) << 8;
570 if (bits & U_LERPFINISH) {
571 MSG_ReadByte (net_message); //FIXME ignored for now. see fitzquake
572 }
573 state->scale = 16;
574 state->glow_size = 0;
575 state->glow_color = 254;
576 state->colormod = 255;
577 } else {
578 baseline->alpha = 255;
579 state->scale = 16;
580 state->glow_size = 0;
581 state->glow_color = 254;
582 state->colormod = 255;
583 }
584
585 state->modelindex = modnum;
586
587 if (forcelink) { // didn't have an update last message
588 //VectorCopy (state->msg_origins[0], state->msg_origins[1]);
589 //VectorCopy (state->msg_origins[0], ent->origin);
590 //VectorCopy (state->msg_angles[0], state->msg_angles[1]);
591 //CL_TransformEntity (ent, state->msg_angles[0], true);
592 //state->forcelink = true;
593 cl_forcelink[num] = true;
594 }
595 }
596
597 static void
CL_ParseBaseline(entity_state_t * baseline,int version)598 CL_ParseBaseline (entity_state_t *baseline, int version)
599 {
600 int bits = 0;
601
602 if (version == 2)
603 bits = MSG_ReadByte (net_message);
604
605 if (bits & B_LARGEMODEL)
606 baseline->modelindex = MSG_ReadShort (net_message);
607 else
608 baseline->modelindex = MSG_ReadByte (net_message);
609
610 if (bits & B_LARGEFRAME)
611 baseline->frame = MSG_ReadShort (net_message);
612 else
613 baseline->frame = MSG_ReadByte (net_message);
614
615 baseline->colormap = MSG_ReadByte (net_message);
616 baseline->skinnum = MSG_ReadByte (net_message);
617
618 MSG_ReadCoordAngleV (net_message, baseline->origin, baseline->angles);
619
620 if (bits & B_ALPHA)
621 baseline->alpha = MSG_ReadByte (net_message);
622 else
623 baseline->alpha = 255;//FIXME alpha
624 baseline->scale = 16;
625 baseline->glow_size = 0;
626 baseline->glow_color = 254;
627 baseline->colormod = 255;
628 }
629
630 /*
631 CL_ParseClientdata
632
633 Server information pertaining to only this client
634 */
635 static void
CL_ParseClientdata(void)636 CL_ParseClientdata (void)
637 {
638 int i, j;
639 int bits;
640
641 bits = MSG_ReadShort (net_message);
642 if (bits & SU_EXTEND1)
643 bits |= MSG_ReadByte (net_message) << 16;
644 if (bits & SU_EXTEND2)
645 bits |= MSG_ReadByte (net_message) << 24;
646
647 if (bits & SU_VIEWHEIGHT)
648 cl.viewheight = ((signed char) MSG_ReadByte (net_message));
649 else
650 cl.viewheight = DEFAULT_VIEWHEIGHT;
651
652 if (bits & SU_IDEALPITCH)
653 cl.idealpitch = ((signed char) MSG_ReadByte (net_message));
654 else
655 cl.idealpitch = 0;
656
657 VectorCopy (cl.mvelocity[0], cl.mvelocity[1]);
658 for (i = 0; i < 3; i++) {
659 if (bits & (SU_PUNCH1 << i))
660 cl.punchangle[i] = ((signed char) MSG_ReadByte (net_message));
661 else
662 cl.punchangle[i] = 0;
663 if (bits & (SU_VELOCITY1 << i))
664 cl.mvelocity[0][i] = ((signed char) MSG_ReadByte (net_message))
665 * 16;
666 else
667 cl.mvelocity[0][i] = 0;
668 }
669
670 //FIXME
671 //if (!VectorCompare (v_punchangles[0], cl.punchangle[0])) {
672 // VectorCopy (v_punchangles[0], v_punchangles[1]);
673 // VectorCopy (cl.punchangle, v_punchangles[0]);
674 //}
675
676 // [always sent] if (bits & SU_ITEMS)
677 i = MSG_ReadLong (net_message);
678
679 if (cl.stats[STAT_ITEMS] != i) { // set flash times
680 Sbar_Changed ();
681 for (j = 0; j < 32; j++)
682 if ((i & (1 << j)) && !(cl.stats[STAT_ITEMS] & (1 << j)))
683 cl.item_gettime[j] = cl.time;
684 cl.stats[STAT_ITEMS] = i;
685 }
686
687 cl.onground = (bits & SU_ONGROUND) ? 0 : -1;
688 cl.inwater = (bits & SU_INWATER) != 0;
689
690 if (bits & SU_WEAPONFRAME)
691 cl.stats[STAT_WEAPONFRAME] = MSG_ReadByte (net_message);
692 else
693 cl.stats[STAT_WEAPONFRAME] = 0;
694
695 if (bits & SU_ARMOR)
696 i = MSG_ReadByte (net_message);
697 else
698 i = 0;
699 if (cl.stats[STAT_ARMOR] != i) {
700 cl.stats[STAT_ARMOR] = i;
701 Sbar_Changed ();
702 }
703
704 if (bits & SU_WEAPON)
705 i = MSG_ReadByte (net_message);
706 else
707 i = 0;
708 if (cl.stats[STAT_WEAPON] != i) {
709 cl.stats[STAT_WEAPON] = i;
710 Sbar_Changed ();
711 }
712
713 i = (short) MSG_ReadShort (net_message);
714 if (cl.stats[STAT_HEALTH] != i) {
715 cl.stats[STAT_HEALTH] = i;
716 Sbar_Changed ();
717 }
718
719 i = MSG_ReadByte (net_message);
720 if (cl.stats[STAT_AMMO] != i) {
721 cl.stats[STAT_AMMO] = i;
722 Sbar_Changed ();
723 }
724
725 for (i = 0; i < 4; i++) {
726 j = MSG_ReadByte (net_message);
727 if (cl.stats[STAT_SHELLS + i] != j) {
728 cl.stats[STAT_SHELLS + i] = j;
729 Sbar_Changed ();
730 }
731 }
732
733 i = MSG_ReadByte (net_message);
734
735 if (standard_quake) {
736 if (cl.stats[STAT_ACTIVEWEAPON] != i) {
737 cl.stats[STAT_ACTIVEWEAPON] = i;
738 Sbar_Changed ();
739 }
740 } else {
741 // hipnotic/rogue weapon "bit field" (stupid idea)
742 if (cl.stats[STAT_ACTIVEWEAPON] != (1 << i)) {
743 cl.stats[STAT_ACTIVEWEAPON] = (1 << i);
744 Sbar_Changed ();
745 }
746 }
747
748 if (bits & SU_WEAPON2)
749 cl.stats[STAT_WEAPON] |= MSG_ReadByte (net_message) << 8;
750 if (bits & SU_ARMOR2)
751 cl.stats[STAT_ARMOR] |= MSG_ReadByte (net_message) << 8;
752 if (bits & SU_AMMO2)
753 cl.stats[STAT_AMMO] |= MSG_ReadByte (net_message) << 8;
754 if (bits & SU_SHELLS2)
755 cl.stats[STAT_SHELLS] |= MSG_ReadByte (net_message) << 8;
756 if (bits & SU_NAILS2)
757 cl.stats[STAT_NAILS] |= MSG_ReadByte (net_message) << 8;
758 if (bits & SU_ROCKETS2)
759 cl.stats[STAT_ROCKETS] |= MSG_ReadByte (net_message) << 8;
760 if (bits & SU_CELLS2)
761 cl.stats[STAT_CELLS] |= MSG_ReadByte (net_message) << 8;
762 if (bits & SU_WEAPONFRAME2)
763 cl.stats[STAT_WEAPONFRAME] |= MSG_ReadByte (net_message) << 8;
764 if (bits & SU_WEAPONALPHA) {
765 byte alpha = MSG_ReadByte (net_message);
766 cl.viewent.colormod[3] = ENTALPHA_DECODE (alpha);
767 } else {
768 cl.viewent.colormod[3] = 1.0;
769 }
770 }
771
772 static void
CL_ParseStatic(int version)773 CL_ParseStatic (int version)
774 {
775 entity_state_t baseline;
776 entity_t *ent;
777
778 ent = r_funcs->R_AllocEntity ();
779 CL_Init_Entity (ent);
780
781 CL_ParseBaseline (&baseline, version);
782
783 // copy it to the current state
784 //FIXME alpha & lerp
785 ent->model = cl.model_precache[baseline.modelindex];
786 ent->frame = baseline.frame;
787 ent->skin = 0;
788 ent->skinnum = baseline.skinnum;
789 VectorCopy (ent_colormod[baseline.colormod], ent->colormod);
790 ent->colormod[3] = ENTALPHA_DECODE (baseline.alpha);
791 ent->scale = baseline.scale / 16.0;
792 VectorCopy (baseline.origin, ent->origin);
793 CL_TransformEntity (ent, baseline.angles, true);
794
795 r_funcs->R_AddEfrags (ent);
796 }
797
798 static void
CL_ParseStaticSound(int version)799 CL_ParseStaticSound (int version)
800 {
801 int sound_num, vol, atten;
802 vec3_t org;
803
804 MSG_ReadCoordV (net_message, org);
805 if (version == 2)
806 sound_num = MSG_ReadShort (net_message);
807 else
808 sound_num = MSG_ReadByte (net_message);
809 vol = MSG_ReadByte (net_message);
810 atten = MSG_ReadByte (net_message);
811
812 S_StaticSound (cl.sound_precache[sound_num], org, vol, atten);
813 }
814
815 static void
CL_SetStat(int stat,int value)816 CL_SetStat (int stat, int value)
817 {
818 if (stat < 0 || stat >= MAX_CL_STATS)
819 Host_Error ("CL_SetStat: %i is invalid", stat);
820 cl.stats[stat] = value;
821 }
822
823 #define SHOWNET(x) \
824 if (cl_shownet->int_val == 2) \
825 Sys_Printf ("%3i:%s\n", net_message->readcount - 1, x);
826
827 void
CL_ParseServerMessage(void)828 CL_ParseServerMessage (void)
829 {
830 int cmd = 0, i, j;
831 const char *str;
832 static dstring_t *stuffbuf;
833 signon_t so;
834
835 // if recording demos, copy the message out
836 if (cl_shownet->int_val == 1)
837 Sys_Printf ("%i ", net_message->message->cursize);
838 else if (cl_shownet->int_val == 2)
839 Sys_Printf ("------------------\n");
840
841 cl.onground = -1; // unless the server says otherwise
842
843 // parse the message
844 MSG_BeginReading (net_message);
845
846 while (1) {
847 if (net_message->badread)
848 Host_Error ("CL_ParseServerMessage: Bad server message: %s\n",
849 svc_strings[cmd]);
850
851 cmd = MSG_ReadByte (net_message);
852
853 if (cmd == -1) {
854 net_message->readcount++; // so the EOM SHOWNET has the right
855 // value
856 SHOWNET ("END OF MESSAGE");
857 break; // end of message
858 }
859 // if the high bit of the command byte is set, it is a fast update
860 if (cmd & U_SIGNAL) {
861 SHOWNET ("fast update");
862 CL_ParseUpdate (cmd & ~U_SIGNAL);
863 continue;
864 }
865
866 SHOWNET (va ("%s(%d)", svc_strings[cmd], cmd));
867
868 // other commands
869 switch (cmd) {
870 default:
871 Host_Error ("CL_ParseServerMessage: Illegible server "
872 "message: %d\n", cmd);
873 break;
874
875 case svc_nop:
876 break;
877
878 case svc_disconnect:
879 if (cls.state == ca_connected)
880 Host_EndGame ("Server disconnected\n"
881 "Server version may not be compatible");
882 else
883 Host_EndGame ("Server disconnected\n");
884
885 case svc_updatestat:
886 i = MSG_ReadByte (net_message);
887 j = MSG_ReadLong (net_message);
888 CL_SetStat (i, j);
889 break;
890
891 case svc_version:
892 i = MSG_ReadLong (net_message);
893 if (i != PROTOCOL_NETQUAKE && i!= PROTOCOL_FITZQUAKE)
894 Host_Error ("CL_ParseServerMessage: Server is protocol %i "
895 "instead of %i or %i\n", i, PROTOCOL_NETQUAKE,
896 PROTOCOL_FITZQUAKE);
897 cl.protocol = i;
898 break;
899
900 case svc_setview:
901 cl.viewentity = MSG_ReadShort (net_message);
902 break;
903
904 case svc_sound:
905 CL_ParseStartSoundPacket ();
906 break;
907
908 case svc_time:
909 cl.mtime[1] = cl.mtime[0];
910 cl.mtime[0] = MSG_ReadFloat (net_message);
911 cl.mindex = !cl.mindex;
912 break;
913
914 case svc_print:
915 Sys_Printf ("%s", MSG_ReadString (net_message));
916 break;
917
918 case svc_stufftext:
919 str = MSG_ReadString (net_message);
920 if (str[strlen (str) - 1] == '\n') {
921 if (stuffbuf && stuffbuf->str[0]) {
922 Sys_MaskPrintf (SYS_DEV, "stufftext: %s%s\n",
923 stuffbuf->str, str);
924 Cbuf_AddText (host_cbuf, stuffbuf->str);
925 dstring_clearstr (stuffbuf);
926 } else {
927 Sys_MaskPrintf (SYS_DEV, "stufftext: %s\n", str);
928 }
929 Cbuf_AddText (host_cbuf, str);
930 } else {
931 Sys_MaskPrintf (SYS_DEV, "partial stufftext: %s\n", str);
932 if (!stuffbuf)
933 stuffbuf = dstring_newstr ();
934 dstring_appendstr (stuffbuf, str);
935 }
936 break;
937
938 case svc_setangle:
939 {
940 vec_t *dest = cl.viewangles;
941
942 MSG_ReadAngleV (net_message, dest);
943 break;
944 }
945 case svc_serverinfo:
946 // make sure any stuffed commands are done
947 if (stuffbuf && stuffbuf->str[0]) {
948 Cbuf_AddText (host_cbuf, stuffbuf->str);
949 dstring_clearstr (stuffbuf);
950 }
951 Cbuf_Execute_Stack (host_cbuf);
952 CL_ParseServerInfo ();
953 // leave full screen intermission
954 r_data->vid->recalc_refdef = true;
955 break;
956
957 case svc_lightstyle:
958 i = MSG_ReadByte (net_message);
959 if (i >= MAX_LIGHTSTYLES)
960 Host_Error ("svc_lightstyle > MAX_LIGHTSTYLES");
961 strcpy (cl.lightstyle[i].map, MSG_ReadString (net_message));
962 cl.lightstyle[i].length = strlen (cl.lightstyle[i].map);
963 if (cl.lightstyle[i].length) {
964 int total = 0;
965
966 cl.lightstyle[i].peak = 'a';
967 for (j = 0; j < cl.lightstyle[i].length; j++) {
968 total += cl.lightstyle[i].map[j] - 'a';
969 cl.lightstyle[i].peak = max (cl.lightstyle[i].peak,
970 cl.lightstyle[i].map[j]);
971 }
972 total /= cl.lightstyle[i].length;
973 cl.lightstyle[i].average = total + 'a';
974 } else {
975 cl.lightstyle[i].average = 'm';
976 cl.lightstyle[i].peak = 'm';
977 }
978 break;
979
980 case svc_updatename:
981 Sbar_Changed ();
982 i = MSG_ReadByte (net_message);
983 if (i >= cl.maxclients)
984 Host_Error ("CL_ParseServerMessage: svc_updatename > "
985 "MAX_SCOREBOARD");
986 Info_SetValueForKey (cl.scores[i].info, "name",
987 MSG_ReadString (net_message), 0);
988 break;
989
990 case svc_updatefrags:
991 Sbar_Changed ();
992 i = MSG_ReadByte (net_message);
993 if (i >= cl.maxclients)
994 Host_Error ("CL_ParseServerMessage: svc_updatefrags > "
995 "MAX_SCOREBOARD");
996 cl.scores[i].frags = (short) MSG_ReadShort (net_message);
997 break;
998
999 case svc_clientdata:
1000 CL_ParseClientdata ();
1001 break;
1002
1003 case svc_stopsound:
1004 i = MSG_ReadShort (net_message);
1005 S_StopSound (i >> 3, i & 7);
1006 break;
1007
1008 case svc_updatecolors:
1009 Sbar_Changed ();
1010 i = MSG_ReadByte (net_message);
1011 if (i >= cl.maxclients) {
1012 Host_Error ("CL_ParseServerMessage: svc_updatecolors > "
1013 "MAX_SCOREBOARD");
1014 } else {
1015 entity_t *ent = &cl_entities[i+1];
1016 byte col = MSG_ReadByte (net_message);
1017 byte top = col >> 4;
1018 byte bot = col & 0xf;
1019 if (top != cl.scores[i].topcolor
1020 || bot != cl.scores[i].bottomcolor)
1021 mod_funcs->Skin_SetTranslation (i + 1, top, bot);
1022 cl.scores[i].topcolor = top;
1023 cl.scores[i].bottomcolor = bot;
1024 ent->skin = mod_funcs->Skin_SetColormap (ent->skin, i + 1);
1025 }
1026 break;
1027
1028 case svc_particle:
1029 CL_ParseParticleEffect ();
1030 break;
1031
1032 case svc_damage:
1033 V_ParseDamage ();
1034 break;
1035
1036 case svc_spawnstatic:
1037 CL_ParseStatic (1);
1038 break;
1039
1040 // svc_spawnbinary
1041
1042 case svc_spawnbaseline:
1043 i = MSG_ReadShort (net_message);
1044 // must use CL_EntityNum () to force cl.num_entities up
1045 CL_ParseBaseline (CL_EntityNum (i), 1);
1046 break;
1047
1048 case svc_temp_entity:
1049 CL_ParseTEnt ();
1050 break;
1051
1052 case svc_setpause:
1053 r_data->paused = cl.paused = MSG_ReadByte (net_message);
1054 if (cl.paused)
1055 CDAudio_Pause ();
1056 else
1057 CDAudio_Resume ();
1058 break;
1059
1060 case svc_signonnum:
1061 so = MSG_ReadByte (net_message);
1062 if (so <= cls.signon || so >= so_active)
1063 Host_Error ("Received signon %i when at %i", so,
1064 cls.signon);
1065 cls.signon = so;
1066 CL_SignonReply ();
1067 break;
1068
1069 case svc_centerprint:
1070 str = MSG_ReadString (net_message);
1071 if (strcmp (str, centerprint->str)) {
1072 dstring_copystr (centerprint, str);
1073 //FIXME logging
1074 }
1075 Sbar_CenterPrint (str);
1076 break;
1077
1078 case svc_killedmonster:
1079 cl.stats[STAT_MONSTERS]++;
1080 break;
1081
1082 case svc_foundsecret:
1083 cl.stats[STAT_SECRETS]++;
1084 break;
1085
1086 case svc_spawnstaticsound:
1087 CL_ParseStaticSound (1);
1088 break;
1089
1090 case svc_intermission:
1091 cl.intermission = 1;
1092 r_data->force_fullscreen = 1;
1093 cl.completed_time = cl.time;
1094 r_data->vid->recalc_refdef = true; // go to full screen
1095 break;
1096
1097 case svc_finale:
1098 cl.intermission = 2;
1099 r_data->force_fullscreen = 1;
1100 cl.completed_time = cl.time;
1101 r_data->vid->recalc_refdef = true; // go to full screen
1102 str = MSG_ReadString (net_message);
1103 if (strcmp (str, centerprint->str)) {
1104 dstring_copystr (centerprint, str);
1105 //FIXME logging
1106 }
1107 Sbar_CenterPrint (str);
1108 break;
1109
1110 case svc_cdtrack:
1111 cl.cdtrack = MSG_ReadByte (net_message);
1112 MSG_ReadByte (net_message); // looptrack (not used)
1113 if ((cls.demoplayback || cls.demorecording)
1114 && (cls.forcetrack != -1))
1115 CDAudio_Play ((byte) cls.forcetrack, true);
1116 else
1117 CDAudio_Play ((byte) cl.cdtrack, true);
1118 break;
1119
1120 case svc_sellscreen:
1121 Cmd_ExecuteString ("help", src_command);
1122 break;
1123
1124 case svc_cutscene:
1125 cl.intermission = 3;
1126 r_data->force_fullscreen = 1;
1127 cl.completed_time = cl.time;
1128 r_data->vid->recalc_refdef = true; // go to full screen
1129 str = MSG_ReadString (net_message);
1130 if (strcmp (str, centerprint->str)) {
1131 dstring_copystr (centerprint, str);
1132 //FIXME logging
1133 }
1134 Sbar_CenterPrint (str);
1135 break;
1136
1137 // svc_smallkick (same value as svc_cutscene)
1138 // svc_bigkick
1139 // svc_updateping
1140 // svc_updateentertime
1141 // svc_updatestatlong
1142 // svc_muzzleflash
1143 // svc_updateuserinfo
1144 // svc_download
1145 // svc_playerinfo
1146 // svc_nails
1147 // svc_chokecount
1148 // svc_modellist
1149 // svc_soundlist
1150 // svc_packetentities
1151 // svc_deltapacketentities
1152 // svc_maxspeed
1153 // svc_entgravity
1154 // svc_setinfo
1155 // svc_serverinfo
1156 // svc_updatepl
1157
1158 // PROTOCOL_FITZQUAKE (these overlap with the above listed qw svcs)
1159 case svc_skybox:
1160 r_funcs->R_LoadSkys (MSG_ReadString(net_message));
1161 break;
1162 case svc_bf:
1163 Cmd_ExecuteString ("bf", src_command);
1164 break;
1165 case svc_fog:
1166 {
1167 float density, red, green, blue, time;
1168 density = MSG_ReadByte (net_message) / 255.0;
1169 red = MSG_ReadByte (net_message) / 255.0;
1170 green = MSG_ReadByte (net_message) / 255.0;
1171 blue = MSG_ReadByte (net_message) / 255.0;
1172 time = (short) MSG_ReadShort (net_message) / 100.0;
1173 time = max (0.0, time);
1174 if (r_funcs->Fog_Update)
1175 r_funcs->Fog_Update (density, red, green, blue, time);
1176 }
1177 break;
1178 case svc_spawnbaseline2:
1179 i = MSG_ReadShort (net_message);
1180 // must use CL_EntityNum() to force cl.num_entities up
1181 CL_ParseBaseline (CL_EntityNum(i), 2);
1182 break;
1183 case svc_spawnstatic2:
1184 CL_ParseStatic (2);
1185 break;
1186 case svc_spawnstaticsound2:
1187 CL_ParseStaticSound (2);
1188 break;
1189 }
1190 }
1191 }
1192