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 strlcpy (key, com_token + 1, sizeof (key));
235 strlcpy (key, com_token, sizeof (key));
236 while (key[strlen(key)-1] == ' ') // remove trailing spaces
237 key[strlen(key)-1] = 0;
238 if (!COM_ParseToken(&data, false))
240 strlcpy (value, com_token, sizeof (value));
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 strlcpy (cl.levelname, str, sizeof(cl.levelname));
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 strlcpy (parse_model_precache[nummodels], str, sizeof (parse_model_precache[nummodels]));
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 strlcpy (parse_sound_precache[numsounds], str, sizeof (parse_sound_precache[numsounds]));
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]);
410 // do the same for sounds
412 for (i = 1;i < numsounds;i++)
414 CL_KeepaliveMessage();
415 S_TouchSound(parse_sound_precache[i]);
419 // now we try to load everything that is new
422 CL_KeepaliveMessage ();
423 cl.model_precache[1] = Mod_ForName(parse_model_precache[1], false, false, true);
424 if (cl.model_precache[1] == NULL)
425 Con_Printf("Map %s not found\n", parse_model_precache[1]);
428 for (i=2 ; i<nummodels ; i++)
430 CL_KeepaliveMessage();
431 if ((cl.model_precache[i] = Mod_ForName(parse_model_precache[i], false, false, false)) == NULL)
432 Con_Printf("Model %s not found\n", parse_model_precache[i]);
436 for (i=1 ; i<numsounds ; i++)
438 CL_KeepaliveMessage();
439 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)
813 // GAME_NEXUIZ hud needs weapon change time
814 // GAME_NEXUIZ uses a bit number as it's STAT_ACTIVEWEAPON, not a bitfield
816 if (cl.stats[STAT_ACTIVEWEAPON] != i)
817 cl.weapontime = cl.time;
818 cl.stats[STAT_ACTIVEWEAPON] = i;
820 cl.viewzoomold = cl.viewzoomnew; // for interpolation
821 if (bits & SU_VIEWZOOM)
826 cl.viewzoomnew = (float) i * (1.0f / 255.0f);
834 =====================
836 =====================
838 void CL_ParseStatic (int large)
842 if (cl_num_static_entities >= cl_max_static_entities)
843 Host_Error ("Too many static entities");
844 ent = &cl_static_entities[cl_num_static_entities++];
845 CL_ParseBaseline (ent, large);
847 // copy it to the current state
848 ent->render.model = cl.model_precache[ent->state_baseline.modelindex];
849 ent->render.frame = ent->render.frame1 = ent->render.frame2 = ent->state_baseline.frame;
850 ent->render.framelerp = 0;
851 // make torchs play out of sync
852 ent->render.frame1time = ent->render.frame2time = lhrandom(-10, -1);
853 ent->render.colormap = -1; // no special coloring
854 ent->render.skinnum = ent->state_baseline.skin;
855 ent->render.effects = ent->state_baseline.effects;
856 ent->render.alpha = 1;
857 //ent->render.scale = 1;
859 //VectorCopy (ent->state_baseline.origin, ent->render.origin);
860 //VectorCopy (ent->state_baseline.angles, ent->render.angles);
862 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);
863 Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix);
864 CL_BoundingBoxForEntity(&ent->render);
866 // This is definitely cheating...
867 if (ent->render.model == NULL)
868 cl_num_static_entities--;
876 void CL_ParseStaticSound (int large)
879 int sound_num, vol, atten;
883 sound_num = (unsigned short) MSG_ReadShort ();
885 sound_num = MSG_ReadByte ();
886 vol = MSG_ReadByte ();
887 atten = MSG_ReadByte ();
889 S_StaticSound (cl.sound_precache[sound_num], org, vol, atten);
892 void CL_ParseEffect (void)
895 int modelindex, startframe, framecount, framerate;
898 modelindex = MSG_ReadByte ();
899 startframe = MSG_ReadByte ();
900 framecount = MSG_ReadByte ();
901 framerate = MSG_ReadByte ();
903 CL_Effect(org, modelindex, startframe, framecount, framerate);
906 void CL_ParseEffect2 (void)
909 int modelindex, startframe, framecount, framerate;
912 modelindex = MSG_ReadShort ();
913 startframe = MSG_ReadShort ();
914 framecount = MSG_ReadByte ();
915 framerate = MSG_ReadByte ();
917 CL_Effect(org, modelindex, startframe, framecount, framerate);
920 model_t *cl_model_bolt = NULL;
921 model_t *cl_model_bolt2 = NULL;
922 model_t *cl_model_bolt3 = NULL;
923 model_t *cl_model_beam = NULL;
925 sfx_t *cl_sfx_wizhit;
926 sfx_t *cl_sfx_knighthit;
931 sfx_t *cl_sfx_r_exp3;
938 void CL_InitTEnts (void)
940 cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav", false);
941 cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav", false);
942 cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav", false);
943 cl_sfx_ric1 = S_PrecacheSound ("weapons/ric1.wav", false);
944 cl_sfx_ric2 = S_PrecacheSound ("weapons/ric2.wav", false);
945 cl_sfx_ric3 = S_PrecacheSound ("weapons/ric3.wav", false);
946 cl_sfx_r_exp3 = S_PrecacheSound ("weapons/r_exp3.wav", false);
949 void CL_ParseBeam (model_t *m, int lightning)
955 ent = MSG_ReadShort ();
956 MSG_ReadVector(start);
959 if (ent >= MAX_EDICTS)
961 Con_Printf("CL_ParseBeam: invalid entity number %i\n", ent);
965 // override any beam with the same entity
966 for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
968 if (b->entity == ent)
971 b->lightning = lightning;
972 b->relativestartvalid = (ent && cl_entities[ent].state_current.active) ? 2 : 0;
974 b->endtime = cl.time + 0.2;
975 VectorCopy (start, b->start);
976 VectorCopy (end, b->end);
982 for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
984 if (!b->model || b->endtime < cl.time)
987 b->lightning = lightning;
988 b->relativestartvalid = (ent && cl_entities[ent].state_current.active) ? 2 : 0;
990 b->endtime = cl.time + 0.2;
991 VectorCopy (start, b->start);
992 VectorCopy (end, b->end);
996 Con_Printf ("beam list overflow!\n");
999 void CL_ParseTempEntity(void)
1007 int colorStart, colorLength, count;
1008 float velspeed, radius;
1010 matrix4x4_t tempmatrix;
1012 type = MSG_ReadByte();
1016 // spike hitting wall
1017 MSG_ReadVector(pos);
1018 CL_FindNonSolidLocation(pos, pos, 4);
1019 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1020 CL_AllocDlight(NULL, &tempmatrix, 150, 0.25f, 1.00f, 0.25f, 250, 0.2, 0, 0, false, 1);
1021 CL_RunParticleEffect(pos, vec3_origin, 20, 30);
1022 S_StartSound(-1, 0, cl_sfx_wizhit, pos, 1, 1);
1025 case TE_KNIGHTSPIKE:
1026 // spike hitting wall
1027 MSG_ReadVector(pos);
1028 CL_FindNonSolidLocation(pos, pos, 4);
1029 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1030 CL_AllocDlight(NULL, &tempmatrix, 150, 1.0f, 0.60f, 0.20f, 250, 0.2, 0, 0, false, 1);
1031 CL_RunParticleEffect(pos, vec3_origin, 226, 20);
1032 S_StartSound(-1, 0, cl_sfx_knighthit, pos, 1, 1);
1036 // spike hitting wall
1037 MSG_ReadVector(pos);
1038 CL_FindNonSolidLocation(pos, pos, 4);
1039 // LordHavoc: changed to spark shower
1040 CL_SparkShower(pos, vec3_origin, 15);
1042 S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1047 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1049 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1051 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1055 // quad spike hitting wall
1056 MSG_ReadVector(pos);
1057 CL_FindNonSolidLocation(pos, pos, 4);
1058 // LordHavoc: changed to spark shower
1059 CL_SparkShower(pos, vec3_origin, 15);
1060 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1061 CL_AllocDlight(NULL, &tempmatrix, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2, 0, 0, true, 1);
1062 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1064 S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1069 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1071 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1073 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1077 // super spike hitting wall
1078 MSG_ReadVector(pos);
1079 CL_FindNonSolidLocation(pos, pos, 4);
1080 // LordHavoc: changed to dust shower
1081 CL_SparkShower(pos, vec3_origin, 30);
1083 S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1088 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1090 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1092 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1095 case TE_SUPERSPIKEQUAD:
1096 // quad super spike hitting wall
1097 MSG_ReadVector(pos);
1098 CL_FindNonSolidLocation(pos, pos, 4);
1099 // LordHavoc: changed to dust shower
1100 CL_SparkShower(pos, vec3_origin, 30);
1101 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1102 CL_AllocDlight(NULL, &tempmatrix, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2, 0, 0, true, 1);
1104 S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1109 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1111 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1113 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1116 // LordHavoc: added for improved blood splatters
1119 MSG_ReadVector(pos);
1120 CL_FindNonSolidLocation(pos, pos, 4);
1121 dir[0] = MSG_ReadChar();
1122 dir[1] = MSG_ReadChar();
1123 dir[2] = MSG_ReadChar();
1124 count = MSG_ReadByte();
1125 CL_BloodPuff(pos, dir, count);
1129 MSG_ReadVector(pos);
1130 CL_FindNonSolidLocation(pos, pos, 4);
1131 dir[0] = MSG_ReadChar();
1132 dir[1] = MSG_ReadChar();
1133 dir[2] = MSG_ReadChar();
1134 count = MSG_ReadByte();
1135 CL_SparkShower(pos, dir, count);
1138 MSG_ReadVector(pos);
1139 CL_FindNonSolidLocation(pos, pos, 4);
1140 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1141 CL_AllocDlight(NULL, &tempmatrix, 200, 1, 1, 1, 1000, 0.2, 0, 0, true, 1);
1144 // LordHavoc: added for improved gore
1145 case TE_BLOODSHOWER:
1147 MSG_ReadVector(pos); // mins
1148 MSG_ReadVector(pos2); // maxs
1149 velspeed = MSG_ReadCoord(); // speed
1150 count = MSG_ReadShort(); // number of particles
1151 CL_BloodShower(pos, pos2, velspeed, count);
1153 case TE_PARTICLECUBE:
1154 // general purpose particle effect
1155 MSG_ReadVector(pos); // mins
1156 MSG_ReadVector(pos2); // maxs
1157 MSG_ReadVector(dir); // dir
1158 count = MSG_ReadShort(); // number of particles
1159 colorStart = MSG_ReadByte(); // color
1160 colorLength = MSG_ReadByte(); // gravity (1 or 0)
1161 velspeed = MSG_ReadCoord(); // randomvel
1162 CL_ParticleCube(pos, pos2, dir, count, colorStart, colorLength, velspeed);
1165 case TE_PARTICLERAIN:
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, 0);
1175 case TE_PARTICLESNOW:
1176 // general purpose particle effect
1177 MSG_ReadVector(pos); // mins
1178 MSG_ReadVector(pos2); // maxs
1179 MSG_ReadVector(dir); // dir
1180 count = MSG_ReadShort(); // number of particles
1181 colorStart = MSG_ReadByte(); // color
1182 CL_ParticleRain(pos, pos2, dir, count, colorStart, 1);
1186 // bullet hitting wall
1187 MSG_ReadVector(pos);
1188 CL_FindNonSolidLocation(pos, pos, 4);
1189 // LordHavoc: changed to dust shower
1190 CL_SparkShower(pos, vec3_origin, 15);
1193 case TE_GUNSHOTQUAD:
1194 // quad bullet hitting wall
1195 MSG_ReadVector(pos);
1196 CL_FindNonSolidLocation(pos, pos, 4);
1197 CL_SparkShower(pos, vec3_origin, 15);
1198 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1199 CL_AllocDlight(NULL, &tempmatrix, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2, 0, 0, true, 1);
1204 MSG_ReadVector(pos);
1205 CL_FindNonSolidLocation(pos, pos, 10);
1206 CL_ParticleExplosion(pos);
1207 // LordHavoc: boosted color from 1.0, 0.8, 0.4 to 1.25, 1.0, 0.5
1208 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1209 CL_AllocDlight(NULL, &tempmatrix, 350, 1.25f, 1.0f, 0.5f, 700, 0.5, 0, 0, true, 1);
1210 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1213 case TE_EXPLOSIONQUAD:
1214 // quad rocket explosion
1215 MSG_ReadVector(pos);
1216 CL_FindNonSolidLocation(pos, pos, 10);
1217 CL_ParticleExplosion(pos);
1218 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1219 CL_AllocDlight(NULL, &tempmatrix, 600, 0.5f, 0.4f, 1.0f, 1200, 0.5, 0, 0, true, 1);
1220 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1224 // Nehahra movie colored lighting explosion
1225 MSG_ReadVector(pos);
1226 CL_FindNonSolidLocation(pos, pos, 10);
1227 CL_ParticleExplosion(pos);
1228 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1229 CL_AllocDlight(NULL, &tempmatrix, 350, MSG_ReadCoord(), MSG_ReadCoord(), MSG_ReadCoord(), 700, 0.5, 0, 0, true, 1);
1230 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1233 case TE_EXPLOSIONRGB:
1234 // colored lighting explosion
1235 MSG_ReadVector(pos);
1236 CL_FindNonSolidLocation(pos, pos, 10);
1237 CL_ParticleExplosion(pos);
1238 color[0] = MSG_ReadByte() * (1.0 / 255.0);
1239 color[1] = MSG_ReadByte() * (1.0 / 255.0);
1240 color[2] = MSG_ReadByte() * (1.0 / 255.0);
1241 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1242 CL_AllocDlight(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, 0, true, 1);
1243 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1246 case TE_TAREXPLOSION:
1247 // tarbaby explosion
1248 MSG_ReadVector(pos);
1249 CL_FindNonSolidLocation(pos, pos, 10);
1250 CL_BlobExplosion(pos);
1252 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1253 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1254 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1255 CL_AllocDlight(NULL, &tempmatrix, 600, 0.8f, 0.4f, 1.0f, 1200, 0.5, 0, 0, true, 1);
1259 MSG_ReadVector(pos);
1260 CL_FindNonSolidLocation(pos, pos, 10);
1261 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1262 CL_AllocDlight(NULL, &tempmatrix, 200, 1, 1, 1, 1000, 0.2, 0, 0, true, 1);
1265 case TE_CUSTOMFLASH:
1266 MSG_ReadVector(pos);
1267 CL_FindNonSolidLocation(pos, pos, 4);
1268 radius = MSG_ReadByte() * 8;
1269 velspeed = (MSG_ReadByte() + 1) * (1.0 / 256.0);
1270 color[0] = MSG_ReadByte() * (1.0 / 255.0);
1271 color[1] = MSG_ReadByte() * (1.0 / 255.0);
1272 color[2] = MSG_ReadByte() * (1.0 / 255.0);
1273 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1274 CL_AllocDlight(NULL, &tempmatrix, radius, color[0], color[1], color[2], radius / velspeed, velspeed, 0, 0, true, 1);
1278 MSG_ReadVector(pos);
1279 MSG_ReadVector(dir);
1280 count = MSG_ReadByte();
1281 CL_Flames(pos, dir, count);
1287 cl_model_bolt = Mod_ForName("progs/bolt.mdl", true, false, false);
1288 CL_ParseBeam(cl_model_bolt, true);
1293 if (!cl_model_bolt2)
1294 cl_model_bolt2 = Mod_ForName("progs/bolt2.mdl", true, false, false);
1295 CL_ParseBeam(cl_model_bolt2, true);
1300 if (!cl_model_bolt3)
1301 cl_model_bolt3 = Mod_ForName("progs/bolt3.mdl", true, false, false);
1302 CL_ParseBeam(cl_model_bolt3, false);
1307 // grappling hook beam
1309 cl_model_beam = Mod_ForName("progs/beam.mdl", true, false, false);
1310 CL_ParseBeam(cl_model_beam, false);
1314 // LordHavoc: for compatibility with the Nehahra movie...
1315 case TE_LIGHTNING4NEH:
1316 CL_ParseBeam(Mod_ForName(MSG_ReadString(), true, false, false), false);
1320 pos[0] = MSG_ReadCoord();
1321 pos[1] = MSG_ReadCoord();
1322 pos[2] = MSG_ReadCoord();
1327 pos[0] = MSG_ReadCoord();
1328 pos[1] = MSG_ReadCoord();
1329 pos[2] = MSG_ReadCoord();
1330 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1331 CL_AllocDlight(NULL, &tempmatrix, 500, 1.0f, 1.0f, 1.0f, 1500, 99.0f, 0, 0, true, 1);
1332 // CL_TeleportSplash(pos);
1336 // color mapped explosion
1337 MSG_ReadVector(pos);
1338 CL_FindNonSolidLocation(pos, pos, 10);
1339 colorStart = MSG_ReadByte();
1340 colorLength = MSG_ReadByte();
1341 CL_ParticleExplosion2(pos, colorStart, colorLength);
1342 tempcolor = (qbyte *)&palette_complete[(rand()%colorLength) + colorStart];
1343 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1344 CL_AllocDlight(NULL, &tempmatrix, 350, tempcolor[0] * (1.0f / 255.0f), tempcolor[1] * (1.0f / 255.0f), tempcolor[2] * (1.0f / 255.0f), 700, 0.5, 0, 0, true, 1);
1345 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1349 MSG_ReadVector(pos);
1350 MSG_ReadVector(pos2);
1351 MSG_ReadVector(dir);
1352 CL_BeamParticle(pos, pos2, 12, 1, 0.3, 0.1, 1, 1);
1353 CL_BeamParticle(pos, pos2, 5, 1, 0.9, 0.3, 1, 1);
1357 MSG_ReadVector(pos);
1358 MSG_ReadVector(dir);
1359 count = MSG_ReadByte();
1360 CL_FindNonSolidLocation(pos, pos, 4);
1361 CL_Tei_Smoke(pos, dir, count);
1364 case TE_TEI_BIGEXPLOSION:
1365 MSG_ReadVector(pos);
1366 CL_FindNonSolidLocation(pos, pos, 10);
1367 CL_ParticleExplosion(pos);
1368 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1369 CL_AllocDlight(NULL, &tempmatrix, 500, 1.25f, 1.0f, 0.5f, 500, 9999, 0, 0, true, 1);
1370 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1373 case TE_TEI_PLASMAHIT:
1374 MSG_ReadVector(pos);
1375 MSG_ReadVector(dir);
1376 count = MSG_ReadByte();
1377 CL_FindNonSolidLocation(pos, pos, 5);
1378 CL_Tei_PlasmaHit(pos, dir, count);
1379 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1380 CL_AllocDlight(NULL, &tempmatrix, 500, 0.3, 0.6, 1.0f, 2000, 9999, 0, 0, true, 1);
1384 Host_Error("CL_ParseTempEntity: bad type %d (hex %02X)", type, type);
1388 #define SHOWNET(x) if(cl_shownet.integer==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x);
1390 static qbyte cgamenetbuffer[65536];
1393 =====================
1394 CL_ParseServerMessage
1395 =====================
1397 int parsingerror = false;
1398 void CL_ParseServerMessage(void)
1401 int i, entitiesupdated;
1403 char *cmdlogname[32], *temp;
1404 int cmdindex, cmdcount = 0;
1406 if (cls.demorecording)
1407 CL_WriteDemoMessage ();
1409 cl.last_received_message = realtime;
1412 // if recording demos, copy the message out
1414 if (cl_shownet.integer == 1)
1415 Con_Printf ("%f %i\n", realtime, net_message.cursize);
1416 else if (cl_shownet.integer == 2)
1417 Con_Printf ("------------------\n");
1419 cl.onground = false; // unless the server says otherwise
1421 // parse the message
1423 //MSG_BeginReading ();
1425 entitiesupdated = false;
1427 parsingerror = true;
1432 Host_Error ("CL_ParseServerMessage: Bad server message");
1434 cmd = MSG_ReadByte ();
1438 SHOWNET("END OF MESSAGE");
1439 break; // end of message
1442 cmdindex = cmdcount & 31;
1444 cmdlog[cmdindex] = cmd;
1446 // if the high bit of the command byte is set, it is a fast update
1449 // 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)
1451 cmdlogname[cmdindex] = temp;
1452 SHOWNET("fast update");
1453 if (cls.signon == SIGNONS - 1)
1455 // first update is the final signon stage
1456 cls.signon = SIGNONS;
1459 CL_ParseUpdate (cmd&127);
1463 SHOWNET(svc_strings[cmd]);
1464 cmdlogname[cmdindex] = svc_strings[cmd];
1465 if (!cmdlogname[cmdindex])
1467 // 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)
1469 cmdlogname[cmdindex] = temp;
1477 char description[32*64], temp[64];
1479 strcpy (description, "packet dump: ");
1483 count = cmdcount - i;
1487 snprintf (temp, sizeof (temp), "%3i:%s ", cmdlog[i], cmdlogname[i]);
1488 strlcat (description, temp, sizeof (description));
1493 description[strlen(description)-1] = '\n'; // replace the last space with a newline
1494 Con_Printf("%s", description);
1495 Host_Error ("CL_ParseServerMessage: Illegible server message\n");
1500 if (cls.signon < SIGNONS)
1501 Con_Printf("<-- server to client keepalive\n");
1505 if (!entitiesupdated)
1507 // this is a new frame, we'll be seeing entities,
1508 // so prepare for entity updates
1509 CL_EntityUpdateSetup();
1510 entitiesupdated = true;
1512 cl.mtime[1] = cl.mtime[0];
1513 cl.mtime[0] = MSG_ReadFloat ();
1516 case svc_clientdata:
1517 i = MSG_ReadShort ();
1518 CL_ParseClientdata (i);
1522 i = MSG_ReadLong ();
1523 // hack for unmarked Nehahra movie demos which had a custom protocol
1524 if (i == PROTOCOL_QUAKE && cls.demoplayback && demo_nehahra.integer)
1525 i = PROTOCOL_NEHAHRAMOVIE;
1526 if (i != PROTOCOL_QUAKE && i != PROTOCOL_DARKPLACES1 && i != PROTOCOL_DARKPLACES2 && i != PROTOCOL_DARKPLACES3 && i != PROTOCOL_DARKPLACES4 && i != PROTOCOL_NEHAHRAMOVIE)
1527 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);
1531 case svc_disconnect:
1532 Host_EndGame ("Server disconnected\n");
1535 Con_Printf ("%s", MSG_ReadString ());
1538 case svc_centerprint:
1539 SCR_CenterPrint (MSG_ReadString ());
1543 Cbuf_AddText (MSG_ReadString ());
1550 case svc_serverinfo:
1551 CL_ParseServerInfo ();
1555 for (i=0 ; i<3 ; i++)
1556 cl.viewangles[i] = MSG_ReadAngle ();
1560 cl.viewentity = (unsigned short)MSG_ReadShort ();
1561 if (cl.viewentity >= MAX_EDICTS)
1562 Host_Error("svc_setview >= MAX_EDICTS\n");
1563 // LordHavoc: assume first setview recieved is the real player entity
1564 if (!cl.playerentity)
1565 cl.playerentity = cl.viewentity;
1568 case svc_lightstyle:
1569 i = MSG_ReadByte ();
1570 if (i >= MAX_LIGHTSTYLES)
1571 Host_Error ("svc_lightstyle >= MAX_LIGHTSTYLES");
1572 strlcpy (cl_lightstyle[i].map, MSG_ReadString(), sizeof (cl_lightstyle[i].map));
1573 cl_lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
1574 cl_lightstyle[i].length = strlen(cl_lightstyle[i].map);
1578 CL_ParseStartSoundPacket(false);
1582 CL_ParseStartSoundPacket(true);
1586 i = MSG_ReadShort();
1587 S_StopSound(i>>3, i&7);
1590 case svc_updatename:
1591 i = MSG_ReadByte ();
1592 if (i >= cl.maxclients)
1593 Host_Error ("CL_ParseServerMessage: svc_updatename >= cl.maxclients");
1594 strlcpy (cl.scores[i].name, MSG_ReadString (), sizeof (cl.scores[i].name));
1597 case svc_updatefrags:
1598 i = MSG_ReadByte ();
1599 if (i >= cl.maxclients)
1600 Host_Error ("CL_ParseServerMessage: svc_updatefrags >= cl.maxclients");
1601 cl.scores[i].frags = MSG_ReadShort ();
1604 case svc_updatecolors:
1605 i = MSG_ReadByte ();
1606 if (i >= cl.maxclients)
1607 Host_Error ("CL_ParseServerMessage: svc_updatecolors >= cl.maxclients");
1608 cl.scores[i].colors = MSG_ReadByte ();
1612 CL_ParseParticleEffect ();
1623 case svc_spawnbaseline:
1624 i = MSG_ReadShort ();
1625 if (i < 0 || i >= MAX_EDICTS)
1626 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i);
1627 CL_ParseBaseline (cl_entities + i, false);
1629 case svc_spawnbaseline2:
1630 i = MSG_ReadShort ();
1631 if (i < 0 || i >= MAX_EDICTS)
1632 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline2: invalid entity number %i", i);
1633 CL_ParseBaseline (cl_entities + i, true);
1635 case svc_spawnstatic:
1636 CL_ParseStatic (false);
1638 case svc_spawnstatic2:
1639 CL_ParseStatic (true);
1641 case svc_temp_entity:
1642 CL_ParseTempEntity ();
1646 cl.paused = MSG_ReadByte ();
1654 i = MSG_ReadByte ();
1655 if (i <= cls.signon)
1656 Host_Error ("Received signon %i when at %i", i, cls.signon);
1661 case svc_killedmonster:
1662 cl.stats[STAT_MONSTERS]++;
1665 case svc_foundsecret:
1666 cl.stats[STAT_SECRETS]++;
1669 case svc_updatestat:
1670 i = MSG_ReadByte ();
1671 if (i < 0 || i >= MAX_CL_STATS)
1672 Host_Error ("svc_updatestat: %i is invalid", i);
1673 cl.stats[i] = MSG_ReadLong ();
1676 case svc_spawnstaticsound:
1677 CL_ParseStaticSound (false);
1680 case svc_spawnstaticsound2:
1681 CL_ParseStaticSound (true);
1685 cl.cdtrack = MSG_ReadByte ();
1686 cl.looptrack = MSG_ReadByte ();
1687 if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )
1688 CDAudio_Play ((qbyte)cls.forcetrack, true);
1690 CDAudio_Play ((qbyte)cl.cdtrack, true);
1693 case svc_intermission:
1694 cl.intermission = 1;
1695 cl.completed_time = cl.time;
1699 cl.intermission = 2;
1700 cl.completed_time = cl.time;
1701 SCR_CenterPrint (MSG_ReadString ());
1705 cl.intermission = 3;
1706 cl.completed_time = cl.time;
1707 SCR_CenterPrint (MSG_ReadString ());
1710 case svc_sellscreen:
1711 Cmd_ExecuteString ("help", src_command);
1714 if (gamemode == GAME_TENEBRAE)
1716 // repeating particle effect
1729 SHOWLMP_decodehide();
1732 if (gamemode == GAME_TENEBRAE)
1742 SHOWLMP_decodeshow();
1745 R_SetSkyBox(MSG_ReadString());
1750 length = (int) ((unsigned short) MSG_ReadShort());
1751 for (i = 0;i < length;i++)
1752 cgamenetbuffer[i] = MSG_ReadByte();
1754 CL_CGVM_ParseNetwork(cgamenetbuffer, length);
1758 if (cls.signon == SIGNONS - 1)
1760 // first update is the final signon stage
1761 cls.signon = SIGNONS;
1764 CL_ReadEntityFrame();
1769 if (entitiesupdated)
1770 CL_EntityUpdateEnd();
1772 parsingerror = false;
1775 void CL_Parse_DumpPacket(void)
1779 Con_Printf("Packet dump:\n");
1780 SZ_HexDumpToConsole(&net_message);
1781 parsingerror = false;
1784 void CL_Parse_Init(void)
1786 // LordHavoc: added demo_nehahra cvar
1787 cl_scores_mempool = Mem_AllocPool("client player info");
1788 Cvar_RegisterVariable (&demo_nehahra);
1789 if (gamemode == GAME_NEHAHRA)
1790 Cvar_SetValue("demo_nehahra", 1);
1791 Cvar_RegisterVariable(&developer_networkentities);