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], true);
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, 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)
480 Con_DPrintf("CL_ValidateState: colormap (%i) > cl.maxclients (%i)", s->colormap, cl.maxclients);
484 model = cl.model_precache[s->modelindex];
485 Mod_CheckLoaded(model);
486 if (model && s->frame >= model->numframes)
488 Con_DPrintf("CL_ValidateState: no such frame %i in \"%s\"\n", s->frame, model->name);
491 if (model && s->skin > 0 && s->skin >= model->numskins)
493 Con_DPrintf("CL_ValidateState: no such skin %i in \"%s\"\n", s->skin, model->name);
498 void CL_MoveLerpEntityStates(entity_t *ent)
500 float odelta[3], adelta[3];
501 VectorSubtract(ent->state_current.origin, ent->persistent.neworigin, odelta);
502 VectorSubtract(ent->state_current.angles, ent->persistent.newangles, adelta);
503 if (!ent->state_previous.active || cls.timedemo || DotProduct(odelta, odelta) > 1000*1000 || cl_nolerp.integer)
505 // we definitely shouldn't lerp
506 ent->persistent.lerpdeltatime = 0;
507 ent->persistent.lerpstarttime = cl.mtime[1];
508 VectorCopy(ent->state_current.origin, ent->persistent.oldorigin);
509 VectorCopy(ent->state_current.angles, ent->persistent.oldangles);
510 VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
511 VectorCopy(ent->state_current.angles, ent->persistent.newangles);
513 else if (ent->state_current.flags & RENDER_STEP)
515 // monster interpolation
516 if (DotProduct(odelta, odelta) + DotProduct(adelta, adelta) > 0.01)
518 ent->persistent.lerpdeltatime = bound(0, cl.mtime[1] - ent->persistent.lerpstarttime, 0.1);
519 ent->persistent.lerpstarttime = cl.mtime[1];
520 VectorCopy(ent->persistent.neworigin, ent->persistent.oldorigin);
521 VectorCopy(ent->persistent.newangles, ent->persistent.oldangles);
522 VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
523 VectorCopy(ent->state_current.angles, ent->persistent.newangles);
529 ent->persistent.lerpstarttime = cl.mtime[1];
530 // no lerp if it's singleplayer
532 ent->persistent.lerpdeltatime = 0;
534 ent->persistent.lerpdeltatime = cl.mtime[0] - cl.mtime[1];
535 VectorCopy(ent->persistent.neworigin, ent->persistent.oldorigin);
536 VectorCopy(ent->persistent.newangles, ent->persistent.oldangles);
537 VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
538 VectorCopy(ent->state_current.angles, ent->persistent.newangles);
546 Parse an entity update message from the server
547 If an entities model or origin changes from frame to frame, it must be
548 relinked. Other attributes can change without relinking.
551 void CL_ParseUpdate (int bits)
557 if (bits & U_MOREBITS)
558 bits |= (MSG_ReadByte()<<8);
559 if ((bits & U_EXTEND1) && cl.protocol != PROTOCOL_NEHAHRAMOVIE)
561 bits |= MSG_ReadByte() << 16;
562 if (bits & U_EXTEND2)
563 bits |= MSG_ReadByte() << 24;
566 if (bits & U_LONGENTITY)
567 num = (unsigned) MSG_ReadShort ();
569 num = (unsigned) MSG_ReadByte ();
571 if (num >= MAX_EDICTS)
572 Host_Error("CL_ParseUpdate: entity number (%i) >= MAX_EDICTS (%i)\n", num, MAX_EDICTS);
574 Host_Error("CL_ParseUpdate: invalid entity number (%i)\n", num);
576 ent = cl_entities + num;
578 // note: this inherits the 'active' state of the baseline chosen
579 // (state_baseline is always active, state_current may not be active if
580 // the entity was missing in the last frame)
582 new = ent->state_current;
585 new = ent->state_baseline;
590 new.time = cl.mtime[0];
592 if (bits & U_MODEL) new.modelindex = (new.modelindex & 0xFF00) | MSG_ReadByte();
593 if (bits & U_FRAME) new.frame = (new.frame & 0xFF00) | MSG_ReadByte();
594 if (bits & U_COLORMAP) new.colormap = MSG_ReadByte();
595 if (bits & U_SKIN) new.skin = MSG_ReadByte();
596 if (bits & U_EFFECTS) new.effects = (new.effects & 0xFF00) | MSG_ReadByte();
597 if (bits & U_ORIGIN1) new.origin[0] = MSG_ReadCoord();
598 if (bits & U_ANGLE1) new.angles[0] = MSG_ReadAngle();
599 if (bits & U_ORIGIN2) new.origin[1] = MSG_ReadCoord();
600 if (bits & U_ANGLE2) new.angles[1] = MSG_ReadAngle();
601 if (bits & U_ORIGIN3) new.origin[2] = MSG_ReadCoord();
602 if (bits & U_ANGLE3) new.angles[2] = MSG_ReadAngle();
603 if (bits & U_STEP) new.flags |= RENDER_STEP;
604 if (bits & U_ALPHA) new.alpha = MSG_ReadByte();
605 if (bits & U_SCALE) new.scale = MSG_ReadByte();
606 if (bits & U_EFFECTS2) new.effects = (new.effects & 0x00FF) | (MSG_ReadByte() << 8);
607 if (bits & U_GLOWSIZE) new.glowsize = MSG_ReadByte();
608 if (bits & U_GLOWCOLOR) new.glowcolor = MSG_ReadByte();
609 // apparently the dpcrush demo uses this (unintended, and it uses white anyway)
610 if (bits & U_COLORMOD) MSG_ReadByte();
611 if (bits & U_GLOWTRAIL) new.flags |= RENDER_GLOWTRAIL;
612 if (bits & U_FRAME2) new.frame = (new.frame & 0x00FF) | (MSG_ReadByte() << 8);
613 if (bits & U_MODEL2) new.modelindex = (new.modelindex & 0x00FF) | (MSG_ReadByte() << 8);
614 if (bits & U_VIEWMODEL) new.flags |= RENDER_VIEWMODEL;
615 if (bits & U_EXTERIORMODEL) new.flags |= RENDER_EXTERIORMODEL;
617 // LordHavoc: to allow playback of the Nehahra movie
618 if (cl.protocol == PROTOCOL_NEHAHRAMOVIE && (bits & U_EXTEND1))
620 // LordHavoc: evil format
621 int i = MSG_ReadFloat();
622 int j = MSG_ReadFloat() * 255.0f;
627 new.effects |= EF_FULLBRIGHT;
631 else if (j == 0 || j >= 255)
638 CL_ValidateState(&new);
640 ent->state_previous = ent->state_current;
641 ent->state_current = new;
642 if (ent->state_current.active)
644 CL_MoveLerpEntityStates(ent);
645 cl_entities_active[ent->state_current.number] = true;
646 // mark as visible (no kill this frame)
647 entlife[ent->state_current.number] = 2;
651 static entity_frame_t entityframe;
652 extern mempool_t *cl_entities_mempool;
653 void CL_ReadEntityFrame(void)
655 if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
659 EntityFrame_Read(&cl.entitydatabase);
660 EntityFrame_FetchFrame(&cl.entitydatabase, EntityFrame_MostRecentlyRecievedFrameNum(&cl.entitydatabase), &entityframe);
661 for (i = 0;i < entityframe.numentities;i++)
664 ent = &cl_entities[entityframe.entitydata[i].number];
665 ent->state_previous = ent->state_current;
666 ent->state_current = entityframe.entitydata[i];
667 CL_MoveLerpEntityStates(ent);
668 // the entity lives again...
669 entlife[ent->state_current.number] = 2;
670 cl_entities_active[ent->state_current.number] = true;
675 if (!cl.entitydatabase4)
676 cl.entitydatabase4 = EntityFrame4_AllocDatabase(cl_entities_mempool);
677 EntityFrame4_CL_ReadFrame(cl.entitydatabase4);
681 void CL_EntityUpdateSetup(void)
685 void CL_EntityUpdateEnd(void)
687 if (cl.protocol == PROTOCOL_QUAKE || cl.protocol == PROTOCOL_NEHAHRAMOVIE || cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
690 // disable entities that disappeared this frame
691 for (i = 1;i < MAX_EDICTS;i++)
693 // clear only the entities that were active last frame but not this
694 // frame, don't waste time clearing all entities (which would cause
700 cl_entities[i].state_previous.active = cl_entities[i].state_current.active = 0;
711 void CL_ParseBaseline (entity_t *ent, int large)
715 ClearStateToDefault(&ent->state_baseline);
716 ent->state_baseline.active = true;
719 ent->state_baseline.modelindex = (unsigned short) MSG_ReadShort ();
720 ent->state_baseline.frame = (unsigned short) MSG_ReadShort ();
724 ent->state_baseline.modelindex = MSG_ReadByte ();
725 ent->state_baseline.frame = MSG_ReadByte ();
727 ent->state_baseline.colormap = MSG_ReadByte();
728 ent->state_baseline.skin = MSG_ReadByte();
729 for (i = 0;i < 3;i++)
731 ent->state_baseline.origin[i] = MSG_ReadCoord ();
732 ent->state_baseline.angles[i] = MSG_ReadAngle ();
734 CL_ValidateState(&ent->state_baseline);
735 ent->state_previous = ent->state_current = ent->state_baseline;
743 Server information pertaining to this client only
746 void CL_ParseClientdata (int bits)
751 if (bits & SU_EXTEND1)
752 bits |= (MSG_ReadByte() << 16);
753 if (bits & SU_EXTEND2)
754 bits |= (MSG_ReadByte() << 24);
756 if (bits & SU_VIEWHEIGHT)
757 cl.viewheight = MSG_ReadChar ();
759 cl.viewheight = DEFAULT_VIEWHEIGHT;
761 if (bits & SU_IDEALPITCH)
762 cl.idealpitch = MSG_ReadChar ();
766 VectorCopy (cl.mvelocity[0], cl.mvelocity[1]);
767 if (cl.protocol == PROTOCOL_DARKPLACES5)
769 for (i = 0;i < 3;i++)
771 if (bits & (SU_PUNCH1<<i) )
772 cl.punchangle[i] = MSG_ReadPreciseAngle();
774 cl.punchangle[i] = 0;
775 if (bits & (SU_PUNCHVEC1<<i))
776 cl.punchvector[i] = MSG_ReadFloat();
778 cl.punchvector[i] = 0;
779 if (bits & (SU_VELOCITY1<<i) )
780 cl.mvelocity[0][i] = MSG_ReadFloat();
782 cl.mvelocity[0][i] = 0;
787 for (i = 0;i < 3;i++)
789 if (bits & (SU_PUNCH1<<i) )
791 if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
792 cl.punchangle[i] = MSG_ReadPreciseAngle();
794 cl.punchangle[i] = MSG_ReadChar();
797 cl.punchangle[i] = 0;
798 if (bits & (SU_PUNCHVEC1<<i))
799 cl.punchvector[i] = MSG_ReadCoord();
801 cl.punchvector[i] = 0;
802 if (bits & (SU_VELOCITY1<<i) )
803 cl.mvelocity[0][i] = MSG_ReadChar()*16;
805 cl.mvelocity[0][i] = 0;
812 for (j=0 ; j<32 ; j++)
813 if ( (i & (1<<j)) && !(cl.items & (1<<j)))
814 cl.item_gettime[j] = cl.time;
818 cl.onground = (bits & SU_ONGROUND) != 0;
819 cl.inwater = (bits & SU_INWATER) != 0;
821 cl.stats[STAT_WEAPONFRAME] = (bits & SU_WEAPONFRAME) ? MSG_ReadByte() : 0;
822 cl.stats[STAT_ARMOR] = (bits & SU_ARMOR) ? MSG_ReadByte() : 0;
823 cl.stats[STAT_WEAPON] = (bits & SU_WEAPON) ? MSG_ReadByte() : 0;
824 cl.stats[STAT_HEALTH] = MSG_ReadShort();
825 cl.stats[STAT_AMMO] = MSG_ReadByte();
827 cl.stats[STAT_SHELLS] = MSG_ReadByte();
828 cl.stats[STAT_NAILS] = MSG_ReadByte();
829 cl.stats[STAT_ROCKETS] = MSG_ReadByte();
830 cl.stats[STAT_CELLS] = MSG_ReadByte();
834 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
836 // GAME_NEXUIZ hud needs weapon change time
837 // GAME_NEXUIZ uses a bit number as it's STAT_ACTIVEWEAPON, not a bitfield
839 if (cl.stats[STAT_ACTIVEWEAPON] != i)
840 cl.weapontime = cl.time;
841 cl.stats[STAT_ACTIVEWEAPON] = i;
843 cl.viewzoomold = cl.viewzoomnew; // for interpolation
844 if (bits & SU_VIEWZOOM)
849 cl.viewzoomnew = (float) i * (1.0f / 255.0f);
857 =====================
859 =====================
861 void CL_ParseStatic (int large)
865 if (cl_num_static_entities >= cl_max_static_entities)
866 Host_Error ("Too many static entities");
867 ent = &cl_static_entities[cl_num_static_entities++];
868 CL_ParseBaseline (ent, large);
870 // copy it to the current state
871 ent->render.model = cl.model_precache[ent->state_baseline.modelindex];
872 ent->render.frame = ent->render.frame1 = ent->render.frame2 = ent->state_baseline.frame;
873 ent->render.framelerp = 0;
874 // make torchs play out of sync
875 ent->render.frame1time = ent->render.frame2time = lhrandom(-10, -1);
876 ent->render.colormap = -1; // no special coloring
877 ent->render.skinnum = ent->state_baseline.skin;
878 ent->render.effects = ent->state_baseline.effects;
879 ent->render.alpha = 1;
880 //ent->render.scale = 1;
882 //VectorCopy (ent->state_baseline.origin, ent->render.origin);
883 //VectorCopy (ent->state_baseline.angles, ent->render.angles);
885 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);
886 Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix);
887 CL_BoundingBoxForEntity(&ent->render);
889 // This is definitely cheating...
890 if (ent->render.model == NULL)
891 cl_num_static_entities--;
899 void CL_ParseStaticSound (int large)
902 int sound_num, vol, atten;
906 sound_num = (unsigned short) MSG_ReadShort ();
908 sound_num = MSG_ReadByte ();
909 vol = MSG_ReadByte ();
910 atten = MSG_ReadByte ();
912 S_StaticSound (cl.sound_precache[sound_num], org, vol, atten);
915 void CL_ParseEffect (void)
918 int modelindex, startframe, framecount, framerate;
921 modelindex = MSG_ReadByte ();
922 startframe = MSG_ReadByte ();
923 framecount = MSG_ReadByte ();
924 framerate = MSG_ReadByte ();
926 CL_Effect(org, modelindex, startframe, framecount, framerate);
929 void CL_ParseEffect2 (void)
932 int modelindex, startframe, framecount, framerate;
935 modelindex = MSG_ReadShort ();
936 startframe = MSG_ReadShort ();
937 framecount = MSG_ReadByte ();
938 framerate = MSG_ReadByte ();
940 CL_Effect(org, modelindex, startframe, framecount, framerate);
943 model_t *cl_model_bolt = NULL;
944 model_t *cl_model_bolt2 = NULL;
945 model_t *cl_model_bolt3 = NULL;
946 model_t *cl_model_beam = NULL;
948 sfx_t *cl_sfx_wizhit;
949 sfx_t *cl_sfx_knighthit;
954 sfx_t *cl_sfx_r_exp3;
961 void CL_InitTEnts (void)
963 cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav", false, true);
964 cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav", false, true);
965 cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav", false, true);
966 cl_sfx_ric1 = S_PrecacheSound ("weapons/ric1.wav", false, true);
967 cl_sfx_ric2 = S_PrecacheSound ("weapons/ric2.wav", false, true);
968 cl_sfx_ric3 = S_PrecacheSound ("weapons/ric3.wav", false, true);
969 cl_sfx_r_exp3 = S_PrecacheSound ("weapons/r_exp3.wav", false, true);
972 void CL_ParseBeam (model_t *m, int lightning)
978 ent = MSG_ReadShort ();
979 MSG_ReadVector(start);
982 if (ent >= MAX_EDICTS)
984 Con_Printf("CL_ParseBeam: invalid entity number %i\n", ent);
988 // override any beam with the same entity
989 for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
991 if (b->entity == ent)
994 b->lightning = lightning;
995 b->relativestartvalid = (ent && cl_entities[ent].state_current.active) ? 2 : 0;
997 b->endtime = cl.time + 0.2;
998 VectorCopy (start, b->start);
999 VectorCopy (end, b->end);
1005 for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
1007 if (!b->model || b->endtime < cl.time)
1010 b->lightning = lightning;
1011 b->relativestartvalid = (ent && cl_entities[ent].state_current.active) ? 2 : 0;
1013 b->endtime = cl.time + 0.2;
1014 VectorCopy (start, b->start);
1015 VectorCopy (end, b->end);
1019 Con_Print("beam list overflow!\n");
1022 void CL_ParseTempEntity(void)
1030 int colorStart, colorLength, count;
1031 float velspeed, radius;
1033 matrix4x4_t tempmatrix;
1035 type = MSG_ReadByte();
1039 // spike hitting wall
1040 MSG_ReadVector(pos);
1041 CL_FindNonSolidLocation(pos, pos, 4);
1042 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1043 CL_AllocDlight(NULL, &tempmatrix, 100, 0.12f, 0.50f, 0.12f, 500, 0.2, 0, 0, false, 1);
1044 CL_RunParticleEffect(pos, vec3_origin, 20, 30);
1045 S_StartSound(-1, 0, cl_sfx_wizhit, pos, 1, 1);
1048 case TE_KNIGHTSPIKE:
1049 // spike hitting wall
1050 MSG_ReadVector(pos);
1051 CL_FindNonSolidLocation(pos, pos, 4);
1052 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1053 CL_AllocDlight(NULL, &tempmatrix, 100, 0.50f, 0.30f, 0.10f, 500, 0.2, 0, 0, false, 1);
1054 CL_RunParticleEffect(pos, vec3_origin, 226, 20);
1055 S_StartSound(-1, 0, cl_sfx_knighthit, pos, 1, 1);
1059 // spike hitting wall
1060 MSG_ReadVector(pos);
1061 CL_FindNonSolidLocation(pos, pos, 4);
1062 // LordHavoc: changed to spark shower
1063 CL_SparkShower(pos, vec3_origin, 15);
1065 S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1070 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1072 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1074 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1078 // quad spike hitting wall
1079 MSG_ReadVector(pos);
1080 CL_FindNonSolidLocation(pos, pos, 4);
1081 // LordHavoc: changed to spark shower
1082 CL_SparkShower(pos, vec3_origin, 15);
1083 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1084 CL_AllocDlight(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, 0, true, 1);
1085 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1087 S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1092 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1094 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1096 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1100 // super spike hitting wall
1101 MSG_ReadVector(pos);
1102 CL_FindNonSolidLocation(pos, pos, 4);
1103 // LordHavoc: changed to dust shower
1104 CL_SparkShower(pos, vec3_origin, 30);
1106 S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1111 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1113 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1115 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1118 case TE_SUPERSPIKEQUAD:
1119 // quad super spike hitting wall
1120 MSG_ReadVector(pos);
1121 CL_FindNonSolidLocation(pos, pos, 4);
1122 // LordHavoc: changed to dust shower
1123 CL_SparkShower(pos, vec3_origin, 30);
1124 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1125 CL_AllocDlight(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, 0, true, 1);
1127 S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1132 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1134 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1136 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1139 // LordHavoc: added for improved blood splatters
1142 MSG_ReadVector(pos);
1143 CL_FindNonSolidLocation(pos, pos, 4);
1144 dir[0] = MSG_ReadChar();
1145 dir[1] = MSG_ReadChar();
1146 dir[2] = MSG_ReadChar();
1147 count = MSG_ReadByte();
1148 CL_BloodPuff(pos, dir, count);
1152 MSG_ReadVector(pos);
1153 CL_FindNonSolidLocation(pos, pos, 4);
1154 dir[0] = MSG_ReadChar();
1155 dir[1] = MSG_ReadChar();
1156 dir[2] = MSG_ReadChar();
1157 count = MSG_ReadByte();
1158 CL_SparkShower(pos, dir, count);
1161 MSG_ReadVector(pos);
1162 CL_FindNonSolidLocation(pos, pos, 4);
1163 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1164 CL_AllocDlight(NULL, &tempmatrix, 200, 1, 1, 1, 1000, 0.2, 0, 0, true, 1);
1167 // LordHavoc: added for improved gore
1168 case TE_BLOODSHOWER:
1170 MSG_ReadVector(pos); // mins
1171 MSG_ReadVector(pos2); // maxs
1172 velspeed = MSG_ReadCoord(); // speed
1173 count = MSG_ReadShort(); // number of particles
1174 CL_BloodShower(pos, pos2, velspeed, count);
1176 case TE_PARTICLECUBE:
1177 // general purpose particle effect
1178 MSG_ReadVector(pos); // mins
1179 MSG_ReadVector(pos2); // maxs
1180 MSG_ReadVector(dir); // dir
1181 count = MSG_ReadShort(); // number of particles
1182 colorStart = MSG_ReadByte(); // color
1183 colorLength = MSG_ReadByte(); // gravity (1 or 0)
1184 velspeed = MSG_ReadCoord(); // randomvel
1185 CL_ParticleCube(pos, pos2, dir, count, colorStart, colorLength, velspeed);
1188 case TE_PARTICLERAIN:
1189 // general purpose particle effect
1190 MSG_ReadVector(pos); // mins
1191 MSG_ReadVector(pos2); // maxs
1192 MSG_ReadVector(dir); // dir
1193 count = MSG_ReadShort(); // number of particles
1194 colorStart = MSG_ReadByte(); // color
1195 CL_ParticleRain(pos, pos2, dir, count, colorStart, 0);
1198 case TE_PARTICLESNOW:
1199 // general purpose particle effect
1200 MSG_ReadVector(pos); // mins
1201 MSG_ReadVector(pos2); // maxs
1202 MSG_ReadVector(dir); // dir
1203 count = MSG_ReadShort(); // number of particles
1204 colorStart = MSG_ReadByte(); // color
1205 CL_ParticleRain(pos, pos2, dir, count, colorStart, 1);
1209 // bullet hitting wall
1210 MSG_ReadVector(pos);
1211 CL_FindNonSolidLocation(pos, pos, 4);
1212 // LordHavoc: changed to dust shower
1213 CL_SparkShower(pos, vec3_origin, 15);
1216 case TE_GUNSHOTQUAD:
1217 // quad bullet hitting wall
1218 MSG_ReadVector(pos);
1219 CL_FindNonSolidLocation(pos, pos, 4);
1220 CL_SparkShower(pos, vec3_origin, 15);
1221 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1222 CL_AllocDlight(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, 0, true, 1);
1227 MSG_ReadVector(pos);
1228 CL_FindNonSolidLocation(pos, pos, 10);
1229 CL_ParticleExplosion(pos);
1230 // LordHavoc: boosted color from 1.0, 0.8, 0.4 to 1.25, 1.0, 0.5
1231 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1232 CL_AllocDlight(NULL, &tempmatrix, 350, 4.0f, 2.0f, 0.50f, 700, 0.5, 0, 0, true, 1);
1233 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1236 case TE_EXPLOSIONQUAD:
1237 // quad rocket explosion
1238 MSG_ReadVector(pos);
1239 CL_FindNonSolidLocation(pos, pos, 10);
1240 CL_ParticleExplosion(pos);
1241 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1242 CL_AllocDlight(NULL, &tempmatrix, 350, 2.5f, 2.0f, 4.0f, 700, 0.5, 0, 0, true, 1);
1243 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1247 // Nehahra movie colored lighting explosion
1248 MSG_ReadVector(pos);
1249 CL_FindNonSolidLocation(pos, pos, 10);
1250 CL_ParticleExplosion(pos);
1251 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1252 color[0] = MSG_ReadCoord() * (2.0f / 1.0f);
1253 color[1] = MSG_ReadCoord() * (2.0f / 1.0f);
1254 color[2] = MSG_ReadCoord() * (2.0f / 1.0f);
1255 CL_AllocDlight(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, 0, true, 1);
1256 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1259 case TE_EXPLOSIONRGB:
1260 // colored lighting explosion
1261 MSG_ReadVector(pos);
1262 CL_FindNonSolidLocation(pos, pos, 10);
1263 CL_ParticleExplosion(pos);
1264 color[0] = MSG_ReadByte() * (2.0f / 255.0f);
1265 color[1] = MSG_ReadByte() * (2.0f / 255.0f);
1266 color[2] = MSG_ReadByte() * (2.0f / 255.0f);
1267 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1268 CL_AllocDlight(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, 0, true, 1);
1269 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1272 case TE_TAREXPLOSION:
1273 // tarbaby explosion
1274 MSG_ReadVector(pos);
1275 CL_FindNonSolidLocation(pos, pos, 10);
1276 CL_BlobExplosion(pos);
1278 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1279 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1280 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1281 CL_AllocDlight(NULL, &tempmatrix, 600, 1.6f, 0.8f, 2.0f, 1200, 0.5, 0, 0, true, 1);
1285 MSG_ReadVector(pos);
1286 CL_FindNonSolidLocation(pos, pos, 10);
1287 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1288 CL_AllocDlight(NULL, &tempmatrix, 200, 2, 2, 2, 1000, 0.2, 0, 0, true, 1);
1291 case TE_CUSTOMFLASH:
1292 MSG_ReadVector(pos);
1293 CL_FindNonSolidLocation(pos, pos, 4);
1294 radius = MSG_ReadByte() * 8;
1295 velspeed = (MSG_ReadByte() + 1) * (1.0 / 256.0);
1296 color[0] = MSG_ReadByte() * (2.0f / 255.0f);
1297 color[1] = MSG_ReadByte() * (2.0f / 255.0f);
1298 color[2] = MSG_ReadByte() * (2.0f / 255.0f);
1299 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1300 CL_AllocDlight(NULL, &tempmatrix, radius, color[0], color[1], color[2], radius / velspeed, velspeed, 0, 0, true, 1);
1304 MSG_ReadVector(pos);
1305 MSG_ReadVector(dir);
1306 count = MSG_ReadByte();
1307 CL_Flames(pos, dir, count);
1313 cl_model_bolt = Mod_ForName("progs/bolt.mdl", false, false, false);
1314 CL_ParseBeam(cl_model_bolt, true);
1319 if (!cl_model_bolt2)
1320 cl_model_bolt2 = Mod_ForName("progs/bolt2.mdl", false, false, false);
1321 CL_ParseBeam(cl_model_bolt2, true);
1326 if (!cl_model_bolt3)
1327 cl_model_bolt3 = Mod_ForName("progs/bolt3.mdl", true, false, false);
1328 CL_ParseBeam(cl_model_bolt3, false);
1333 // grappling hook beam
1335 cl_model_beam = Mod_ForName("progs/beam.mdl", true, false, false);
1336 CL_ParseBeam(cl_model_beam, false);
1340 // LordHavoc: for compatibility with the Nehahra movie...
1341 case TE_LIGHTNING4NEH:
1342 CL_ParseBeam(Mod_ForName(MSG_ReadString(), true, false, false), false);
1346 MSG_ReadVector(pos);
1351 MSG_ReadVector(pos);
1352 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1353 CL_AllocDlight(NULL, &tempmatrix, 500, 1.0f, 1.0f, 1.0f, 1500, 99.0f, 0, 0, true, 1);
1354 // CL_TeleportSplash(pos);
1358 // color mapped explosion
1359 MSG_ReadVector(pos);
1360 CL_FindNonSolidLocation(pos, pos, 10);
1361 colorStart = MSG_ReadByte();
1362 colorLength = MSG_ReadByte();
1363 CL_ParticleExplosion2(pos, colorStart, colorLength);
1364 tempcolor = (qbyte *)&palette_complete[(rand()%colorLength) + colorStart];
1365 color[0] = tempcolor[0] * (2.0f / 255.0f);
1366 color[1] = tempcolor[1] * (2.0f / 255.0f);
1367 color[2] = tempcolor[2] * (2.0f / 255.0f);
1368 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1369 CL_AllocDlight(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, 0, true, 1);
1370 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1374 MSG_ReadVector(pos);
1375 MSG_ReadVector(pos2);
1376 MSG_ReadVector(dir);
1377 CL_BeamParticle(pos, pos2, 12, 1, 0.3, 0.1, 1, 1);
1378 CL_BeamParticle(pos, pos2, 5, 1, 0.9, 0.3, 1, 1);
1382 MSG_ReadVector(pos);
1383 MSG_ReadVector(dir);
1384 count = MSG_ReadByte();
1385 CL_FindNonSolidLocation(pos, pos, 4);
1386 CL_Tei_Smoke(pos, dir, count);
1389 case TE_TEI_BIGEXPLOSION:
1390 MSG_ReadVector(pos);
1391 CL_FindNonSolidLocation(pos, pos, 10);
1392 CL_ParticleExplosion(pos);
1393 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1394 CL_AllocDlight(NULL, &tempmatrix, 500, 2.5f, 2.0f, 1.0f, 500, 9999, 0, 0, true, 1);
1395 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1398 case TE_TEI_PLASMAHIT:
1399 MSG_ReadVector(pos);
1400 MSG_ReadVector(dir);
1401 count = MSG_ReadByte();
1402 CL_FindNonSolidLocation(pos, pos, 5);
1403 CL_Tei_PlasmaHit(pos, dir, count);
1404 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1405 CL_AllocDlight(NULL, &tempmatrix, 500, 0.6, 1.2, 2.0f, 2000, 9999, 0, 0, true, 1);
1409 Host_Error("CL_ParseTempEntity: bad type %d (hex %02X)", type, type);
1413 #define SHOWNET(x) if(cl_shownet.integer==2)Con_Printf("%3i:%s\n", msg_readcount-1, x);
1415 static qbyte cgamenetbuffer[65536];
1418 =====================
1419 CL_ParseServerMessage
1420 =====================
1422 int parsingerror = false;
1423 void CL_ParseServerMessage(void)
1426 int i, entitiesupdated;
1428 char *cmdlogname[32], *temp;
1429 int cmdindex, cmdcount = 0;
1431 if (cls.demorecording)
1432 CL_WriteDemoMessage ();
1434 cl.last_received_message = realtime;
1437 // if recording demos, copy the message out
1439 if (cl_shownet.integer == 1)
1440 Con_Printf("%f %i\n", realtime, net_message.cursize);
1441 else if (cl_shownet.integer == 2)
1442 Con_Print("------------------\n");
1444 cl.onground = false; // unless the server says otherwise
1446 // parse the message
1448 //MSG_BeginReading ();
1450 entitiesupdated = false;
1452 parsingerror = true;
1457 Host_Error ("CL_ParseServerMessage: Bad server message");
1459 cmd = MSG_ReadByte ();
1463 SHOWNET("END OF MESSAGE");
1464 break; // end of message
1467 cmdindex = cmdcount & 31;
1469 cmdlog[cmdindex] = cmd;
1471 // if the high bit of the command byte is set, it is a fast update
1474 // 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)
1476 cmdlogname[cmdindex] = temp;
1477 SHOWNET("fast update");
1478 if (cls.signon == SIGNONS - 1)
1480 // first update is the final signon stage
1481 cls.signon = SIGNONS;
1484 CL_ParseUpdate (cmd&127);
1488 SHOWNET(svc_strings[cmd]);
1489 cmdlogname[cmdindex] = svc_strings[cmd];
1490 if (!cmdlogname[cmdindex])
1492 // 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)
1494 cmdlogname[cmdindex] = temp;
1502 char description[32*64], temp[64];
1504 strcpy (description, "packet dump: ");
1508 count = cmdcount - i;
1512 snprintf (temp, sizeof (temp), "%3i:%s ", cmdlog[i], cmdlogname[i]);
1513 strlcat (description, temp, sizeof (description));
1518 description[strlen(description)-1] = '\n'; // replace the last space with a newline
1519 Con_Print(description);
1520 Host_Error ("CL_ParseServerMessage: Illegible server message\n");
1525 if (cls.signon < SIGNONS)
1526 Con_Print("<-- server to client keepalive\n");
1530 if (!entitiesupdated)
1532 // this is a new frame, we'll be seeing entities,
1533 // so prepare for entity updates
1534 CL_EntityUpdateSetup();
1535 entitiesupdated = true;
1537 cl.mtime[1] = cl.mtime[0];
1538 cl.mtime[0] = MSG_ReadFloat ();
1541 case svc_clientdata:
1542 i = MSG_ReadShort ();
1543 CL_ParseClientdata (i);
1547 i = MSG_ReadLong ();
1548 // hack for unmarked Nehahra movie demos which had a custom protocol
1549 if (i == PROTOCOL_QUAKE && cls.demoplayback && demo_nehahra.integer)
1550 i = PROTOCOL_NEHAHRAMOVIE;
1551 if (i != PROTOCOL_QUAKE && i != PROTOCOL_DARKPLACES1 && i != PROTOCOL_DARKPLACES2 && i != PROTOCOL_DARKPLACES3 && i != PROTOCOL_DARKPLACES4 && i != PROTOCOL_DARKPLACES5 && i != PROTOCOL_NEHAHRAMOVIE)
1552 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);
1556 case svc_disconnect:
1557 Con_Printf ("Server disconnected\n");
1558 if (cls.demonum != -1)
1565 Con_Print(MSG_ReadString());
1568 case svc_centerprint:
1569 SCR_CenterPrint(MSG_ReadString ());
1573 Cbuf_AddText (MSG_ReadString ());
1580 case svc_serverinfo:
1581 CL_ParseServerInfo ();
1585 for (i=0 ; i<3 ; i++)
1586 cl.viewangles[i] = MSG_ReadAngle ();
1590 cl.viewentity = (unsigned short)MSG_ReadShort ();
1591 if (cl.viewentity >= MAX_EDICTS)
1592 Host_Error("svc_setview >= MAX_EDICTS\n");
1593 // LordHavoc: assume first setview recieved is the real player entity
1594 if (!cl.playerentity)
1595 cl.playerentity = cl.viewentity;
1598 case svc_lightstyle:
1599 i = MSG_ReadByte ();
1600 if (i >= MAX_LIGHTSTYLES)
1601 Host_Error ("svc_lightstyle >= MAX_LIGHTSTYLES");
1602 strlcpy (cl_lightstyle[i].map, MSG_ReadString(), sizeof (cl_lightstyle[i].map));
1603 cl_lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
1604 cl_lightstyle[i].length = strlen(cl_lightstyle[i].map);
1608 CL_ParseStartSoundPacket(false);
1612 CL_ParseStartSoundPacket(true);
1616 i = MSG_ReadShort();
1617 S_StopSound(i>>3, i&7);
1620 case svc_updatename:
1621 i = MSG_ReadByte ();
1622 if (i >= cl.maxclients)
1623 Host_Error ("CL_ParseServerMessage: svc_updatename >= cl.maxclients");
1624 strlcpy (cl.scores[i].name, MSG_ReadString (), sizeof (cl.scores[i].name));
1627 case svc_updatefrags:
1628 i = MSG_ReadByte ();
1629 if (i >= cl.maxclients)
1630 Host_Error ("CL_ParseServerMessage: svc_updatefrags >= cl.maxclients");
1631 cl.scores[i].frags = MSG_ReadShort ();
1634 case svc_updatecolors:
1635 i = MSG_ReadByte ();
1636 if (i >= cl.maxclients)
1637 Host_Error ("CL_ParseServerMessage: svc_updatecolors >= cl.maxclients");
1638 cl.scores[i].colors = MSG_ReadByte ();
1642 CL_ParseParticleEffect ();
1653 case svc_spawnbaseline:
1654 i = MSG_ReadShort ();
1655 if (i < 0 || i >= MAX_EDICTS)
1656 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i);
1657 CL_ParseBaseline (cl_entities + i, false);
1659 case svc_spawnbaseline2:
1660 i = MSG_ReadShort ();
1661 if (i < 0 || i >= MAX_EDICTS)
1662 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline2: invalid entity number %i", i);
1663 CL_ParseBaseline (cl_entities + i, true);
1665 case svc_spawnstatic:
1666 CL_ParseStatic (false);
1668 case svc_spawnstatic2:
1669 CL_ParseStatic (true);
1671 case svc_temp_entity:
1672 CL_ParseTempEntity ();
1676 cl.paused = MSG_ReadByte ();
1680 S_PauseGameSounds ();
1685 S_ResumeGameSounds ();
1690 i = MSG_ReadByte ();
1691 if (i <= cls.signon)
1692 Host_Error ("Received signon %i when at %i", i, cls.signon);
1697 case svc_killedmonster:
1698 cl.stats[STAT_MONSTERS]++;
1701 case svc_foundsecret:
1702 cl.stats[STAT_SECRETS]++;
1705 case svc_updatestat:
1706 i = MSG_ReadByte ();
1707 if (i < 0 || i >= MAX_CL_STATS)
1708 Host_Error ("svc_updatestat: %i is invalid", i);
1709 cl.stats[i] = MSG_ReadLong ();
1712 case svc_spawnstaticsound:
1713 CL_ParseStaticSound (false);
1716 case svc_spawnstaticsound2:
1717 CL_ParseStaticSound (true);
1721 cl.cdtrack = MSG_ReadByte ();
1722 cl.looptrack = MSG_ReadByte ();
1723 if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )
1724 CDAudio_Play ((qbyte)cls.forcetrack, true);
1726 CDAudio_Play ((qbyte)cl.cdtrack, true);
1729 case svc_intermission:
1730 cl.intermission = 1;
1731 cl.completed_time = cl.time;
1735 cl.intermission = 2;
1736 cl.completed_time = cl.time;
1737 SCR_CenterPrint(MSG_ReadString ());
1741 cl.intermission = 3;
1742 cl.completed_time = cl.time;
1743 SCR_CenterPrint(MSG_ReadString ());
1746 case svc_sellscreen:
1747 Cmd_ExecuteString ("help", src_command);
1750 if (gamemode == GAME_TENEBRAE)
1752 // repeating particle effect
1765 SHOWLMP_decodehide();
1768 if (gamemode == GAME_TENEBRAE)
1778 SHOWLMP_decodeshow();
1781 R_SetSkyBox(MSG_ReadString());
1786 length = (int) ((unsigned short) MSG_ReadShort());
1787 for (i = 0;i < length;i++)
1788 cgamenetbuffer[i] = MSG_ReadByte();
1790 CL_CGVM_ParseNetwork(cgamenetbuffer, length);
1794 if (cls.signon == SIGNONS - 1)
1796 // first update is the final signon stage
1797 cls.signon = SIGNONS;
1800 CL_ReadEntityFrame();
1805 if (entitiesupdated)
1806 CL_EntityUpdateEnd();
1808 parsingerror = false;
1811 void CL_Parse_DumpPacket(void)
1815 Con_Print("Packet dump:\n");
1816 SZ_HexDumpToConsole(&net_message);
1817 parsingerror = false;
1820 void CL_Parse_Init(void)
1822 // LordHavoc: added demo_nehahra cvar
1823 cl_scores_mempool = Mem_AllocPool("client player info", 0, NULL);
1824 Cvar_RegisterVariable (&demo_nehahra);
1825 if (gamemode == GAME_NEHAHRA)
1826 Cvar_SetValue("demo_nehahra", 1);
1827 Cvar_RegisterVariable(&developer_networkentities);