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", 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, 150, 0.25f, 1.00f, 0.25f, 250, 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, 150, 1.0f, 0.60f, 0.20f, 250, 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, 200, 0.1f, 0.1f, 1.0f, 1000, 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, 200, 0.1f, 0.1f, 1.0f, 1000, 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, 200, 0.1f, 0.1f, 1.0f, 1000, 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, 1.25f, 1.0f, 0.5f, 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, 600, 0.5f, 0.4f, 1.0f, 1200, 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 CL_AllocDlight(NULL, &tempmatrix, 350, MSG_ReadCoord(), MSG_ReadCoord(), MSG_ReadCoord(), 700, 0.5, 0, 0, true, 1);
1250 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1253 case TE_EXPLOSIONRGB:
1254 // colored lighting explosion
1255 MSG_ReadVector(pos);
1256 CL_FindNonSolidLocation(pos, pos, 10);
1257 CL_ParticleExplosion(pos);
1258 color[0] = MSG_ReadByte() * (1.0 / 255.0);
1259 color[1] = MSG_ReadByte() * (1.0 / 255.0);
1260 color[2] = MSG_ReadByte() * (1.0 / 255.0);
1261 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1262 CL_AllocDlight(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, 0, true, 1);
1263 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1266 case TE_TAREXPLOSION:
1267 // tarbaby explosion
1268 MSG_ReadVector(pos);
1269 CL_FindNonSolidLocation(pos, pos, 10);
1270 CL_BlobExplosion(pos);
1272 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1273 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1274 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1275 CL_AllocDlight(NULL, &tempmatrix, 600, 0.8f, 0.4f, 1.0f, 1200, 0.5, 0, 0, true, 1);
1279 MSG_ReadVector(pos);
1280 CL_FindNonSolidLocation(pos, pos, 10);
1281 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1282 CL_AllocDlight(NULL, &tempmatrix, 200, 1, 1, 1, 1000, 0.2, 0, 0, true, 1);
1285 case TE_CUSTOMFLASH:
1286 MSG_ReadVector(pos);
1287 CL_FindNonSolidLocation(pos, pos, 4);
1288 radius = MSG_ReadByte() * 8;
1289 velspeed = (MSG_ReadByte() + 1) * (1.0 / 256.0);
1290 color[0] = MSG_ReadByte() * (1.0 / 255.0);
1291 color[1] = MSG_ReadByte() * (1.0 / 255.0);
1292 color[2] = MSG_ReadByte() * (1.0 / 255.0);
1293 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1294 CL_AllocDlight(NULL, &tempmatrix, radius, color[0], color[1], color[2], radius / velspeed, velspeed, 0, 0, true, 1);
1298 MSG_ReadVector(pos);
1299 MSG_ReadVector(dir);
1300 count = MSG_ReadByte();
1301 CL_Flames(pos, dir, count);
1307 cl_model_bolt = Mod_ForName("progs/bolt.mdl", true, false, false);
1308 CL_ParseBeam(cl_model_bolt, true);
1313 if (!cl_model_bolt2)
1314 cl_model_bolt2 = Mod_ForName("progs/bolt2.mdl", true, false, false);
1315 CL_ParseBeam(cl_model_bolt2, true);
1320 if (!cl_model_bolt3)
1321 cl_model_bolt3 = Mod_ForName("progs/bolt3.mdl", true, false, false);
1322 CL_ParseBeam(cl_model_bolt3, false);
1327 // grappling hook beam
1329 cl_model_beam = Mod_ForName("progs/beam.mdl", true, false, false);
1330 CL_ParseBeam(cl_model_beam, false);
1334 // LordHavoc: for compatibility with the Nehahra movie...
1335 case TE_LIGHTNING4NEH:
1336 CL_ParseBeam(Mod_ForName(MSG_ReadString(), true, false, false), false);
1340 MSG_ReadVector(pos);
1345 MSG_ReadVector(pos);
1346 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1347 CL_AllocDlight(NULL, &tempmatrix, 500, 1.0f, 1.0f, 1.0f, 1500, 99.0f, 0, 0, true, 1);
1348 // CL_TeleportSplash(pos);
1352 // color mapped explosion
1353 MSG_ReadVector(pos);
1354 CL_FindNonSolidLocation(pos, pos, 10);
1355 colorStart = MSG_ReadByte();
1356 colorLength = MSG_ReadByte();
1357 CL_ParticleExplosion2(pos, colorStart, colorLength);
1358 tempcolor = (qbyte *)&palette_complete[(rand()%colorLength) + colorStart];
1359 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1360 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);
1361 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1365 MSG_ReadVector(pos);
1366 MSG_ReadVector(pos2);
1367 MSG_ReadVector(dir);
1368 CL_BeamParticle(pos, pos2, 12, 1, 0.3, 0.1, 1, 1);
1369 CL_BeamParticle(pos, pos2, 5, 1, 0.9, 0.3, 1, 1);
1373 MSG_ReadVector(pos);
1374 MSG_ReadVector(dir);
1375 count = MSG_ReadByte();
1376 CL_FindNonSolidLocation(pos, pos, 4);
1377 CL_Tei_Smoke(pos, dir, count);
1380 case TE_TEI_BIGEXPLOSION:
1381 MSG_ReadVector(pos);
1382 CL_FindNonSolidLocation(pos, pos, 10);
1383 CL_ParticleExplosion(pos);
1384 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1385 CL_AllocDlight(NULL, &tempmatrix, 500, 1.25f, 1.0f, 0.5f, 500, 9999, 0, 0, true, 1);
1386 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1389 case TE_TEI_PLASMAHIT:
1390 MSG_ReadVector(pos);
1391 MSG_ReadVector(dir);
1392 count = MSG_ReadByte();
1393 CL_FindNonSolidLocation(pos, pos, 5);
1394 CL_Tei_PlasmaHit(pos, dir, count);
1395 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1396 CL_AllocDlight(NULL, &tempmatrix, 500, 0.3, 0.6, 1.0f, 2000, 9999, 0, 0, true, 1);
1400 Host_Error("CL_ParseTempEntity: bad type %d (hex %02X)", type, type);
1404 #define SHOWNET(x) if(cl_shownet.integer==2)Con_Printf("%3i:%s\n", msg_readcount-1, x);
1406 static qbyte cgamenetbuffer[65536];
1409 =====================
1410 CL_ParseServerMessage
1411 =====================
1413 int parsingerror = false;
1414 void CL_ParseServerMessage(void)
1417 int i, entitiesupdated;
1419 char *cmdlogname[32], *temp;
1420 int cmdindex, cmdcount = 0;
1422 if (cls.demorecording)
1423 CL_WriteDemoMessage ();
1425 cl.last_received_message = realtime;
1428 // if recording demos, copy the message out
1430 if (cl_shownet.integer == 1)
1431 Con_Printf("%f %i\n", realtime, net_message.cursize);
1432 else if (cl_shownet.integer == 2)
1433 Con_Print("------------------\n");
1435 cl.onground = false; // unless the server says otherwise
1437 // parse the message
1439 //MSG_BeginReading ();
1441 entitiesupdated = false;
1443 parsingerror = true;
1448 Host_Error ("CL_ParseServerMessage: Bad server message");
1450 cmd = MSG_ReadByte ();
1454 SHOWNET("END OF MESSAGE");
1455 break; // end of message
1458 cmdindex = cmdcount & 31;
1460 cmdlog[cmdindex] = cmd;
1462 // if the high bit of the command byte is set, it is a fast update
1465 // 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)
1467 cmdlogname[cmdindex] = temp;
1468 SHOWNET("fast update");
1469 if (cls.signon == SIGNONS - 1)
1471 // first update is the final signon stage
1472 cls.signon = SIGNONS;
1475 CL_ParseUpdate (cmd&127);
1479 SHOWNET(svc_strings[cmd]);
1480 cmdlogname[cmdindex] = svc_strings[cmd];
1481 if (!cmdlogname[cmdindex])
1483 // 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)
1485 cmdlogname[cmdindex] = temp;
1493 char description[32*64], temp[64];
1495 strcpy (description, "packet dump: ");
1499 count = cmdcount - i;
1503 snprintf (temp, sizeof (temp), "%3i:%s ", cmdlog[i], cmdlogname[i]);
1504 strlcat (description, temp, sizeof (description));
1509 description[strlen(description)-1] = '\n'; // replace the last space with a newline
1510 Con_Print(description);
1511 Host_Error ("CL_ParseServerMessage: Illegible server message\n");
1516 if (cls.signon < SIGNONS)
1517 Con_Print("<-- server to client keepalive\n");
1521 if (!entitiesupdated)
1523 // this is a new frame, we'll be seeing entities,
1524 // so prepare for entity updates
1525 CL_EntityUpdateSetup();
1526 entitiesupdated = true;
1528 cl.mtime[1] = cl.mtime[0];
1529 cl.mtime[0] = MSG_ReadFloat ();
1532 case svc_clientdata:
1533 i = MSG_ReadShort ();
1534 CL_ParseClientdata (i);
1538 i = MSG_ReadLong ();
1539 // hack for unmarked Nehahra movie demos which had a custom protocol
1540 if (i == PROTOCOL_QUAKE && cls.demoplayback && demo_nehahra.integer)
1541 i = PROTOCOL_NEHAHRAMOVIE;
1542 if (i != PROTOCOL_QUAKE && i != PROTOCOL_DARKPLACES1 && i != PROTOCOL_DARKPLACES2 && i != PROTOCOL_DARKPLACES3 && i != PROTOCOL_DARKPLACES4 && i != PROTOCOL_DARKPLACES5 && i != PROTOCOL_NEHAHRAMOVIE)
1543 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);
1547 case svc_disconnect:
1548 Host_EndGame ("Server disconnected\n");
1551 Con_Print(MSG_ReadString());
1554 case svc_centerprint:
1555 SCR_CenterPrint(MSG_ReadString ());
1559 Cbuf_AddText (MSG_ReadString ());
1566 case svc_serverinfo:
1567 CL_ParseServerInfo ();
1571 for (i=0 ; i<3 ; i++)
1572 cl.viewangles[i] = MSG_ReadAngle ();
1576 cl.viewentity = (unsigned short)MSG_ReadShort ();
1577 if (cl.viewentity >= MAX_EDICTS)
1578 Host_Error("svc_setview >= MAX_EDICTS\n");
1579 // LordHavoc: assume first setview recieved is the real player entity
1580 if (!cl.playerentity)
1581 cl.playerentity = cl.viewentity;
1584 case svc_lightstyle:
1585 i = MSG_ReadByte ();
1586 if (i >= MAX_LIGHTSTYLES)
1587 Host_Error ("svc_lightstyle >= MAX_LIGHTSTYLES");
1588 strlcpy (cl_lightstyle[i].map, MSG_ReadString(), sizeof (cl_lightstyle[i].map));
1589 cl_lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
1590 cl_lightstyle[i].length = strlen(cl_lightstyle[i].map);
1594 CL_ParseStartSoundPacket(false);
1598 CL_ParseStartSoundPacket(true);
1602 i = MSG_ReadShort();
1603 S_StopSound(i>>3, i&7);
1606 case svc_updatename:
1607 i = MSG_ReadByte ();
1608 if (i >= cl.maxclients)
1609 Host_Error ("CL_ParseServerMessage: svc_updatename >= cl.maxclients");
1610 strlcpy (cl.scores[i].name, MSG_ReadString (), sizeof (cl.scores[i].name));
1613 case svc_updatefrags:
1614 i = MSG_ReadByte ();
1615 if (i >= cl.maxclients)
1616 Host_Error ("CL_ParseServerMessage: svc_updatefrags >= cl.maxclients");
1617 cl.scores[i].frags = MSG_ReadShort ();
1620 case svc_updatecolors:
1621 i = MSG_ReadByte ();
1622 if (i >= cl.maxclients)
1623 Host_Error ("CL_ParseServerMessage: svc_updatecolors >= cl.maxclients");
1624 cl.scores[i].colors = MSG_ReadByte ();
1628 CL_ParseParticleEffect ();
1639 case svc_spawnbaseline:
1640 i = MSG_ReadShort ();
1641 if (i < 0 || i >= MAX_EDICTS)
1642 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i);
1643 CL_ParseBaseline (cl_entities + i, false);
1645 case svc_spawnbaseline2:
1646 i = MSG_ReadShort ();
1647 if (i < 0 || i >= MAX_EDICTS)
1648 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline2: invalid entity number %i", i);
1649 CL_ParseBaseline (cl_entities + i, true);
1651 case svc_spawnstatic:
1652 CL_ParseStatic (false);
1654 case svc_spawnstatic2:
1655 CL_ParseStatic (true);
1657 case svc_temp_entity:
1658 CL_ParseTempEntity ();
1662 cl.paused = MSG_ReadByte ();
1670 i = MSG_ReadByte ();
1671 if (i <= cls.signon)
1672 Host_Error ("Received signon %i when at %i", i, cls.signon);
1677 case svc_killedmonster:
1678 cl.stats[STAT_MONSTERS]++;
1681 case svc_foundsecret:
1682 cl.stats[STAT_SECRETS]++;
1685 case svc_updatestat:
1686 i = MSG_ReadByte ();
1687 if (i < 0 || i >= MAX_CL_STATS)
1688 Host_Error ("svc_updatestat: %i is invalid", i);
1689 cl.stats[i] = MSG_ReadLong ();
1692 case svc_spawnstaticsound:
1693 CL_ParseStaticSound (false);
1696 case svc_spawnstaticsound2:
1697 CL_ParseStaticSound (true);
1701 cl.cdtrack = MSG_ReadByte ();
1702 cl.looptrack = MSG_ReadByte ();
1703 if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )
1704 CDAudio_Play ((qbyte)cls.forcetrack, true);
1706 CDAudio_Play ((qbyte)cl.cdtrack, true);
1709 case svc_intermission:
1710 cl.intermission = 1;
1711 cl.completed_time = cl.time;
1715 cl.intermission = 2;
1716 cl.completed_time = cl.time;
1717 SCR_CenterPrint(MSG_ReadString ());
1721 cl.intermission = 3;
1722 cl.completed_time = cl.time;
1723 SCR_CenterPrint(MSG_ReadString ());
1726 case svc_sellscreen:
1727 Cmd_ExecuteString ("help", src_command);
1730 if (gamemode == GAME_TENEBRAE)
1732 // repeating particle effect
1745 SHOWLMP_decodehide();
1748 if (gamemode == GAME_TENEBRAE)
1758 SHOWLMP_decodeshow();
1761 R_SetSkyBox(MSG_ReadString());
1766 length = (int) ((unsigned short) MSG_ReadShort());
1767 for (i = 0;i < length;i++)
1768 cgamenetbuffer[i] = MSG_ReadByte();
1770 CL_CGVM_ParseNetwork(cgamenetbuffer, length);
1774 if (cls.signon == SIGNONS - 1)
1776 // first update is the final signon stage
1777 cls.signon = SIGNONS;
1780 CL_ReadEntityFrame();
1785 if (entitiesupdated)
1786 CL_EntityUpdateEnd();
1788 parsingerror = false;
1791 void CL_Parse_DumpPacket(void)
1795 Con_Print("Packet dump:\n");
1796 SZ_HexDumpToConsole(&net_message);
1797 parsingerror = false;
1800 void CL_Parse_Init(void)
1802 // LordHavoc: added demo_nehahra cvar
1803 cl_scores_mempool = Mem_AllocPool("client player info");
1804 Cvar_RegisterVariable (&demo_nehahra);
1805 if (gamemode == GAME_NEHAHRA)
1806 Cvar_SetValue("demo_nehahra", 1);
1807 Cvar_RegisterVariable(&developer_networkentities);