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)
117 field_mask = MSG_ReadByte();
119 if (field_mask & SND_VOLUME)
120 volume = MSG_ReadByte ();
122 volume = DEFAULT_SOUND_PACKET_VOLUME;
124 if (field_mask & SND_ATTENUATION)
125 attenuation = MSG_ReadByte () / 64.0;
127 attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;
129 if (field_mask & SND_LARGEENTITY)
131 ent = (unsigned short) MSG_ReadShort ();
132 channel = MSG_ReadByte ();
136 channel = (unsigned short) MSG_ReadShort ();
141 if (largesoundindex || field_mask & SND_LARGESOUND)
142 sound_num = (unsigned short) MSG_ReadShort ();
144 sound_num = MSG_ReadByte ();
146 if (sound_num >= MAX_SOUNDS)
147 Host_Error("CL_ParseStartSoundPacket: sound_num (%i) >= MAX_SOUNDS (%i)\n", sound_num, MAX_SOUNDS);
150 if (ent >= MAX_EDICTS)
151 Host_Error ("CL_ParseStartSoundPacket: ent = %i", ent);
155 S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation);
162 When the client is taking a long time to load stuff, send keepalive messages
163 so the server doesn't disconnect.
167 static qbyte olddata[NET_MAXMESSAGE];
168 void CL_KeepaliveMessage (void)
171 static float lastmsg;
176 // no need if server is local and definitely not if this is a demo
177 if (sv.active || cls.demoplayback)
180 // read messages from server, should just be nops
181 oldreadcount = msg_readcount;
182 oldbadread = msg_badread;
184 memcpy(olddata, net_message.data, net_message.cursize);
186 NetConn_ClientFrame();
188 msg_readcount = oldreadcount;
189 msg_badread = oldbadread;
191 memcpy(net_message.data, olddata, net_message.cursize);
193 if (cls.netcon && NetConn_CanSendMessage(cls.netcon) && (time = Sys_DoubleTime()) - lastmsg >= 5)
199 // LordHavoc: must use unreliable because reliable could kill the sigon message!
200 Con_Print("--> client to server keepalive\n");
202 msg.maxsize = sizeof(buf);
204 MSG_WriteChar(&msg, svc_nop);
205 NetConn_SendUnreliableMessage(cls.netcon, &msg);
206 // try not to utterly crush the computer with work, that's just rude
211 void CL_ParseEntityLump(char *entdata)
214 char key[128], value[4096];
215 FOG_clear(); // LordHavoc: no fog until set
216 // LordHavoc: default to the map's sky (q3 shader parsing sets this)
217 R_SetSkyBox(cl.worldmodel->brush.skybox);
221 if (!COM_ParseToken(&data, false))
223 if (com_token[0] != '{')
227 if (!COM_ParseToken(&data, false))
229 if (com_token[0] == '}')
230 break; // end of worldspawn
231 if (com_token[0] == '_')
232 strlcpy (key, com_token + 1, sizeof (key));
234 strlcpy (key, com_token, sizeof (key));
235 while (key[strlen(key)-1] == ' ') // remove trailing spaces
236 key[strlen(key)-1] = 0;
237 if (!COM_ParseToken(&data, false))
239 strlcpy (value, com_token, sizeof (value));
240 if (!strcmp("sky", key))
242 else if (!strcmp("skyname", key)) // non-standard, introduced by QuakeForge... sigh.
244 else if (!strcmp("qlsky", key)) // non-standard, introduced by QuakeLives (EEK)
246 else if (!strcmp("fog", key))
247 sscanf(value, "%f %f %f %f", &fog_density, &fog_red, &fog_green, &fog_blue);
248 else if (!strcmp("fog_density", key))
249 fog_density = atof(value);
250 else if (!strcmp("fog_red", key))
251 fog_red = atof(value);
252 else if (!strcmp("fog_green", key))
253 fog_green = atof(value);
254 else if (!strcmp("fog_blue", key))
255 fog_blue = atof(value);
260 =====================
263 An svc_signonnum has been received, perform a client side setup
264 =====================
266 static void CL_SignonReply (void)
270 Con_DPrintf("CL_SignonReply: %i\n", cls.signon);
275 MSG_WriteByte (&cls.message, clc_stringcmd);
276 MSG_WriteString (&cls.message, "prespawn");
280 MSG_WriteByte (&cls.message, clc_stringcmd);
281 MSG_WriteString (&cls.message, va("name \"%s\"\n", cl_name.string));
283 MSG_WriteByte (&cls.message, clc_stringcmd);
284 MSG_WriteString (&cls.message, va("color %i %i\n", cl_color.integer >> 4, cl_color.integer & 15));
286 if (cl_pmodel.integer)
288 MSG_WriteByte (&cls.message, clc_stringcmd);
289 MSG_WriteString (&cls.message, va("pmodel %i\n", cl_pmodel.integer));
292 MSG_WriteByte (&cls.message, clc_stringcmd);
293 MSG_WriteString (&cls.message, va("rate %i\n", cl_rate.integer));
295 MSG_WriteByte (&cls.message, clc_stringcmd);
296 MSG_WriteString (&cls.message, "spawn");
300 MSG_WriteByte (&cls.message, clc_stringcmd);
301 MSG_WriteString (&cls.message, "begin");
315 qbyte entlife[MAX_EDICTS];
316 // FIXME: this is a lot of memory to be keeping around, this needs to be dynamically allocated and freed
317 static char parse_model_precache[MAX_MODELS][MAX_QPATH];
318 static char parse_sound_precache[MAX_SOUNDS][MAX_QPATH];
319 void CL_ParseServerInfo (void)
323 int nummodels, numsounds;
326 Con_DPrint("Serverinfo packet received.\n");
328 // wipe the client_state_t struct
332 // parse protocol version number
334 // hack for unmarked Nehahra movie demos which had a custom protocol
335 if (i == PROTOCOL_QUAKE && cls.demoplayback && demo_nehahra.integer)
336 i = PROTOCOL_NEHAHRAMOVIE;
337 if (i != PROTOCOL_QUAKE && i != PROTOCOL_DARKPLACES1 && i != PROTOCOL_DARKPLACES2 && i != PROTOCOL_DARKPLACES3 && i != PROTOCOL_DARKPLACES4 && i != PROTOCOL_DARKPLACES5 && i != PROTOCOL_NEHAHRAMOVIE)
339 Host_Error("CL_ParseServerInfo: Server is protocol %i, not %i (Quake), %i (DP1), %i (DP2), %i (DP3), %i (DP4), %i (DP5), or %i (Nehahra movie)", i, PROTOCOL_QUAKE, PROTOCOL_DARKPLACES1, PROTOCOL_DARKPLACES2, PROTOCOL_DARKPLACES3, PROTOCOL_DARKPLACES4, PROTOCOL_DARKPLACES5, PROTOCOL_NEHAHRAMOVIE);
345 cl.maxclients = MSG_ReadByte ();
346 if (cl.maxclients < 1 || cl.maxclients > MAX_SCOREBOARD)
348 Con_Printf("Bad maxclients (%u) from server\n", cl.maxclients);
351 Mem_EmptyPool(cl_scores_mempool);
352 cl.scores = Mem_Alloc(cl_scores_mempool, cl.maxclients*sizeof(*cl.scores));
355 cl.gametype = MSG_ReadByte ();
357 // parse signon message
358 str = MSG_ReadString ();
359 strlcpy (cl.levelname, str, sizeof(cl.levelname));
361 // seperate the printfs so the server message can have a color
362 if (cl.protocol != PROTOCOL_NEHAHRAMOVIE) // no messages when playing the Nehahra movie
363 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\2%s\n", str);
365 // check memory integrity
366 Mem_CheckSentinelsGlobal();
368 // disable until we get textures for it
371 memset(cl.model_precache, 0, sizeof(cl.model_precache));
372 memset(cl.sound_precache, 0, sizeof(cl.sound_precache));
374 // parse model precache list
375 for (nummodels=1 ; ; nummodels++)
377 str = MSG_ReadString();
380 if (nummodels==MAX_MODELS)
381 Host_Error ("Server sent too many model precaches\n");
382 if (strlen(str) >= MAX_QPATH)
383 Host_Error ("Server sent a precache name of %i characters (max %i)", strlen(str), MAX_QPATH - 1);
384 strlcpy (parse_model_precache[nummodels], str, sizeof (parse_model_precache[nummodels]));
386 // parse sound precache list
387 for (numsounds=1 ; ; numsounds++)
389 str = MSG_ReadString();
392 if (numsounds==MAX_SOUNDS)
393 Host_Error("Server sent too many sound precaches\n");
394 if (strlen(str) >= MAX_QPATH)
395 Host_Error("Server sent a precache name of %i characters (max %i)", strlen(str), MAX_QPATH - 1);
396 strlcpy (parse_sound_precache[numsounds], str, sizeof (parse_sound_precache[numsounds]));
399 // touch all of the precached models that are still loaded so we can free
400 // anything that isn't needed
402 for (i = 1;i < nummodels;i++)
404 CL_KeepaliveMessage();
405 Mod_TouchModel(parse_model_precache[i]);
409 // do the same for sounds
411 for (i = 1;i < numsounds;i++)
413 CL_KeepaliveMessage();
414 S_TouchSound(parse_sound_precache[i]);
418 // now we try to load everything that is new
421 CL_KeepaliveMessage ();
422 cl.model_precache[1] = Mod_ForName(parse_model_precache[1], false, false, true);
423 if (cl.model_precache[1] == NULL)
424 Con_Printf("Map %s not found\n", parse_model_precache[1]);
427 for (i=2 ; i<nummodels ; i++)
429 CL_KeepaliveMessage();
430 if ((cl.model_precache[i] = Mod_ForName(parse_model_precache[i], false, false, false)) == NULL)
431 Con_Printf("Model %s not found\n", parse_model_precache[i]);
435 for (i=1 ; i<numsounds ; i++)
437 CL_KeepaliveMessage();
438 cl.sound_precache[i] = S_PrecacheSound(parse_sound_precache[i], true);
442 ent = &cl_entities[0];
443 // entire entity array was cleared, so just fill in a few fields
444 ent->state_current.active = true;
445 ent->render.model = cl.worldmodel = cl.model_precache[1];
446 ent->render.scale = 1; // some of the renderer still relies on scale
447 ent->render.alpha = 1;
448 ent->render.flags = RENDER_SHADOW | RENDER_LIGHT;
449 Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, 0, 0, 0, 0, 0, 0, 1);
450 Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix);
451 CL_BoundingBoxForEntity(&ent->render);
452 // clear entlife array
453 memset(entlife, 0, MAX_EDICTS);
460 // noclip is turned off at start
461 noclip_anglehack = false;
463 // check memory integrity
464 Mem_CheckSentinelsGlobal();
467 void CL_ValidateState(entity_state_t *s)
474 if (s->modelindex >= MAX_MODELS)
475 Host_Error("CL_ValidateState: modelindex (%i) >= MAX_MODELS (%i)\n", s->modelindex, MAX_MODELS);
477 // colormap is client index + 1
478 if (s->colormap > cl.maxclients)
479 Host_Error ("CL_ValidateState: colormap (%i) > cl.maxclients (%i)", s->colormap, cl.maxclients);
481 model = cl.model_precache[s->modelindex];
482 Mod_CheckLoaded(model);
483 if (model && s->frame >= model->numframes)
485 Con_DPrintf("CL_ValidateState: no such frame %i in \"%s\"\n", s->frame, model->name);
488 if (model && s->skin > 0 && s->skin >= model->numskins)
490 Con_DPrintf("CL_ValidateState: no such skin %i in \"%s\"\n", s->skin, model->name);
495 void CL_MoveLerpEntityStates(entity_t *ent)
497 float odelta[3], adelta[3];
498 VectorSubtract(ent->state_current.origin, ent->persistent.neworigin, odelta);
499 VectorSubtract(ent->state_current.angles, ent->persistent.newangles, adelta);
500 if (!ent->state_previous.active || cls.timedemo || DotProduct(odelta, odelta) > 1000*1000 || cl_nolerp.integer)
502 // we definitely shouldn't lerp
503 ent->persistent.lerpdeltatime = 0;
504 ent->persistent.lerpstarttime = cl.mtime[1];
505 VectorCopy(ent->state_current.origin, ent->persistent.oldorigin);
506 VectorCopy(ent->state_current.angles, ent->persistent.oldangles);
507 VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
508 VectorCopy(ent->state_current.angles, ent->persistent.newangles);
510 else if (ent->state_current.flags & RENDER_STEP)
512 // monster interpolation
513 if (DotProduct(odelta, odelta) + DotProduct(adelta, adelta) > 0.01)
515 ent->persistent.lerpdeltatime = bound(0, cl.mtime[1] - ent->persistent.lerpstarttime, 0.1);
516 ent->persistent.lerpstarttime = cl.mtime[1];
517 VectorCopy(ent->persistent.neworigin, ent->persistent.oldorigin);
518 VectorCopy(ent->persistent.newangles, ent->persistent.oldangles);
519 VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
520 VectorCopy(ent->state_current.angles, ent->persistent.newangles);
526 ent->persistent.lerpstarttime = cl.mtime[1];
527 // no lerp if it's singleplayer
529 ent->persistent.lerpdeltatime = 0;
531 ent->persistent.lerpdeltatime = cl.mtime[0] - cl.mtime[1];
532 VectorCopy(ent->persistent.neworigin, ent->persistent.oldorigin);
533 VectorCopy(ent->persistent.newangles, ent->persistent.oldangles);
534 VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
535 VectorCopy(ent->state_current.angles, ent->persistent.newangles);
543 Parse an entity update message from the server
544 If an entities model or origin changes from frame to frame, it must be
545 relinked. Other attributes can change without relinking.
548 void CL_ParseUpdate (int bits)
554 if (bits & U_MOREBITS)
555 bits |= (MSG_ReadByte()<<8);
556 if ((bits & U_EXTEND1) && cl.protocol != PROTOCOL_NEHAHRAMOVIE)
558 bits |= MSG_ReadByte() << 16;
559 if (bits & U_EXTEND2)
560 bits |= MSG_ReadByte() << 24;
563 if (bits & U_LONGENTITY)
564 num = (unsigned) MSG_ReadShort ();
566 num = (unsigned) MSG_ReadByte ();
568 if (num >= MAX_EDICTS)
569 Host_Error("CL_ParseUpdate: entity number (%i) >= MAX_EDICTS (%i)\n", num, MAX_EDICTS);
571 Host_Error("CL_ParseUpdate: invalid entity number (%i)\n", num);
573 ent = cl_entities + num;
575 // note: this inherits the 'active' state of the baseline chosen
576 // (state_baseline is always active, state_current may not be active if
577 // the entity was missing in the last frame)
579 new = ent->state_current;
582 new = ent->state_baseline;
587 new.time = cl.mtime[0];
589 if (bits & U_MODEL) new.modelindex = (new.modelindex & 0xFF00) | MSG_ReadByte();
590 if (bits & U_FRAME) new.frame = (new.frame & 0xFF00) | MSG_ReadByte();
591 if (bits & U_COLORMAP) new.colormap = MSG_ReadByte();
592 if (bits & U_SKIN) new.skin = MSG_ReadByte();
593 if (bits & U_EFFECTS) new.effects = (new.effects & 0xFF00) | MSG_ReadByte();
594 if (bits & U_ORIGIN1) new.origin[0] = MSG_ReadCoord();
595 if (bits & U_ANGLE1) new.angles[0] = MSG_ReadAngle();
596 if (bits & U_ORIGIN2) new.origin[1] = MSG_ReadCoord();
597 if (bits & U_ANGLE2) new.angles[1] = MSG_ReadAngle();
598 if (bits & U_ORIGIN3) new.origin[2] = MSG_ReadCoord();
599 if (bits & U_ANGLE3) new.angles[2] = MSG_ReadAngle();
600 if (bits & U_STEP) new.flags |= RENDER_STEP;
601 if (bits & U_ALPHA) new.alpha = MSG_ReadByte();
602 if (bits & U_SCALE) new.scale = MSG_ReadByte();
603 if (bits & U_EFFECTS2) new.effects = (new.effects & 0x00FF) | (MSG_ReadByte() << 8);
604 if (bits & U_GLOWSIZE) new.glowsize = MSG_ReadByte();
605 if (bits & U_GLOWCOLOR) new.glowcolor = MSG_ReadByte();
606 // apparently the dpcrush demo uses this (unintended, and it uses white anyway)
607 if (bits & U_COLORMOD) MSG_ReadByte();
608 if (bits & U_GLOWTRAIL) new.flags |= RENDER_GLOWTRAIL;
609 if (bits & U_FRAME2) new.frame = (new.frame & 0x00FF) | (MSG_ReadByte() << 8);
610 if (bits & U_MODEL2) new.modelindex = (new.modelindex & 0x00FF) | (MSG_ReadByte() << 8);
611 if (bits & U_VIEWMODEL) new.flags |= RENDER_VIEWMODEL;
612 if (bits & U_EXTERIORMODEL) new.flags |= RENDER_EXTERIORMODEL;
614 // LordHavoc: to allow playback of the Nehahra movie
615 if (cl.protocol == PROTOCOL_NEHAHRAMOVIE && (bits & U_EXTEND1))
617 // LordHavoc: evil format
618 int i = MSG_ReadFloat();
619 int j = MSG_ReadFloat() * 255.0f;
624 new.effects |= EF_FULLBRIGHT;
628 else if (j == 0 || j >= 255)
635 CL_ValidateState(&new);
637 ent->state_previous = ent->state_current;
638 ent->state_current = new;
639 if (ent->state_current.active)
641 CL_MoveLerpEntityStates(ent);
642 cl_entities_active[ent->state_current.number] = true;
643 // mark as visible (no kill this frame)
644 entlife[ent->state_current.number] = 2;
648 static entity_frame_t entityframe;
649 extern mempool_t *cl_entities_mempool;
650 void CL_ReadEntityFrame(void)
652 if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
656 EntityFrame_Read(&cl.entitydatabase);
657 EntityFrame_FetchFrame(&cl.entitydatabase, EntityFrame_MostRecentlyRecievedFrameNum(&cl.entitydatabase), &entityframe);
658 for (i = 0;i < entityframe.numentities;i++)
661 ent = &cl_entities[entityframe.entitydata[i].number];
662 ent->state_previous = ent->state_current;
663 ent->state_current = entityframe.entitydata[i];
664 CL_MoveLerpEntityStates(ent);
665 // the entity lives again...
666 entlife[ent->state_current.number] = 2;
667 cl_entities_active[ent->state_current.number] = true;
672 if (!cl.entitydatabase4)
673 cl.entitydatabase4 = EntityFrame4_AllocDatabase(cl_entities_mempool);
674 EntityFrame4_CL_ReadFrame(cl.entitydatabase4);
678 void CL_EntityUpdateSetup(void)
682 void CL_EntityUpdateEnd(void)
684 if (cl.protocol == PROTOCOL_QUAKE || cl.protocol == PROTOCOL_NEHAHRAMOVIE || cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
687 // disable entities that disappeared this frame
688 for (i = 1;i < MAX_EDICTS;i++)
690 // clear only the entities that were active last frame but not this
691 // frame, don't waste time clearing all entities (which would cause
697 cl_entities[i].state_previous.active = cl_entities[i].state_current.active = 0;
708 void CL_ParseBaseline (entity_t *ent, int large)
712 ClearStateToDefault(&ent->state_baseline);
713 ent->state_baseline.active = true;
716 ent->state_baseline.modelindex = (unsigned short) MSG_ReadShort ();
717 ent->state_baseline.frame = (unsigned short) MSG_ReadShort ();
721 ent->state_baseline.modelindex = MSG_ReadByte ();
722 ent->state_baseline.frame = MSG_ReadByte ();
724 ent->state_baseline.colormap = MSG_ReadByte();
725 ent->state_baseline.skin = MSG_ReadByte();
726 for (i = 0;i < 3;i++)
728 ent->state_baseline.origin[i] = MSG_ReadCoord ();
729 ent->state_baseline.angles[i] = MSG_ReadAngle ();
731 CL_ValidateState(&ent->state_baseline);
732 ent->state_previous = ent->state_current = ent->state_baseline;
740 Server information pertaining to this client only
743 void CL_ParseClientdata (int bits)
748 if (bits & SU_EXTEND1)
749 bits |= (MSG_ReadByte() << 16);
750 if (bits & SU_EXTEND2)
751 bits |= (MSG_ReadByte() << 24);
753 if (bits & SU_VIEWHEIGHT)
754 cl.viewheight = MSG_ReadChar ();
756 cl.viewheight = DEFAULT_VIEWHEIGHT;
758 if (bits & SU_IDEALPITCH)
759 cl.idealpitch = MSG_ReadChar ();
763 VectorCopy (cl.mvelocity[0], cl.mvelocity[1]);
764 if (cl.protocol == PROTOCOL_DARKPLACES5)
766 for (i = 0;i < 3;i++)
768 if (bits & (SU_PUNCH1<<i) )
769 cl.punchangle[i] = MSG_ReadPreciseAngle();
771 cl.punchangle[i] = 0;
772 if (bits & (SU_PUNCHVEC1<<i))
773 cl.punchvector[i] = MSG_ReadFloat();
775 cl.punchvector[i] = 0;
776 if (bits & (SU_VELOCITY1<<i) )
777 cl.mvelocity[0][i] = MSG_ReadFloat();
779 cl.mvelocity[0][i] = 0;
784 for (i = 0;i < 3;i++)
786 if (bits & (SU_PUNCH1<<i) )
788 if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
789 cl.punchangle[i] = MSG_ReadPreciseAngle();
791 cl.punchangle[i] = MSG_ReadChar();
794 cl.punchangle[i] = 0;
795 if (bits & (SU_PUNCHVEC1<<i))
796 cl.punchvector[i] = MSG_ReadCoord();
798 cl.punchvector[i] = 0;
799 if (bits & (SU_VELOCITY1<<i) )
800 cl.mvelocity[0][i] = MSG_ReadChar()*16;
802 cl.mvelocity[0][i] = 0;
809 for (j=0 ; j<32 ; j++)
810 if ( (i & (1<<j)) && !(cl.items & (1<<j)))
811 cl.item_gettime[j] = cl.time;
815 cl.onground = (bits & SU_ONGROUND) != 0;
816 cl.inwater = (bits & SU_INWATER) != 0;
818 cl.stats[STAT_WEAPONFRAME] = (bits & SU_WEAPONFRAME) ? MSG_ReadByte() : 0;
819 cl.stats[STAT_ARMOR] = (bits & SU_ARMOR) ? MSG_ReadByte() : 0;
820 cl.stats[STAT_WEAPON] = (bits & SU_WEAPON) ? MSG_ReadByte() : 0;
821 cl.stats[STAT_HEALTH] = MSG_ReadShort();
822 cl.stats[STAT_AMMO] = MSG_ReadByte();
824 cl.stats[STAT_SHELLS] = MSG_ReadByte();
825 cl.stats[STAT_NAILS] = MSG_ReadByte();
826 cl.stats[STAT_ROCKETS] = MSG_ReadByte();
827 cl.stats[STAT_CELLS] = MSG_ReadByte();
831 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
833 // GAME_NEXUIZ hud needs weapon change time
834 // GAME_NEXUIZ uses a bit number as it's STAT_ACTIVEWEAPON, not a bitfield
836 if (cl.stats[STAT_ACTIVEWEAPON] != i)
837 cl.weapontime = cl.time;
838 cl.stats[STAT_ACTIVEWEAPON] = i;
840 cl.viewzoomold = cl.viewzoomnew; // for interpolation
841 if (bits & SU_VIEWZOOM)
846 cl.viewzoomnew = (float) i * (1.0f / 255.0f);
854 =====================
856 =====================
858 void CL_ParseStatic (int large)
862 if (cl_num_static_entities >= cl_max_static_entities)
863 Host_Error ("Too many static entities");
864 ent = &cl_static_entities[cl_num_static_entities++];
865 CL_ParseBaseline (ent, large);
867 // copy it to the current state
868 ent->render.model = cl.model_precache[ent->state_baseline.modelindex];
869 ent->render.frame = ent->render.frame1 = ent->render.frame2 = ent->state_baseline.frame;
870 ent->render.framelerp = 0;
871 // make torchs play out of sync
872 ent->render.frame1time = ent->render.frame2time = lhrandom(-10, -1);
873 ent->render.colormap = -1; // no special coloring
874 ent->render.skinnum = ent->state_baseline.skin;
875 ent->render.effects = ent->state_baseline.effects;
876 ent->render.alpha = 1;
877 //ent->render.scale = 1;
879 //VectorCopy (ent->state_baseline.origin, ent->render.origin);
880 //VectorCopy (ent->state_baseline.angles, ent->render.angles);
882 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);
883 Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix);
884 CL_BoundingBoxForEntity(&ent->render);
886 // This is definitely cheating...
887 if (ent->render.model == NULL)
888 cl_num_static_entities--;
896 void CL_ParseStaticSound (int large)
899 int sound_num, vol, atten;
903 sound_num = (unsigned short) MSG_ReadShort ();
905 sound_num = MSG_ReadByte ();
906 vol = MSG_ReadByte ();
907 atten = MSG_ReadByte ();
909 S_StaticSound (cl.sound_precache[sound_num], org, vol, atten);
912 void CL_ParseEffect (void)
915 int modelindex, startframe, framecount, framerate;
918 modelindex = MSG_ReadByte ();
919 startframe = MSG_ReadByte ();
920 framecount = MSG_ReadByte ();
921 framerate = MSG_ReadByte ();
923 CL_Effect(org, modelindex, startframe, framecount, framerate);
926 void CL_ParseEffect2 (void)
929 int modelindex, startframe, framecount, framerate;
932 modelindex = MSG_ReadShort ();
933 startframe = MSG_ReadShort ();
934 framecount = MSG_ReadByte ();
935 framerate = MSG_ReadByte ();
937 CL_Effect(org, modelindex, startframe, framecount, framerate);
940 model_t *cl_model_bolt = NULL;
941 model_t *cl_model_bolt2 = NULL;
942 model_t *cl_model_bolt3 = NULL;
943 model_t *cl_model_beam = NULL;
945 sfx_t *cl_sfx_wizhit;
946 sfx_t *cl_sfx_knighthit;
951 sfx_t *cl_sfx_r_exp3;
958 void CL_InitTEnts (void)
960 cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav", false);
961 cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav", false);
962 cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav", false);
963 cl_sfx_ric1 = S_PrecacheSound ("weapons/ric1.wav", false);
964 cl_sfx_ric2 = S_PrecacheSound ("weapons/ric2.wav", false);
965 cl_sfx_ric3 = S_PrecacheSound ("weapons/ric3.wav", false);
966 cl_sfx_r_exp3 = S_PrecacheSound ("weapons/r_exp3.wav", false);
969 void CL_ParseBeam (model_t *m, int lightning)
975 ent = MSG_ReadShort ();
976 MSG_ReadVector(start);
979 if (ent >= MAX_EDICTS)
981 Con_Printf("CL_ParseBeam: invalid entity number %i\n", ent);
985 // override any beam with the same entity
986 for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
988 if (b->entity == ent)
991 b->lightning = lightning;
992 b->relativestartvalid = (ent && cl_entities[ent].state_current.active) ? 2 : 0;
994 b->endtime = cl.time + 0.2;
995 VectorCopy (start, b->start);
996 VectorCopy (end, b->end);
1002 for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
1004 if (!b->model || b->endtime < cl.time)
1007 b->lightning = lightning;
1008 b->relativestartvalid = (ent && cl_entities[ent].state_current.active) ? 2 : 0;
1010 b->endtime = cl.time + 0.2;
1011 VectorCopy (start, b->start);
1012 VectorCopy (end, b->end);
1016 Con_Print("beam list overflow!\n");
1019 void CL_ParseTempEntity(void)
1027 int colorStart, colorLength, count;
1028 float velspeed, radius;
1030 matrix4x4_t tempmatrix;
1032 type = MSG_ReadByte();
1036 // spike hitting wall
1037 MSG_ReadVector(pos);
1038 CL_FindNonSolidLocation(pos, pos, 4);
1039 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1040 CL_AllocDlight(NULL, &tempmatrix, 100, 0.12f, 0.50f, 0.12f, 500, 0.2, 0, 0, false, 1);
1041 CL_RunParticleEffect(pos, vec3_origin, 20, 30);
1042 S_StartSound(-1, 0, cl_sfx_wizhit, pos, 1, 1);
1045 case TE_KNIGHTSPIKE:
1046 // spike hitting wall
1047 MSG_ReadVector(pos);
1048 CL_FindNonSolidLocation(pos, pos, 4);
1049 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1050 CL_AllocDlight(NULL, &tempmatrix, 100, 0.50f, 0.30f, 0.10f, 500, 0.2, 0, 0, false, 1);
1051 CL_RunParticleEffect(pos, vec3_origin, 226, 20);
1052 S_StartSound(-1, 0, cl_sfx_knighthit, pos, 1, 1);
1056 // spike hitting wall
1057 MSG_ReadVector(pos);
1058 CL_FindNonSolidLocation(pos, pos, 4);
1059 // LordHavoc: changed to spark shower
1060 CL_SparkShower(pos, vec3_origin, 15);
1062 S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1067 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1069 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1071 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1075 // quad spike hitting wall
1076 MSG_ReadVector(pos);
1077 CL_FindNonSolidLocation(pos, pos, 4);
1078 // LordHavoc: changed to spark shower
1079 CL_SparkShower(pos, vec3_origin, 15);
1080 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1081 CL_AllocDlight(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, 0, true, 1);
1082 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1084 S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1089 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1091 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1093 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1097 // super spike hitting wall
1098 MSG_ReadVector(pos);
1099 CL_FindNonSolidLocation(pos, pos, 4);
1100 // LordHavoc: changed to dust shower
1101 CL_SparkShower(pos, vec3_origin, 30);
1103 S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1108 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1110 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1112 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1115 case TE_SUPERSPIKEQUAD:
1116 // quad super spike hitting wall
1117 MSG_ReadVector(pos);
1118 CL_FindNonSolidLocation(pos, pos, 4);
1119 // LordHavoc: changed to dust shower
1120 CL_SparkShower(pos, vec3_origin, 30);
1121 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1122 CL_AllocDlight(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, 0, true, 1);
1124 S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1129 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1131 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1133 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1136 // LordHavoc: added for improved blood splatters
1139 MSG_ReadVector(pos);
1140 CL_FindNonSolidLocation(pos, pos, 4);
1141 dir[0] = MSG_ReadChar();
1142 dir[1] = MSG_ReadChar();
1143 dir[2] = MSG_ReadChar();
1144 count = MSG_ReadByte();
1145 CL_BloodPuff(pos, dir, count);
1149 MSG_ReadVector(pos);
1150 CL_FindNonSolidLocation(pos, pos, 4);
1151 dir[0] = MSG_ReadChar();
1152 dir[1] = MSG_ReadChar();
1153 dir[2] = MSG_ReadChar();
1154 count = MSG_ReadByte();
1155 CL_SparkShower(pos, dir, count);
1158 MSG_ReadVector(pos);
1159 CL_FindNonSolidLocation(pos, pos, 4);
1160 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1161 CL_AllocDlight(NULL, &tempmatrix, 200, 1, 1, 1, 1000, 0.2, 0, 0, true, 1);
1164 // LordHavoc: added for improved gore
1165 case TE_BLOODSHOWER:
1167 MSG_ReadVector(pos); // mins
1168 MSG_ReadVector(pos2); // maxs
1169 velspeed = MSG_ReadCoord(); // speed
1170 count = MSG_ReadShort(); // number of particles
1171 CL_BloodShower(pos, pos2, velspeed, count);
1173 case TE_PARTICLECUBE:
1174 // general purpose particle effect
1175 MSG_ReadVector(pos); // mins
1176 MSG_ReadVector(pos2); // maxs
1177 MSG_ReadVector(dir); // dir
1178 count = MSG_ReadShort(); // number of particles
1179 colorStart = MSG_ReadByte(); // color
1180 colorLength = MSG_ReadByte(); // gravity (1 or 0)
1181 velspeed = MSG_ReadCoord(); // randomvel
1182 CL_ParticleCube(pos, pos2, dir, count, colorStart, colorLength, velspeed);
1185 case TE_PARTICLERAIN:
1186 // general purpose particle effect
1187 MSG_ReadVector(pos); // mins
1188 MSG_ReadVector(pos2); // maxs
1189 MSG_ReadVector(dir); // dir
1190 count = MSG_ReadShort(); // number of particles
1191 colorStart = MSG_ReadByte(); // color
1192 CL_ParticleRain(pos, pos2, dir, count, colorStart, 0);
1195 case TE_PARTICLESNOW:
1196 // general purpose particle effect
1197 MSG_ReadVector(pos); // mins
1198 MSG_ReadVector(pos2); // maxs
1199 MSG_ReadVector(dir); // dir
1200 count = MSG_ReadShort(); // number of particles
1201 colorStart = MSG_ReadByte(); // color
1202 CL_ParticleRain(pos, pos2, dir, count, colorStart, 1);
1206 // bullet hitting wall
1207 MSG_ReadVector(pos);
1208 CL_FindNonSolidLocation(pos, pos, 4);
1209 // LordHavoc: changed to dust shower
1210 CL_SparkShower(pos, vec3_origin, 15);
1213 case TE_GUNSHOTQUAD:
1214 // quad bullet hitting wall
1215 MSG_ReadVector(pos);
1216 CL_FindNonSolidLocation(pos, pos, 4);
1217 CL_SparkShower(pos, vec3_origin, 15);
1218 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1219 CL_AllocDlight(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, 0, true, 1);
1224 MSG_ReadVector(pos);
1225 CL_FindNonSolidLocation(pos, pos, 10);
1226 CL_ParticleExplosion(pos);
1227 // LordHavoc: boosted color from 1.0, 0.8, 0.4 to 1.25, 1.0, 0.5
1228 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1229 CL_AllocDlight(NULL, &tempmatrix, 350, 2.5f, 2.0f, 1.0f, 700, 0.5, 0, 0, true, 1);
1230 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1233 case TE_EXPLOSIONQUAD:
1234 // quad rocket explosion
1235 MSG_ReadVector(pos);
1236 CL_FindNonSolidLocation(pos, pos, 10);
1237 CL_ParticleExplosion(pos);
1238 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1239 CL_AllocDlight(NULL, &tempmatrix, 350, 2.5f, 2.0f, 4.0f, 700, 0.5, 0, 0, true, 1);
1240 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1244 // Nehahra movie colored lighting explosion
1245 MSG_ReadVector(pos);
1246 CL_FindNonSolidLocation(pos, pos, 10);
1247 CL_ParticleExplosion(pos);
1248 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1249 color[0] = MSG_ReadCoord() * (2.0f / 1.0f);
1250 color[1] = MSG_ReadCoord() * (2.0f / 1.0f);
1251 color[2] = MSG_ReadCoord() * (2.0f / 1.0f);
1252 CL_AllocDlight(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, 0, true, 1);
1253 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1256 case TE_EXPLOSIONRGB:
1257 // colored lighting explosion
1258 MSG_ReadVector(pos);
1259 CL_FindNonSolidLocation(pos, pos, 10);
1260 CL_ParticleExplosion(pos);
1261 color[0] = MSG_ReadByte() * (2.0f / 255.0f);
1262 color[1] = MSG_ReadByte() * (2.0f / 255.0f);
1263 color[2] = MSG_ReadByte() * (2.0f / 255.0f);
1264 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1265 CL_AllocDlight(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, 0, true, 1);
1266 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1269 case TE_TAREXPLOSION:
1270 // tarbaby explosion
1271 MSG_ReadVector(pos);
1272 CL_FindNonSolidLocation(pos, pos, 10);
1273 CL_BlobExplosion(pos);
1275 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1276 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1277 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1278 CL_AllocDlight(NULL, &tempmatrix, 600, 1.6f, 0.8f, 2.0f, 1200, 0.5, 0, 0, true, 1);
1282 MSG_ReadVector(pos);
1283 CL_FindNonSolidLocation(pos, pos, 10);
1284 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1285 CL_AllocDlight(NULL, &tempmatrix, 200, 2, 2, 2, 1000, 0.2, 0, 0, true, 1);
1288 case TE_CUSTOMFLASH:
1289 MSG_ReadVector(pos);
1290 CL_FindNonSolidLocation(pos, pos, 4);
1291 radius = MSG_ReadByte() * 8;
1292 velspeed = (MSG_ReadByte() + 1) * (1.0 / 256.0);
1293 color[0] = MSG_ReadByte() * (2.0f / 255.0f);
1294 color[1] = MSG_ReadByte() * (2.0f / 255.0f);
1295 color[2] = MSG_ReadByte() * (2.0f / 255.0f);
1296 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1297 CL_AllocDlight(NULL, &tempmatrix, radius, color[0], color[1], color[2], radius / velspeed, velspeed, 0, 0, true, 1);
1301 MSG_ReadVector(pos);
1302 MSG_ReadVector(dir);
1303 count = MSG_ReadByte();
1304 CL_Flames(pos, dir, count);
1310 cl_model_bolt = Mod_ForName("progs/bolt.mdl", true, false, false);
1311 CL_ParseBeam(cl_model_bolt, true);
1316 if (!cl_model_bolt2)
1317 cl_model_bolt2 = Mod_ForName("progs/bolt2.mdl", true, false, false);
1318 CL_ParseBeam(cl_model_bolt2, true);
1323 if (!cl_model_bolt3)
1324 cl_model_bolt3 = Mod_ForName("progs/bolt3.mdl", true, false, false);
1325 CL_ParseBeam(cl_model_bolt3, false);
1330 // grappling hook beam
1332 cl_model_beam = Mod_ForName("progs/beam.mdl", true, false, false);
1333 CL_ParseBeam(cl_model_beam, false);
1337 // LordHavoc: for compatibility with the Nehahra movie...
1338 case TE_LIGHTNING4NEH:
1339 CL_ParseBeam(Mod_ForName(MSG_ReadString(), true, false, false), false);
1343 MSG_ReadVector(pos);
1348 MSG_ReadVector(pos);
1349 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1350 CL_AllocDlight(NULL, &tempmatrix, 500, 1.0f, 1.0f, 1.0f, 1500, 99.0f, 0, 0, true, 1);
1351 // CL_TeleportSplash(pos);
1355 // color mapped explosion
1356 MSG_ReadVector(pos);
1357 CL_FindNonSolidLocation(pos, pos, 10);
1358 colorStart = MSG_ReadByte();
1359 colorLength = MSG_ReadByte();
1360 CL_ParticleExplosion2(pos, colorStart, colorLength);
1361 tempcolor = (qbyte *)&palette_complete[(rand()%colorLength) + colorStart];
1362 color[0] = tempcolor[0] * (2.0f / 255.0f);
1363 color[1] = tempcolor[1] * (2.0f / 255.0f);
1364 color[2] = tempcolor[2] * (2.0f / 255.0f);
1365 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1366 CL_AllocDlight(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, 0, true, 1);
1367 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1371 MSG_ReadVector(pos);
1372 MSG_ReadVector(pos2);
1373 MSG_ReadVector(dir);
1374 CL_BeamParticle(pos, pos2, 12, 1, 0.3, 0.1, 1, 1);
1375 CL_BeamParticle(pos, pos2, 5, 1, 0.9, 0.3, 1, 1);
1379 MSG_ReadVector(pos);
1380 MSG_ReadVector(dir);
1381 count = MSG_ReadByte();
1382 CL_FindNonSolidLocation(pos, pos, 4);
1383 CL_Tei_Smoke(pos, dir, count);
1386 case TE_TEI_BIGEXPLOSION:
1387 MSG_ReadVector(pos);
1388 CL_FindNonSolidLocation(pos, pos, 10);
1389 CL_ParticleExplosion(pos);
1390 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1391 CL_AllocDlight(NULL, &tempmatrix, 500, 2.5f, 2.0f, 1.0f, 500, 9999, 0, 0, true, 1);
1392 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1395 case TE_TEI_PLASMAHIT:
1396 MSG_ReadVector(pos);
1397 MSG_ReadVector(dir);
1398 count = MSG_ReadByte();
1399 CL_FindNonSolidLocation(pos, pos, 5);
1400 CL_Tei_PlasmaHit(pos, dir, count);
1401 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1402 CL_AllocDlight(NULL, &tempmatrix, 500, 0.6, 1.2, 2.0f, 2000, 9999, 0, 0, true, 1);
1406 Host_Error("CL_ParseTempEntity: bad type %d (hex %02X)", type, type);
1410 #define SHOWNET(x) if(cl_shownet.integer==2)Con_Printf("%3i:%s\n", msg_readcount-1, x);
1412 static qbyte cgamenetbuffer[65536];
1415 =====================
1416 CL_ParseServerMessage
1417 =====================
1419 int parsingerror = false;
1420 void CL_ParseServerMessage(void)
1423 int i, entitiesupdated;
1425 char *cmdlogname[32], *temp;
1426 int cmdindex, cmdcount = 0;
1428 if (cls.demorecording)
1429 CL_WriteDemoMessage ();
1431 cl.last_received_message = realtime;
1434 // if recording demos, copy the message out
1436 if (cl_shownet.integer == 1)
1437 Con_Printf("%f %i\n", realtime, net_message.cursize);
1438 else if (cl_shownet.integer == 2)
1439 Con_Print("------------------\n");
1441 cl.onground = false; // unless the server says otherwise
1443 // parse the message
1445 //MSG_BeginReading ();
1447 entitiesupdated = false;
1449 parsingerror = true;
1454 Host_Error ("CL_ParseServerMessage: Bad server message");
1456 cmd = MSG_ReadByte ();
1460 SHOWNET("END OF MESSAGE");
1461 break; // end of message
1464 cmdindex = cmdcount & 31;
1466 cmdlog[cmdindex] = cmd;
1468 // if the high bit of the command byte is set, it is a fast update
1471 // 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)
1473 cmdlogname[cmdindex] = temp;
1474 SHOWNET("fast update");
1475 if (cls.signon == SIGNONS - 1)
1477 // first update is the final signon stage
1478 cls.signon = SIGNONS;
1481 CL_ParseUpdate (cmd&127);
1485 SHOWNET(svc_strings[cmd]);
1486 cmdlogname[cmdindex] = svc_strings[cmd];
1487 if (!cmdlogname[cmdindex])
1489 // 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)
1491 cmdlogname[cmdindex] = temp;
1499 char description[32*64], temp[64];
1501 strcpy (description, "packet dump: ");
1505 count = cmdcount - i;
1509 snprintf (temp, sizeof (temp), "%3i:%s ", cmdlog[i], cmdlogname[i]);
1510 strlcat (description, temp, sizeof (description));
1515 description[strlen(description)-1] = '\n'; // replace the last space with a newline
1516 Con_Print(description);
1517 Host_Error ("CL_ParseServerMessage: Illegible server message\n");
1522 if (cls.signon < SIGNONS)
1523 Con_Print("<-- server to client keepalive\n");
1527 if (!entitiesupdated)
1529 // this is a new frame, we'll be seeing entities,
1530 // so prepare for entity updates
1531 CL_EntityUpdateSetup();
1532 entitiesupdated = true;
1534 cl.mtime[1] = cl.mtime[0];
1535 cl.mtime[0] = MSG_ReadFloat ();
1538 case svc_clientdata:
1539 i = MSG_ReadShort ();
1540 CL_ParseClientdata (i);
1544 i = MSG_ReadLong ();
1545 // hack for unmarked Nehahra movie demos which had a custom protocol
1546 if (i == PROTOCOL_QUAKE && cls.demoplayback && demo_nehahra.integer)
1547 i = PROTOCOL_NEHAHRAMOVIE;
1548 if (i != PROTOCOL_QUAKE && i != PROTOCOL_DARKPLACES1 && i != PROTOCOL_DARKPLACES2 && i != PROTOCOL_DARKPLACES3 && i != PROTOCOL_DARKPLACES4 && i != PROTOCOL_DARKPLACES5 && i != PROTOCOL_NEHAHRAMOVIE)
1549 Host_Error("CL_ParseServerMessage: Server is protocol %i, not %i (Quake), %i (DP1), %i (DP2), %i (DP3), %i (DP4), %i (DP5), or %i (Nehahra movie)", i, PROTOCOL_QUAKE, PROTOCOL_DARKPLACES1, PROTOCOL_DARKPLACES2, PROTOCOL_DARKPLACES3, PROTOCOL_DARKPLACES4, PROTOCOL_DARKPLACES5, PROTOCOL_NEHAHRAMOVIE);
1553 case svc_disconnect:
1554 Host_EndGame ("Server disconnected\n");
1557 Con_Print(MSG_ReadString());
1560 case svc_centerprint:
1561 SCR_CenterPrint(MSG_ReadString ());
1565 Cbuf_AddText (MSG_ReadString ());
1572 case svc_serverinfo:
1573 CL_ParseServerInfo ();
1577 for (i=0 ; i<3 ; i++)
1578 cl.viewangles[i] = MSG_ReadAngle ();
1582 cl.viewentity = (unsigned short)MSG_ReadShort ();
1583 if (cl.viewentity >= MAX_EDICTS)
1584 Host_Error("svc_setview >= MAX_EDICTS\n");
1585 // LordHavoc: assume first setview recieved is the real player entity
1586 if (!cl.playerentity)
1587 cl.playerentity = cl.viewentity;
1590 case svc_lightstyle:
1591 i = MSG_ReadByte ();
1592 if (i >= MAX_LIGHTSTYLES)
1593 Host_Error ("svc_lightstyle >= MAX_LIGHTSTYLES");
1594 strlcpy (cl_lightstyle[i].map, MSG_ReadString(), sizeof (cl_lightstyle[i].map));
1595 cl_lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
1596 cl_lightstyle[i].length = strlen(cl_lightstyle[i].map);
1600 CL_ParseStartSoundPacket(false);
1604 CL_ParseStartSoundPacket(true);
1608 i = MSG_ReadShort();
1609 S_StopSound(i>>3, i&7);
1612 case svc_updatename:
1613 i = MSG_ReadByte ();
1614 if (i >= cl.maxclients)
1615 Host_Error ("CL_ParseServerMessage: svc_updatename >= cl.maxclients");
1616 strlcpy (cl.scores[i].name, MSG_ReadString (), sizeof (cl.scores[i].name));
1619 case svc_updatefrags:
1620 i = MSG_ReadByte ();
1621 if (i >= cl.maxclients)
1622 Host_Error ("CL_ParseServerMessage: svc_updatefrags >= cl.maxclients");
1623 cl.scores[i].frags = MSG_ReadShort ();
1626 case svc_updatecolors:
1627 i = MSG_ReadByte ();
1628 if (i >= cl.maxclients)
1629 Host_Error ("CL_ParseServerMessage: svc_updatecolors >= cl.maxclients");
1630 cl.scores[i].colors = MSG_ReadByte ();
1634 CL_ParseParticleEffect ();
1645 case svc_spawnbaseline:
1646 i = MSG_ReadShort ();
1647 if (i < 0 || i >= MAX_EDICTS)
1648 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i);
1649 CL_ParseBaseline (cl_entities + i, false);
1651 case svc_spawnbaseline2:
1652 i = MSG_ReadShort ();
1653 if (i < 0 || i >= MAX_EDICTS)
1654 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline2: invalid entity number %i", i);
1655 CL_ParseBaseline (cl_entities + i, true);
1657 case svc_spawnstatic:
1658 CL_ParseStatic (false);
1660 case svc_spawnstatic2:
1661 CL_ParseStatic (true);
1663 case svc_temp_entity:
1664 CL_ParseTempEntity ();
1668 cl.paused = MSG_ReadByte ();
1672 S_PauseGameSounds ();
1677 S_ResumeGameSounds ();
1682 i = MSG_ReadByte ();
1683 if (i <= cls.signon)
1684 Host_Error ("Received signon %i when at %i", i, cls.signon);
1689 case svc_killedmonster:
1690 cl.stats[STAT_MONSTERS]++;
1693 case svc_foundsecret:
1694 cl.stats[STAT_SECRETS]++;
1697 case svc_updatestat:
1698 i = MSG_ReadByte ();
1699 if (i < 0 || i >= MAX_CL_STATS)
1700 Host_Error ("svc_updatestat: %i is invalid", i);
1701 cl.stats[i] = MSG_ReadLong ();
1704 case svc_spawnstaticsound:
1705 CL_ParseStaticSound (false);
1708 case svc_spawnstaticsound2:
1709 CL_ParseStaticSound (true);
1713 cl.cdtrack = MSG_ReadByte ();
1714 cl.looptrack = MSG_ReadByte ();
1715 if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )
1716 CDAudio_Play ((qbyte)cls.forcetrack, true);
1718 CDAudio_Play ((qbyte)cl.cdtrack, true);
1721 case svc_intermission:
1722 cl.intermission = 1;
1723 cl.completed_time = cl.time;
1727 cl.intermission = 2;
1728 cl.completed_time = cl.time;
1729 SCR_CenterPrint(MSG_ReadString ());
1733 cl.intermission = 3;
1734 cl.completed_time = cl.time;
1735 SCR_CenterPrint(MSG_ReadString ());
1738 case svc_sellscreen:
1739 Cmd_ExecuteString ("help", src_command);
1742 if (gamemode == GAME_TENEBRAE)
1744 // repeating particle effect
1757 SHOWLMP_decodehide();
1760 if (gamemode == GAME_TENEBRAE)
1770 SHOWLMP_decodeshow();
1773 R_SetSkyBox(MSG_ReadString());
1778 length = (int) ((unsigned short) MSG_ReadShort());
1779 for (i = 0;i < length;i++)
1780 cgamenetbuffer[i] = MSG_ReadByte();
1782 CL_CGVM_ParseNetwork(cgamenetbuffer, length);
1786 if (cls.signon == SIGNONS - 1)
1788 // first update is the final signon stage
1789 cls.signon = SIGNONS;
1792 CL_ReadEntityFrame();
1797 if (entitiesupdated)
1798 CL_EntityUpdateEnd();
1800 parsingerror = false;
1803 void CL_Parse_DumpPacket(void)
1807 Con_Print("Packet dump:\n");
1808 SZ_HexDumpToConsole(&net_message);
1809 parsingerror = false;
1812 void CL_Parse_Init(void)
1814 // LordHavoc: added demo_nehahra cvar
1815 cl_scores_mempool = Mem_AllocPool("client player info");
1816 Cvar_RegisterVariable (&demo_nehahra);
1817 if (gamemode == GAME_NEHAHRA)
1818 Cvar_SetValue("demo_nehahra", 1);
1819 Cvar_RegisterVariable(&developer_networkentities);