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, va("rate %i\n", cl_rate.integer));
296 MSG_WriteByte (&cls.message, clc_stringcmd);
297 MSG_WriteString (&cls.message, "spawn");
301 MSG_WriteByte (&cls.message, clc_stringcmd);
302 MSG_WriteString (&cls.message, "begin");
316 qbyte entlife[MAX_EDICTS];
317 // FIXME: this is a lot of memory to be keeping around, this needs to be dynamically allocated and freed
318 static char parse_model_precache[MAX_MODELS][MAX_QPATH];
319 static char parse_sound_precache[MAX_SOUNDS][MAX_QPATH];
320 void CL_ParseServerInfo (void)
324 int nummodels, numsounds;
327 Con_DPrintf ("Serverinfo packet received.\n");
329 // wipe the client_state_t struct
333 // parse protocol version number
335 // hack for unmarked Nehahra movie demos which had a custom protocol
336 if (i == PROTOCOL_QUAKE && cls.demoplayback && demo_nehahra.integer)
337 i = PROTOCOL_NEHAHRAMOVIE;
338 if (i != PROTOCOL_QUAKE && i != PROTOCOL_DARKPLACES1 && i != PROTOCOL_DARKPLACES2 && i != PROTOCOL_DARKPLACES3 && i != PROTOCOL_DARKPLACES4 && i != PROTOCOL_NEHAHRAMOVIE)
340 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);
346 cl.maxclients = MSG_ReadByte ();
347 if (cl.maxclients < 1 || cl.maxclients > MAX_SCOREBOARD)
349 Con_Printf("Bad maxclients (%u) from server\n", cl.maxclients);
352 Mem_EmptyPool(cl_scores_mempool);
353 cl.scores = Mem_Alloc(cl_scores_mempool, cl.maxclients*sizeof(*cl.scores));
356 cl.gametype = MSG_ReadByte ();
358 // parse signon message
359 str = MSG_ReadString ();
360 strlcpy (cl.levelname, str, sizeof(cl.levelname));
362 // seperate the printfs so the server message can have a color
363 if (cl.protocol != PROTOCOL_NEHAHRAMOVIE) // no messages when playing the Nehahra movie
365 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");
366 Con_Printf("%c%s\n", 2, str);
369 // check memory integrity
370 Mem_CheckSentinelsGlobal();
372 // disable until we get textures for it
375 memset(cl.model_precache, 0, sizeof(cl.model_precache));
376 memset(cl.sound_precache, 0, sizeof(cl.sound_precache));
378 // parse model precache list
379 for (nummodels=1 ; ; nummodels++)
381 str = MSG_ReadString();
384 if (nummodels==MAX_MODELS)
385 Host_Error ("Server sent too many model precaches\n");
386 if (strlen(str) >= MAX_QPATH)
387 Host_Error ("Server sent a precache name of %i characters (max %i)", strlen(str), MAX_QPATH - 1);
388 strlcpy (parse_model_precache[nummodels], str, sizeof (parse_model_precache[nummodels]));
390 // parse sound precache list
391 for (numsounds=1 ; ; numsounds++)
393 str = MSG_ReadString();
396 if (numsounds==MAX_SOUNDS)
397 Host_Error("Server sent too many sound precaches\n");
398 if (strlen(str) >= MAX_QPATH)
399 Host_Error("Server sent a precache name of %i characters (max %i)", strlen(str), MAX_QPATH - 1);
400 strlcpy (parse_sound_precache[numsounds], str, sizeof (parse_sound_precache[numsounds]));
403 // touch all of the precached models that are still loaded so we can free
404 // anything that isn't needed
406 for (i = 1;i < nummodels;i++)
408 CL_KeepaliveMessage();
409 Mod_TouchModel(parse_model_precache[i]);
413 // do the same for sounds
415 for (i = 1;i < numsounds;i++)
417 CL_KeepaliveMessage();
418 S_TouchSound(parse_sound_precache[i]);
422 // now we try to load everything that is new
425 CL_KeepaliveMessage ();
426 cl.model_precache[1] = Mod_ForName(parse_model_precache[1], false, false, true);
427 if (cl.model_precache[1] == NULL)
428 Con_Printf("Map %s not found\n", parse_model_precache[1]);
431 for (i=2 ; i<nummodels ; i++)
433 CL_KeepaliveMessage();
434 if ((cl.model_precache[i] = Mod_ForName(parse_model_precache[i], false, false, false)) == NULL)
435 Con_Printf("Model %s not found\n", parse_model_precache[i]);
439 for (i=1 ; i<numsounds ; i++)
441 CL_KeepaliveMessage();
442 cl.sound_precache[i] = S_PrecacheSound(parse_sound_precache[i], true);
446 ent = &cl_entities[0];
447 // entire entity array was cleared, so just fill in a few fields
448 ent->state_current.active = true;
449 ent->render.model = cl.worldmodel = cl.model_precache[1];
450 //ent->render.scale = 1;
451 ent->render.alpha = 1;
452 ent->render.flags = RENDER_SHADOW;
453 Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, 0, 0, 0, 0, 0, 0, 1);
454 Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix);
455 CL_BoundingBoxForEntity(&ent->render);
456 // clear entlife array
457 memset(entlife, 0, MAX_EDICTS);
464 // noclip is turned off at start
465 noclip_anglehack = false;
467 // check memory integrity
468 Mem_CheckSentinelsGlobal();
471 void CL_ValidateState(entity_state_t *s)
478 if (s->modelindex >= MAX_MODELS)
479 Host_Error("CL_ValidateState: modelindex (%i) >= MAX_MODELS (%i)\n", s->modelindex, MAX_MODELS);
481 // colormap is client index + 1
482 if (s->colormap > cl.maxclients)
483 Host_Error ("CL_ValidateState: colormap (%i) > cl.maxclients (%i)", s->colormap, cl.maxclients);
485 model = cl.model_precache[s->modelindex];
486 Mod_CheckLoaded(model);
487 if (model && s->frame >= model->numframes)
489 Con_DPrintf("CL_ValidateState: no such frame %i in \"%s\"\n", s->frame, model->name);
492 if (model && s->skin > 0 && s->skin >= model->numskins)
494 Con_DPrintf("CL_ValidateState: no such skin %i in \"%s\"\n", s->skin, model->name);
499 void CL_MoveLerpEntityStates(entity_t *ent)
501 float odelta[3], adelta[3];
502 VectorSubtract(ent->state_current.origin, ent->persistent.neworigin, odelta);
503 VectorSubtract(ent->state_current.angles, ent->persistent.newangles, adelta);
504 if (!ent->state_previous.active || cls.timedemo || DotProduct(odelta, odelta) > 1000*1000 || cl_nolerp.integer)
506 // we definitely shouldn't lerp
507 ent->persistent.lerpdeltatime = 0;
508 ent->persistent.lerpstarttime = cl.mtime[1];
509 VectorCopy(ent->state_current.origin, ent->persistent.oldorigin);
510 VectorCopy(ent->state_current.angles, ent->persistent.oldangles);
511 VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
512 VectorCopy(ent->state_current.angles, ent->persistent.newangles);
514 else if (ent->state_current.flags & RENDER_STEP)
516 // monster interpolation
517 if (DotProduct(odelta, odelta) + DotProduct(adelta, adelta) > 0.01)
519 ent->persistent.lerpdeltatime = bound(0, cl.mtime[1] - ent->persistent.lerpstarttime, 0.1);
520 ent->persistent.lerpstarttime = cl.mtime[1];
521 VectorCopy(ent->persistent.neworigin, ent->persistent.oldorigin);
522 VectorCopy(ent->persistent.newangles, ent->persistent.oldangles);
523 VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
524 VectorCopy(ent->state_current.angles, ent->persistent.newangles);
530 ent->persistent.lerpstarttime = cl.mtime[1];
531 // no lerp if it's singleplayer
533 ent->persistent.lerpdeltatime = 0;
535 ent->persistent.lerpdeltatime = cl.mtime[0] - cl.mtime[1];
536 VectorCopy(ent->persistent.neworigin, ent->persistent.oldorigin);
537 VectorCopy(ent->persistent.newangles, ent->persistent.oldangles);
538 VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
539 VectorCopy(ent->state_current.angles, ent->persistent.newangles);
547 Parse an entity update message from the server
548 If an entities model or origin changes from frame to frame, it must be
549 relinked. Other attributes can change without relinking.
552 void CL_ParseUpdate (int bits)
558 if (bits & U_MOREBITS)
559 bits |= (MSG_ReadByte()<<8);
560 if ((bits & U_EXTEND1) && cl.protocol != PROTOCOL_NEHAHRAMOVIE)
562 bits |= MSG_ReadByte() << 16;
563 if (bits & U_EXTEND2)
564 bits |= MSG_ReadByte() << 24;
567 if (bits & U_LONGENTITY)
568 num = (unsigned) MSG_ReadShort ();
570 num = (unsigned) MSG_ReadByte ();
572 if (num >= MAX_EDICTS)
573 Host_Error("CL_ParseUpdate: entity number (%i) >= MAX_EDICTS (%i)\n", num, MAX_EDICTS);
575 Host_Error("CL_ParseUpdate: invalid entity number (%i)\n", num);
577 ent = cl_entities + num;
579 // note: this inherits the 'active' state of the baseline chosen
580 // (state_baseline is always active, state_current may not be active if
581 // the entity was missing in the last frame)
583 new = ent->state_current;
586 new = ent->state_baseline;
591 new.time = cl.mtime[0];
593 if (bits & U_MODEL) new.modelindex = (new.modelindex & 0xFF00) | MSG_ReadByte();
594 if (bits & U_FRAME) new.frame = (new.frame & 0xFF00) | MSG_ReadByte();
595 if (bits & U_COLORMAP) new.colormap = MSG_ReadByte();
596 if (bits & U_SKIN) new.skin = MSG_ReadByte();
597 if (bits & U_EFFECTS) new.effects = (new.effects & 0xFF00) | MSG_ReadByte();
598 if (bits & U_ORIGIN1) new.origin[0] = MSG_ReadCoord();
599 if (bits & U_ANGLE1) new.angles[0] = MSG_ReadAngle();
600 if (bits & U_ORIGIN2) new.origin[1] = MSG_ReadCoord();
601 if (bits & U_ANGLE2) new.angles[1] = MSG_ReadAngle();
602 if (bits & U_ORIGIN3) new.origin[2] = MSG_ReadCoord();
603 if (bits & U_ANGLE3) new.angles[2] = MSG_ReadAngle();
604 if (bits & U_STEP) new.flags |= RENDER_STEP;
605 if (bits & U_ALPHA) new.alpha = MSG_ReadByte();
606 if (bits & U_SCALE) new.scale = MSG_ReadByte();
607 if (bits & U_EFFECTS2) new.effects = (new.effects & 0x00FF) | (MSG_ReadByte() << 8);
608 if (bits & U_GLOWSIZE) new.glowsize = MSG_ReadByte();
609 if (bits & U_GLOWCOLOR) new.glowcolor = MSG_ReadByte();
610 // apparently the dpcrush demo uses this (unintended, and it uses white anyway)
611 if (bits & U_COLORMOD) MSG_ReadByte();
612 if (bits & U_GLOWTRAIL) new.flags |= RENDER_GLOWTRAIL;
613 if (bits & U_FRAME2) new.frame = (new.frame & 0x00FF) | (MSG_ReadByte() << 8);
614 if (bits & U_MODEL2) new.modelindex = (new.modelindex & 0x00FF) | (MSG_ReadByte() << 8);
615 if (bits & U_VIEWMODEL) new.flags |= RENDER_VIEWMODEL;
616 if (bits & U_EXTERIORMODEL) new.flags |= RENDER_EXTERIORMODEL;
618 // LordHavoc: to allow playback of the Nehahra movie
619 if (cl.protocol == PROTOCOL_NEHAHRAMOVIE && (bits & U_EXTEND1))
621 // LordHavoc: evil format
622 int i = MSG_ReadFloat();
623 int j = MSG_ReadFloat() * 255.0f;
628 new.effects |= EF_FULLBRIGHT;
632 else if (j == 0 || j >= 255)
639 CL_ValidateState(&new);
641 ent->state_previous = ent->state_current;
642 ent->state_current = new;
643 if (ent->state_current.active)
645 CL_MoveLerpEntityStates(ent);
646 cl_entities_active[ent->state_current.number] = true;
647 // mark as visible (no kill this frame)
648 entlife[ent->state_current.number] = 2;
652 static entity_frame_t entityframe;
653 extern mempool_t *cl_entities_mempool;
654 void CL_ReadEntityFrame(void)
656 if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
660 EntityFrame_Read(&cl.entitydatabase);
661 EntityFrame_FetchFrame(&cl.entitydatabase, EntityFrame_MostRecentlyRecievedFrameNum(&cl.entitydatabase), &entityframe);
662 for (i = 0;i < entityframe.numentities;i++)
665 ent = &cl_entities[entityframe.entitydata[i].number];
666 ent->state_previous = ent->state_current;
667 ent->state_current = entityframe.entitydata[i];
668 CL_MoveLerpEntityStates(ent);
669 // the entity lives again...
670 entlife[ent->state_current.number] = 2;
671 cl_entities_active[ent->state_current.number] = true;
676 if (!cl.entitydatabase4)
677 cl.entitydatabase4 = EntityFrame4_AllocDatabase(cl_entities_mempool);
678 EntityFrame4_CL_ReadFrame(cl.entitydatabase4);
682 void CL_EntityUpdateSetup(void)
686 void CL_EntityUpdateEnd(void)
688 if (cl.protocol == PROTOCOL_QUAKE || cl.protocol == PROTOCOL_NEHAHRAMOVIE || cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
691 // disable entities that disappeared this frame
692 for (i = 1;i < MAX_EDICTS;i++)
694 // clear only the entities that were active last frame but not this
695 // frame, don't waste time clearing all entities (which would cause
701 cl_entities[i].state_previous.active = cl_entities[i].state_current.active = 0;
712 void CL_ParseBaseline (entity_t *ent, int large)
716 ClearStateToDefault(&ent->state_baseline);
717 ent->state_baseline.active = true;
720 ent->state_baseline.modelindex = (unsigned short) MSG_ReadShort ();
721 ent->state_baseline.frame = (unsigned short) MSG_ReadShort ();
725 ent->state_baseline.modelindex = MSG_ReadByte ();
726 ent->state_baseline.frame = MSG_ReadByte ();
728 ent->state_baseline.colormap = MSG_ReadByte();
729 ent->state_baseline.skin = MSG_ReadByte();
730 for (i = 0;i < 3;i++)
732 ent->state_baseline.origin[i] = MSG_ReadCoord ();
733 ent->state_baseline.angles[i] = MSG_ReadAngle ();
735 CL_ValidateState(&ent->state_baseline);
736 ent->state_previous = ent->state_current = ent->state_baseline;
744 Server information pertaining to this client only
747 void CL_ParseClientdata (int bits)
752 if (bits & SU_EXTEND1)
753 bits |= (MSG_ReadByte() << 16);
754 if (bits & SU_EXTEND2)
755 bits |= (MSG_ReadByte() << 24);
757 if (bits & SU_VIEWHEIGHT)
758 cl.viewheight = MSG_ReadChar ();
760 cl.viewheight = DEFAULT_VIEWHEIGHT;
762 if (bits & SU_IDEALPITCH)
763 cl.idealpitch = MSG_ReadChar ();
767 VectorCopy (cl.mvelocity[0], cl.mvelocity[1]);
768 for (i=0 ; i<3 ; i++)
770 if (bits & (SU_PUNCH1<<i) )
772 if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4)
773 cl.punchangle[i] = MSG_ReadPreciseAngle();
775 cl.punchangle[i] = MSG_ReadChar();
778 cl.punchangle[i] = 0;
779 if (bits & (SU_PUNCHVEC1<<i))
780 cl.punchvector[i] = MSG_ReadCoord();
782 cl.punchvector[i] = 0;
783 if (bits & (SU_VELOCITY1<<i) )
784 cl.mvelocity[0][i] = MSG_ReadChar()*16;
786 cl.mvelocity[0][i] = 0;
792 for (j=0 ; j<32 ; j++)
793 if ( (i & (1<<j)) && !(cl.items & (1<<j)))
794 cl.item_gettime[j] = cl.time;
798 cl.onground = (bits & SU_ONGROUND) != 0;
799 cl.inwater = (bits & SU_INWATER) != 0;
801 cl.stats[STAT_WEAPONFRAME] = (bits & SU_WEAPONFRAME) ? MSG_ReadByte() : 0;
802 cl.stats[STAT_ARMOR] = (bits & SU_ARMOR) ? MSG_ReadByte() : 0;
803 cl.stats[STAT_WEAPON] = (bits & SU_WEAPON) ? MSG_ReadByte() : 0;
804 cl.stats[STAT_HEALTH] = MSG_ReadShort();
805 cl.stats[STAT_AMMO] = MSG_ReadByte();
807 cl.stats[STAT_SHELLS] = MSG_ReadByte();
808 cl.stats[STAT_NAILS] = MSG_ReadByte();
809 cl.stats[STAT_ROCKETS] = MSG_ReadByte();
810 cl.stats[STAT_CELLS] = MSG_ReadByte();
814 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
816 // GAME_NEXUIZ hud needs weapon change time
817 // GAME_NEXUIZ uses a bit number as it's STAT_ACTIVEWEAPON, not a bitfield
819 if (cl.stats[STAT_ACTIVEWEAPON] != i)
820 cl.weapontime = cl.time;
821 cl.stats[STAT_ACTIVEWEAPON] = i;
823 cl.viewzoomold = cl.viewzoomnew; // for interpolation
824 if (bits & SU_VIEWZOOM)
829 cl.viewzoomnew = (float) i * (1.0f / 255.0f);
837 =====================
839 =====================
841 void CL_ParseStatic (int large)
845 if (cl_num_static_entities >= cl_max_static_entities)
846 Host_Error ("Too many static entities");
847 ent = &cl_static_entities[cl_num_static_entities++];
848 CL_ParseBaseline (ent, large);
850 // copy it to the current state
851 ent->render.model = cl.model_precache[ent->state_baseline.modelindex];
852 ent->render.frame = ent->render.frame1 = ent->render.frame2 = ent->state_baseline.frame;
853 ent->render.framelerp = 0;
854 // make torchs play out of sync
855 ent->render.frame1time = ent->render.frame2time = lhrandom(-10, -1);
856 ent->render.colormap = -1; // no special coloring
857 ent->render.skinnum = ent->state_baseline.skin;
858 ent->render.effects = ent->state_baseline.effects;
859 ent->render.alpha = 1;
860 //ent->render.scale = 1;
862 //VectorCopy (ent->state_baseline.origin, ent->render.origin);
863 //VectorCopy (ent->state_baseline.angles, ent->render.angles);
865 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);
866 Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix);
867 CL_BoundingBoxForEntity(&ent->render);
869 // This is definitely cheating...
870 if (ent->render.model == NULL)
871 cl_num_static_entities--;
879 void CL_ParseStaticSound (int large)
882 int sound_num, vol, atten;
886 sound_num = (unsigned short) MSG_ReadShort ();
888 sound_num = MSG_ReadByte ();
889 vol = MSG_ReadByte ();
890 atten = MSG_ReadByte ();
892 S_StaticSound (cl.sound_precache[sound_num], org, vol, atten);
895 void CL_ParseEffect (void)
898 int modelindex, startframe, framecount, framerate;
901 modelindex = MSG_ReadByte ();
902 startframe = MSG_ReadByte ();
903 framecount = MSG_ReadByte ();
904 framerate = MSG_ReadByte ();
906 CL_Effect(org, modelindex, startframe, framecount, framerate);
909 void CL_ParseEffect2 (void)
912 int modelindex, startframe, framecount, framerate;
915 modelindex = MSG_ReadShort ();
916 startframe = MSG_ReadShort ();
917 framecount = MSG_ReadByte ();
918 framerate = MSG_ReadByte ();
920 CL_Effect(org, modelindex, startframe, framecount, framerate);
923 model_t *cl_model_bolt = NULL;
924 model_t *cl_model_bolt2 = NULL;
925 model_t *cl_model_bolt3 = NULL;
926 model_t *cl_model_beam = NULL;
928 sfx_t *cl_sfx_wizhit;
929 sfx_t *cl_sfx_knighthit;
934 sfx_t *cl_sfx_r_exp3;
941 void CL_InitTEnts (void)
943 cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav", false);
944 cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav", false);
945 cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav", false);
946 cl_sfx_ric1 = S_PrecacheSound ("weapons/ric1.wav", false);
947 cl_sfx_ric2 = S_PrecacheSound ("weapons/ric2.wav", false);
948 cl_sfx_ric3 = S_PrecacheSound ("weapons/ric3.wav", false);
949 cl_sfx_r_exp3 = S_PrecacheSound ("weapons/r_exp3.wav", false);
952 void CL_ParseBeam (model_t *m, int lightning)
958 ent = MSG_ReadShort ();
959 MSG_ReadVector(start);
962 if (ent >= MAX_EDICTS)
964 Con_Printf("CL_ParseBeam: invalid entity number %i\n", ent);
968 // override any beam with the same entity
969 for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
971 if (b->entity == ent)
974 b->lightning = lightning;
975 b->relativestartvalid = (ent && cl_entities[ent].state_current.active) ? 2 : 0;
977 b->endtime = cl.time + 0.2;
978 VectorCopy (start, b->start);
979 VectorCopy (end, b->end);
985 for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
987 if (!b->model || b->endtime < cl.time)
990 b->lightning = lightning;
991 b->relativestartvalid = (ent && cl_entities[ent].state_current.active) ? 2 : 0;
993 b->endtime = cl.time + 0.2;
994 VectorCopy (start, b->start);
995 VectorCopy (end, b->end);
999 Con_Printf ("beam list overflow!\n");
1002 void CL_ParseTempEntity(void)
1010 int colorStart, colorLength, count;
1011 float velspeed, radius;
1013 matrix4x4_t tempmatrix;
1015 type = MSG_ReadByte();
1019 // spike hitting wall
1020 MSG_ReadVector(pos);
1021 CL_FindNonSolidLocation(pos, pos, 4);
1022 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1023 CL_AllocDlight(NULL, &tempmatrix, 150, 0.25f, 1.00f, 0.25f, 250, 0.2, 0, 0, false, 1);
1024 CL_RunParticleEffect(pos, vec3_origin, 20, 30);
1025 S_StartSound(-1, 0, cl_sfx_wizhit, pos, 1, 1);
1028 case TE_KNIGHTSPIKE:
1029 // spike hitting wall
1030 MSG_ReadVector(pos);
1031 CL_FindNonSolidLocation(pos, pos, 4);
1032 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1033 CL_AllocDlight(NULL, &tempmatrix, 150, 1.0f, 0.60f, 0.20f, 250, 0.2, 0, 0, false, 1);
1034 CL_RunParticleEffect(pos, vec3_origin, 226, 20);
1035 S_StartSound(-1, 0, cl_sfx_knighthit, pos, 1, 1);
1039 // spike hitting wall
1040 MSG_ReadVector(pos);
1041 CL_FindNonSolidLocation(pos, pos, 4);
1042 // LordHavoc: changed to spark shower
1043 CL_SparkShower(pos, vec3_origin, 15);
1045 S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1050 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1052 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1054 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1058 // quad spike hitting wall
1059 MSG_ReadVector(pos);
1060 CL_FindNonSolidLocation(pos, pos, 4);
1061 // LordHavoc: changed to spark shower
1062 CL_SparkShower(pos, vec3_origin, 15);
1063 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1064 CL_AllocDlight(NULL, &tempmatrix, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2, 0, 0, true, 1);
1065 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1067 S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1072 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1074 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1076 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1080 // super spike hitting wall
1081 MSG_ReadVector(pos);
1082 CL_FindNonSolidLocation(pos, pos, 4);
1083 // LordHavoc: changed to dust shower
1084 CL_SparkShower(pos, vec3_origin, 30);
1086 S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1091 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1093 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1095 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1098 case TE_SUPERSPIKEQUAD:
1099 // quad super spike hitting wall
1100 MSG_ReadVector(pos);
1101 CL_FindNonSolidLocation(pos, pos, 4);
1102 // LordHavoc: changed to dust shower
1103 CL_SparkShower(pos, vec3_origin, 30);
1104 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1105 CL_AllocDlight(NULL, &tempmatrix, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2, 0, 0, true, 1);
1107 S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1112 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1114 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1116 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1119 // LordHavoc: added for improved blood splatters
1122 MSG_ReadVector(pos);
1123 CL_FindNonSolidLocation(pos, pos, 4);
1124 dir[0] = MSG_ReadChar();
1125 dir[1] = MSG_ReadChar();
1126 dir[2] = MSG_ReadChar();
1127 count = MSG_ReadByte();
1128 CL_BloodPuff(pos, dir, count);
1132 MSG_ReadVector(pos);
1133 CL_FindNonSolidLocation(pos, pos, 4);
1134 dir[0] = MSG_ReadChar();
1135 dir[1] = MSG_ReadChar();
1136 dir[2] = MSG_ReadChar();
1137 count = MSG_ReadByte();
1138 CL_SparkShower(pos, dir, count);
1141 MSG_ReadVector(pos);
1142 CL_FindNonSolidLocation(pos, pos, 4);
1143 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1144 CL_AllocDlight(NULL, &tempmatrix, 200, 1, 1, 1, 1000, 0.2, 0, 0, true, 1);
1147 // LordHavoc: added for improved gore
1148 case TE_BLOODSHOWER:
1150 MSG_ReadVector(pos); // mins
1151 MSG_ReadVector(pos2); // maxs
1152 velspeed = MSG_ReadCoord(); // speed
1153 count = MSG_ReadShort(); // number of particles
1154 CL_BloodShower(pos, pos2, velspeed, count);
1156 case TE_PARTICLECUBE:
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 colorLength = MSG_ReadByte(); // gravity (1 or 0)
1164 velspeed = MSG_ReadCoord(); // randomvel
1165 CL_ParticleCube(pos, pos2, dir, count, colorStart, colorLength, velspeed);
1168 case TE_PARTICLERAIN:
1169 // general purpose particle effect
1170 MSG_ReadVector(pos); // mins
1171 MSG_ReadVector(pos2); // maxs
1172 MSG_ReadVector(dir); // dir
1173 count = MSG_ReadShort(); // number of particles
1174 colorStart = MSG_ReadByte(); // color
1175 CL_ParticleRain(pos, pos2, dir, count, colorStart, 0);
1178 case TE_PARTICLESNOW:
1179 // general purpose particle effect
1180 MSG_ReadVector(pos); // mins
1181 MSG_ReadVector(pos2); // maxs
1182 MSG_ReadVector(dir); // dir
1183 count = MSG_ReadShort(); // number of particles
1184 colorStart = MSG_ReadByte(); // color
1185 CL_ParticleRain(pos, pos2, dir, count, colorStart, 1);
1189 // bullet hitting wall
1190 MSG_ReadVector(pos);
1191 CL_FindNonSolidLocation(pos, pos, 4);
1192 // LordHavoc: changed to dust shower
1193 CL_SparkShower(pos, vec3_origin, 15);
1196 case TE_GUNSHOTQUAD:
1197 // quad bullet hitting wall
1198 MSG_ReadVector(pos);
1199 CL_FindNonSolidLocation(pos, pos, 4);
1200 CL_SparkShower(pos, vec3_origin, 15);
1201 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1202 CL_AllocDlight(NULL, &tempmatrix, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2, 0, 0, true, 1);
1207 MSG_ReadVector(pos);
1208 CL_FindNonSolidLocation(pos, pos, 10);
1209 CL_ParticleExplosion(pos);
1210 // LordHavoc: boosted color from 1.0, 0.8, 0.4 to 1.25, 1.0, 0.5
1211 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1212 CL_AllocDlight(NULL, &tempmatrix, 350, 1.25f, 1.0f, 0.5f, 700, 0.5, 0, 0, true, 1);
1213 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1216 case TE_EXPLOSIONQUAD:
1217 // quad rocket explosion
1218 MSG_ReadVector(pos);
1219 CL_FindNonSolidLocation(pos, pos, 10);
1220 CL_ParticleExplosion(pos);
1221 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1222 CL_AllocDlight(NULL, &tempmatrix, 600, 0.5f, 0.4f, 1.0f, 1200, 0.5, 0, 0, true, 1);
1223 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1227 // Nehahra movie colored lighting explosion
1228 MSG_ReadVector(pos);
1229 CL_FindNonSolidLocation(pos, pos, 10);
1230 CL_ParticleExplosion(pos);
1231 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1232 CL_AllocDlight(NULL, &tempmatrix, 350, MSG_ReadCoord(), MSG_ReadCoord(), MSG_ReadCoord(), 700, 0.5, 0, 0, true, 1);
1233 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1236 case TE_EXPLOSIONRGB:
1237 // colored lighting explosion
1238 MSG_ReadVector(pos);
1239 CL_FindNonSolidLocation(pos, pos, 10);
1240 CL_ParticleExplosion(pos);
1241 color[0] = MSG_ReadByte() * (1.0 / 255.0);
1242 color[1] = MSG_ReadByte() * (1.0 / 255.0);
1243 color[2] = MSG_ReadByte() * (1.0 / 255.0);
1244 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1245 CL_AllocDlight(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, 0, true, 1);
1246 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1249 case TE_TAREXPLOSION:
1250 // tarbaby explosion
1251 MSG_ReadVector(pos);
1252 CL_FindNonSolidLocation(pos, pos, 10);
1253 CL_BlobExplosion(pos);
1255 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1256 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1257 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1258 CL_AllocDlight(NULL, &tempmatrix, 600, 0.8f, 0.4f, 1.0f, 1200, 0.5, 0, 0, true, 1);
1262 MSG_ReadVector(pos);
1263 CL_FindNonSolidLocation(pos, pos, 10);
1264 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1265 CL_AllocDlight(NULL, &tempmatrix, 200, 1, 1, 1, 1000, 0.2, 0, 0, true, 1);
1268 case TE_CUSTOMFLASH:
1269 MSG_ReadVector(pos);
1270 CL_FindNonSolidLocation(pos, pos, 4);
1271 radius = MSG_ReadByte() * 8;
1272 velspeed = (MSG_ReadByte() + 1) * (1.0 / 256.0);
1273 color[0] = MSG_ReadByte() * (1.0 / 255.0);
1274 color[1] = MSG_ReadByte() * (1.0 / 255.0);
1275 color[2] = MSG_ReadByte() * (1.0 / 255.0);
1276 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1277 CL_AllocDlight(NULL, &tempmatrix, radius, color[0], color[1], color[2], radius / velspeed, velspeed, 0, 0, true, 1);
1281 MSG_ReadVector(pos);
1282 MSG_ReadVector(dir);
1283 count = MSG_ReadByte();
1284 CL_Flames(pos, dir, count);
1290 cl_model_bolt = Mod_ForName("progs/bolt.mdl", true, false, false);
1291 CL_ParseBeam(cl_model_bolt, true);
1296 if (!cl_model_bolt2)
1297 cl_model_bolt2 = Mod_ForName("progs/bolt2.mdl", true, false, false);
1298 CL_ParseBeam(cl_model_bolt2, true);
1303 if (!cl_model_bolt3)
1304 cl_model_bolt3 = Mod_ForName("progs/bolt3.mdl", true, false, false);
1305 CL_ParseBeam(cl_model_bolt3, false);
1310 // grappling hook beam
1312 cl_model_beam = Mod_ForName("progs/beam.mdl", true, false, false);
1313 CL_ParseBeam(cl_model_beam, false);
1317 // LordHavoc: for compatibility with the Nehahra movie...
1318 case TE_LIGHTNING4NEH:
1319 CL_ParseBeam(Mod_ForName(MSG_ReadString(), true, false, false), false);
1323 pos[0] = MSG_ReadCoord();
1324 pos[1] = MSG_ReadCoord();
1325 pos[2] = MSG_ReadCoord();
1330 pos[0] = MSG_ReadCoord();
1331 pos[1] = MSG_ReadCoord();
1332 pos[2] = MSG_ReadCoord();
1333 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1334 CL_AllocDlight(NULL, &tempmatrix, 500, 1.0f, 1.0f, 1.0f, 1500, 99.0f, 0, 0, true, 1);
1335 // CL_TeleportSplash(pos);
1339 // color mapped explosion
1340 MSG_ReadVector(pos);
1341 CL_FindNonSolidLocation(pos, pos, 10);
1342 colorStart = MSG_ReadByte();
1343 colorLength = MSG_ReadByte();
1344 CL_ParticleExplosion2(pos, colorStart, colorLength);
1345 tempcolor = (qbyte *)&palette_complete[(rand()%colorLength) + colorStart];
1346 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1347 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);
1348 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1352 MSG_ReadVector(pos);
1353 MSG_ReadVector(pos2);
1354 MSG_ReadVector(dir);
1355 CL_BeamParticle(pos, pos2, 12, 1, 0.3, 0.1, 1, 1);
1356 CL_BeamParticle(pos, pos2, 5, 1, 0.9, 0.3, 1, 1);
1360 MSG_ReadVector(pos);
1361 MSG_ReadVector(dir);
1362 count = MSG_ReadByte();
1363 CL_FindNonSolidLocation(pos, pos, 4);
1364 CL_Tei_Smoke(pos, dir, count);
1367 case TE_TEI_BIGEXPLOSION:
1368 MSG_ReadVector(pos);
1369 CL_FindNonSolidLocation(pos, pos, 10);
1370 CL_ParticleExplosion(pos);
1371 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1372 CL_AllocDlight(NULL, &tempmatrix, 500, 1.25f, 1.0f, 0.5f, 500, 9999, 0, 0, true, 1);
1373 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1376 case TE_TEI_PLASMAHIT:
1377 MSG_ReadVector(pos);
1378 MSG_ReadVector(dir);
1379 count = MSG_ReadByte();
1380 CL_FindNonSolidLocation(pos, pos, 5);
1381 CL_Tei_PlasmaHit(pos, dir, count);
1382 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1383 CL_AllocDlight(NULL, &tempmatrix, 500, 0.3, 0.6, 1.0f, 2000, 9999, 0, 0, true, 1);
1387 Host_Error("CL_ParseTempEntity: bad type %d (hex %02X)", type, type);
1391 #define SHOWNET(x) if(cl_shownet.integer==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x);
1393 static qbyte cgamenetbuffer[65536];
1396 =====================
1397 CL_ParseServerMessage
1398 =====================
1400 int parsingerror = false;
1401 void CL_ParseServerMessage(void)
1404 int i, entitiesupdated;
1406 char *cmdlogname[32], *temp;
1407 int cmdindex, cmdcount = 0;
1409 if (cls.demorecording)
1410 CL_WriteDemoMessage ();
1412 cl.last_received_message = realtime;
1415 // if recording demos, copy the message out
1417 if (cl_shownet.integer == 1)
1418 Con_Printf ("%f %i\n", realtime, net_message.cursize);
1419 else if (cl_shownet.integer == 2)
1420 Con_Printf ("------------------\n");
1422 cl.onground = false; // unless the server says otherwise
1424 // parse the message
1426 //MSG_BeginReading ();
1428 entitiesupdated = false;
1430 parsingerror = true;
1435 Host_Error ("CL_ParseServerMessage: Bad server message");
1437 cmd = MSG_ReadByte ();
1441 SHOWNET("END OF MESSAGE");
1442 break; // end of message
1445 cmdindex = cmdcount & 31;
1447 cmdlog[cmdindex] = cmd;
1449 // if the high bit of the command byte is set, it is a fast update
1452 // 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)
1454 cmdlogname[cmdindex] = temp;
1455 SHOWNET("fast update");
1456 if (cls.signon == SIGNONS - 1)
1458 // first update is the final signon stage
1459 cls.signon = SIGNONS;
1462 CL_ParseUpdate (cmd&127);
1466 SHOWNET(svc_strings[cmd]);
1467 cmdlogname[cmdindex] = svc_strings[cmd];
1468 if (!cmdlogname[cmdindex])
1470 // 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)
1472 cmdlogname[cmdindex] = temp;
1480 char description[32*64], temp[64];
1482 strcpy (description, "packet dump: ");
1486 count = cmdcount - i;
1490 snprintf (temp, sizeof (temp), "%3i:%s ", cmdlog[i], cmdlogname[i]);
1491 strlcat (description, temp, sizeof (description));
1496 description[strlen(description)-1] = '\n'; // replace the last space with a newline
1497 Con_Printf("%s", description);
1498 Host_Error ("CL_ParseServerMessage: Illegible server message\n");
1503 if (cls.signon < SIGNONS)
1504 Con_Printf("<-- server to client keepalive\n");
1508 if (!entitiesupdated)
1510 // this is a new frame, we'll be seeing entities,
1511 // so prepare for entity updates
1512 CL_EntityUpdateSetup();
1513 entitiesupdated = true;
1515 cl.mtime[1] = cl.mtime[0];
1516 cl.mtime[0] = MSG_ReadFloat ();
1519 case svc_clientdata:
1520 i = MSG_ReadShort ();
1521 CL_ParseClientdata (i);
1525 i = MSG_ReadLong ();
1526 // hack for unmarked Nehahra movie demos which had a custom protocol
1527 if (i == PROTOCOL_QUAKE && cls.demoplayback && demo_nehahra.integer)
1528 i = PROTOCOL_NEHAHRAMOVIE;
1529 if (i != PROTOCOL_QUAKE && i != PROTOCOL_DARKPLACES1 && i != PROTOCOL_DARKPLACES2 && i != PROTOCOL_DARKPLACES3 && i != PROTOCOL_DARKPLACES4 && i != PROTOCOL_NEHAHRAMOVIE)
1530 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);
1534 case svc_disconnect:
1535 Host_EndGame ("Server disconnected\n");
1538 Con_Printf ("%s", MSG_ReadString ());
1541 case svc_centerprint:
1542 SCR_CenterPrint (MSG_ReadString ());
1546 Cbuf_AddText (MSG_ReadString ());
1553 case svc_serverinfo:
1554 CL_ParseServerInfo ();
1558 for (i=0 ; i<3 ; i++)
1559 cl.viewangles[i] = MSG_ReadAngle ();
1563 cl.viewentity = (unsigned short)MSG_ReadShort ();
1564 if (cl.viewentity >= MAX_EDICTS)
1565 Host_Error("svc_setview >= MAX_EDICTS\n");
1566 // LordHavoc: assume first setview recieved is the real player entity
1567 if (!cl.playerentity)
1568 cl.playerentity = cl.viewentity;
1571 case svc_lightstyle:
1572 i = MSG_ReadByte ();
1573 if (i >= MAX_LIGHTSTYLES)
1574 Host_Error ("svc_lightstyle >= MAX_LIGHTSTYLES");
1575 strlcpy (cl_lightstyle[i].map, MSG_ReadString(), sizeof (cl_lightstyle[i].map));
1576 cl_lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
1577 cl_lightstyle[i].length = strlen(cl_lightstyle[i].map);
1581 CL_ParseStartSoundPacket(false);
1585 CL_ParseStartSoundPacket(true);
1589 i = MSG_ReadShort();
1590 S_StopSound(i>>3, i&7);
1593 case svc_updatename:
1594 i = MSG_ReadByte ();
1595 if (i >= cl.maxclients)
1596 Host_Error ("CL_ParseServerMessage: svc_updatename >= cl.maxclients");
1597 strlcpy (cl.scores[i].name, MSG_ReadString (), sizeof (cl.scores[i].name));
1600 case svc_updatefrags:
1601 i = MSG_ReadByte ();
1602 if (i >= cl.maxclients)
1603 Host_Error ("CL_ParseServerMessage: svc_updatefrags >= cl.maxclients");
1604 cl.scores[i].frags = MSG_ReadShort ();
1607 case svc_updatecolors:
1608 i = MSG_ReadByte ();
1609 if (i >= cl.maxclients)
1610 Host_Error ("CL_ParseServerMessage: svc_updatecolors >= cl.maxclients");
1611 cl.scores[i].colors = MSG_ReadByte ();
1615 CL_ParseParticleEffect ();
1626 case svc_spawnbaseline:
1627 i = MSG_ReadShort ();
1628 if (i < 0 || i >= MAX_EDICTS)
1629 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i);
1630 CL_ParseBaseline (cl_entities + i, false);
1632 case svc_spawnbaseline2:
1633 i = MSG_ReadShort ();
1634 if (i < 0 || i >= MAX_EDICTS)
1635 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline2: invalid entity number %i", i);
1636 CL_ParseBaseline (cl_entities + i, true);
1638 case svc_spawnstatic:
1639 CL_ParseStatic (false);
1641 case svc_spawnstatic2:
1642 CL_ParseStatic (true);
1644 case svc_temp_entity:
1645 CL_ParseTempEntity ();
1649 cl.paused = MSG_ReadByte ();
1657 i = MSG_ReadByte ();
1658 if (i <= cls.signon)
1659 Host_Error ("Received signon %i when at %i", i, cls.signon);
1664 case svc_killedmonster:
1665 cl.stats[STAT_MONSTERS]++;
1668 case svc_foundsecret:
1669 cl.stats[STAT_SECRETS]++;
1672 case svc_updatestat:
1673 i = MSG_ReadByte ();
1674 if (i < 0 || i >= MAX_CL_STATS)
1675 Host_Error ("svc_updatestat: %i is invalid", i);
1676 cl.stats[i] = MSG_ReadLong ();
1679 case svc_spawnstaticsound:
1680 CL_ParseStaticSound (false);
1683 case svc_spawnstaticsound2:
1684 CL_ParseStaticSound (true);
1688 cl.cdtrack = MSG_ReadByte ();
1689 cl.looptrack = MSG_ReadByte ();
1690 if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )
1691 CDAudio_Play ((qbyte)cls.forcetrack, true);
1693 CDAudio_Play ((qbyte)cl.cdtrack, true);
1696 case svc_intermission:
1697 cl.intermission = 1;
1698 cl.completed_time = cl.time;
1702 cl.intermission = 2;
1703 cl.completed_time = cl.time;
1704 SCR_CenterPrint (MSG_ReadString ());
1708 cl.intermission = 3;
1709 cl.completed_time = cl.time;
1710 SCR_CenterPrint (MSG_ReadString ());
1713 case svc_sellscreen:
1714 Cmd_ExecuteString ("help", src_command);
1717 if (gamemode == GAME_TENEBRAE)
1719 // repeating particle effect
1732 SHOWLMP_decodehide();
1735 if (gamemode == GAME_TENEBRAE)
1745 SHOWLMP_decodeshow();
1748 R_SetSkyBox(MSG_ReadString());
1753 length = (int) ((unsigned short) MSG_ReadShort());
1754 for (i = 0;i < length;i++)
1755 cgamenetbuffer[i] = MSG_ReadByte();
1757 CL_CGVM_ParseNetwork(cgamenetbuffer, length);
1761 if (cls.signon == SIGNONS - 1)
1763 // first update is the final signon stage
1764 cls.signon = SIGNONS;
1767 CL_ReadEntityFrame();
1772 if (entitiesupdated)
1773 CL_EntityUpdateEnd();
1775 parsingerror = false;
1778 void CL_Parse_DumpPacket(void)
1782 Con_Printf("Packet dump:\n");
1783 SZ_HexDumpToConsole(&net_message);
1784 parsingerror = false;
1787 void CL_Parse_Init(void)
1789 // LordHavoc: added demo_nehahra cvar
1790 cl_scores_mempool = Mem_AllocPool("client player info");
1791 Cvar_RegisterVariable (&demo_nehahra);
1792 if (gamemode == GAME_NEHAHRA)
1793 Cvar_SetValue("demo_nehahra", 1);
1794 Cvar_RegisterVariable(&developer_networkentities);