2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
20 // cl_parse.c -- parse a message received from the server
24 char *svc_strings[128] =
30 "svc_version", // [long] server version
31 "svc_setview", // [short] entity number
32 "svc_sound", // <see code>
33 "svc_time", // [float] server time
34 "svc_print", // [string] null terminated string
35 "svc_stufftext", // [string] stuffed into client's console buffer
36 // the string should be \n terminated
37 "svc_setangle", // [vec3] set the view angle to this absolute value
39 "svc_serverinfo", // [long] version
40 // [string] signon string
41 // [string]..[0]model cache [string]...[0]sounds cache
42 // [string]..[0]item cache
43 "svc_lightstyle", // [byte] [string]
44 "svc_updatename", // [byte] [string]
45 "svc_updatefrags", // [byte] [short]
46 "svc_clientdata", // <shortbits + data>
47 "svc_stopsound", // <see code>
48 "svc_updatecolors", // [byte] [byte]
49 "svc_particle", // [vec3] <variable>
50 "svc_damage", // [byte] impact [byte] blood [vec3] from
53 "OBSOLETE svc_spawnbinary",
56 "svc_temp_entity", // <variable>
62 "svc_spawnstaticsound",
64 "svc_finale", // [string] music [string] text
65 "svc_cdtrack", // [byte] track [byte] looptrack
68 "svc_showlmp", // [string] iconlabel [string] lmpfile [short] x [short] y
69 "svc_hidelmp", // [string] iconlabel
70 "svc_skybox", // [string] skyname
83 "svc_cgame", // 50 // [short] length [bytes] data
84 "svc_unusedlh1", // 51 // unused
85 "svc_effect", // 52 // [vector] org [byte] modelindex [byte] startframe [byte] framecount [byte] framerate
86 "svc_effect2", // 53 // [vector] org [short] modelindex [short] startframe [byte] framecount [byte] framerate
87 "svc_sound2", // 54 // short soundindex instead of byte
88 "svc_spawnbaseline2", // 55 // short modelindex instead of byte
89 "svc_spawnstatic2", // 56 // short modelindex instead of byte
90 "svc_entities", // 57 // [int] deltaframe [int] thisframe [float vector] eye [variable length] entitydata
91 "svc_unusedlh3", // 58
92 "svc_spawnstaticsound2", // 59 // [coord3] [short] samp [byte] vol [byte] aten
95 //=============================================================================
97 cvar_t demo_nehahra = {0, "demo_nehahra", "0"};
99 qboolean Nehahrademcompatibility; // LordHavoc: to allow playback of the early Nehahra movie segments
100 int dpprotocol; // LordHavoc: version of network protocol, or 0 if not DarkPlaces
102 mempool_t *cl_scores_mempool;
106 CL_ParseStartSoundPacket
109 void CL_ParseStartSoundPacket(int largesoundindex)
119 field_mask = MSG_ReadByte();
121 if (field_mask & SND_VOLUME)
122 volume = MSG_ReadByte ();
124 volume = DEFAULT_SOUND_PACKET_VOLUME;
126 if (field_mask & SND_ATTENUATION)
127 attenuation = MSG_ReadByte () / 64.0;
129 attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;
131 if (field_mask & SND_LARGEENTITY)
133 ent = (unsigned short) MSG_ReadShort ();
134 channel = MSG_ReadByte ();
138 channel = (unsigned short) MSG_ReadShort ();
143 if (largesoundindex || field_mask & SND_LARGESOUND)
144 sound_num = (unsigned short) MSG_ReadShort ();
146 sound_num = MSG_ReadByte ();
148 if (sound_num >= MAX_SOUNDS)
149 Host_Error("CL_ParseStartSoundPacket: sound_num (%i) >= MAX_SOUNDS (%i)\n", sound_num, MAX_SOUNDS);
152 if (ent >= MAX_EDICTS)
153 Host_Error ("CL_ParseStartSoundPacket: ent = %i", ent);
155 for (i = 0;i < 3;i++)
156 pos[i] = MSG_ReadCoord ();
158 S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation);
165 When the client is taking a long time to load stuff, send keepalive messages
166 so the server doesn't disconnect.
170 static qbyte olddata[NET_MAXMESSAGE];
171 void CL_KeepaliveMessage (void)
174 static float lastmsg;
179 // no need if server is local and definitely not if this is a demo
180 if (sv.active || cls.demoplayback)
183 // read messages from server, should just be nops
184 oldreadcount = msg_readcount;
185 oldbadread = msg_badread;
187 memcpy(olddata, net_message.data, net_message.cursize);
189 NetConn_ClientFrame();
191 msg_readcount = oldreadcount;
192 msg_badread = oldbadread;
194 memcpy(net_message.data, olddata, net_message.cursize);
196 if (cls.netcon && NetConn_CanSendMessage(cls.netcon) && (time = Sys_DoubleTime()) - lastmsg >= 5)
202 // LordHavoc: must use unreliable because reliable could kill the sigon message!
203 Con_Printf("--> client to server keepalive\n");
205 msg.maxsize = sizeof(buf);
207 MSG_WriteChar(&msg, svc_nop);
208 NetConn_SendUnreliableMessage(cls.netcon, &msg);
209 // try not to utterly crush the computer with work, that's just rude
214 void CL_ParseEntityLump(char *entdata)
217 char key[128], value[4096];
218 FOG_clear(); // LordHavoc: no fog until set
219 R_SetSkyBox(""); // LordHavoc: no environment mapped sky until set
223 if (!COM_ParseToken(&data))
225 if (com_token[0] != '{')
229 if (!COM_ParseToken(&data))
231 if (com_token[0] == '}')
232 break; // end of worldspawn
233 if (com_token[0] == '_')
234 strcpy(key, com_token + 1);
236 strcpy(key, com_token);
237 while (key[strlen(key)-1] == ' ') // remove trailing spaces
238 key[strlen(key)-1] = 0;
239 if (!COM_ParseToken(&data))
241 strcpy(value, com_token);
242 if (!strcmp("sky", key))
244 else if (!strcmp("skyname", key)) // non-standard, introduced by QuakeForge... sigh.
246 else if (!strcmp("qlsky", key)) // non-standard, introduced by QuakeLives (EEK)
248 else if (!strcmp("fog", key))
249 sscanf(value, "%f %f %f %f", &fog_density, &fog_red, &fog_green, &fog_blue);
250 else if (!strcmp("fog_density", key))
251 fog_density = atof(value);
252 else if (!strcmp("fog_red", key))
253 fog_red = atof(value);
254 else if (!strcmp("fog_green", key))
255 fog_green = atof(value);
256 else if (!strcmp("fog_blue", key))
257 fog_blue = atof(value);
262 =====================
265 An svc_signonnum has been received, perform a client side setup
266 =====================
268 static void CL_SignonReply (void)
272 Con_DPrintf ("CL_SignonReply: %i\n", cls.signon);
277 MSG_WriteByte (&cls.message, clc_stringcmd);
278 MSG_WriteString (&cls.message, "prespawn");
282 MSG_WriteByte (&cls.message, clc_stringcmd);
283 MSG_WriteString (&cls.message, va("name \"%s\"\n", cl_name.string));
285 MSG_WriteByte (&cls.message, clc_stringcmd);
286 MSG_WriteString (&cls.message, va("color %i %i\n", cl_color.integer >> 4, cl_color.integer & 15));
288 if (cl_pmodel.integer)
290 MSG_WriteByte (&cls.message, clc_stringcmd);
291 MSG_WriteString (&cls.message, va("pmodel %i\n", cl_pmodel.integer));
294 MSG_WriteByte (&cls.message, clc_stringcmd);
295 MSG_WriteString (&cls.message, "spawn");
299 MSG_WriteByte (&cls.message, clc_stringcmd);
300 MSG_WriteString (&cls.message, "begin");
314 qbyte entlife[MAX_EDICTS];
315 // FIXME: this is a lot of memory to be keeping around, this needs to be dynamically allocated and freed
316 static char parse_model_precache[MAX_MODELS][MAX_QPATH];
317 static char parse_sound_precache[MAX_SOUNDS][MAX_QPATH];
318 void CL_ParseServerInfo (void)
322 int nummodels, numsounds;
325 Con_DPrintf ("Serverinfo packet received.\n");
327 // wipe the client_state_t struct
331 // parse protocol version number
333 if (i != PROTOCOL_VERSION && i != DPPROTOCOL_VERSION1 && i != DPPROTOCOL_VERSION2 && i != DPPROTOCOL_VERSION3 && i != 250)
335 Host_Error ("Server is protocol %i, not %i, %i, %i or %i", i, DPPROTOCOL_VERSION1, DPPROTOCOL_VERSION2, DPPROTOCOL_VERSION3, PROTOCOL_VERSION);
338 Nehahrademcompatibility = false;
340 Nehahrademcompatibility = true;
341 if (cls.demoplayback && demo_nehahra.integer)
342 Nehahrademcompatibility = true;
344 if (dpprotocol != DPPROTOCOL_VERSION1 && dpprotocol != DPPROTOCOL_VERSION2 && dpprotocol != DPPROTOCOL_VERSION3)
348 cl.maxclients = MSG_ReadByte ();
349 if (cl.maxclients < 1 || cl.maxclients > MAX_SCOREBOARD)
351 Con_Printf("Bad maxclients (%u) from server\n", cl.maxclients);
354 Mem_EmptyPool(cl_scores_mempool);
355 cl.scores = Mem_Alloc(cl_scores_mempool, cl.maxclients*sizeof(*cl.scores));
358 cl.gametype = MSG_ReadByte ();
360 // parse signon message
361 str = MSG_ReadString ();
362 strncpy (cl.levelname, str, sizeof(cl.levelname)-1);
364 // seperate the printfs so the server message can have a color
365 if (!Nehahrademcompatibility) // no messages when playing the Nehahra movie
367 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");
368 Con_Printf ("%c%s\n", 2, str);
371 // check memory integrity
372 Mem_CheckSentinelsGlobal();
374 // disable until we get textures for it
377 memset(cl.model_precache, 0, sizeof(cl.model_precache));
378 memset(cl.sound_precache, 0, sizeof(cl.sound_precache));
380 // parse model precache list
381 for (nummodels=1 ; ; nummodels++)
383 str = MSG_ReadString();
386 if (nummodels==MAX_MODELS)
387 Host_Error ("Server sent too many model precaches\n");
388 if (strlen(str) >= MAX_QPATH)
389 Host_Error ("Server sent a precache name of %i characters (max %i)", strlen(str), MAX_QPATH - 1);
390 strcpy(parse_model_precache[nummodels], str);
392 // parse sound precache list
393 for (numsounds=1 ; ; numsounds++)
395 str = MSG_ReadString();
398 if (numsounds==MAX_SOUNDS)
399 Host_Error("Server sent too many sound precaches\n");
400 if (strlen(str) >= MAX_QPATH)
401 Host_Error("Server sent a precache name of %i characters (max %i)", strlen(str), MAX_QPATH - 1);
402 strcpy(parse_sound_precache[numsounds], str);
405 // touch all of the precached models that are still loaded so we can free
406 // anything that isn't needed
408 for (i = 1;i < nummodels;i++)
410 CL_KeepaliveMessage();
411 Mod_TouchModel(parse_model_precache[i]);
413 // do the same for sounds
414 for (i = 1;i < numsounds;i++)
416 CL_KeepaliveMessage();
417 S_TouchSound(parse_sound_precache[i]);
419 // purge anything that was not touched
422 // now we try to load everything that is new
425 CL_KeepaliveMessage ();
426 cl.model_precache[1] = Mod_ForName(parse_model_precache[1], false, false, true);
427 if (cl.model_precache[1] == NULL)
428 Con_Printf("Map %s not found\n", parse_model_precache[1]);
431 for (i=2 ; i<nummodels ; i++)
433 CL_KeepaliveMessage();
434 if ((cl.model_precache[i] = Mod_ForName(parse_model_precache[i], false, false, false)) == NULL)
435 Con_Printf("Model %s not found\n", parse_model_precache[i]);
439 S_BeginPrecaching ();
440 for (i=1 ; i<numsounds ; i++)
442 CL_KeepaliveMessage();
443 cl.sound_precache[i] = S_PrecacheSound(parse_sound_precache[i], true);
448 ent = &cl_entities[0];
449 // entire entity array was cleared, so just fill in a few fields
450 ent->state_current.active = true;
451 ent->render.model = cl.worldmodel = cl.model_precache[1];
452 //ent->render.scale = 1;
453 ent->render.alpha = 1;
454 ent->render.flags = RENDER_SHADOW;
455 Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, 0, 0, 0, 0, 0, 0, 1);
456 Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix);
457 CL_BoundingBoxForEntity(&ent->render);
458 // clear entlife array
459 memset(entlife, 0, MAX_EDICTS);
466 // noclip is turned off at start
467 noclip_anglehack = false;
469 // check memory integrity
470 Mem_CheckSentinelsGlobal();
473 void CL_ValidateState(entity_state_t *s)
480 if (s->modelindex >= MAX_MODELS)
481 Host_Error("CL_ValidateState: modelindex (%i) >= MAX_MODELS (%i)\n", s->modelindex, MAX_MODELS);
483 // colormap is client index + 1
484 if (s->colormap > cl.maxclients)
485 Host_Error ("CL_ValidateState: colormap (%i) > cl.maxclients (%i)", s->colormap, cl.maxclients);
487 model = cl.model_precache[s->modelindex];
488 Mod_CheckLoaded(model);
489 if (model && s->frame >= model->numframes)
491 Con_DPrintf("CL_ValidateState: no such frame %i in \"%s\"\n", s->frame, model->name);
494 if (model && s->skin > 0 && s->skin >= model->numskins)
496 Con_DPrintf("CL_ValidateState: no such skin %i in \"%s\"\n", s->skin, model->name);
501 void CL_MoveLerpEntityStates(entity_t *ent)
503 float odelta[3], adelta[3];
504 VectorSubtract(ent->state_current.origin, ent->persistent.neworigin, odelta);
505 VectorSubtract(ent->state_current.angles, ent->persistent.newangles, adelta);
506 if (!ent->state_previous.active || cls.timedemo || DotProduct(odelta, odelta) > 1000*1000 || cl_nolerp.integer)
508 // we definitely shouldn't lerp
509 ent->persistent.lerpdeltatime = 0;
510 ent->persistent.lerpstarttime = cl.mtime[1];
511 VectorCopy(ent->state_current.origin, ent->persistent.oldorigin);
512 VectorCopy(ent->state_current.angles, ent->persistent.oldangles);
513 VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
514 VectorCopy(ent->state_current.angles, ent->persistent.newangles);
516 else if (ent->state_current.flags & RENDER_STEP)
518 // monster interpolation
519 if (DotProduct(odelta, odelta) + DotProduct(adelta, adelta) > 0.01)
521 ent->persistent.lerpdeltatime = bound(0, cl.mtime[1] - ent->persistent.lerpstarttime, 0.1);
522 ent->persistent.lerpstarttime = cl.mtime[1];
523 VectorCopy(ent->persistent.neworigin, ent->persistent.oldorigin);
524 VectorCopy(ent->persistent.newangles, ent->persistent.oldangles);
525 VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
526 VectorCopy(ent->state_current.angles, ent->persistent.newangles);
532 ent->persistent.lerpstarttime = cl.mtime[1];
533 // no lerp if it's singleplayer
534 if (sv.active && svs.maxclients == 1)
535 ent->persistent.lerpdeltatime = 0;
537 ent->persistent.lerpdeltatime = cl.mtime[0] - cl.mtime[1];
538 VectorCopy(ent->persistent.neworigin, ent->persistent.oldorigin);
539 VectorCopy(ent->persistent.newangles, ent->persistent.oldangles);
540 VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
541 VectorCopy(ent->state_current.angles, ent->persistent.newangles);
549 Parse an entity update message from the server
550 If an entities model or origin changes from frame to frame, it must be
551 relinked. Other attributes can change without relinking.
554 void CL_ParseUpdate (int bits)
560 if (bits & U_MOREBITS)
561 bits |= (MSG_ReadByte()<<8);
562 if ((bits & U_EXTEND1) && (!Nehahrademcompatibility))
564 bits |= MSG_ReadByte() << 16;
565 if (bits & U_EXTEND2)
566 bits |= MSG_ReadByte() << 24;
569 if (bits & U_LONGENTITY)
570 num = (unsigned) MSG_ReadShort ();
572 num = (unsigned) MSG_ReadByte ();
574 if (num >= MAX_EDICTS)
575 Host_Error("CL_ParseUpdate: entity number (%i) >= MAX_EDICTS (%i)\n", num, MAX_EDICTS);
577 Host_Error("CL_ParseUpdate: invalid entity number (%i)\n", num);
579 ent = cl_entities + num;
581 // note: this inherits the 'active' state of the baseline chosen
582 // (state_baseline is always active, state_current may not be active if
583 // the entity was missing in the last frame)
585 new = ent->state_current;
588 new = ent->state_baseline;
593 new.time = cl.mtime[0];
595 if (bits & U_MODEL) new.modelindex = (new.modelindex & 0xFF00) | MSG_ReadByte();
596 if (bits & U_FRAME) new.frame = (new.frame & 0xFF00) | MSG_ReadByte();
597 if (bits & U_COLORMAP) new.colormap = MSG_ReadByte();
598 if (bits & U_SKIN) new.skin = MSG_ReadByte();
599 if (bits & U_EFFECTS) new.effects = (new.effects & 0xFF00) | MSG_ReadByte();
600 if (bits & U_ORIGIN1) new.origin[0] = MSG_ReadCoord();
601 if (bits & U_ANGLE1) new.angles[0] = MSG_ReadAngle();
602 if (bits & U_ORIGIN2) new.origin[1] = MSG_ReadCoord();
603 if (bits & U_ANGLE2) new.angles[1] = MSG_ReadAngle();
604 if (bits & U_ORIGIN3) new.origin[2] = MSG_ReadCoord();
605 if (bits & U_ANGLE3) new.angles[2] = MSG_ReadAngle();
606 if (bits & U_STEP) new.flags |= RENDER_STEP;
607 if (bits & U_ALPHA) new.alpha = MSG_ReadByte();
608 if (bits & U_SCALE) new.scale = MSG_ReadByte();
609 if (bits & U_EFFECTS2) new.effects = (new.effects & 0x00FF) | (MSG_ReadByte() << 8);
610 if (bits & U_GLOWSIZE) new.glowsize = MSG_ReadByte();
611 if (bits & U_GLOWCOLOR) new.glowcolor = MSG_ReadByte();
612 // apparently the dpcrush demo uses this (unintended, and it uses white anyway)
613 if (bits & U_COLORMOD) MSG_ReadByte();
614 if (bits & U_GLOWTRAIL) new.flags |= RENDER_GLOWTRAIL;
615 if (bits & U_FRAME2) new.frame = (new.frame & 0x00FF) | (MSG_ReadByte() << 8);
616 if (bits & U_MODEL2) new.modelindex = (new.modelindex & 0x00FF) | (MSG_ReadByte() << 8);
617 if (bits & U_VIEWMODEL) new.flags |= RENDER_VIEWMODEL;
618 if (bits & U_EXTERIORMODEL) new.flags |= RENDER_EXTERIORMODEL;
620 // LordHavoc: to allow playback of the Nehahra movie
621 if (Nehahrademcompatibility && (bits & U_EXTEND1))
623 // LordHavoc: evil format
624 int i = MSG_ReadFloat();
625 int j = MSG_ReadFloat() * 255.0f;
630 new.effects |= EF_FULLBRIGHT;
634 else if (j == 0 || j >= 255)
641 CL_ValidateState(&new);
643 ent->state_previous = ent->state_current;
644 ent->state_current = new;
645 if (ent->state_current.active)
647 CL_MoveLerpEntityStates(ent);
648 cl_entities_active[ent->state_current.number] = true;
649 // mark as visible (no kill this frame)
650 entlife[ent->state_current.number] = 2;
654 static entity_frame_t entityframe;
655 void CL_ReadEntityFrame(void)
659 EntityFrame_Read(&cl.entitydatabase);
660 EntityFrame_FetchFrame(&cl.entitydatabase, EntityFrame_MostRecentlyRecievedFrameNum(&cl.entitydatabase), &entityframe);
661 for (i = 0;i < entityframe.numentities;i++)
664 ent = &cl_entities[entityframe.entitydata[i].number];
665 ent->state_previous = ent->state_current;
666 ent->state_current = entityframe.entitydata[i];
667 CL_MoveLerpEntityStates(ent);
668 // the entity lives again...
669 entlife[ent->state_current.number] = 2;
670 cl_entities_active[ent->state_current.number] = true;
674 void CL_EntityUpdateSetup(void)
678 void CL_EntityUpdateEnd(void)
681 // disable entities that disappeared this frame
682 for (i = 1;i < MAX_EDICTS;i++)
684 // clear only the entities that were active last frame but not this
685 // frame, don't waste time clearing all entities (which would cause
691 cl_entities[i].state_previous.active = cl_entities[i].state_current.active = 0;
701 void CL_ParseBaseline (entity_t *ent, int large)
705 memset(&ent->state_baseline, 0, sizeof(entity_state_t));
706 ent->state_baseline.active = true;
709 ent->state_baseline.modelindex = (unsigned short) MSG_ReadShort ();
710 ent->state_baseline.frame = (unsigned short) MSG_ReadShort ();
714 ent->state_baseline.modelindex = MSG_ReadByte ();
715 ent->state_baseline.frame = MSG_ReadByte ();
717 ent->state_baseline.colormap = MSG_ReadByte();
718 ent->state_baseline.skin = MSG_ReadByte();
719 for (i = 0;i < 3;i++)
721 ent->state_baseline.origin[i] = MSG_ReadCoord ();
722 ent->state_baseline.angles[i] = MSG_ReadAngle ();
724 ent->state_baseline.alpha = 255;
725 ent->state_baseline.scale = 16;
726 ent->state_baseline.glowsize = 0;
727 ent->state_baseline.glowcolor = 254;
728 ent->state_previous = ent->state_current = ent->state_baseline;
730 CL_ValidateState(&ent->state_baseline);
738 Server information pertaining to this client only
741 void CL_ParseClientdata (int bits)
746 if (bits & SU_EXTEND1)
747 bits |= (MSG_ReadByte() << 16);
748 if (bits & SU_EXTEND2)
749 bits |= (MSG_ReadByte() << 24);
751 if (bits & SU_VIEWHEIGHT)
752 cl.viewheight = MSG_ReadChar ();
754 cl.viewheight = DEFAULT_VIEWHEIGHT;
756 if (bits & SU_IDEALPITCH)
757 cl.idealpitch = MSG_ReadChar ();
761 VectorCopy (cl.mvelocity[0], cl.mvelocity[1]);
762 for (i=0 ; i<3 ; i++)
764 if (bits & (SU_PUNCH1<<i) )
767 cl.punchangle[i] = MSG_ReadPreciseAngle();
769 cl.punchangle[i] = MSG_ReadChar();
772 cl.punchangle[i] = 0;
773 if (bits & (SU_PUNCHVEC1<<i))
774 cl.punchvector[i] = MSG_ReadCoord();
776 cl.punchvector[i] = 0;
777 if (bits & (SU_VELOCITY1<<i) )
778 cl.mvelocity[0][i] = MSG_ReadChar()*16;
780 cl.mvelocity[0][i] = 0;
786 for (j=0 ; j<32 ; j++)
787 if ( (i & (1<<j)) && !(cl.items & (1<<j)))
788 cl.item_gettime[j] = cl.time;
792 cl.onground = (bits & SU_ONGROUND) != 0;
793 cl.inwater = (bits & SU_INWATER) != 0;
795 cl.stats[STAT_WEAPONFRAME] = (bits & SU_WEAPONFRAME) ? MSG_ReadByte() : 0;
796 cl.stats[STAT_ARMOR] = (bits & SU_ARMOR) ? MSG_ReadByte() : 0;
797 cl.stats[STAT_WEAPON] = (bits & SU_WEAPON) ? MSG_ReadByte() : 0;
798 cl.stats[STAT_HEALTH] = MSG_ReadShort();
799 cl.stats[STAT_AMMO] = MSG_ReadByte();
801 cl.stats[STAT_SHELLS] = MSG_ReadByte();
802 cl.stats[STAT_NAILS] = MSG_ReadByte();
803 cl.stats[STAT_ROCKETS] = MSG_ReadByte();
804 cl.stats[STAT_CELLS] = MSG_ReadByte();
808 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
809 cl.stats[STAT_ACTIVEWEAPON] = (1<<i);
811 cl.stats[STAT_ACTIVEWEAPON] = i;
813 cl.viewzoomold = cl.viewzoomnew; // for interpolation
814 if (bits & SU_VIEWZOOM)
819 cl.viewzoomnew = (float) i * (1.0f / 255.0f);
827 =====================
829 =====================
831 void CL_ParseStatic (int large)
835 if (cl_num_static_entities >= cl_max_static_entities)
836 Host_Error ("Too many static entities");
837 ent = &cl_static_entities[cl_num_static_entities++];
838 CL_ParseBaseline (ent, large);
840 // copy it to the current state
841 ent->render.model = cl.model_precache[ent->state_baseline.modelindex];
842 ent->render.frame = ent->render.frame1 = ent->render.frame2 = ent->state_baseline.frame;
843 ent->render.framelerp = 0;
844 // make torchs play out of sync
845 ent->render.frame1time = ent->render.frame2time = lhrandom(-10, -1);
846 ent->render.colormap = -1; // no special coloring
847 ent->render.skinnum = ent->state_baseline.skin;
848 ent->render.effects = ent->state_baseline.effects;
849 ent->render.alpha = 1;
850 //ent->render.scale = 1;
852 //VectorCopy (ent->state_baseline.origin, ent->render.origin);
853 //VectorCopy (ent->state_baseline.angles, ent->render.angles);
855 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);
856 Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix);
857 CL_BoundingBoxForEntity(&ent->render);
859 // This is definitely cheating...
860 if (ent->render.model == NULL)
861 cl_num_static_entities--;
869 void CL_ParseStaticSound (int large)
872 int sound_num, vol, atten;
876 sound_num = (unsigned short) MSG_ReadShort ();
878 sound_num = MSG_ReadByte ();
879 vol = MSG_ReadByte ();
880 atten = MSG_ReadByte ();
882 S_StaticSound (cl.sound_precache[sound_num], org, vol, atten);
885 void CL_ParseEffect (void)
888 int modelindex, startframe, framecount, framerate;
891 modelindex = MSG_ReadByte ();
892 startframe = MSG_ReadByte ();
893 framecount = MSG_ReadByte ();
894 framerate = MSG_ReadByte ();
896 CL_Effect(org, modelindex, startframe, framecount, framerate);
899 void CL_ParseEffect2 (void)
902 int modelindex, startframe, framecount, framerate;
905 modelindex = MSG_ReadShort ();
906 startframe = MSG_ReadShort ();
907 framecount = MSG_ReadByte ();
908 framerate = MSG_ReadByte ();
910 CL_Effect(org, modelindex, startframe, framecount, framerate);
913 model_t *cl_model_bolt = NULL;
914 model_t *cl_model_bolt2 = NULL;
915 model_t *cl_model_bolt3 = NULL;
916 model_t *cl_model_beam = NULL;
918 sfx_t *cl_sfx_wizhit;
919 sfx_t *cl_sfx_knighthit;
924 sfx_t *cl_sfx_r_exp3;
931 void CL_InitTEnts (void)
933 cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav", false);
934 cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav", false);
935 cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav", false);
936 cl_sfx_ric1 = S_PrecacheSound ("weapons/ric1.wav", false);
937 cl_sfx_ric2 = S_PrecacheSound ("weapons/ric2.wav", false);
938 cl_sfx_ric3 = S_PrecacheSound ("weapons/ric3.wav", false);
939 cl_sfx_r_exp3 = S_PrecacheSound ("weapons/r_exp3.wav", false);
942 void CL_ParseBeam (model_t *m, int lightning)
948 ent = MSG_ReadShort ();
949 MSG_ReadVector(start);
952 if (ent >= MAX_EDICTS)
954 Con_Printf("CL_ParseBeam: invalid entity number %i\n", ent);
958 // override any beam with the same entity
959 for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
961 if (b->entity == ent)
964 b->lightning = lightning;
965 b->relativestartvalid = (ent && cl_entities[ent].state_current.active) ? 2 : 0;
967 b->endtime = cl.time + 0.2;
968 VectorCopy (start, b->start);
969 VectorCopy (end, b->end);
975 for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
977 if (!b->model || b->endtime < cl.time)
980 b->lightning = lightning;
981 b->relativestartvalid = (ent && cl_entities[ent].state_current.active) ? 2 : 0;
983 b->endtime = cl.time + 0.2;
984 VectorCopy (start, b->start);
985 VectorCopy (end, b->end);
989 Con_Printf ("beam list overflow!\n");
992 void CL_ParseTempEntity (void)
1000 int colorStart, colorLength, count;
1001 float velspeed, radius;
1004 type = MSG_ReadByte ();
1008 // spike hitting wall
1009 MSG_ReadVector(pos);
1010 if (cl.worldmodel) cl.worldmodel->FindNonSolidLocation(cl.worldmodel, pos, pos, 4);
1011 CL_AllocDlight (NULL, pos, 50, 0.25f, 1.00f, 0.25f, 250, 0.2);
1012 CL_RunParticleEffect (pos, vec3_origin, 20, 30);
1013 S_StartSound (-1, 0, cl_sfx_wizhit, pos, 1, 1);
1016 case TE_KNIGHTSPIKE:
1017 // spike hitting wall
1018 MSG_ReadVector(pos);
1019 if (cl.worldmodel) cl.worldmodel->FindNonSolidLocation(cl.worldmodel, pos, pos, 4);
1020 CL_AllocDlight (NULL, pos, 50, 1.0f, 0.60f, 0.20f, 250, 0.2);
1021 CL_RunParticleEffect (pos, vec3_origin, 226, 20);
1022 S_StartSound (-1, 0, cl_sfx_knighthit, pos, 1, 1);
1026 // spike hitting wall
1027 MSG_ReadVector(pos);
1028 if (cl.worldmodel) cl.worldmodel->FindNonSolidLocation(cl.worldmodel, pos, pos, 4);
1029 // LordHavoc: changed to spark shower
1030 CL_SparkShower(pos, vec3_origin, 15);
1032 S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
1037 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
1039 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
1041 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
1045 // quad spike hitting wall
1046 MSG_ReadVector(pos);
1047 if (cl.worldmodel) cl.worldmodel->FindNonSolidLocation(cl.worldmodel, pos, pos, 4);
1048 // LordHavoc: changed to spark shower
1049 CL_SparkShower(pos, vec3_origin, 15);
1050 CL_AllocDlight (NULL, pos, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2);
1051 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1053 S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
1058 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
1060 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
1062 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
1066 // super spike hitting wall
1067 MSG_ReadVector(pos);
1068 if (cl.worldmodel) cl.worldmodel->FindNonSolidLocation(cl.worldmodel, pos, pos, 4);
1069 // LordHavoc: changed to dust shower
1070 CL_SparkShower(pos, vec3_origin, 30);
1072 S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
1077 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
1079 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
1081 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
1084 case TE_SUPERSPIKEQUAD:
1085 // quad super spike hitting wall
1086 MSG_ReadVector(pos);
1087 if (cl.worldmodel) cl.worldmodel->FindNonSolidLocation(cl.worldmodel, pos, pos, 4);
1088 // LordHavoc: changed to dust shower
1089 CL_SparkShower(pos, vec3_origin, 30);
1090 CL_AllocDlight (NULL, pos, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2);
1092 S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
1097 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
1099 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
1101 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
1104 // LordHavoc: added for improved blood splatters
1107 MSG_ReadVector(pos);
1108 if (cl.worldmodel) cl.worldmodel->FindNonSolidLocation(cl.worldmodel, pos, pos, 4);
1109 dir[0] = MSG_ReadChar ();
1110 dir[1] = MSG_ReadChar ();
1111 dir[2] = MSG_ReadChar ();
1112 count = MSG_ReadByte ();
1113 CL_BloodPuff(pos, dir, count);
1117 MSG_ReadVector(pos);
1118 if (cl.worldmodel) cl.worldmodel->FindNonSolidLocation(cl.worldmodel, pos, pos, 4);
1119 CL_BloodPuff(pos, vec3_origin, 10);
1123 MSG_ReadVector(pos);
1124 if (cl.worldmodel) cl.worldmodel->FindNonSolidLocation(cl.worldmodel, pos, pos, 4);
1125 dir[0] = MSG_ReadChar ();
1126 dir[1] = MSG_ReadChar ();
1127 dir[2] = MSG_ReadChar ();
1128 count = MSG_ReadByte ();
1129 CL_SparkShower(pos, dir, count);
1132 MSG_ReadVector(pos);
1133 if (cl.worldmodel) cl.worldmodel->FindNonSolidLocation(cl.worldmodel, pos, pos, 4);
1134 CL_AllocDlight(NULL, pos, 200, 1, 1, 1, 1000, 0.2);
1137 // LordHavoc: added for improved gore
1138 case TE_BLOODSHOWER:
1140 MSG_ReadVector(pos); // mins
1141 MSG_ReadVector(pos2); // maxs
1142 velspeed = MSG_ReadCoord (); // speed
1143 count = MSG_ReadShort (); // number of particles
1144 CL_BloodShower(pos, pos2, velspeed, count);
1146 case TE_PARTICLECUBE:
1147 // general purpose particle effect
1148 MSG_ReadVector(pos); // mins
1149 MSG_ReadVector(pos2); // maxs
1150 MSG_ReadVector(dir); // dir
1151 count = MSG_ReadShort (); // number of particles
1152 colorStart = MSG_ReadByte (); // color
1153 colorLength = MSG_ReadByte (); // gravity (1 or 0)
1154 velspeed = MSG_ReadCoord (); // randomvel
1155 CL_ParticleCube(pos, pos2, dir, count, colorStart, colorLength, velspeed);
1158 case TE_PARTICLERAIN:
1159 // general purpose particle effect
1160 MSG_ReadVector(pos); // mins
1161 MSG_ReadVector(pos2); // maxs
1162 MSG_ReadVector(dir); // dir
1163 count = MSG_ReadShort (); // number of particles
1164 colorStart = MSG_ReadByte (); // color
1165 CL_ParticleRain(pos, pos2, dir, count, colorStart, 0);
1168 case TE_PARTICLESNOW:
1169 // general purpose particle effect
1170 MSG_ReadVector(pos); // mins
1171 MSG_ReadVector(pos2); // maxs
1172 MSG_ReadVector(dir); // dir
1173 count = MSG_ReadShort (); // number of particles
1174 colorStart = MSG_ReadByte (); // color
1175 CL_ParticleRain(pos, pos2, dir, count, colorStart, 1);
1179 // bullet hitting wall
1180 MSG_ReadVector(pos);
1181 if (cl.worldmodel) cl.worldmodel->FindNonSolidLocation(cl.worldmodel, pos, pos, 4);
1182 // LordHavoc: changed to dust shower
1183 CL_SparkShower(pos, vec3_origin, 15);
1186 case TE_GUNSHOTQUAD:
1187 // quad bullet hitting wall
1188 MSG_ReadVector(pos);
1189 if (cl.worldmodel) cl.worldmodel->FindNonSolidLocation(cl.worldmodel, pos, pos, 4);
1190 CL_SparkShower(pos, vec3_origin, 15);
1191 CL_AllocDlight (NULL, pos, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2);
1196 MSG_ReadVector(pos);
1197 if (cl.worldmodel) cl.worldmodel->FindNonSolidLocation(cl.worldmodel, pos, pos, 10);
1198 CL_ParticleExplosion (pos);
1199 // LordHavoc: boosted color from 1.0, 0.8, 0.4 to 1.25, 1.0, 0.5
1200 CL_AllocDlight (NULL, pos, 350, 1.25f, 1.0f, 0.5f, 700, 0.5);
1201 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1204 case TE_EXPLOSIONQUAD:
1205 // quad rocket explosion
1206 MSG_ReadVector(pos);
1207 if (cl.worldmodel) cl.worldmodel->FindNonSolidLocation(cl.worldmodel, pos, pos, 10);
1208 CL_ParticleExplosion (pos);
1209 CL_AllocDlight (NULL, pos, 600, 0.5f, 0.4f, 1.0f, 1200, 0.5);
1210 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1214 // Nehahra movie colored lighting explosion
1215 MSG_ReadVector(pos);
1216 if (cl.worldmodel) cl.worldmodel->FindNonSolidLocation(cl.worldmodel, pos, pos, 10);
1217 CL_ParticleExplosion (pos);
1218 CL_AllocDlight (NULL, pos, 350, MSG_ReadCoord(), MSG_ReadCoord(), MSG_ReadCoord(), 700, 0.5);
1219 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1222 case TE_EXPLOSIONRGB:
1223 // colored lighting explosion
1224 MSG_ReadVector(pos);
1225 if (cl.worldmodel) cl.worldmodel->FindNonSolidLocation(cl.worldmodel, pos, pos, 10);
1226 CL_ParticleExplosion (pos);
1227 color[0] = MSG_ReadByte() * (1.0 / 255.0);
1228 color[1] = MSG_ReadByte() * (1.0 / 255.0);
1229 color[2] = MSG_ReadByte() * (1.0 / 255.0);
1230 CL_AllocDlight (NULL, pos, 350, color[0], color[1], color[2], 700, 0.5);
1231 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1234 case TE_TAREXPLOSION:
1235 // tarbaby explosion
1236 MSG_ReadVector(pos);
1237 if (cl.worldmodel) cl.worldmodel->FindNonSolidLocation(cl.worldmodel, pos, pos, 10);
1238 CL_BlobExplosion (pos);
1240 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1241 CL_AllocDlight (NULL, pos, 600, 0.8f, 0.4f, 1.0f, 1200, 0.5);
1242 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1246 MSG_ReadVector(pos);
1247 if (cl.worldmodel) cl.worldmodel->FindNonSolidLocation(cl.worldmodel, pos, pos, 10);
1248 CL_AllocDlight (NULL, pos, 200, 1, 1, 1, 1000, 0.2);
1251 case TE_CUSTOMFLASH:
1252 MSG_ReadVector(pos);
1253 if (cl.worldmodel) cl.worldmodel->FindNonSolidLocation(cl.worldmodel, pos, pos, 4);
1254 radius = MSG_ReadByte() * 8;
1255 velspeed = (MSG_ReadByte() + 1) * (1.0 / 256.0);
1256 color[0] = MSG_ReadByte() * (1.0 / 255.0);
1257 color[1] = MSG_ReadByte() * (1.0 / 255.0);
1258 color[2] = MSG_ReadByte() * (1.0 / 255.0);
1259 CL_AllocDlight (NULL, pos, radius, color[0], color[1], color[2], radius / velspeed, velspeed);
1263 MSG_ReadVector(pos);
1264 MSG_ReadVector(dir);
1265 count = MSG_ReadByte();
1266 CL_Flames(pos, dir, count);
1272 cl_model_bolt = Mod_ForName("progs/bolt.mdl", true, false, false);
1273 CL_ParseBeam (cl_model_bolt, true);
1278 if (!cl_model_bolt2)
1279 cl_model_bolt2 = Mod_ForName("progs/bolt2.mdl", true, false, false);
1280 CL_ParseBeam (cl_model_bolt2, true);
1285 if (!cl_model_bolt3)
1286 cl_model_bolt3 = Mod_ForName("progs/bolt3.mdl", true, false, false);
1287 CL_ParseBeam (cl_model_bolt3, false);
1292 // grappling hook beam
1294 cl_model_beam = Mod_ForName("progs/beam.mdl", true, false, false);
1295 CL_ParseBeam (cl_model_beam, false);
1299 // LordHavoc: for compatibility with the Nehahra movie...
1300 case TE_LIGHTNING4NEH:
1301 CL_ParseBeam (Mod_ForName(MSG_ReadString(), true, false, false), false);
1305 pos[0] = MSG_ReadCoord ();
1306 pos[1] = MSG_ReadCoord ();
1307 pos[2] = MSG_ReadCoord ();
1308 CL_LavaSplash (pos);
1312 pos[0] = MSG_ReadCoord ();
1313 pos[1] = MSG_ReadCoord ();
1314 pos[2] = MSG_ReadCoord ();
1315 CL_AllocDlight (NULL, pos, 500, 1.0f, 1.0f, 1.0f, 1500, 99.0f);
1316 // CL_TeleportSplash (pos);
1320 // color mapped explosion
1321 MSG_ReadVector(pos);
1322 if (cl.worldmodel) cl.worldmodel->FindNonSolidLocation(cl.worldmodel, pos, pos, 10);
1323 colorStart = MSG_ReadByte ();
1324 colorLength = MSG_ReadByte ();
1325 CL_ParticleExplosion2 (pos, colorStart, colorLength);
1326 tempcolor = (qbyte *)&palette_complete[(rand()%colorLength) + colorStart];
1327 CL_AllocDlight (NULL, pos, 350, tempcolor[0] * (1.0f / 255.0f), tempcolor[1] * (1.0f / 255.0f), tempcolor[2] * (1.0f / 255.0f), 700, 0.5);
1328 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1332 MSG_ReadVector(pos);
1333 MSG_ReadVector(pos2);
1334 MSG_ReadVector(dir);
1335 CL_BeamParticle(pos, pos2, 12, 1, 0.3, 0.1, 1, 1);
1336 CL_BeamParticle(pos, pos2, 5, 1, 0.9, 0.3, 1, 1);
1340 MSG_ReadVector(pos);
1341 MSG_ReadVector(dir);
1342 count = MSG_ReadByte ();
1343 if (cl.worldmodel) cl.worldmodel->FindNonSolidLocation(cl.worldmodel, pos, pos, 4);
1344 CL_Tei_Smoke(pos, dir, count);
1347 case TE_TEI_BIGEXPLOSION:
1348 MSG_ReadVector(pos);
1349 if (cl.worldmodel) cl.worldmodel->FindNonSolidLocation(cl.worldmodel, pos, pos, 10);
1350 CL_ParticleExplosion (pos);
1351 CL_AllocDlight (NULL, pos, 500, 1.25f, 1.0f, 0.5f, 500, 9999);
1352 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1355 case TE_TEI_PLASMAHIT:
1356 MSG_ReadVector(pos);
1357 MSG_ReadVector(dir);
1358 count = MSG_ReadByte ();
1359 if (cl.worldmodel) cl.worldmodel->FindNonSolidLocation(cl.worldmodel, pos, pos, 5);
1360 CL_Tei_PlasmaHit(pos, dir, count);
1361 CL_AllocDlight (NULL, pos, 500, 0.3, 0.6, 1.0f, 2000, 9999);
1365 Host_Error ("CL_ParseTempEntity: bad type %d (hex %02X)", type, type);
1369 #define SHOWNET(x) if(cl_shownet.integer==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x);
1371 static qbyte cgamenetbuffer[65536];
1374 =====================
1375 CL_ParseServerMessage
1376 =====================
1378 int parsingerror = false;
1379 void CL_ParseServerMessage(void)
1382 int i, entitiesupdated;
1384 char *cmdlogname[32], *temp;
1385 int cmdindex, cmdcount = 0;
1387 if (cls.demorecording)
1388 CL_WriteDemoMessage ();
1390 cl.last_received_message = realtime;
1393 // if recording demos, copy the message out
1395 if (cl_shownet.integer == 1)
1396 Con_Printf ("%f %i\n", realtime, net_message.cursize);
1397 else if (cl_shownet.integer == 2)
1398 Con_Printf ("------------------\n");
1400 cl.onground = false; // unless the server says otherwise
1402 // parse the message
1404 //MSG_BeginReading ();
1406 entitiesupdated = false;
1408 parsingerror = true;
1413 Host_Error ("CL_ParseServerMessage: Bad server message");
1415 cmd = MSG_ReadByte ();
1419 SHOWNET("END OF MESSAGE");
1420 break; // end of message
1423 cmdindex = cmdcount & 31;
1425 cmdlog[cmdindex] = cmd;
1427 // if the high bit of the command byte is set, it is a fast update
1430 // LordHavoc: fix for bizarre problem in MSVC that I do not understand (if I assign the string pointer directly it ends up storing a NULL pointer)
1432 cmdlogname[cmdindex] = temp;
1433 SHOWNET("fast update");
1434 if (cls.signon == SIGNONS - 1)
1436 // first update is the final signon stage
1437 cls.signon = SIGNONS;
1440 CL_ParseUpdate (cmd&127);
1444 SHOWNET(svc_strings[cmd]);
1445 cmdlogname[cmdindex] = svc_strings[cmd];
1446 if (!cmdlogname[cmdindex])
1448 // LordHavoc: fix for bizarre problem in MSVC that I do not understand (if I assign the string pointer directly it ends up storing a NULL pointer)
1450 cmdlogname[cmdindex] = temp;
1458 char description[32*64], temp[64];
1460 strcpy(description, "packet dump: ");
1464 count = cmdcount - i;
1468 sprintf(temp, "%3i:%s ", cmdlog[i], cmdlogname[i]);
1469 strcat(description, temp);
1474 description[strlen(description)-1] = '\n'; // replace the last space with a newline
1475 Con_Printf("%s", description);
1476 Host_Error ("CL_ParseServerMessage: Illegible server message\n");
1481 if (cls.signon < SIGNONS)
1482 Con_Printf("<-- server to client keepalive\n");
1486 if (!entitiesupdated)
1488 // this is a new frame, we'll be seeing entities,
1489 // so prepare for entity updates
1490 CL_EntityUpdateSetup();
1491 entitiesupdated = true;
1493 cl.mtime[1] = cl.mtime[0];
1494 cl.mtime[0] = MSG_ReadFloat ();
1497 case svc_clientdata:
1498 i = MSG_ReadShort ();
1499 CL_ParseClientdata (i);
1503 i = MSG_ReadLong ();
1504 if (i != PROTOCOL_VERSION && i != DPPROTOCOL_VERSION1 && i != DPPROTOCOL_VERSION2 && i != DPPROTOCOL_VERSION3 && i != 250)
1505 Host_Error ("CL_ParseServerMessage: Server is protocol %i, not %i, %i, %i or %i", i, DPPROTOCOL_VERSION1, DPPROTOCOL_VERSION2, DPPROTOCOL_VERSION3, PROTOCOL_VERSION);
1506 Nehahrademcompatibility = false;
1508 Nehahrademcompatibility = true;
1509 if (cls.demoplayback && demo_nehahra.integer)
1510 Nehahrademcompatibility = true;
1512 if (dpprotocol != DPPROTOCOL_VERSION1 && dpprotocol != DPPROTOCOL_VERSION2 && dpprotocol != DPPROTOCOL_VERSION3)
1516 case svc_disconnect:
1517 Host_EndGame ("Server disconnected\n");
1520 Con_Printf ("%s", MSG_ReadString ());
1523 case svc_centerprint:
1524 SCR_CenterPrint (MSG_ReadString ());
1528 Cbuf_AddText (MSG_ReadString ());
1535 case svc_serverinfo:
1536 CL_ParseServerInfo ();
1540 for (i=0 ; i<3 ; i++)
1541 cl.viewangles[i] = MSG_ReadAngle ();
1545 cl.viewentity = (unsigned short)MSG_ReadShort ();
1546 if (cl.viewentity >= MAX_EDICTS)
1547 Host_Error("svc_setview >= MAX_EDICTS\n");
1548 // LordHavoc: assume first setview recieved is the real player entity
1549 if (!cl.playerentity)
1550 cl.playerentity = cl.viewentity;
1553 case svc_lightstyle:
1554 i = MSG_ReadByte ();
1555 if (i >= MAX_LIGHTSTYLES)
1556 Host_Error ("svc_lightstyle >= MAX_LIGHTSTYLES");
1557 strncpy (cl_lightstyle[i].map, MSG_ReadString(), MAX_STYLESTRING - 1);
1558 cl_lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
1559 cl_lightstyle[i].length = strlen(cl_lightstyle[i].map);
1563 CL_ParseStartSoundPacket(false);
1567 CL_ParseStartSoundPacket(true);
1571 i = MSG_ReadShort();
1572 S_StopSound(i>>3, i&7);
1575 case svc_updatename:
1576 i = MSG_ReadByte ();
1577 if (i >= cl.maxclients)
1578 Host_Error ("CL_ParseServerMessage: svc_updatename >= cl.maxclients");
1579 strcpy (cl.scores[i].name, MSG_ReadString ());
1582 case svc_updatefrags:
1583 i = MSG_ReadByte ();
1584 if (i >= cl.maxclients)
1585 Host_Error ("CL_ParseServerMessage: svc_updatefrags >= cl.maxclients");
1586 cl.scores[i].frags = MSG_ReadShort ();
1589 case svc_updatecolors:
1590 i = MSG_ReadByte ();
1591 if (i >= cl.maxclients)
1592 Host_Error ("CL_ParseServerMessage: svc_updatecolors >= cl.maxclients");
1593 cl.scores[i].colors = MSG_ReadByte ();
1597 CL_ParseParticleEffect ();
1608 case svc_spawnbaseline:
1609 i = MSG_ReadShort ();
1610 if (i < 0 || i >= MAX_EDICTS)
1611 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i);
1612 CL_ParseBaseline (cl_entities + i, false);
1614 case svc_spawnbaseline2:
1615 i = MSG_ReadShort ();
1616 if (i < 0 || i >= MAX_EDICTS)
1617 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline2: invalid entity number %i", i);
1618 CL_ParseBaseline (cl_entities + i, true);
1620 case svc_spawnstatic:
1621 CL_ParseStatic (false);
1623 case svc_spawnstatic2:
1624 CL_ParseStatic (true);
1626 case svc_temp_entity:
1627 CL_ParseTempEntity ();
1631 cl.paused = MSG_ReadByte ();
1639 i = MSG_ReadByte ();
1640 if (i <= cls.signon)
1641 Host_Error ("Received signon %i when at %i", i, cls.signon);
1646 case svc_killedmonster:
1647 cl.stats[STAT_MONSTERS]++;
1650 case svc_foundsecret:
1651 cl.stats[STAT_SECRETS]++;
1654 case svc_updatestat:
1655 i = MSG_ReadByte ();
1656 if (i < 0 || i >= MAX_CL_STATS)
1657 Host_Error ("svc_updatestat: %i is invalid", i);
1658 cl.stats[i] = MSG_ReadLong ();
1661 case svc_spawnstaticsound:
1662 CL_ParseStaticSound (false);
1665 case svc_spawnstaticsound2:
1666 CL_ParseStaticSound (true);
1670 cl.cdtrack = MSG_ReadByte ();
1671 cl.looptrack = MSG_ReadByte ();
1672 if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )
1673 CDAudio_Play ((qbyte)cls.forcetrack, true);
1675 CDAudio_Play ((qbyte)cl.cdtrack, true);
1678 case svc_intermission:
1679 cl.intermission = 1;
1680 cl.completed_time = cl.time;
1684 cl.intermission = 2;
1685 cl.completed_time = cl.time;
1686 SCR_CenterPrint (MSG_ReadString ());
1690 cl.intermission = 3;
1691 cl.completed_time = cl.time;
1692 SCR_CenterPrint (MSG_ReadString ());
1695 case svc_sellscreen:
1696 Cmd_ExecuteString ("help", src_command);
1699 SHOWLMP_decodehide();
1702 SHOWLMP_decodeshow();
1705 R_SetSkyBox(MSG_ReadString());
1710 length = (int) ((unsigned short) MSG_ReadShort());
1711 for (i = 0;i < length;i++)
1712 cgamenetbuffer[i] = MSG_ReadByte();
1714 CL_CGVM_ParseNetwork(cgamenetbuffer, length);
1718 if (cls.signon == SIGNONS - 1)
1720 // first update is the final signon stage
1721 cls.signon = SIGNONS;
1724 CL_ReadEntityFrame();
1729 if (entitiesupdated)
1730 CL_EntityUpdateEnd();
1732 parsingerror = false;
1735 void CL_Parse_DumpPacket(void)
1739 Con_Printf("Packet dump:\n");
1740 SZ_HexDumpToConsole(&net_message);
1741 parsingerror = false;
1744 void CL_Parse_Init(void)
1746 // LordHavoc: added demo_nehahra cvar
1747 cl_scores_mempool = Mem_AllocPool("client player info");
1748 Cvar_RegisterVariable (&demo_nehahra);
1749 if (gamemode == GAME_NEHAHRA)
1750 Cvar_SetValue("demo_nehahra", 1);