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();
810 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
812 // GAME_NEXUIZ hud needs weapon change time
813 if (cl.stats[STAT_ACTIVEWEAPON] != i)
814 cl.weapontime = cl.time;
815 cl.stats[STAT_ACTIVEWEAPON] = i;
817 cl.viewzoomold = cl.viewzoomnew; // for interpolation
818 if (bits & SU_VIEWZOOM)
823 cl.viewzoomnew = (float) i * (1.0f / 255.0f);
831 =====================
833 =====================
835 void CL_ParseStatic (int large)
839 if (cl_num_static_entities >= cl_max_static_entities)
840 Host_Error ("Too many static entities");
841 ent = &cl_static_entities[cl_num_static_entities++];
842 CL_ParseBaseline (ent, large);
844 // copy it to the current state
845 ent->render.model = cl.model_precache[ent->state_baseline.modelindex];
846 ent->render.frame = ent->render.frame1 = ent->render.frame2 = ent->state_baseline.frame;
847 ent->render.framelerp = 0;
848 // make torchs play out of sync
849 ent->render.frame1time = ent->render.frame2time = lhrandom(-10, -1);
850 ent->render.colormap = -1; // no special coloring
851 ent->render.skinnum = ent->state_baseline.skin;
852 ent->render.effects = ent->state_baseline.effects;
853 ent->render.alpha = 1;
854 //ent->render.scale = 1;
856 //VectorCopy (ent->state_baseline.origin, ent->render.origin);
857 //VectorCopy (ent->state_baseline.angles, ent->render.angles);
859 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);
860 Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix);
861 CL_BoundingBoxForEntity(&ent->render);
863 // This is definitely cheating...
864 if (ent->render.model == NULL)
865 cl_num_static_entities--;
873 void CL_ParseStaticSound (int large)
876 int sound_num, vol, atten;
880 sound_num = (unsigned short) MSG_ReadShort ();
882 sound_num = MSG_ReadByte ();
883 vol = MSG_ReadByte ();
884 atten = MSG_ReadByte ();
886 S_StaticSound (cl.sound_precache[sound_num], org, vol, atten);
889 void CL_ParseEffect (void)
892 int modelindex, startframe, framecount, framerate;
895 modelindex = MSG_ReadByte ();
896 startframe = MSG_ReadByte ();
897 framecount = MSG_ReadByte ();
898 framerate = MSG_ReadByte ();
900 CL_Effect(org, modelindex, startframe, framecount, framerate);
903 void CL_ParseEffect2 (void)
906 int modelindex, startframe, framecount, framerate;
909 modelindex = MSG_ReadShort ();
910 startframe = MSG_ReadShort ();
911 framecount = MSG_ReadByte ();
912 framerate = MSG_ReadByte ();
914 CL_Effect(org, modelindex, startframe, framecount, framerate);
917 model_t *cl_model_bolt = NULL;
918 model_t *cl_model_bolt2 = NULL;
919 model_t *cl_model_bolt3 = NULL;
920 model_t *cl_model_beam = NULL;
922 sfx_t *cl_sfx_wizhit;
923 sfx_t *cl_sfx_knighthit;
928 sfx_t *cl_sfx_r_exp3;
935 void CL_InitTEnts (void)
937 cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav", false);
938 cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav", false);
939 cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav", false);
940 cl_sfx_ric1 = S_PrecacheSound ("weapons/ric1.wav", false);
941 cl_sfx_ric2 = S_PrecacheSound ("weapons/ric2.wav", false);
942 cl_sfx_ric3 = S_PrecacheSound ("weapons/ric3.wav", false);
943 cl_sfx_r_exp3 = S_PrecacheSound ("weapons/r_exp3.wav", false);
946 void CL_ParseBeam (model_t *m, int lightning)
952 ent = MSG_ReadShort ();
953 MSG_ReadVector(start);
956 if (ent >= MAX_EDICTS)
958 Con_Printf("CL_ParseBeam: invalid entity number %i\n", ent);
962 // override any beam with the same entity
963 for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
965 if (b->entity == ent)
968 b->lightning = lightning;
969 b->relativestartvalid = (ent && cl_entities[ent].state_current.active) ? 2 : 0;
971 b->endtime = cl.time + 0.2;
972 VectorCopy (start, b->start);
973 VectorCopy (end, b->end);
979 for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
981 if (!b->model || b->endtime < cl.time)
984 b->lightning = lightning;
985 b->relativestartvalid = (ent && cl_entities[ent].state_current.active) ? 2 : 0;
987 b->endtime = cl.time + 0.2;
988 VectorCopy (start, b->start);
989 VectorCopy (end, b->end);
993 Con_Printf ("beam list overflow!\n");
996 void CL_ParseTempEntity(void)
1004 int colorStart, colorLength, count;
1005 float velspeed, radius;
1008 type = MSG_ReadByte();
1012 // spike hitting wall
1013 MSG_ReadVector(pos);
1014 CL_FindNonSolidLocation(pos, pos, 4);
1015 CL_AllocDlight(NULL, pos, 50, 0.25f, 1.00f, 0.25f, 250, 0.2);
1016 CL_RunParticleEffect(pos, vec3_origin, 20, 30);
1017 S_StartSound(-1, 0, cl_sfx_wizhit, pos, 1, 1);
1020 case TE_KNIGHTSPIKE:
1021 // spike hitting wall
1022 MSG_ReadVector(pos);
1023 CL_FindNonSolidLocation(pos, pos, 4);
1024 CL_AllocDlight(NULL, pos, 50, 1.0f, 0.60f, 0.20f, 250, 0.2);
1025 CL_RunParticleEffect(pos, vec3_origin, 226, 20);
1026 S_StartSound(-1, 0, cl_sfx_knighthit, pos, 1, 1);
1030 // spike hitting wall
1031 MSG_ReadVector(pos);
1032 CL_FindNonSolidLocation(pos, pos, 4);
1033 // LordHavoc: changed to spark shower
1034 CL_SparkShower(pos, vec3_origin, 15);
1036 S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1041 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1043 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1045 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1049 // quad spike hitting wall
1050 MSG_ReadVector(pos);
1051 CL_FindNonSolidLocation(pos, pos, 4);
1052 // LordHavoc: changed to spark shower
1053 CL_SparkShower(pos, vec3_origin, 15);
1054 CL_AllocDlight(NULL, pos, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2);
1055 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1057 S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1062 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1064 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1066 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1070 // super spike hitting wall
1071 MSG_ReadVector(pos);
1072 CL_FindNonSolidLocation(pos, pos, 4);
1073 // LordHavoc: changed to dust shower
1074 CL_SparkShower(pos, vec3_origin, 30);
1076 S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1081 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1083 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1085 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1088 case TE_SUPERSPIKEQUAD:
1089 // quad super spike hitting wall
1090 MSG_ReadVector(pos);
1091 CL_FindNonSolidLocation(pos, pos, 4);
1092 // LordHavoc: changed to dust shower
1093 CL_SparkShower(pos, vec3_origin, 30);
1094 CL_AllocDlight(NULL, pos, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2);
1096 S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1101 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1103 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1105 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1108 // LordHavoc: added for improved blood splatters
1111 MSG_ReadVector(pos);
1112 CL_FindNonSolidLocation(pos, pos, 4);
1113 dir[0] = MSG_ReadChar();
1114 dir[1] = MSG_ReadChar();
1115 dir[2] = MSG_ReadChar();
1116 count = MSG_ReadByte();
1117 CL_BloodPuff(pos, dir, count);
1121 MSG_ReadVector(pos);
1122 CL_FindNonSolidLocation(pos, pos, 4);
1123 dir[0] = MSG_ReadChar();
1124 dir[1] = MSG_ReadChar();
1125 dir[2] = MSG_ReadChar();
1126 count = MSG_ReadByte();
1127 CL_SparkShower(pos, dir, count);
1130 MSG_ReadVector(pos);
1131 CL_FindNonSolidLocation(pos, pos, 4);
1132 CL_AllocDlight(NULL, pos, 200, 1, 1, 1, 1000, 0.2);
1135 // LordHavoc: added for improved gore
1136 case TE_BLOODSHOWER:
1138 MSG_ReadVector(pos); // mins
1139 MSG_ReadVector(pos2); // maxs
1140 velspeed = MSG_ReadCoord(); // speed
1141 count = MSG_ReadShort(); // number of particles
1142 CL_BloodShower(pos, pos2, velspeed, count);
1144 case TE_PARTICLECUBE:
1145 // general purpose particle effect
1146 MSG_ReadVector(pos); // mins
1147 MSG_ReadVector(pos2); // maxs
1148 MSG_ReadVector(dir); // dir
1149 count = MSG_ReadShort(); // number of particles
1150 colorStart = MSG_ReadByte(); // color
1151 colorLength = MSG_ReadByte(); // gravity (1 or 0)
1152 velspeed = MSG_ReadCoord(); // randomvel
1153 CL_ParticleCube(pos, pos2, dir, count, colorStart, colorLength, velspeed);
1156 case TE_PARTICLERAIN:
1157 // general purpose particle effect
1158 MSG_ReadVector(pos); // mins
1159 MSG_ReadVector(pos2); // maxs
1160 MSG_ReadVector(dir); // dir
1161 count = MSG_ReadShort(); // number of particles
1162 colorStart = MSG_ReadByte(); // color
1163 CL_ParticleRain(pos, pos2, dir, count, colorStart, 0);
1166 case TE_PARTICLESNOW:
1167 // general purpose particle effect
1168 MSG_ReadVector(pos); // mins
1169 MSG_ReadVector(pos2); // maxs
1170 MSG_ReadVector(dir); // dir
1171 count = MSG_ReadShort(); // number of particles
1172 colorStart = MSG_ReadByte(); // color
1173 CL_ParticleRain(pos, pos2, dir, count, colorStart, 1);
1177 // bullet hitting wall
1178 MSG_ReadVector(pos);
1179 CL_FindNonSolidLocation(pos, pos, 4);
1180 // LordHavoc: changed to dust shower
1181 CL_SparkShower(pos, vec3_origin, 15);
1184 case TE_GUNSHOTQUAD:
1185 // quad bullet hitting wall
1186 MSG_ReadVector(pos);
1187 CL_FindNonSolidLocation(pos, pos, 4);
1188 CL_SparkShower(pos, vec3_origin, 15);
1189 CL_AllocDlight(NULL, pos, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2);
1194 MSG_ReadVector(pos);
1195 CL_FindNonSolidLocation(pos, pos, 10);
1196 CL_ParticleExplosion(pos);
1197 // LordHavoc: boosted color from 1.0, 0.8, 0.4 to 1.25, 1.0, 0.5
1198 CL_AllocDlight(NULL, pos, 350, 1.25f, 1.0f, 0.5f, 700, 0.5);
1199 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1202 case TE_EXPLOSIONQUAD:
1203 // quad rocket explosion
1204 MSG_ReadVector(pos);
1205 CL_FindNonSolidLocation(pos, pos, 10);
1206 CL_ParticleExplosion(pos);
1207 CL_AllocDlight(NULL, pos, 600, 0.5f, 0.4f, 1.0f, 1200, 0.5);
1208 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1212 // Nehahra movie colored lighting explosion
1213 MSG_ReadVector(pos);
1214 CL_FindNonSolidLocation(pos, pos, 10);
1215 CL_ParticleExplosion(pos);
1216 CL_AllocDlight(NULL, pos, 350, MSG_ReadCoord(), MSG_ReadCoord(), MSG_ReadCoord(), 700, 0.5);
1217 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1220 case TE_EXPLOSIONRGB:
1221 // colored lighting explosion
1222 MSG_ReadVector(pos);
1223 CL_FindNonSolidLocation(pos, pos, 10);
1224 CL_ParticleExplosion(pos);
1225 color[0] = MSG_ReadByte() * (1.0 / 255.0);
1226 color[1] = MSG_ReadByte() * (1.0 / 255.0);
1227 color[2] = MSG_ReadByte() * (1.0 / 255.0);
1228 CL_AllocDlight(NULL, pos, 350, color[0], color[1], color[2], 700, 0.5);
1229 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1232 case TE_TAREXPLOSION:
1233 // tarbaby explosion
1234 MSG_ReadVector(pos);
1235 CL_FindNonSolidLocation(pos, pos, 10);
1236 CL_BlobExplosion(pos);
1238 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1239 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1240 CL_AllocDlight(NULL, pos, 600, 0.8f, 0.4f, 1.0f, 1200, 0.5);
1244 MSG_ReadVector(pos);
1245 CL_FindNonSolidLocation(pos, pos, 10);
1246 CL_AllocDlight(NULL, pos, 200, 1, 1, 1, 1000, 0.2);
1249 case TE_CUSTOMFLASH:
1250 MSG_ReadVector(pos);
1251 CL_FindNonSolidLocation(pos, pos, 4);
1252 radius = MSG_ReadByte() * 8;
1253 velspeed = (MSG_ReadByte() + 1) * (1.0 / 256.0);
1254 color[0] = MSG_ReadByte() * (1.0 / 255.0);
1255 color[1] = MSG_ReadByte() * (1.0 / 255.0);
1256 color[2] = MSG_ReadByte() * (1.0 / 255.0);
1257 CL_AllocDlight(NULL, pos, radius, color[0], color[1], color[2], radius / velspeed, velspeed);
1261 MSG_ReadVector(pos);
1262 MSG_ReadVector(dir);
1263 count = MSG_ReadByte();
1264 CL_Flames(pos, dir, count);
1270 cl_model_bolt = Mod_ForName("progs/bolt.mdl", true, false, false);
1271 CL_ParseBeam(cl_model_bolt, true);
1276 if (!cl_model_bolt2)
1277 cl_model_bolt2 = Mod_ForName("progs/bolt2.mdl", true, false, false);
1278 CL_ParseBeam(cl_model_bolt2, true);
1283 if (!cl_model_bolt3)
1284 cl_model_bolt3 = Mod_ForName("progs/bolt3.mdl", true, false, false);
1285 CL_ParseBeam(cl_model_bolt3, false);
1290 // grappling hook beam
1292 cl_model_beam = Mod_ForName("progs/beam.mdl", true, false, false);
1293 CL_ParseBeam(cl_model_beam, false);
1297 // LordHavoc: for compatibility with the Nehahra movie...
1298 case TE_LIGHTNING4NEH:
1299 CL_ParseBeam(Mod_ForName(MSG_ReadString(), true, false, false), false);
1303 pos[0] = MSG_ReadCoord();
1304 pos[1] = MSG_ReadCoord();
1305 pos[2] = MSG_ReadCoord();
1310 pos[0] = MSG_ReadCoord();
1311 pos[1] = MSG_ReadCoord();
1312 pos[2] = MSG_ReadCoord();
1313 CL_AllocDlight(NULL, pos, 500, 1.0f, 1.0f, 1.0f, 1500, 99.0f);
1314 // CL_TeleportSplash(pos);
1318 // color mapped explosion
1319 MSG_ReadVector(pos);
1320 CL_FindNonSolidLocation(pos, pos, 10);
1321 colorStart = MSG_ReadByte();
1322 colorLength = MSG_ReadByte();
1323 CL_ParticleExplosion2(pos, colorStart, colorLength);
1324 tempcolor = (qbyte *)&palette_complete[(rand()%colorLength) + colorStart];
1325 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);
1326 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1330 MSG_ReadVector(pos);
1331 MSG_ReadVector(pos2);
1332 MSG_ReadVector(dir);
1333 CL_BeamParticle(pos, pos2, 12, 1, 0.3, 0.1, 1, 1);
1334 CL_BeamParticle(pos, pos2, 5, 1, 0.9, 0.3, 1, 1);
1338 MSG_ReadVector(pos);
1339 MSG_ReadVector(dir);
1340 count = MSG_ReadByte();
1341 CL_FindNonSolidLocation(pos, pos, 4);
1342 CL_Tei_Smoke(pos, dir, count);
1345 case TE_TEI_BIGEXPLOSION:
1346 MSG_ReadVector(pos);
1347 CL_FindNonSolidLocation(pos, pos, 10);
1348 CL_ParticleExplosion(pos);
1349 CL_AllocDlight(NULL, pos, 500, 1.25f, 1.0f, 0.5f, 500, 9999);
1350 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1353 case TE_TEI_PLASMAHIT:
1354 MSG_ReadVector(pos);
1355 MSG_ReadVector(dir);
1356 count = MSG_ReadByte();
1357 CL_FindNonSolidLocation(pos, pos, 5);
1358 CL_Tei_PlasmaHit(pos, dir, count);
1359 CL_AllocDlight(NULL, pos, 500, 0.3, 0.6, 1.0f, 2000, 9999);
1363 Host_Error("CL_ParseTempEntity: bad type %d (hex %02X)", type, type);
1367 #define SHOWNET(x) if(cl_shownet.integer==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x);
1369 static qbyte cgamenetbuffer[65536];
1372 =====================
1373 CL_ParseServerMessage
1374 =====================
1376 int parsingerror = false;
1377 void CL_ParseServerMessage(void)
1380 int i, entitiesupdated;
1382 char *cmdlogname[32], *temp;
1383 int cmdindex, cmdcount = 0;
1385 if (cls.demorecording)
1386 CL_WriteDemoMessage ();
1388 cl.last_received_message = realtime;
1391 // if recording demos, copy the message out
1393 if (cl_shownet.integer == 1)
1394 Con_Printf ("%f %i\n", realtime, net_message.cursize);
1395 else if (cl_shownet.integer == 2)
1396 Con_Printf ("------------------\n");
1398 cl.onground = false; // unless the server says otherwise
1400 // parse the message
1402 //MSG_BeginReading ();
1404 entitiesupdated = false;
1406 parsingerror = true;
1411 Host_Error ("CL_ParseServerMessage: Bad server message");
1413 cmd = MSG_ReadByte ();
1417 SHOWNET("END OF MESSAGE");
1418 break; // end of message
1421 cmdindex = cmdcount & 31;
1423 cmdlog[cmdindex] = cmd;
1425 // if the high bit of the command byte is set, it is a fast update
1428 // 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)
1430 cmdlogname[cmdindex] = temp;
1431 SHOWNET("fast update");
1432 if (cls.signon == SIGNONS - 1)
1434 // first update is the final signon stage
1435 cls.signon = SIGNONS;
1438 CL_ParseUpdate (cmd&127);
1442 SHOWNET(svc_strings[cmd]);
1443 cmdlogname[cmdindex] = svc_strings[cmd];
1444 if (!cmdlogname[cmdindex])
1446 // 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)
1448 cmdlogname[cmdindex] = temp;
1456 char description[32*64], temp[64];
1458 strcpy(description, "packet dump: ");
1462 count = cmdcount - i;
1466 sprintf(temp, "%3i:%s ", cmdlog[i], cmdlogname[i]);
1467 strcat(description, temp);
1472 description[strlen(description)-1] = '\n'; // replace the last space with a newline
1473 Con_Printf("%s", description);
1474 Host_Error ("CL_ParseServerMessage: Illegible server message\n");
1479 if (cls.signon < SIGNONS)
1480 Con_Printf("<-- server to client keepalive\n");
1484 if (!entitiesupdated)
1486 // this is a new frame, we'll be seeing entities,
1487 // so prepare for entity updates
1488 CL_EntityUpdateSetup();
1489 entitiesupdated = true;
1491 cl.mtime[1] = cl.mtime[0];
1492 cl.mtime[0] = MSG_ReadFloat ();
1495 case svc_clientdata:
1496 i = MSG_ReadShort ();
1497 CL_ParseClientdata (i);
1501 i = MSG_ReadLong ();
1502 // hack for unmarked Nehahra movie demos which had a custom protocol
1503 if (i == PROTOCOL_QUAKE && cls.demoplayback && demo_nehahra.integer)
1504 i = PROTOCOL_NEHAHRAMOVIE;
1505 if (i != PROTOCOL_QUAKE && i != PROTOCOL_DARKPLACES1 && i != PROTOCOL_DARKPLACES2 && i != PROTOCOL_DARKPLACES3 && i != PROTOCOL_DARKPLACES4 && i != PROTOCOL_NEHAHRAMOVIE)
1506 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);
1510 case svc_disconnect:
1511 Host_EndGame ("Server disconnected\n");
1514 Con_Printf ("%s", MSG_ReadString ());
1517 case svc_centerprint:
1518 SCR_CenterPrint (MSG_ReadString ());
1522 Cbuf_AddText (MSG_ReadString ());
1529 case svc_serverinfo:
1530 CL_ParseServerInfo ();
1534 for (i=0 ; i<3 ; i++)
1535 cl.viewangles[i] = MSG_ReadAngle ();
1539 cl.viewentity = (unsigned short)MSG_ReadShort ();
1540 if (cl.viewentity >= MAX_EDICTS)
1541 Host_Error("svc_setview >= MAX_EDICTS\n");
1542 // LordHavoc: assume first setview recieved is the real player entity
1543 if (!cl.playerentity)
1544 cl.playerentity = cl.viewentity;
1547 case svc_lightstyle:
1548 i = MSG_ReadByte ();
1549 if (i >= MAX_LIGHTSTYLES)
1550 Host_Error ("svc_lightstyle >= MAX_LIGHTSTYLES");
1551 strncpy (cl_lightstyle[i].map, MSG_ReadString(), MAX_STYLESTRING - 1);
1552 cl_lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
1553 cl_lightstyle[i].length = strlen(cl_lightstyle[i].map);
1557 CL_ParseStartSoundPacket(false);
1561 CL_ParseStartSoundPacket(true);
1565 i = MSG_ReadShort();
1566 S_StopSound(i>>3, i&7);
1569 case svc_updatename:
1570 i = MSG_ReadByte ();
1571 if (i >= cl.maxclients)
1572 Host_Error ("CL_ParseServerMessage: svc_updatename >= cl.maxclients");
1573 strcpy (cl.scores[i].name, MSG_ReadString ());
1576 case svc_updatefrags:
1577 i = MSG_ReadByte ();
1578 if (i >= cl.maxclients)
1579 Host_Error ("CL_ParseServerMessage: svc_updatefrags >= cl.maxclients");
1580 cl.scores[i].frags = MSG_ReadShort ();
1583 case svc_updatecolors:
1584 i = MSG_ReadByte ();
1585 if (i >= cl.maxclients)
1586 Host_Error ("CL_ParseServerMessage: svc_updatecolors >= cl.maxclients");
1587 cl.scores[i].colors = MSG_ReadByte ();
1591 CL_ParseParticleEffect ();
1602 case svc_spawnbaseline:
1603 i = MSG_ReadShort ();
1604 if (i < 0 || i >= MAX_EDICTS)
1605 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i);
1606 CL_ParseBaseline (cl_entities + i, false);
1608 case svc_spawnbaseline2:
1609 i = MSG_ReadShort ();
1610 if (i < 0 || i >= MAX_EDICTS)
1611 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline2: invalid entity number %i", i);
1612 CL_ParseBaseline (cl_entities + i, true);
1614 case svc_spawnstatic:
1615 CL_ParseStatic (false);
1617 case svc_spawnstatic2:
1618 CL_ParseStatic (true);
1620 case svc_temp_entity:
1621 CL_ParseTempEntity ();
1625 cl.paused = MSG_ReadByte ();
1633 i = MSG_ReadByte ();
1634 if (i <= cls.signon)
1635 Host_Error ("Received signon %i when at %i", i, cls.signon);
1640 case svc_killedmonster:
1641 cl.stats[STAT_MONSTERS]++;
1644 case svc_foundsecret:
1645 cl.stats[STAT_SECRETS]++;
1648 case svc_updatestat:
1649 i = MSG_ReadByte ();
1650 if (i < 0 || i >= MAX_CL_STATS)
1651 Host_Error ("svc_updatestat: %i is invalid", i);
1652 cl.stats[i] = MSG_ReadLong ();
1655 case svc_spawnstaticsound:
1656 CL_ParseStaticSound (false);
1659 case svc_spawnstaticsound2:
1660 CL_ParseStaticSound (true);
1664 cl.cdtrack = MSG_ReadByte ();
1665 cl.looptrack = MSG_ReadByte ();
1666 if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )
1667 CDAudio_Play ((qbyte)cls.forcetrack, true);
1669 CDAudio_Play ((qbyte)cl.cdtrack, true);
1672 case svc_intermission:
1673 cl.intermission = 1;
1674 cl.completed_time = cl.time;
1678 cl.intermission = 2;
1679 cl.completed_time = cl.time;
1680 SCR_CenterPrint (MSG_ReadString ());
1684 cl.intermission = 3;
1685 cl.completed_time = cl.time;
1686 SCR_CenterPrint (MSG_ReadString ());
1689 case svc_sellscreen:
1690 Cmd_ExecuteString ("help", src_command);
1693 SHOWLMP_decodehide();
1696 SHOWLMP_decodeshow();
1699 R_SetSkyBox(MSG_ReadString());
1704 length = (int) ((unsigned short) MSG_ReadShort());
1705 for (i = 0;i < length;i++)
1706 cgamenetbuffer[i] = MSG_ReadByte();
1708 CL_CGVM_ParseNetwork(cgamenetbuffer, length);
1712 if (cls.signon == SIGNONS - 1)
1714 // first update is the final signon stage
1715 cls.signon = SIGNONS;
1718 CL_ReadEntityFrame();
1723 if (entitiesupdated)
1724 CL_EntityUpdateEnd();
1726 parsingerror = false;
1729 void CL_Parse_DumpPacket(void)
1733 Con_Printf("Packet dump:\n");
1734 SZ_HexDumpToConsole(&net_message);
1735 parsingerror = false;
1738 void CL_Parse_Init(void)
1740 // LordHavoc: added demo_nehahra cvar
1741 cl_scores_mempool = Mem_AllocPool("client player info");
1742 Cvar_RegisterVariable (&demo_nehahra);
1743 if (gamemode == GAME_NEHAHRA)
1744 Cvar_SetValue("demo_nehahra", 1);
1745 Cvar_RegisterVariable(&developer_networkentities);