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
23 #include "cl_collision.h"
25 char *svc_strings[128] =
31 "svc_version", // [long] server version
32 "svc_setview", // [short] entity number
33 "svc_sound", // <see code>
34 "svc_time", // [float] server time
35 "svc_print", // [string] null terminated string
36 "svc_stufftext", // [string] stuffed into client's console buffer
37 // the string should be \n terminated
38 "svc_setangle", // [vec3] set the view angle to this absolute value
40 "svc_serverinfo", // [long] version
41 // [string] signon string
42 // [string]..[0]model cache [string]...[0]sounds cache
43 // [string]..[0]item cache
44 "svc_lightstyle", // [byte] [string]
45 "svc_updatename", // [byte] [string]
46 "svc_updatefrags", // [byte] [short]
47 "svc_clientdata", // <shortbits + data>
48 "svc_stopsound", // <see code>
49 "svc_updatecolors", // [byte] [byte]
50 "svc_particle", // [vec3] <variable>
51 "svc_damage", // [byte] impact [byte] blood [vec3] from
54 "OBSOLETE svc_spawnbinary",
57 "svc_temp_entity", // <variable>
63 "svc_spawnstaticsound",
65 "svc_finale", // [string] music [string] text
66 "svc_cdtrack", // [byte] track [byte] looptrack
69 "svc_showlmp", // [string] iconlabel [string] lmpfile [short] x [short] y
70 "svc_hidelmp", // [string] iconlabel
71 "svc_skybox", // [string] skyname
84 "svc_cgame", // 50 // [short] length [bytes] data
85 "svc_unusedlh1", // 51 // unused
86 "svc_effect", // 52 // [vector] org [byte] modelindex [byte] startframe [byte] framecount [byte] framerate
87 "svc_effect2", // 53 // [vector] org [short] modelindex [short] startframe [byte] framecount [byte] framerate
88 "svc_sound2", // 54 // short soundindex instead of byte
89 "svc_spawnbaseline2", // 55 // short modelindex instead of byte
90 "svc_spawnstatic2", // 56 // short modelindex instead of byte
91 "svc_entities", // 57 // [int] deltaframe [int] thisframe [float vector] eye [variable length] entitydata
92 "svc_unusedlh3", // 58
93 "svc_spawnstaticsound2", // 59 // [coord3] [short] samp [byte] vol [byte] aten
96 //=============================================================================
98 cvar_t demo_nehahra = {0, "demo_nehahra", "0"};
99 cvar_t developer_networkentities = {0, "developer_networkentities", "0"};
101 mempool_t *cl_scores_mempool;
105 CL_ParseStartSoundPacket
108 void CL_ParseStartSoundPacket(int largesoundindex)
118 field_mask = MSG_ReadByte();
120 if (field_mask & SND_VOLUME)
121 volume = MSG_ReadByte ();
123 volume = DEFAULT_SOUND_PACKET_VOLUME;
125 if (field_mask & SND_ATTENUATION)
126 attenuation = MSG_ReadByte () / 64.0;
128 attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;
130 if (field_mask & SND_LARGEENTITY)
132 ent = (unsigned short) MSG_ReadShort ();
133 channel = MSG_ReadByte ();
137 channel = (unsigned short) MSG_ReadShort ();
142 if (largesoundindex || field_mask & SND_LARGESOUND)
143 sound_num = (unsigned short) MSG_ReadShort ();
145 sound_num = MSG_ReadByte ();
147 if (sound_num >= MAX_SOUNDS)
148 Host_Error("CL_ParseStartSoundPacket: sound_num (%i) >= MAX_SOUNDS (%i)\n", sound_num, MAX_SOUNDS);
151 if (ent >= MAX_EDICTS)
152 Host_Error ("CL_ParseStartSoundPacket: ent = %i", ent);
154 for (i = 0;i < 3;i++)
155 pos[i] = MSG_ReadCoord ();
157 S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation);
164 When the client is taking a long time to load stuff, send keepalive messages
165 so the server doesn't disconnect.
169 static qbyte olddata[NET_MAXMESSAGE];
170 void CL_KeepaliveMessage (void)
173 static float lastmsg;
178 // no need if server is local and definitely not if this is a demo
179 if (sv.active || cls.demoplayback)
182 // read messages from server, should just be nops
183 oldreadcount = msg_readcount;
184 oldbadread = msg_badread;
186 memcpy(olddata, net_message.data, net_message.cursize);
188 NetConn_ClientFrame();
190 msg_readcount = oldreadcount;
191 msg_badread = oldbadread;
193 memcpy(net_message.data, olddata, net_message.cursize);
195 if (cls.netcon && NetConn_CanSendMessage(cls.netcon) && (time = Sys_DoubleTime()) - lastmsg >= 5)
201 // LordHavoc: must use unreliable because reliable could kill the sigon message!
202 Con_Printf("--> client to server keepalive\n");
204 msg.maxsize = sizeof(buf);
206 MSG_WriteChar(&msg, svc_nop);
207 NetConn_SendUnreliableMessage(cls.netcon, &msg);
208 // try not to utterly crush the computer with work, that's just rude
213 void CL_ParseEntityLump(char *entdata)
216 char key[128], value[4096];
217 FOG_clear(); // LordHavoc: no fog until set
218 R_SetSkyBox(""); // LordHavoc: no environment mapped sky until set
222 if (!COM_ParseToken(&data, false))
224 if (com_token[0] != '{')
228 if (!COM_ParseToken(&data, false))
230 if (com_token[0] == '}')
231 break; // end of worldspawn
232 if (com_token[0] == '_')
233 strcpy(key, com_token + 1);
235 strcpy(key, com_token);
236 while (key[strlen(key)-1] == ' ') // remove trailing spaces
237 key[strlen(key)-1] = 0;
238 if (!COM_ParseToken(&data, false))
240 strcpy(value, com_token);
241 if (!strcmp("sky", key))
243 else if (!strcmp("skyname", key)) // non-standard, introduced by QuakeForge... sigh.
245 else if (!strcmp("qlsky", key)) // non-standard, introduced by QuakeLives (EEK)
247 else if (!strcmp("fog", key))
248 sscanf(value, "%f %f %f %f", &fog_density, &fog_red, &fog_green, &fog_blue);
249 else if (!strcmp("fog_density", key))
250 fog_density = atof(value);
251 else if (!strcmp("fog_red", key))
252 fog_red = atof(value);
253 else if (!strcmp("fog_green", key))
254 fog_green = atof(value);
255 else if (!strcmp("fog_blue", key))
256 fog_blue = atof(value);
261 =====================
264 An svc_signonnum has been received, perform a client side setup
265 =====================
267 static void CL_SignonReply (void)
271 Con_DPrintf ("CL_SignonReply: %i\n", cls.signon);
276 MSG_WriteByte (&cls.message, clc_stringcmd);
277 MSG_WriteString (&cls.message, "prespawn");
281 MSG_WriteByte (&cls.message, clc_stringcmd);
282 MSG_WriteString (&cls.message, va("name \"%s\"\n", cl_name.string));
284 MSG_WriteByte (&cls.message, clc_stringcmd);
285 MSG_WriteString (&cls.message, va("color %i %i\n", cl_color.integer >> 4, cl_color.integer & 15));
287 if (cl_pmodel.integer)
289 MSG_WriteByte (&cls.message, clc_stringcmd);
290 MSG_WriteString (&cls.message, va("pmodel %i\n", cl_pmodel.integer));
293 MSG_WriteByte (&cls.message, clc_stringcmd);
294 MSG_WriteString (&cls.message, "spawn");
298 MSG_WriteByte (&cls.message, clc_stringcmd);
299 MSG_WriteString (&cls.message, "begin");
313 qbyte entlife[MAX_EDICTS];
314 // FIXME: this is a lot of memory to be keeping around, this needs to be dynamically allocated and freed
315 static char parse_model_precache[MAX_MODELS][MAX_QPATH];
316 static char parse_sound_precache[MAX_SOUNDS][MAX_QPATH];
317 void CL_ParseServerInfo (void)
321 int nummodels, numsounds;
324 Con_DPrintf ("Serverinfo packet received.\n");
326 // wipe the client_state_t struct
330 // parse protocol version number
332 // hack for unmarked Nehahra movie demos which had a custom protocol
333 if (i == PROTOCOL_QUAKE && cls.demoplayback && demo_nehahra.integer)
334 i = PROTOCOL_NEHAHRAMOVIE;
335 if (i != PROTOCOL_QUAKE && i != PROTOCOL_DARKPLACES1 && i != PROTOCOL_DARKPLACES2 && i != PROTOCOL_DARKPLACES3 && i != PROTOCOL_DARKPLACES4 && i != PROTOCOL_NEHAHRAMOVIE)
337 Host_Error("CL_ParseServerInfo: Server is protocol %i, not %i (Quake), %i (DP1), %i (DP2), %i (DP3), %i (DP4), or %i (Nehahra movie)", i, PROTOCOL_QUAKE, PROTOCOL_DARKPLACES1, PROTOCOL_DARKPLACES2, PROTOCOL_DARKPLACES3, PROTOCOL_DARKPLACES4, PROTOCOL_NEHAHRAMOVIE);
343 cl.maxclients = MSG_ReadByte ();
344 if (cl.maxclients < 1 || cl.maxclients > MAX_SCOREBOARD)
346 Con_Printf("Bad maxclients (%u) from server\n", cl.maxclients);
349 Mem_EmptyPool(cl_scores_mempool);
350 cl.scores = Mem_Alloc(cl_scores_mempool, cl.maxclients*sizeof(*cl.scores));
353 cl.gametype = MSG_ReadByte ();
355 // parse signon message
356 str = MSG_ReadString ();
357 strncpy (cl.levelname, str, sizeof(cl.levelname)-1);
359 // seperate the printfs so the server message can have a color
360 if (cl.protocol != PROTOCOL_NEHAHRAMOVIE) // no messages when playing the Nehahra movie
362 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");
363 Con_Printf("%c%s\n", 2, str);
366 // check memory integrity
367 Mem_CheckSentinelsGlobal();
369 // disable until we get textures for it
372 memset(cl.model_precache, 0, sizeof(cl.model_precache));
373 memset(cl.sound_precache, 0, sizeof(cl.sound_precache));
375 // parse model precache list
376 for (nummodels=1 ; ; nummodels++)
378 str = MSG_ReadString();
381 if (nummodels==MAX_MODELS)
382 Host_Error ("Server sent too many model precaches\n");
383 if (strlen(str) >= MAX_QPATH)
384 Host_Error ("Server sent a precache name of %i characters (max %i)", strlen(str), MAX_QPATH - 1);
385 strcpy(parse_model_precache[nummodels], str);
387 // parse sound precache list
388 for (numsounds=1 ; ; numsounds++)
390 str = MSG_ReadString();
393 if (numsounds==MAX_SOUNDS)
394 Host_Error("Server sent too many sound precaches\n");
395 if (strlen(str) >= MAX_QPATH)
396 Host_Error("Server sent a precache name of %i characters (max %i)", strlen(str), MAX_QPATH - 1);
397 strcpy(parse_sound_precache[numsounds], str);
400 // touch all of the precached models that are still loaded so we can free
401 // anything that isn't needed
403 for (i = 1;i < nummodels;i++)
405 CL_KeepaliveMessage();
406 Mod_TouchModel(parse_model_precache[i]);
408 // do the same for sounds
409 for (i = 1;i < numsounds;i++)
411 CL_KeepaliveMessage();
412 S_TouchSound(parse_sound_precache[i]);
414 // purge anything that was not touched
417 // now we try to load everything that is new
420 CL_KeepaliveMessage ();
421 cl.model_precache[1] = Mod_ForName(parse_model_precache[1], false, false, true);
422 if (cl.model_precache[1] == NULL)
423 Con_Printf("Map %s not found\n", parse_model_precache[1]);
426 for (i=2 ; i<nummodels ; i++)
428 CL_KeepaliveMessage();
429 if ((cl.model_precache[i] = Mod_ForName(parse_model_precache[i], false, false, false)) == NULL)
430 Con_Printf("Model %s not found\n", parse_model_precache[i]);
434 S_BeginPrecaching ();
435 for (i=1 ; i<numsounds ; i++)
437 CL_KeepaliveMessage();
438 cl.sound_precache[i] = S_PrecacheSound(parse_sound_precache[i], true);
443 ent = &cl_entities[0];
444 // entire entity array was cleared, so just fill in a few fields
445 ent->state_current.active = true;
446 ent->render.model = cl.worldmodel = cl.model_precache[1];
447 //ent->render.scale = 1;
448 ent->render.alpha = 1;
449 ent->render.flags = RENDER_SHADOW;
450 Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, 0, 0, 0, 0, 0, 0, 1);
451 Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix);
452 CL_BoundingBoxForEntity(&ent->render);
453 // clear entlife array
454 memset(entlife, 0, MAX_EDICTS);
461 // noclip is turned off at start
462 noclip_anglehack = false;
464 // check memory integrity
465 Mem_CheckSentinelsGlobal();
468 void CL_ValidateState(entity_state_t *s)
475 if (s->modelindex >= MAX_MODELS)
476 Host_Error("CL_ValidateState: modelindex (%i) >= MAX_MODELS (%i)\n", s->modelindex, MAX_MODELS);
478 // colormap is client index + 1
479 if (s->colormap > cl.maxclients)
480 Host_Error ("CL_ValidateState: colormap (%i) > cl.maxclients (%i)", s->colormap, cl.maxclients);
482 model = cl.model_precache[s->modelindex];
483 Mod_CheckLoaded(model);
484 if (model && s->frame >= model->numframes)
486 Con_DPrintf("CL_ValidateState: no such frame %i in \"%s\"\n", s->frame, model->name);
489 if (model && s->skin > 0 && s->skin >= model->numskins)
491 Con_DPrintf("CL_ValidateState: no such skin %i in \"%s\"\n", s->skin, model->name);
496 void CL_MoveLerpEntityStates(entity_t *ent)
498 float odelta[3], adelta[3];
499 VectorSubtract(ent->state_current.origin, ent->persistent.neworigin, odelta);
500 VectorSubtract(ent->state_current.angles, ent->persistent.newangles, adelta);
501 if (!ent->state_previous.active || cls.timedemo || DotProduct(odelta, odelta) > 1000*1000 || cl_nolerp.integer)
503 // we definitely shouldn't lerp
504 ent->persistent.lerpdeltatime = 0;
505 ent->persistent.lerpstarttime = cl.mtime[1];
506 VectorCopy(ent->state_current.origin, ent->persistent.oldorigin);
507 VectorCopy(ent->state_current.angles, ent->persistent.oldangles);
508 VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
509 VectorCopy(ent->state_current.angles, ent->persistent.newangles);
511 else if (ent->state_current.flags & RENDER_STEP)
513 // monster interpolation
514 if (DotProduct(odelta, odelta) + DotProduct(adelta, adelta) > 0.01)
516 ent->persistent.lerpdeltatime = bound(0, cl.mtime[1] - ent->persistent.lerpstarttime, 0.1);
517 ent->persistent.lerpstarttime = cl.mtime[1];
518 VectorCopy(ent->persistent.neworigin, ent->persistent.oldorigin);
519 VectorCopy(ent->persistent.newangles, ent->persistent.oldangles);
520 VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
521 VectorCopy(ent->state_current.angles, ent->persistent.newangles);
527 ent->persistent.lerpstarttime = cl.mtime[1];
528 // no lerp if it's singleplayer
530 ent->persistent.lerpdeltatime = 0;
532 ent->persistent.lerpdeltatime = cl.mtime[0] - cl.mtime[1];
533 VectorCopy(ent->persistent.neworigin, ent->persistent.oldorigin);
534 VectorCopy(ent->persistent.newangles, ent->persistent.oldangles);
535 VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
536 VectorCopy(ent->state_current.angles, ent->persistent.newangles);
544 Parse an entity update message from the server
545 If an entities model or origin changes from frame to frame, it must be
546 relinked. Other attributes can change without relinking.
549 void CL_ParseUpdate (int bits)
555 if (bits & U_MOREBITS)
556 bits |= (MSG_ReadByte()<<8);
557 if ((bits & U_EXTEND1) && cl.protocol != PROTOCOL_NEHAHRAMOVIE)
559 bits |= MSG_ReadByte() << 16;
560 if (bits & U_EXTEND2)
561 bits |= MSG_ReadByte() << 24;
564 if (bits & U_LONGENTITY)
565 num = (unsigned) MSG_ReadShort ();
567 num = (unsigned) MSG_ReadByte ();
569 if (num >= MAX_EDICTS)
570 Host_Error("CL_ParseUpdate: entity number (%i) >= MAX_EDICTS (%i)\n", num, MAX_EDICTS);
572 Host_Error("CL_ParseUpdate: invalid entity number (%i)\n", num);
574 ent = cl_entities + num;
576 // note: this inherits the 'active' state of the baseline chosen
577 // (state_baseline is always active, state_current may not be active if
578 // the entity was missing in the last frame)
580 new = ent->state_current;
583 new = ent->state_baseline;
588 new.time = cl.mtime[0];
590 if (bits & U_MODEL) new.modelindex = (new.modelindex & 0xFF00) | MSG_ReadByte();
591 if (bits & U_FRAME) new.frame = (new.frame & 0xFF00) | MSG_ReadByte();
592 if (bits & U_COLORMAP) new.colormap = MSG_ReadByte();
593 if (bits & U_SKIN) new.skin = MSG_ReadByte();
594 if (bits & U_EFFECTS) new.effects = (new.effects & 0xFF00) | MSG_ReadByte();
595 if (bits & U_ORIGIN1) new.origin[0] = MSG_ReadCoord();
596 if (bits & U_ANGLE1) new.angles[0] = MSG_ReadAngle();
597 if (bits & U_ORIGIN2) new.origin[1] = MSG_ReadCoord();
598 if (bits & U_ANGLE2) new.angles[1] = MSG_ReadAngle();
599 if (bits & U_ORIGIN3) new.origin[2] = MSG_ReadCoord();
600 if (bits & U_ANGLE3) new.angles[2] = MSG_ReadAngle();
601 if (bits & U_STEP) new.flags |= RENDER_STEP;
602 if (bits & U_ALPHA) new.alpha = MSG_ReadByte();
603 if (bits & U_SCALE) new.scale = MSG_ReadByte();
604 if (bits & U_EFFECTS2) new.effects = (new.effects & 0x00FF) | (MSG_ReadByte() << 8);
605 if (bits & U_GLOWSIZE) new.glowsize = MSG_ReadByte();
606 if (bits & U_GLOWCOLOR) new.glowcolor = MSG_ReadByte();
607 // apparently the dpcrush demo uses this (unintended, and it uses white anyway)
608 if (bits & U_COLORMOD) MSG_ReadByte();
609 if (bits & U_GLOWTRAIL) new.flags |= RENDER_GLOWTRAIL;
610 if (bits & U_FRAME2) new.frame = (new.frame & 0x00FF) | (MSG_ReadByte() << 8);
611 if (bits & U_MODEL2) new.modelindex = (new.modelindex & 0x00FF) | (MSG_ReadByte() << 8);
612 if (bits & U_VIEWMODEL) new.flags |= RENDER_VIEWMODEL;
613 if (bits & U_EXTERIORMODEL) new.flags |= RENDER_EXTERIORMODEL;
615 // LordHavoc: to allow playback of the Nehahra movie
616 if (cl.protocol == PROTOCOL_NEHAHRAMOVIE && (bits & U_EXTEND1))
618 // LordHavoc: evil format
619 int i = MSG_ReadFloat();
620 int j = MSG_ReadFloat() * 255.0f;
625 new.effects |= EF_FULLBRIGHT;
629 else if (j == 0 || j >= 255)
636 CL_ValidateState(&new);
638 ent->state_previous = ent->state_current;
639 ent->state_current = new;
640 if (ent->state_current.active)
642 CL_MoveLerpEntityStates(ent);
643 cl_entities_active[ent->state_current.number] = true;
644 // mark as visible (no kill this frame)
645 entlife[ent->state_current.number] = 2;
649 static entity_frame_t entityframe;
650 extern mempool_t *cl_entities_mempool;
651 void CL_ReadEntityFrame(void)
653 if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
657 EntityFrame_Read(&cl.entitydatabase);
658 EntityFrame_FetchFrame(&cl.entitydatabase, EntityFrame_MostRecentlyRecievedFrameNum(&cl.entitydatabase), &entityframe);
659 for (i = 0;i < entityframe.numentities;i++)
662 ent = &cl_entities[entityframe.entitydata[i].number];
663 ent->state_previous = ent->state_current;
664 ent->state_current = entityframe.entitydata[i];
665 CL_MoveLerpEntityStates(ent);
666 // the entity lives again...
667 entlife[ent->state_current.number] = 2;
668 cl_entities_active[ent->state_current.number] = true;
673 if (!cl.entitydatabase4)
674 cl.entitydatabase4 = EntityFrame4_AllocDatabase(cl_entities_mempool);
675 EntityFrame4_CL_ReadFrame(cl.entitydatabase4);
679 void CL_EntityUpdateSetup(void)
683 void CL_EntityUpdateEnd(void)
685 if (cl.protocol == PROTOCOL_QUAKE || cl.protocol == PROTOCOL_NEHAHRAMOVIE || cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
688 // disable entities that disappeared this frame
689 for (i = 1;i < MAX_EDICTS;i++)
691 // clear only the entities that were active last frame but not this
692 // frame, don't waste time clearing all entities (which would cause
698 cl_entities[i].state_previous.active = cl_entities[i].state_current.active = 0;
709 void CL_ParseBaseline (entity_t *ent, int large)
713 ClearStateToDefault(&ent->state_baseline);
714 ent->state_baseline.active = true;
717 ent->state_baseline.modelindex = (unsigned short) MSG_ReadShort ();
718 ent->state_baseline.frame = (unsigned short) MSG_ReadShort ();
722 ent->state_baseline.modelindex = MSG_ReadByte ();
723 ent->state_baseline.frame = MSG_ReadByte ();
725 ent->state_baseline.colormap = MSG_ReadByte();
726 ent->state_baseline.skin = MSG_ReadByte();
727 for (i = 0;i < 3;i++)
729 ent->state_baseline.origin[i] = MSG_ReadCoord ();
730 ent->state_baseline.angles[i] = MSG_ReadAngle ();
732 CL_ValidateState(&ent->state_baseline);
733 ent->state_previous = ent->state_current = ent->state_baseline;
741 Server information pertaining to this client only
744 void CL_ParseClientdata (int bits)
749 if (bits & SU_EXTEND1)
750 bits |= (MSG_ReadByte() << 16);
751 if (bits & SU_EXTEND2)
752 bits |= (MSG_ReadByte() << 24);
754 if (bits & SU_VIEWHEIGHT)
755 cl.viewheight = MSG_ReadChar ();
757 cl.viewheight = DEFAULT_VIEWHEIGHT;
759 if (bits & SU_IDEALPITCH)
760 cl.idealpitch = MSG_ReadChar ();
764 VectorCopy (cl.mvelocity[0], cl.mvelocity[1]);
765 for (i=0 ; i<3 ; i++)
767 if (bits & (SU_PUNCH1<<i) )
769 if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4)
770 cl.punchangle[i] = MSG_ReadPreciseAngle();
772 cl.punchangle[i] = MSG_ReadChar();
775 cl.punchangle[i] = 0;
776 if (bits & (SU_PUNCHVEC1<<i))
777 cl.punchvector[i] = MSG_ReadCoord();
779 cl.punchvector[i] = 0;
780 if (bits & (SU_VELOCITY1<<i) )
781 cl.mvelocity[0][i] = MSG_ReadChar()*16;
783 cl.mvelocity[0][i] = 0;
789 for (j=0 ; j<32 ; j++)
790 if ( (i & (1<<j)) && !(cl.items & (1<<j)))
791 cl.item_gettime[j] = cl.time;
795 cl.onground = (bits & SU_ONGROUND) != 0;
796 cl.inwater = (bits & SU_INWATER) != 0;
798 cl.stats[STAT_WEAPONFRAME] = (bits & SU_WEAPONFRAME) ? MSG_ReadByte() : 0;
799 cl.stats[STAT_ARMOR] = (bits & SU_ARMOR) ? MSG_ReadByte() : 0;
800 cl.stats[STAT_WEAPON] = (bits & SU_WEAPON) ? MSG_ReadByte() : 0;
801 cl.stats[STAT_HEALTH] = MSG_ReadShort();
802 cl.stats[STAT_AMMO] = MSG_ReadByte();
804 cl.stats[STAT_SHELLS] = MSG_ReadByte();
805 cl.stats[STAT_NAILS] = MSG_ReadByte();
806 cl.stats[STAT_ROCKETS] = MSG_ReadByte();
807 cl.stats[STAT_CELLS] = MSG_ReadByte();
811 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
812 cl.stats[STAT_ACTIVEWEAPON] = (1<<i);
814 cl.stats[STAT_ACTIVEWEAPON] = i;
816 cl.viewzoomold = cl.viewzoomnew; // for interpolation
817 if (bits & SU_VIEWZOOM)
822 cl.viewzoomnew = (float) i * (1.0f / 255.0f);
830 =====================
832 =====================
834 void CL_ParseStatic (int large)
838 if (cl_num_static_entities >= cl_max_static_entities)
839 Host_Error ("Too many static entities");
840 ent = &cl_static_entities[cl_num_static_entities++];
841 CL_ParseBaseline (ent, large);
843 // copy it to the current state
844 ent->render.model = cl.model_precache[ent->state_baseline.modelindex];
845 ent->render.frame = ent->render.frame1 = ent->render.frame2 = ent->state_baseline.frame;
846 ent->render.framelerp = 0;
847 // make torchs play out of sync
848 ent->render.frame1time = ent->render.frame2time = lhrandom(-10, -1);
849 ent->render.colormap = -1; // no special coloring
850 ent->render.skinnum = ent->state_baseline.skin;
851 ent->render.effects = ent->state_baseline.effects;
852 ent->render.alpha = 1;
853 //ent->render.scale = 1;
855 //VectorCopy (ent->state_baseline.origin, ent->render.origin);
856 //VectorCopy (ent->state_baseline.angles, ent->render.angles);
858 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);
859 Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix);
860 CL_BoundingBoxForEntity(&ent->render);
862 // This is definitely cheating...
863 if (ent->render.model == NULL)
864 cl_num_static_entities--;
872 void CL_ParseStaticSound (int large)
875 int sound_num, vol, atten;
879 sound_num = (unsigned short) MSG_ReadShort ();
881 sound_num = MSG_ReadByte ();
882 vol = MSG_ReadByte ();
883 atten = MSG_ReadByte ();
885 S_StaticSound (cl.sound_precache[sound_num], org, vol, atten);
888 void CL_ParseEffect (void)
891 int modelindex, startframe, framecount, framerate;
894 modelindex = MSG_ReadByte ();
895 startframe = MSG_ReadByte ();
896 framecount = MSG_ReadByte ();
897 framerate = MSG_ReadByte ();
899 CL_Effect(org, modelindex, startframe, framecount, framerate);
902 void CL_ParseEffect2 (void)
905 int modelindex, startframe, framecount, framerate;
908 modelindex = MSG_ReadShort ();
909 startframe = MSG_ReadShort ();
910 framecount = MSG_ReadByte ();
911 framerate = MSG_ReadByte ();
913 CL_Effect(org, modelindex, startframe, framecount, framerate);
916 model_t *cl_model_bolt = NULL;
917 model_t *cl_model_bolt2 = NULL;
918 model_t *cl_model_bolt3 = NULL;
919 model_t *cl_model_beam = NULL;
921 sfx_t *cl_sfx_wizhit;
922 sfx_t *cl_sfx_knighthit;
927 sfx_t *cl_sfx_r_exp3;
934 void CL_InitTEnts (void)
936 cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav", false);
937 cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav", false);
938 cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav", false);
939 cl_sfx_ric1 = S_PrecacheSound ("weapons/ric1.wav", false);
940 cl_sfx_ric2 = S_PrecacheSound ("weapons/ric2.wav", false);
941 cl_sfx_ric3 = S_PrecacheSound ("weapons/ric3.wav", false);
942 cl_sfx_r_exp3 = S_PrecacheSound ("weapons/r_exp3.wav", false);
945 void CL_ParseBeam (model_t *m, int lightning)
951 ent = MSG_ReadShort ();
952 MSG_ReadVector(start);
955 if (ent >= MAX_EDICTS)
957 Con_Printf("CL_ParseBeam: invalid entity number %i\n", ent);
961 // override any beam with the same entity
962 for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
964 if (b->entity == ent)
967 b->lightning = lightning;
968 b->relativestartvalid = (ent && cl_entities[ent].state_current.active) ? 2 : 0;
970 b->endtime = cl.time + 0.2;
971 VectorCopy (start, b->start);
972 VectorCopy (end, b->end);
978 for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
980 if (!b->model || b->endtime < cl.time)
983 b->lightning = lightning;
984 b->relativestartvalid = (ent && cl_entities[ent].state_current.active) ? 2 : 0;
986 b->endtime = cl.time + 0.2;
987 VectorCopy (start, b->start);
988 VectorCopy (end, b->end);
992 Con_Printf ("beam list overflow!\n");
995 void CL_ParseTempEntity(void)
1003 int colorStart, colorLength, count;
1004 float velspeed, radius;
1007 type = MSG_ReadByte();
1011 // spike hitting wall
1012 MSG_ReadVector(pos);
1013 CL_FindNonSolidLocation(pos, pos, 4);
1014 CL_AllocDlight(NULL, pos, 50, 0.25f, 1.00f, 0.25f, 250, 0.2);
1015 CL_RunParticleEffect(pos, vec3_origin, 20, 30);
1016 S_StartSound(-1, 0, cl_sfx_wizhit, pos, 1, 1);
1019 case TE_KNIGHTSPIKE:
1020 // spike hitting wall
1021 MSG_ReadVector(pos);
1022 CL_FindNonSolidLocation(pos, pos, 4);
1023 CL_AllocDlight(NULL, pos, 50, 1.0f, 0.60f, 0.20f, 250, 0.2);
1024 CL_RunParticleEffect(pos, vec3_origin, 226, 20);
1025 S_StartSound(-1, 0, cl_sfx_knighthit, pos, 1, 1);
1029 // spike hitting wall
1030 MSG_ReadVector(pos);
1031 CL_FindNonSolidLocation(pos, pos, 4);
1032 // LordHavoc: changed to spark shower
1033 CL_SparkShower(pos, vec3_origin, 15);
1035 S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1040 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1042 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1044 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1048 // quad spike hitting wall
1049 MSG_ReadVector(pos);
1050 CL_FindNonSolidLocation(pos, pos, 4);
1051 // LordHavoc: changed to spark shower
1052 CL_SparkShower(pos, vec3_origin, 15);
1053 CL_AllocDlight(NULL, pos, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2);
1054 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1056 S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1061 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1063 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1065 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1069 // super spike hitting wall
1070 MSG_ReadVector(pos);
1071 CL_FindNonSolidLocation(pos, pos, 4);
1072 // LordHavoc: changed to dust shower
1073 CL_SparkShower(pos, vec3_origin, 30);
1075 S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1080 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1082 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1084 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1087 case TE_SUPERSPIKEQUAD:
1088 // quad super spike hitting wall
1089 MSG_ReadVector(pos);
1090 CL_FindNonSolidLocation(pos, pos, 4);
1091 // LordHavoc: changed to dust shower
1092 CL_SparkShower(pos, vec3_origin, 30);
1093 CL_AllocDlight(NULL, pos, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2);
1095 S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1100 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1102 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1104 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1107 // LordHavoc: added for improved blood splatters
1110 MSG_ReadVector(pos);
1111 CL_FindNonSolidLocation(pos, pos, 4);
1112 dir[0] = MSG_ReadChar();
1113 dir[1] = MSG_ReadChar();
1114 dir[2] = MSG_ReadChar();
1115 count = MSG_ReadByte();
1116 CL_BloodPuff(pos, dir, count);
1120 MSG_ReadVector(pos);
1121 CL_FindNonSolidLocation(pos, pos, 4);
1122 dir[0] = MSG_ReadChar();
1123 dir[1] = MSG_ReadChar();
1124 dir[2] = MSG_ReadChar();
1125 count = MSG_ReadByte();
1126 CL_SparkShower(pos, dir, count);
1129 MSG_ReadVector(pos);
1130 CL_FindNonSolidLocation(pos, pos, 4);
1131 CL_AllocDlight(NULL, pos, 200, 1, 1, 1, 1000, 0.2);
1134 // LordHavoc: added for improved gore
1135 case TE_BLOODSHOWER:
1137 MSG_ReadVector(pos); // mins
1138 MSG_ReadVector(pos2); // maxs
1139 velspeed = MSG_ReadCoord(); // speed
1140 count = MSG_ReadShort(); // number of particles
1141 CL_BloodShower(pos, pos2, velspeed, count);
1143 case TE_PARTICLECUBE:
1144 // general purpose particle effect
1145 MSG_ReadVector(pos); // mins
1146 MSG_ReadVector(pos2); // maxs
1147 MSG_ReadVector(dir); // dir
1148 count = MSG_ReadShort(); // number of particles
1149 colorStart = MSG_ReadByte(); // color
1150 colorLength = MSG_ReadByte(); // gravity (1 or 0)
1151 velspeed = MSG_ReadCoord(); // randomvel
1152 CL_ParticleCube(pos, pos2, dir, count, colorStart, colorLength, velspeed);
1155 case TE_PARTICLERAIN:
1156 // general purpose particle effect
1157 MSG_ReadVector(pos); // mins
1158 MSG_ReadVector(pos2); // maxs
1159 MSG_ReadVector(dir); // dir
1160 count = MSG_ReadShort(); // number of particles
1161 colorStart = MSG_ReadByte(); // color
1162 CL_ParticleRain(pos, pos2, dir, count, colorStart, 0);
1165 case TE_PARTICLESNOW:
1166 // general purpose particle effect
1167 MSG_ReadVector(pos); // mins
1168 MSG_ReadVector(pos2); // maxs
1169 MSG_ReadVector(dir); // dir
1170 count = MSG_ReadShort(); // number of particles
1171 colorStart = MSG_ReadByte(); // color
1172 CL_ParticleRain(pos, pos2, dir, count, colorStart, 1);
1176 // bullet hitting wall
1177 MSG_ReadVector(pos);
1178 CL_FindNonSolidLocation(pos, pos, 4);
1179 // LordHavoc: changed to dust shower
1180 CL_SparkShower(pos, vec3_origin, 15);
1183 case TE_GUNSHOTQUAD:
1184 // quad bullet hitting wall
1185 MSG_ReadVector(pos);
1186 CL_FindNonSolidLocation(pos, pos, 4);
1187 CL_SparkShower(pos, vec3_origin, 15);
1188 CL_AllocDlight(NULL, pos, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2);
1193 MSG_ReadVector(pos);
1194 CL_FindNonSolidLocation(pos, pos, 10);
1195 CL_ParticleExplosion(pos);
1196 // LordHavoc: boosted color from 1.0, 0.8, 0.4 to 1.25, 1.0, 0.5
1197 CL_AllocDlight(NULL, pos, 350, 1.25f, 1.0f, 0.5f, 700, 0.5);
1198 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1201 case TE_EXPLOSIONQUAD:
1202 // quad rocket explosion
1203 MSG_ReadVector(pos);
1204 CL_FindNonSolidLocation(pos, pos, 10);
1205 CL_ParticleExplosion(pos);
1206 CL_AllocDlight(NULL, pos, 600, 0.5f, 0.4f, 1.0f, 1200, 0.5);
1207 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1211 // Nehahra movie colored lighting explosion
1212 MSG_ReadVector(pos);
1213 CL_FindNonSolidLocation(pos, pos, 10);
1214 CL_ParticleExplosion(pos);
1215 CL_AllocDlight(NULL, pos, 350, MSG_ReadCoord(), MSG_ReadCoord(), MSG_ReadCoord(), 700, 0.5);
1216 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1219 case TE_EXPLOSIONRGB:
1220 // colored lighting explosion
1221 MSG_ReadVector(pos);
1222 CL_FindNonSolidLocation(pos, pos, 10);
1223 CL_ParticleExplosion(pos);
1224 color[0] = MSG_ReadByte() * (1.0 / 255.0);
1225 color[1] = MSG_ReadByte() * (1.0 / 255.0);
1226 color[2] = MSG_ReadByte() * (1.0 / 255.0);
1227 CL_AllocDlight(NULL, pos, 350, color[0], color[1], color[2], 700, 0.5);
1228 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1231 case TE_TAREXPLOSION:
1232 // tarbaby explosion
1233 MSG_ReadVector(pos);
1234 CL_FindNonSolidLocation(pos, pos, 10);
1235 CL_BlobExplosion(pos);
1237 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1238 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1239 CL_AllocDlight(NULL, pos, 600, 0.8f, 0.4f, 1.0f, 1200, 0.5);
1243 MSG_ReadVector(pos);
1244 CL_FindNonSolidLocation(pos, pos, 10);
1245 CL_AllocDlight(NULL, pos, 200, 1, 1, 1, 1000, 0.2);
1248 case TE_CUSTOMFLASH:
1249 MSG_ReadVector(pos);
1250 CL_FindNonSolidLocation(pos, pos, 4);
1251 radius = MSG_ReadByte() * 8;
1252 velspeed = (MSG_ReadByte() + 1) * (1.0 / 256.0);
1253 color[0] = MSG_ReadByte() * (1.0 / 255.0);
1254 color[1] = MSG_ReadByte() * (1.0 / 255.0);
1255 color[2] = MSG_ReadByte() * (1.0 / 255.0);
1256 CL_AllocDlight(NULL, pos, radius, color[0], color[1], color[2], radius / velspeed, velspeed);
1260 MSG_ReadVector(pos);
1261 MSG_ReadVector(dir);
1262 count = MSG_ReadByte();
1263 CL_Flames(pos, dir, count);
1269 cl_model_bolt = Mod_ForName("progs/bolt.mdl", true, false, false);
1270 CL_ParseBeam(cl_model_bolt, true);
1275 if (!cl_model_bolt2)
1276 cl_model_bolt2 = Mod_ForName("progs/bolt2.mdl", true, false, false);
1277 CL_ParseBeam(cl_model_bolt2, true);
1282 if (!cl_model_bolt3)
1283 cl_model_bolt3 = Mod_ForName("progs/bolt3.mdl", true, false, false);
1284 CL_ParseBeam(cl_model_bolt3, false);
1289 // grappling hook beam
1291 cl_model_beam = Mod_ForName("progs/beam.mdl", true, false, false);
1292 CL_ParseBeam(cl_model_beam, false);
1296 // LordHavoc: for compatibility with the Nehahra movie...
1297 case TE_LIGHTNING4NEH:
1298 CL_ParseBeam(Mod_ForName(MSG_ReadString(), true, false, false), false);
1302 pos[0] = MSG_ReadCoord();
1303 pos[1] = MSG_ReadCoord();
1304 pos[2] = MSG_ReadCoord();
1309 pos[0] = MSG_ReadCoord();
1310 pos[1] = MSG_ReadCoord();
1311 pos[2] = MSG_ReadCoord();
1312 CL_AllocDlight(NULL, pos, 500, 1.0f, 1.0f, 1.0f, 1500, 99.0f);
1313 // CL_TeleportSplash(pos);
1317 // color mapped explosion
1318 MSG_ReadVector(pos);
1319 CL_FindNonSolidLocation(pos, pos, 10);
1320 colorStart = MSG_ReadByte();
1321 colorLength = MSG_ReadByte();
1322 CL_ParticleExplosion2(pos, colorStart, colorLength);
1323 tempcolor = (qbyte *)&palette_complete[(rand()%colorLength) + colorStart];
1324 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);
1325 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1329 MSG_ReadVector(pos);
1330 MSG_ReadVector(pos2);
1331 MSG_ReadVector(dir);
1332 CL_BeamParticle(pos, pos2, 12, 1, 0.3, 0.1, 1, 1);
1333 CL_BeamParticle(pos, pos2, 5, 1, 0.9, 0.3, 1, 1);
1337 MSG_ReadVector(pos);
1338 MSG_ReadVector(dir);
1339 count = MSG_ReadByte();
1340 CL_FindNonSolidLocation(pos, pos, 4);
1341 CL_Tei_Smoke(pos, dir, count);
1344 case TE_TEI_BIGEXPLOSION:
1345 MSG_ReadVector(pos);
1346 CL_FindNonSolidLocation(pos, pos, 10);
1347 CL_ParticleExplosion(pos);
1348 CL_AllocDlight(NULL, pos, 500, 1.25f, 1.0f, 0.5f, 500, 9999);
1349 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1352 case TE_TEI_PLASMAHIT:
1353 MSG_ReadVector(pos);
1354 MSG_ReadVector(dir);
1355 count = MSG_ReadByte();
1356 CL_FindNonSolidLocation(pos, pos, 5);
1357 CL_Tei_PlasmaHit(pos, dir, count);
1358 CL_AllocDlight(NULL, pos, 500, 0.3, 0.6, 1.0f, 2000, 9999);
1362 Host_Error("CL_ParseTempEntity: bad type %d (hex %02X)", type, type);
1366 #define SHOWNET(x) if(cl_shownet.integer==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x);
1368 static qbyte cgamenetbuffer[65536];
1371 =====================
1372 CL_ParseServerMessage
1373 =====================
1375 int parsingerror = false;
1376 void CL_ParseServerMessage(void)
1379 int i, entitiesupdated;
1381 char *cmdlogname[32], *temp;
1382 int cmdindex, cmdcount = 0;
1384 if (cls.demorecording)
1385 CL_WriteDemoMessage ();
1387 cl.last_received_message = realtime;
1390 // if recording demos, copy the message out
1392 if (cl_shownet.integer == 1)
1393 Con_Printf ("%f %i\n", realtime, net_message.cursize);
1394 else if (cl_shownet.integer == 2)
1395 Con_Printf ("------------------\n");
1397 cl.onground = false; // unless the server says otherwise
1399 // parse the message
1401 //MSG_BeginReading ();
1403 entitiesupdated = false;
1405 parsingerror = true;
1410 Host_Error ("CL_ParseServerMessage: Bad server message");
1412 cmd = MSG_ReadByte ();
1416 SHOWNET("END OF MESSAGE");
1417 break; // end of message
1420 cmdindex = cmdcount & 31;
1422 cmdlog[cmdindex] = cmd;
1424 // if the high bit of the command byte is set, it is a fast update
1427 // 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)
1429 cmdlogname[cmdindex] = temp;
1430 SHOWNET("fast update");
1431 if (cls.signon == SIGNONS - 1)
1433 // first update is the final signon stage
1434 cls.signon = SIGNONS;
1437 CL_ParseUpdate (cmd&127);
1441 SHOWNET(svc_strings[cmd]);
1442 cmdlogname[cmdindex] = svc_strings[cmd];
1443 if (!cmdlogname[cmdindex])
1445 // 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)
1447 cmdlogname[cmdindex] = temp;
1455 char description[32*64], temp[64];
1457 strcpy(description, "packet dump: ");
1461 count = cmdcount - i;
1465 sprintf(temp, "%3i:%s ", cmdlog[i], cmdlogname[i]);
1466 strcat(description, temp);
1471 description[strlen(description)-1] = '\n'; // replace the last space with a newline
1472 Con_Printf("%s", description);
1473 Host_Error ("CL_ParseServerMessage: Illegible server message\n");
1478 if (cls.signon < SIGNONS)
1479 Con_Printf("<-- server to client keepalive\n");
1483 if (!entitiesupdated)
1485 // this is a new frame, we'll be seeing entities,
1486 // so prepare for entity updates
1487 CL_EntityUpdateSetup();
1488 entitiesupdated = true;
1490 cl.mtime[1] = cl.mtime[0];
1491 cl.mtime[0] = MSG_ReadFloat ();
1494 case svc_clientdata:
1495 i = MSG_ReadShort ();
1496 CL_ParseClientdata (i);
1500 i = MSG_ReadLong ();
1501 // hack for unmarked Nehahra movie demos which had a custom protocol
1502 if (i == PROTOCOL_QUAKE && cls.demoplayback && demo_nehahra.integer)
1503 i = PROTOCOL_NEHAHRAMOVIE;
1504 if (i != PROTOCOL_QUAKE && i != PROTOCOL_DARKPLACES1 && i != PROTOCOL_DARKPLACES2 && i != PROTOCOL_DARKPLACES3 && i != PROTOCOL_DARKPLACES4 && i != PROTOCOL_NEHAHRAMOVIE)
1505 Host_Error("CL_ParseServerMessage: Server is protocol %i, not %i (Quake), %i (DP1), %i (DP2), %i (DP3), %i (DP4), or %i (Nehahra movie)", i, PROTOCOL_QUAKE, PROTOCOL_DARKPLACES1, PROTOCOL_DARKPLACES2, PROTOCOL_DARKPLACES3, PROTOCOL_DARKPLACES4, PROTOCOL_NEHAHRAMOVIE);
1509 case svc_disconnect:
1510 Host_EndGame ("Server disconnected\n");
1513 Con_Printf ("%s", MSG_ReadString ());
1516 case svc_centerprint:
1517 SCR_CenterPrint (MSG_ReadString ());
1521 Cbuf_AddText (MSG_ReadString ());
1528 case svc_serverinfo:
1529 CL_ParseServerInfo ();
1533 for (i=0 ; i<3 ; i++)
1534 cl.viewangles[i] = MSG_ReadAngle ();
1538 cl.viewentity = (unsigned short)MSG_ReadShort ();
1539 if (cl.viewentity >= MAX_EDICTS)
1540 Host_Error("svc_setview >= MAX_EDICTS\n");
1541 // LordHavoc: assume first setview recieved is the real player entity
1542 if (!cl.playerentity)
1543 cl.playerentity = cl.viewentity;
1546 case svc_lightstyle:
1547 i = MSG_ReadByte ();
1548 if (i >= MAX_LIGHTSTYLES)
1549 Host_Error ("svc_lightstyle >= MAX_LIGHTSTYLES");
1550 strncpy (cl_lightstyle[i].map, MSG_ReadString(), MAX_STYLESTRING - 1);
1551 cl_lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
1552 cl_lightstyle[i].length = strlen(cl_lightstyle[i].map);
1556 CL_ParseStartSoundPacket(false);
1560 CL_ParseStartSoundPacket(true);
1564 i = MSG_ReadShort();
1565 S_StopSound(i>>3, i&7);
1568 case svc_updatename:
1569 i = MSG_ReadByte ();
1570 if (i >= cl.maxclients)
1571 Host_Error ("CL_ParseServerMessage: svc_updatename >= cl.maxclients");
1572 strcpy (cl.scores[i].name, MSG_ReadString ());
1575 case svc_updatefrags:
1576 i = MSG_ReadByte ();
1577 if (i >= cl.maxclients)
1578 Host_Error ("CL_ParseServerMessage: svc_updatefrags >= cl.maxclients");
1579 cl.scores[i].frags = MSG_ReadShort ();
1582 case svc_updatecolors:
1583 i = MSG_ReadByte ();
1584 if (i >= cl.maxclients)
1585 Host_Error ("CL_ParseServerMessage: svc_updatecolors >= cl.maxclients");
1586 cl.scores[i].colors = MSG_ReadByte ();
1590 CL_ParseParticleEffect ();
1601 case svc_spawnbaseline:
1602 i = MSG_ReadShort ();
1603 if (i < 0 || i >= MAX_EDICTS)
1604 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i);
1605 CL_ParseBaseline (cl_entities + i, false);
1607 case svc_spawnbaseline2:
1608 i = MSG_ReadShort ();
1609 if (i < 0 || i >= MAX_EDICTS)
1610 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline2: invalid entity number %i", i);
1611 CL_ParseBaseline (cl_entities + i, true);
1613 case svc_spawnstatic:
1614 CL_ParseStatic (false);
1616 case svc_spawnstatic2:
1617 CL_ParseStatic (true);
1619 case svc_temp_entity:
1620 CL_ParseTempEntity ();
1624 cl.paused = MSG_ReadByte ();
1632 i = MSG_ReadByte ();
1633 if (i <= cls.signon)
1634 Host_Error ("Received signon %i when at %i", i, cls.signon);
1639 case svc_killedmonster:
1640 cl.stats[STAT_MONSTERS]++;
1643 case svc_foundsecret:
1644 cl.stats[STAT_SECRETS]++;
1647 case svc_updatestat:
1648 i = MSG_ReadByte ();
1649 if (i < 0 || i >= MAX_CL_STATS)
1650 Host_Error ("svc_updatestat: %i is invalid", i);
1651 cl.stats[i] = MSG_ReadLong ();
1654 case svc_spawnstaticsound:
1655 CL_ParseStaticSound (false);
1658 case svc_spawnstaticsound2:
1659 CL_ParseStaticSound (true);
1663 cl.cdtrack = MSG_ReadByte ();
1664 cl.looptrack = MSG_ReadByte ();
1665 if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )
1666 CDAudio_Play ((qbyte)cls.forcetrack, true);
1668 CDAudio_Play ((qbyte)cl.cdtrack, true);
1671 case svc_intermission:
1672 cl.intermission = 1;
1673 cl.completed_time = cl.time;
1677 cl.intermission = 2;
1678 cl.completed_time = cl.time;
1679 SCR_CenterPrint (MSG_ReadString ());
1683 cl.intermission = 3;
1684 cl.completed_time = cl.time;
1685 SCR_CenterPrint (MSG_ReadString ());
1688 case svc_sellscreen:
1689 Cmd_ExecuteString ("help", src_command);
1692 SHOWLMP_decodehide();
1695 SHOWLMP_decodeshow();
1698 R_SetSkyBox(MSG_ReadString());
1703 length = (int) ((unsigned short) MSG_ReadShort());
1704 for (i = 0;i < length;i++)
1705 cgamenetbuffer[i] = MSG_ReadByte();
1707 CL_CGVM_ParseNetwork(cgamenetbuffer, length);
1711 if (cls.signon == SIGNONS - 1)
1713 // first update is the final signon stage
1714 cls.signon = SIGNONS;
1717 CL_ReadEntityFrame();
1722 if (entitiesupdated)
1723 CL_EntityUpdateEnd();
1725 parsingerror = false;
1728 void CL_Parse_DumpPacket(void)
1732 Con_Printf("Packet dump:\n");
1733 SZ_HexDumpToConsole(&net_message);
1734 parsingerror = false;
1737 void CL_Parse_Init(void)
1739 // LordHavoc: added demo_nehahra cvar
1740 cl_scores_mempool = Mem_AllocPool("client player info");
1741 Cvar_RegisterVariable (&demo_nehahra);
1742 if (gamemode == GAME_NEHAHRA)
1743 Cvar_SetValue("demo_nehahra", 1);
1744 Cvar_RegisterVariable(&developer_networkentities);