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_Printf("--> 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 R_SetSkyBox(""); // LordHavoc: no environment mapped sky until set
220 if (!COM_ParseToken(&data, false))
222 if (com_token[0] != '{')
226 if (!COM_ParseToken(&data, false))
228 if (com_token[0] == '}')
229 break; // end of worldspawn
230 if (com_token[0] == '_')
231 strlcpy (key, com_token + 1, sizeof (key));
233 strlcpy (key, com_token, sizeof (key));
234 while (key[strlen(key)-1] == ' ') // remove trailing spaces
235 key[strlen(key)-1] = 0;
236 if (!COM_ParseToken(&data, false))
238 strlcpy (value, com_token, sizeof (value));
239 if (!strcmp("sky", key))
241 else if (!strcmp("skyname", key)) // non-standard, introduced by QuakeForge... sigh.
243 else if (!strcmp("qlsky", key)) // non-standard, introduced by QuakeLives (EEK)
245 else if (!strcmp("fog", key))
246 sscanf(value, "%f %f %f %f", &fog_density, &fog_red, &fog_green, &fog_blue);
247 else if (!strcmp("fog_density", key))
248 fog_density = atof(value);
249 else if (!strcmp("fog_red", key))
250 fog_red = atof(value);
251 else if (!strcmp("fog_green", key))
252 fog_green = atof(value);
253 else if (!strcmp("fog_blue", key))
254 fog_blue = atof(value);
259 =====================
262 An svc_signonnum has been received, perform a client side setup
263 =====================
265 static void CL_SignonReply (void)
269 Con_DPrintf ("CL_SignonReply: %i\n", cls.signon);
274 MSG_WriteByte (&cls.message, clc_stringcmd);
275 MSG_WriteString (&cls.message, "prespawn");
279 MSG_WriteByte (&cls.message, clc_stringcmd);
280 MSG_WriteString (&cls.message, va("name \"%s\"\n", cl_name.string));
282 MSG_WriteByte (&cls.message, clc_stringcmd);
283 MSG_WriteString (&cls.message, va("color %i %i\n", cl_color.integer >> 4, cl_color.integer & 15));
285 if (cl_pmodel.integer)
287 MSG_WriteByte (&cls.message, clc_stringcmd);
288 MSG_WriteString (&cls.message, va("pmodel %i\n", cl_pmodel.integer));
291 MSG_WriteByte (&cls.message, clc_stringcmd);
292 MSG_WriteString (&cls.message, va("rate %i\n", cl_rate.integer));
294 MSG_WriteByte (&cls.message, clc_stringcmd);
295 MSG_WriteString (&cls.message, "spawn");
299 MSG_WriteByte (&cls.message, clc_stringcmd);
300 MSG_WriteString (&cls.message, "begin");
314 qbyte entlife[MAX_EDICTS];
315 // FIXME: this is a lot of memory to be keeping around, this needs to be dynamically allocated and freed
316 static char parse_model_precache[MAX_MODELS][MAX_QPATH];
317 static char parse_sound_precache[MAX_SOUNDS][MAX_QPATH];
318 void CL_ParseServerInfo (void)
322 int nummodels, numsounds;
325 Con_DPrintf ("Serverinfo packet received.\n");
327 // wipe the client_state_t struct
331 // parse protocol version number
333 // hack for unmarked Nehahra movie demos which had a custom protocol
334 if (i == PROTOCOL_QUAKE && cls.demoplayback && demo_nehahra.integer)
335 i = PROTOCOL_NEHAHRAMOVIE;
336 if (i != PROTOCOL_QUAKE && i != PROTOCOL_DARKPLACES1 && i != PROTOCOL_DARKPLACES2 && i != PROTOCOL_DARKPLACES3 && i != PROTOCOL_DARKPLACES4 && i != PROTOCOL_DARKPLACES5 && i != PROTOCOL_NEHAHRAMOVIE)
338 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);
344 cl.maxclients = MSG_ReadByte ();
345 if (cl.maxclients < 1 || cl.maxclients > MAX_SCOREBOARD)
347 Con_Printf("Bad maxclients (%u) from server\n", cl.maxclients);
350 Mem_EmptyPool(cl_scores_mempool);
351 cl.scores = Mem_Alloc(cl_scores_mempool, cl.maxclients*sizeof(*cl.scores));
354 cl.gametype = MSG_ReadByte ();
356 // parse signon message
357 str = MSG_ReadString ();
358 strlcpy (cl.levelname, str, sizeof(cl.levelname));
360 // seperate the printfs so the server message can have a color
361 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");
364 Con_Printf("%c%s\n", 2, str);
367 // check memory integrity
368 Mem_CheckSentinelsGlobal();
370 // disable until we get textures for it
373 memset(cl.model_precache, 0, sizeof(cl.model_precache));
374 memset(cl.sound_precache, 0, sizeof(cl.sound_precache));
376 // parse model precache list
377 for (nummodels=1 ; ; nummodels++)
379 str = MSG_ReadString();
382 if (nummodels==MAX_MODELS)
383 Host_Error ("Server sent too many model precaches\n");
384 if (strlen(str) >= MAX_QPATH)
385 Host_Error ("Server sent a precache name of %i characters (max %i)", strlen(str), MAX_QPATH - 1);
386 strlcpy (parse_model_precache[nummodels], str, sizeof (parse_model_precache[nummodels]));
388 // parse sound precache list
389 for (numsounds=1 ; ; numsounds++)
391 str = MSG_ReadString();
394 if (numsounds==MAX_SOUNDS)
395 Host_Error("Server sent too many sound precaches\n");
396 if (strlen(str) >= MAX_QPATH)
397 Host_Error("Server sent a precache name of %i characters (max %i)", strlen(str), MAX_QPATH - 1);
398 strlcpy (parse_sound_precache[numsounds], str, sizeof (parse_sound_precache[numsounds]));
401 // touch all of the precached models that are still loaded so we can free
402 // anything that isn't needed
404 for (i = 1;i < nummodels;i++)
406 CL_KeepaliveMessage();
407 Mod_TouchModel(parse_model_precache[i]);
411 // do the same for sounds
413 for (i = 1;i < numsounds;i++)
415 CL_KeepaliveMessage();
416 S_TouchSound(parse_sound_precache[i]);
420 // now we try to load everything that is new
423 CL_KeepaliveMessage ();
424 cl.model_precache[1] = Mod_ForName(parse_model_precache[1], false, false, true);
425 if (cl.model_precache[1] == NULL)
426 Con_Printf("Map %s not found\n", parse_model_precache[1]);
429 for (i=2 ; i<nummodels ; i++)
431 CL_KeepaliveMessage();
432 if ((cl.model_precache[i] = Mod_ForName(parse_model_precache[i], false, false, false)) == NULL)
433 Con_Printf("Model %s not found\n", parse_model_precache[i]);
437 for (i=1 ; i<numsounds ; i++)
439 CL_KeepaliveMessage();
440 cl.sound_precache[i] = S_PrecacheSound(parse_sound_precache[i], true);
444 ent = &cl_entities[0];
445 // entire entity array was cleared, so just fill in a few fields
446 ent->state_current.active = true;
447 ent->render.model = cl.worldmodel = cl.model_precache[1];
448 ent->render.scale = 1; // some of the renderer still relies on scale
449 ent->render.alpha = 1;
450 ent->render.flags = RENDER_SHADOW | RENDER_LIGHT;
451 Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, 0, 0, 0, 0, 0, 0, 1);
452 Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix);
453 CL_BoundingBoxForEntity(&ent->render);
454 // clear entlife array
455 memset(entlife, 0, MAX_EDICTS);
462 // noclip is turned off at start
463 noclip_anglehack = false;
465 // check memory integrity
466 Mem_CheckSentinelsGlobal();
469 void CL_ValidateState(entity_state_t *s)
476 if (s->modelindex >= MAX_MODELS)
477 Host_Error("CL_ValidateState: modelindex (%i) >= MAX_MODELS (%i)\n", s->modelindex, MAX_MODELS);
479 // colormap is client index + 1
480 if (s->colormap > cl.maxclients)
481 Host_Error ("CL_ValidateState: colormap (%i) > cl.maxclients (%i)", s->colormap, cl.maxclients);
483 model = cl.model_precache[s->modelindex];
484 Mod_CheckLoaded(model);
485 if (model && s->frame >= model->numframes)
487 Con_DPrintf("CL_ValidateState: no such frame %i in \"%s\"\n", s->frame, model->name);
490 if (model && s->skin > 0 && s->skin >= model->numskins)
492 Con_DPrintf("CL_ValidateState: no such skin %i in \"%s\"\n", s->skin, model->name);
497 void CL_MoveLerpEntityStates(entity_t *ent)
499 float odelta[3], adelta[3];
500 VectorSubtract(ent->state_current.origin, ent->persistent.neworigin, odelta);
501 VectorSubtract(ent->state_current.angles, ent->persistent.newangles, adelta);
502 if (!ent->state_previous.active || cls.timedemo || DotProduct(odelta, odelta) > 1000*1000 || cl_nolerp.integer)
504 // we definitely shouldn't lerp
505 ent->persistent.lerpdeltatime = 0;
506 ent->persistent.lerpstarttime = cl.mtime[1];
507 VectorCopy(ent->state_current.origin, ent->persistent.oldorigin);
508 VectorCopy(ent->state_current.angles, ent->persistent.oldangles);
509 VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
510 VectorCopy(ent->state_current.angles, ent->persistent.newangles);
512 else if (ent->state_current.flags & RENDER_STEP)
514 // monster interpolation
515 if (DotProduct(odelta, odelta) + DotProduct(adelta, adelta) > 0.01)
517 ent->persistent.lerpdeltatime = bound(0, cl.mtime[1] - ent->persistent.lerpstarttime, 0.1);
518 ent->persistent.lerpstarttime = cl.mtime[1];
519 VectorCopy(ent->persistent.neworigin, ent->persistent.oldorigin);
520 VectorCopy(ent->persistent.newangles, ent->persistent.oldangles);
521 VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
522 VectorCopy(ent->state_current.angles, ent->persistent.newangles);
528 ent->persistent.lerpstarttime = cl.mtime[1];
529 // no lerp if it's singleplayer
531 ent->persistent.lerpdeltatime = 0;
533 ent->persistent.lerpdeltatime = cl.mtime[0] - cl.mtime[1];
534 VectorCopy(ent->persistent.neworigin, ent->persistent.oldorigin);
535 VectorCopy(ent->persistent.newangles, ent->persistent.oldangles);
536 VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
537 VectorCopy(ent->state_current.angles, ent->persistent.newangles);
545 Parse an entity update message from the server
546 If an entities model or origin changes from frame to frame, it must be
547 relinked. Other attributes can change without relinking.
550 void CL_ParseUpdate (int bits)
556 if (bits & U_MOREBITS)
557 bits |= (MSG_ReadByte()<<8);
558 if ((bits & U_EXTEND1) && cl.protocol != PROTOCOL_NEHAHRAMOVIE)
560 bits |= MSG_ReadByte() << 16;
561 if (bits & U_EXTEND2)
562 bits |= MSG_ReadByte() << 24;
565 if (bits & U_LONGENTITY)
566 num = (unsigned) MSG_ReadShort ();
568 num = (unsigned) MSG_ReadByte ();
570 if (num >= MAX_EDICTS)
571 Host_Error("CL_ParseUpdate: entity number (%i) >= MAX_EDICTS (%i)\n", num, MAX_EDICTS);
573 Host_Error("CL_ParseUpdate: invalid entity number (%i)\n", num);
575 ent = cl_entities + num;
577 // note: this inherits the 'active' state of the baseline chosen
578 // (state_baseline is always active, state_current may not be active if
579 // the entity was missing in the last frame)
581 new = ent->state_current;
584 new = ent->state_baseline;
589 new.time = cl.mtime[0];
591 if (bits & U_MODEL) new.modelindex = (new.modelindex & 0xFF00) | MSG_ReadByte();
592 if (bits & U_FRAME) new.frame = (new.frame & 0xFF00) | MSG_ReadByte();
593 if (bits & U_COLORMAP) new.colormap = MSG_ReadByte();
594 if (bits & U_SKIN) new.skin = MSG_ReadByte();
595 if (bits & U_EFFECTS) new.effects = (new.effects & 0xFF00) | MSG_ReadByte();
596 if (bits & U_ORIGIN1) new.origin[0] = MSG_ReadCoord();
597 if (bits & U_ANGLE1) new.angles[0] = MSG_ReadAngle();
598 if (bits & U_ORIGIN2) new.origin[1] = MSG_ReadCoord();
599 if (bits & U_ANGLE2) new.angles[1] = MSG_ReadAngle();
600 if (bits & U_ORIGIN3) new.origin[2] = MSG_ReadCoord();
601 if (bits & U_ANGLE3) new.angles[2] = MSG_ReadAngle();
602 if (bits & U_STEP) new.flags |= RENDER_STEP;
603 if (bits & U_ALPHA) new.alpha = MSG_ReadByte();
604 if (bits & U_SCALE) new.scale = MSG_ReadByte();
605 if (bits & U_EFFECTS2) new.effects = (new.effects & 0x00FF) | (MSG_ReadByte() << 8);
606 if (bits & U_GLOWSIZE) new.glowsize = MSG_ReadByte();
607 if (bits & U_GLOWCOLOR) new.glowcolor = MSG_ReadByte();
608 // apparently the dpcrush demo uses this (unintended, and it uses white anyway)
609 if (bits & U_COLORMOD) MSG_ReadByte();
610 if (bits & U_GLOWTRAIL) new.flags |= RENDER_GLOWTRAIL;
611 if (bits & U_FRAME2) new.frame = (new.frame & 0x00FF) | (MSG_ReadByte() << 8);
612 if (bits & U_MODEL2) new.modelindex = (new.modelindex & 0x00FF) | (MSG_ReadByte() << 8);
613 if (bits & U_VIEWMODEL) new.flags |= RENDER_VIEWMODEL;
614 if (bits & U_EXTERIORMODEL) new.flags |= RENDER_EXTERIORMODEL;
616 // LordHavoc: to allow playback of the Nehahra movie
617 if (cl.protocol == PROTOCOL_NEHAHRAMOVIE && (bits & U_EXTEND1))
619 // LordHavoc: evil format
620 int i = MSG_ReadFloat();
621 int j = MSG_ReadFloat() * 255.0f;
626 new.effects |= EF_FULLBRIGHT;
630 else if (j == 0 || j >= 255)
637 CL_ValidateState(&new);
639 ent->state_previous = ent->state_current;
640 ent->state_current = new;
641 if (ent->state_current.active)
643 CL_MoveLerpEntityStates(ent);
644 cl_entities_active[ent->state_current.number] = true;
645 // mark as visible (no kill this frame)
646 entlife[ent->state_current.number] = 2;
650 static entity_frame_t entityframe;
651 extern mempool_t *cl_entities_mempool;
652 void CL_ReadEntityFrame(void)
654 if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
658 EntityFrame_Read(&cl.entitydatabase);
659 EntityFrame_FetchFrame(&cl.entitydatabase, EntityFrame_MostRecentlyRecievedFrameNum(&cl.entitydatabase), &entityframe);
660 for (i = 0;i < entityframe.numentities;i++)
663 ent = &cl_entities[entityframe.entitydata[i].number];
664 ent->state_previous = ent->state_current;
665 ent->state_current = entityframe.entitydata[i];
666 CL_MoveLerpEntityStates(ent);
667 // the entity lives again...
668 entlife[ent->state_current.number] = 2;
669 cl_entities_active[ent->state_current.number] = true;
674 if (!cl.entitydatabase4)
675 cl.entitydatabase4 = EntityFrame4_AllocDatabase(cl_entities_mempool);
676 EntityFrame4_CL_ReadFrame(cl.entitydatabase4);
680 void CL_EntityUpdateSetup(void)
684 void CL_EntityUpdateEnd(void)
686 if (cl.protocol == PROTOCOL_QUAKE || cl.protocol == PROTOCOL_NEHAHRAMOVIE || cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
689 // disable entities that disappeared this frame
690 for (i = 1;i < MAX_EDICTS;i++)
692 // clear only the entities that were active last frame but not this
693 // frame, don't waste time clearing all entities (which would cause
699 cl_entities[i].state_previous.active = cl_entities[i].state_current.active = 0;
710 void CL_ParseBaseline (entity_t *ent, int large)
714 ClearStateToDefault(&ent->state_baseline);
715 ent->state_baseline.active = true;
718 ent->state_baseline.modelindex = (unsigned short) MSG_ReadShort ();
719 ent->state_baseline.frame = (unsigned short) MSG_ReadShort ();
723 ent->state_baseline.modelindex = MSG_ReadByte ();
724 ent->state_baseline.frame = MSG_ReadByte ();
726 ent->state_baseline.colormap = MSG_ReadByte();
727 ent->state_baseline.skin = MSG_ReadByte();
728 for (i = 0;i < 3;i++)
730 ent->state_baseline.origin[i] = MSG_ReadCoord ();
731 ent->state_baseline.angles[i] = MSG_ReadAngle ();
733 CL_ValidateState(&ent->state_baseline);
734 ent->state_previous = ent->state_current = ent->state_baseline;
742 Server information pertaining to this client only
745 void CL_ParseClientdata (int bits)
750 if (bits & SU_EXTEND1)
751 bits |= (MSG_ReadByte() << 16);
752 if (bits & SU_EXTEND2)
753 bits |= (MSG_ReadByte() << 24);
755 if (bits & SU_VIEWHEIGHT)
756 cl.viewheight = MSG_ReadChar ();
758 cl.viewheight = DEFAULT_VIEWHEIGHT;
760 if (bits & SU_IDEALPITCH)
761 cl.idealpitch = MSG_ReadChar ();
765 VectorCopy (cl.mvelocity[0], cl.mvelocity[1]);
766 if (cl.protocol == PROTOCOL_DARKPLACES5)
768 for (i = 0;i < 3;i++)
770 if (bits & (SU_PUNCH1<<i) )
771 cl.punchangle[i] = MSG_ReadPreciseAngle();
773 cl.punchangle[i] = 0;
774 if (bits & (SU_PUNCHVEC1<<i))
775 cl.punchvector[i] = MSG_ReadFloat();
777 cl.punchvector[i] = 0;
778 if (bits & (SU_VELOCITY1<<i) )
779 cl.mvelocity[0][i] = MSG_ReadFloat();
781 cl.mvelocity[0][i] = 0;
786 for (i = 0;i < 3;i++)
788 if (bits & (SU_PUNCH1<<i) )
790 if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
791 cl.punchangle[i] = MSG_ReadPreciseAngle();
793 cl.punchangle[i] = MSG_ReadChar();
796 cl.punchangle[i] = 0;
797 if (bits & (SU_PUNCHVEC1<<i))
798 cl.punchvector[i] = MSG_ReadCoord();
800 cl.punchvector[i] = 0;
801 if (bits & (SU_VELOCITY1<<i) )
802 cl.mvelocity[0][i] = MSG_ReadChar()*16;
804 cl.mvelocity[0][i] = 0;
811 for (j=0 ; j<32 ; j++)
812 if ( (i & (1<<j)) && !(cl.items & (1<<j)))
813 cl.item_gettime[j] = cl.time;
817 cl.onground = (bits & SU_ONGROUND) != 0;
818 cl.inwater = (bits & SU_INWATER) != 0;
820 cl.stats[STAT_WEAPONFRAME] = (bits & SU_WEAPONFRAME) ? MSG_ReadByte() : 0;
821 cl.stats[STAT_ARMOR] = (bits & SU_ARMOR) ? MSG_ReadByte() : 0;
822 cl.stats[STAT_WEAPON] = (bits & SU_WEAPON) ? MSG_ReadByte() : 0;
823 cl.stats[STAT_HEALTH] = MSG_ReadShort();
824 cl.stats[STAT_AMMO] = MSG_ReadByte();
826 cl.stats[STAT_SHELLS] = MSG_ReadByte();
827 cl.stats[STAT_NAILS] = MSG_ReadByte();
828 cl.stats[STAT_ROCKETS] = MSG_ReadByte();
829 cl.stats[STAT_CELLS] = MSG_ReadByte();
833 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
835 // GAME_NEXUIZ hud needs weapon change time
836 // GAME_NEXUIZ uses a bit number as it's STAT_ACTIVEWEAPON, not a bitfield
838 if (cl.stats[STAT_ACTIVEWEAPON] != i)
839 cl.weapontime = cl.time;
840 cl.stats[STAT_ACTIVEWEAPON] = i;
842 cl.viewzoomold = cl.viewzoomnew; // for interpolation
843 if (bits & SU_VIEWZOOM)
848 cl.viewzoomnew = (float) i * (1.0f / 255.0f);
856 =====================
858 =====================
860 void CL_ParseStatic (int large)
864 if (cl_num_static_entities >= cl_max_static_entities)
865 Host_Error ("Too many static entities");
866 ent = &cl_static_entities[cl_num_static_entities++];
867 CL_ParseBaseline (ent, large);
869 // copy it to the current state
870 ent->render.model = cl.model_precache[ent->state_baseline.modelindex];
871 ent->render.frame = ent->render.frame1 = ent->render.frame2 = ent->state_baseline.frame;
872 ent->render.framelerp = 0;
873 // make torchs play out of sync
874 ent->render.frame1time = ent->render.frame2time = lhrandom(-10, -1);
875 ent->render.colormap = -1; // no special coloring
876 ent->render.skinnum = ent->state_baseline.skin;
877 ent->render.effects = ent->state_baseline.effects;
878 ent->render.alpha = 1;
879 //ent->render.scale = 1;
881 //VectorCopy (ent->state_baseline.origin, ent->render.origin);
882 //VectorCopy (ent->state_baseline.angles, ent->render.angles);
884 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);
885 Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix);
886 CL_BoundingBoxForEntity(&ent->render);
888 // This is definitely cheating...
889 if (ent->render.model == NULL)
890 cl_num_static_entities--;
898 void CL_ParseStaticSound (int large)
901 int sound_num, vol, atten;
905 sound_num = (unsigned short) MSG_ReadShort ();
907 sound_num = MSG_ReadByte ();
908 vol = MSG_ReadByte ();
909 atten = MSG_ReadByte ();
911 S_StaticSound (cl.sound_precache[sound_num], org, vol, atten);
914 void CL_ParseEffect (void)
917 int modelindex, startframe, framecount, framerate;
920 modelindex = MSG_ReadByte ();
921 startframe = MSG_ReadByte ();
922 framecount = MSG_ReadByte ();
923 framerate = MSG_ReadByte ();
925 CL_Effect(org, modelindex, startframe, framecount, framerate);
928 void CL_ParseEffect2 (void)
931 int modelindex, startframe, framecount, framerate;
934 modelindex = MSG_ReadShort ();
935 startframe = MSG_ReadShort ();
936 framecount = MSG_ReadByte ();
937 framerate = MSG_ReadByte ();
939 CL_Effect(org, modelindex, startframe, framecount, framerate);
942 model_t *cl_model_bolt = NULL;
943 model_t *cl_model_bolt2 = NULL;
944 model_t *cl_model_bolt3 = NULL;
945 model_t *cl_model_beam = NULL;
947 sfx_t *cl_sfx_wizhit;
948 sfx_t *cl_sfx_knighthit;
953 sfx_t *cl_sfx_r_exp3;
960 void CL_InitTEnts (void)
962 cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav", false);
963 cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav", false);
964 cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav", false);
965 cl_sfx_ric1 = S_PrecacheSound ("weapons/ric1.wav", false);
966 cl_sfx_ric2 = S_PrecacheSound ("weapons/ric2.wav", false);
967 cl_sfx_ric3 = S_PrecacheSound ("weapons/ric3.wav", false);
968 cl_sfx_r_exp3 = S_PrecacheSound ("weapons/r_exp3.wav", false);
971 void CL_ParseBeam (model_t *m, int lightning)
977 ent = MSG_ReadShort ();
978 MSG_ReadVector(start);
981 if (ent >= MAX_EDICTS)
983 Con_Printf("CL_ParseBeam: invalid entity number %i\n", ent);
987 // override any beam with the same entity
988 for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
990 if (b->entity == ent)
993 b->lightning = lightning;
994 b->relativestartvalid = (ent && cl_entities[ent].state_current.active) ? 2 : 0;
996 b->endtime = cl.time + 0.2;
997 VectorCopy (start, b->start);
998 VectorCopy (end, b->end);
1004 for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
1006 if (!b->model || b->endtime < cl.time)
1009 b->lightning = lightning;
1010 b->relativestartvalid = (ent && cl_entities[ent].state_current.active) ? 2 : 0;
1012 b->endtime = cl.time + 0.2;
1013 VectorCopy (start, b->start);
1014 VectorCopy (end, b->end);
1018 Con_Printf ("beam list overflow!\n");
1021 void CL_ParseTempEntity(void)
1029 int colorStart, colorLength, count;
1030 float velspeed, radius;
1032 matrix4x4_t tempmatrix;
1034 type = MSG_ReadByte();
1038 // spike hitting wall
1039 MSG_ReadVector(pos);
1040 CL_FindNonSolidLocation(pos, pos, 4);
1041 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1042 CL_AllocDlight(NULL, &tempmatrix, 150, 0.25f, 1.00f, 0.25f, 250, 0.2, 0, 0, false, 1);
1043 CL_RunParticleEffect(pos, vec3_origin, 20, 30);
1044 S_StartSound(-1, 0, cl_sfx_wizhit, pos, 1, 1);
1047 case TE_KNIGHTSPIKE:
1048 // spike hitting wall
1049 MSG_ReadVector(pos);
1050 CL_FindNonSolidLocation(pos, pos, 4);
1051 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1052 CL_AllocDlight(NULL, &tempmatrix, 150, 1.0f, 0.60f, 0.20f, 250, 0.2, 0, 0, false, 1);
1053 CL_RunParticleEffect(pos, vec3_origin, 226, 20);
1054 S_StartSound(-1, 0, cl_sfx_knighthit, pos, 1, 1);
1058 // spike hitting wall
1059 MSG_ReadVector(pos);
1060 CL_FindNonSolidLocation(pos, pos, 4);
1061 // LordHavoc: changed to spark shower
1062 CL_SparkShower(pos, vec3_origin, 15);
1064 S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1069 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1071 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1073 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1077 // quad spike hitting wall
1078 MSG_ReadVector(pos);
1079 CL_FindNonSolidLocation(pos, pos, 4);
1080 // LordHavoc: changed to spark shower
1081 CL_SparkShower(pos, vec3_origin, 15);
1082 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1083 CL_AllocDlight(NULL, &tempmatrix, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2, 0, 0, true, 1);
1084 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1086 S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1091 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1093 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1095 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1099 // super spike hitting wall
1100 MSG_ReadVector(pos);
1101 CL_FindNonSolidLocation(pos, pos, 4);
1102 // LordHavoc: changed to dust shower
1103 CL_SparkShower(pos, vec3_origin, 30);
1105 S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1110 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1112 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1114 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1117 case TE_SUPERSPIKEQUAD:
1118 // quad super spike hitting wall
1119 MSG_ReadVector(pos);
1120 CL_FindNonSolidLocation(pos, pos, 4);
1121 // LordHavoc: changed to dust shower
1122 CL_SparkShower(pos, vec3_origin, 30);
1123 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1124 CL_AllocDlight(NULL, &tempmatrix, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2, 0, 0, true, 1);
1126 S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
1131 S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
1133 S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
1135 S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
1138 // LordHavoc: added for improved blood splatters
1141 MSG_ReadVector(pos);
1142 CL_FindNonSolidLocation(pos, pos, 4);
1143 dir[0] = MSG_ReadChar();
1144 dir[1] = MSG_ReadChar();
1145 dir[2] = MSG_ReadChar();
1146 count = MSG_ReadByte();
1147 CL_BloodPuff(pos, dir, count);
1151 MSG_ReadVector(pos);
1152 CL_FindNonSolidLocation(pos, pos, 4);
1153 dir[0] = MSG_ReadChar();
1154 dir[1] = MSG_ReadChar();
1155 dir[2] = MSG_ReadChar();
1156 count = MSG_ReadByte();
1157 CL_SparkShower(pos, dir, count);
1160 MSG_ReadVector(pos);
1161 CL_FindNonSolidLocation(pos, pos, 4);
1162 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1163 CL_AllocDlight(NULL, &tempmatrix, 200, 1, 1, 1, 1000, 0.2, 0, 0, true, 1);
1166 // LordHavoc: added for improved gore
1167 case TE_BLOODSHOWER:
1169 MSG_ReadVector(pos); // mins
1170 MSG_ReadVector(pos2); // maxs
1171 velspeed = MSG_ReadCoord(); // speed
1172 count = MSG_ReadShort(); // number of particles
1173 CL_BloodShower(pos, pos2, velspeed, count);
1175 case TE_PARTICLECUBE:
1176 // general purpose particle effect
1177 MSG_ReadVector(pos); // mins
1178 MSG_ReadVector(pos2); // maxs
1179 MSG_ReadVector(dir); // dir
1180 count = MSG_ReadShort(); // number of particles
1181 colorStart = MSG_ReadByte(); // color
1182 colorLength = MSG_ReadByte(); // gravity (1 or 0)
1183 velspeed = MSG_ReadCoord(); // randomvel
1184 CL_ParticleCube(pos, pos2, dir, count, colorStart, colorLength, velspeed);
1187 case TE_PARTICLERAIN:
1188 // general purpose particle effect
1189 MSG_ReadVector(pos); // mins
1190 MSG_ReadVector(pos2); // maxs
1191 MSG_ReadVector(dir); // dir
1192 count = MSG_ReadShort(); // number of particles
1193 colorStart = MSG_ReadByte(); // color
1194 CL_ParticleRain(pos, pos2, dir, count, colorStart, 0);
1197 case TE_PARTICLESNOW:
1198 // general purpose particle effect
1199 MSG_ReadVector(pos); // mins
1200 MSG_ReadVector(pos2); // maxs
1201 MSG_ReadVector(dir); // dir
1202 count = MSG_ReadShort(); // number of particles
1203 colorStart = MSG_ReadByte(); // color
1204 CL_ParticleRain(pos, pos2, dir, count, colorStart, 1);
1208 // bullet hitting wall
1209 MSG_ReadVector(pos);
1210 CL_FindNonSolidLocation(pos, pos, 4);
1211 // LordHavoc: changed to dust shower
1212 CL_SparkShower(pos, vec3_origin, 15);
1215 case TE_GUNSHOTQUAD:
1216 // quad bullet hitting wall
1217 MSG_ReadVector(pos);
1218 CL_FindNonSolidLocation(pos, pos, 4);
1219 CL_SparkShower(pos, vec3_origin, 15);
1220 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1221 CL_AllocDlight(NULL, &tempmatrix, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2, 0, 0, true, 1);
1226 MSG_ReadVector(pos);
1227 CL_FindNonSolidLocation(pos, pos, 10);
1228 CL_ParticleExplosion(pos);
1229 // LordHavoc: boosted color from 1.0, 0.8, 0.4 to 1.25, 1.0, 0.5
1230 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1231 CL_AllocDlight(NULL, &tempmatrix, 350, 1.25f, 1.0f, 0.5f, 700, 0.5, 0, 0, true, 1);
1232 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1235 case TE_EXPLOSIONQUAD:
1236 // quad rocket explosion
1237 MSG_ReadVector(pos);
1238 CL_FindNonSolidLocation(pos, pos, 10);
1239 CL_ParticleExplosion(pos);
1240 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1241 CL_AllocDlight(NULL, &tempmatrix, 600, 0.5f, 0.4f, 1.0f, 1200, 0.5, 0, 0, true, 1);
1242 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1246 // Nehahra movie colored lighting explosion
1247 MSG_ReadVector(pos);
1248 CL_FindNonSolidLocation(pos, pos, 10);
1249 CL_ParticleExplosion(pos);
1250 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1251 CL_AllocDlight(NULL, &tempmatrix, 350, MSG_ReadCoord(), MSG_ReadCoord(), MSG_ReadCoord(), 700, 0.5, 0, 0, true, 1);
1252 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1255 case TE_EXPLOSIONRGB:
1256 // colored lighting explosion
1257 MSG_ReadVector(pos);
1258 CL_FindNonSolidLocation(pos, pos, 10);
1259 CL_ParticleExplosion(pos);
1260 color[0] = MSG_ReadByte() * (1.0 / 255.0);
1261 color[1] = MSG_ReadByte() * (1.0 / 255.0);
1262 color[2] = MSG_ReadByte() * (1.0 / 255.0);
1263 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1264 CL_AllocDlight(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, 0, true, 1);
1265 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1268 case TE_TAREXPLOSION:
1269 // tarbaby explosion
1270 MSG_ReadVector(pos);
1271 CL_FindNonSolidLocation(pos, pos, 10);
1272 CL_BlobExplosion(pos);
1274 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1275 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1276 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1277 CL_AllocDlight(NULL, &tempmatrix, 600, 0.8f, 0.4f, 1.0f, 1200, 0.5, 0, 0, true, 1);
1281 MSG_ReadVector(pos);
1282 CL_FindNonSolidLocation(pos, pos, 10);
1283 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1284 CL_AllocDlight(NULL, &tempmatrix, 200, 1, 1, 1, 1000, 0.2, 0, 0, true, 1);
1287 case TE_CUSTOMFLASH:
1288 MSG_ReadVector(pos);
1289 CL_FindNonSolidLocation(pos, pos, 4);
1290 radius = MSG_ReadByte() * 8;
1291 velspeed = (MSG_ReadByte() + 1) * (1.0 / 256.0);
1292 color[0] = MSG_ReadByte() * (1.0 / 255.0);
1293 color[1] = MSG_ReadByte() * (1.0 / 255.0);
1294 color[2] = MSG_ReadByte() * (1.0 / 255.0);
1295 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1296 CL_AllocDlight(NULL, &tempmatrix, radius, color[0], color[1], color[2], radius / velspeed, velspeed, 0, 0, true, 1);
1300 MSG_ReadVector(pos);
1301 MSG_ReadVector(dir);
1302 count = MSG_ReadByte();
1303 CL_Flames(pos, dir, count);
1309 cl_model_bolt = Mod_ForName("progs/bolt.mdl", true, false, false);
1310 CL_ParseBeam(cl_model_bolt, true);
1315 if (!cl_model_bolt2)
1316 cl_model_bolt2 = Mod_ForName("progs/bolt2.mdl", true, false, false);
1317 CL_ParseBeam(cl_model_bolt2, true);
1322 if (!cl_model_bolt3)
1323 cl_model_bolt3 = Mod_ForName("progs/bolt3.mdl", true, false, false);
1324 CL_ParseBeam(cl_model_bolt3, false);
1329 // grappling hook beam
1331 cl_model_beam = Mod_ForName("progs/beam.mdl", true, false, false);
1332 CL_ParseBeam(cl_model_beam, false);
1336 // LordHavoc: for compatibility with the Nehahra movie...
1337 case TE_LIGHTNING4NEH:
1338 CL_ParseBeam(Mod_ForName(MSG_ReadString(), true, false, false), false);
1342 MSG_ReadVector(pos);
1347 MSG_ReadVector(pos);
1348 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1349 CL_AllocDlight(NULL, &tempmatrix, 500, 1.0f, 1.0f, 1.0f, 1500, 99.0f, 0, 0, true, 1);
1350 // CL_TeleportSplash(pos);
1354 // color mapped explosion
1355 MSG_ReadVector(pos);
1356 CL_FindNonSolidLocation(pos, pos, 10);
1357 colorStart = MSG_ReadByte();
1358 colorLength = MSG_ReadByte();
1359 CL_ParticleExplosion2(pos, colorStart, colorLength);
1360 tempcolor = (qbyte *)&palette_complete[(rand()%colorLength) + colorStart];
1361 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1362 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);
1363 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1367 MSG_ReadVector(pos);
1368 MSG_ReadVector(pos2);
1369 MSG_ReadVector(dir);
1370 CL_BeamParticle(pos, pos2, 12, 1, 0.3, 0.1, 1, 1);
1371 CL_BeamParticle(pos, pos2, 5, 1, 0.9, 0.3, 1, 1);
1375 MSG_ReadVector(pos);
1376 MSG_ReadVector(dir);
1377 count = MSG_ReadByte();
1378 CL_FindNonSolidLocation(pos, pos, 4);
1379 CL_Tei_Smoke(pos, dir, count);
1382 case TE_TEI_BIGEXPLOSION:
1383 MSG_ReadVector(pos);
1384 CL_FindNonSolidLocation(pos, pos, 10);
1385 CL_ParticleExplosion(pos);
1386 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1387 CL_AllocDlight(NULL, &tempmatrix, 500, 1.25f, 1.0f, 0.5f, 500, 9999, 0, 0, true, 1);
1388 S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
1391 case TE_TEI_PLASMAHIT:
1392 MSG_ReadVector(pos);
1393 MSG_ReadVector(dir);
1394 count = MSG_ReadByte();
1395 CL_FindNonSolidLocation(pos, pos, 5);
1396 CL_Tei_PlasmaHit(pos, dir, count);
1397 Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
1398 CL_AllocDlight(NULL, &tempmatrix, 500, 0.3, 0.6, 1.0f, 2000, 9999, 0, 0, true, 1);
1402 Host_Error("CL_ParseTempEntity: bad type %d (hex %02X)", type, type);
1406 #define SHOWNET(x) if(cl_shownet.integer==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x);
1408 static qbyte cgamenetbuffer[65536];
1411 =====================
1412 CL_ParseServerMessage
1413 =====================
1415 int parsingerror = false;
1416 void CL_ParseServerMessage(void)
1419 int i, entitiesupdated;
1421 char *cmdlogname[32], *temp;
1422 int cmdindex, cmdcount = 0;
1424 if (cls.demorecording)
1425 CL_WriteDemoMessage ();
1427 cl.last_received_message = realtime;
1430 // if recording demos, copy the message out
1432 if (cl_shownet.integer == 1)
1433 Con_Printf ("%f %i\n", realtime, net_message.cursize);
1434 else if (cl_shownet.integer == 2)
1435 Con_Printf ("------------------\n");
1437 cl.onground = false; // unless the server says otherwise
1439 // parse the message
1441 //MSG_BeginReading ();
1443 entitiesupdated = false;
1445 parsingerror = true;
1450 Host_Error ("CL_ParseServerMessage: Bad server message");
1452 cmd = MSG_ReadByte ();
1456 SHOWNET("END OF MESSAGE");
1457 break; // end of message
1460 cmdindex = cmdcount & 31;
1462 cmdlog[cmdindex] = cmd;
1464 // if the high bit of the command byte is set, it is a fast update
1467 // LordHavoc: fix for bizarre problem in MSVC that I do not understand (if I assign the string pointer directly it ends up storing a NULL pointer)
1469 cmdlogname[cmdindex] = temp;
1470 SHOWNET("fast update");
1471 if (cls.signon == SIGNONS - 1)
1473 // first update is the final signon stage
1474 cls.signon = SIGNONS;
1477 CL_ParseUpdate (cmd&127);
1481 SHOWNET(svc_strings[cmd]);
1482 cmdlogname[cmdindex] = svc_strings[cmd];
1483 if (!cmdlogname[cmdindex])
1485 // 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)
1487 cmdlogname[cmdindex] = temp;
1495 char description[32*64], temp[64];
1497 strcpy (description, "packet dump: ");
1501 count = cmdcount - i;
1505 snprintf (temp, sizeof (temp), "%3i:%s ", cmdlog[i], cmdlogname[i]);
1506 strlcat (description, temp, sizeof (description));
1511 description[strlen(description)-1] = '\n'; // replace the last space with a newline
1512 Con_Printf("%s", description);
1513 Host_Error ("CL_ParseServerMessage: Illegible server message\n");
1518 if (cls.signon < SIGNONS)
1519 Con_Printf("<-- server to client keepalive\n");
1523 if (!entitiesupdated)
1525 // this is a new frame, we'll be seeing entities,
1526 // so prepare for entity updates
1527 CL_EntityUpdateSetup();
1528 entitiesupdated = true;
1530 cl.mtime[1] = cl.mtime[0];
1531 cl.mtime[0] = MSG_ReadFloat ();
1534 case svc_clientdata:
1535 i = MSG_ReadShort ();
1536 CL_ParseClientdata (i);
1540 i = MSG_ReadLong ();
1541 // hack for unmarked Nehahra movie demos which had a custom protocol
1542 if (i == PROTOCOL_QUAKE && cls.demoplayback && demo_nehahra.integer)
1543 i = PROTOCOL_NEHAHRAMOVIE;
1544 if (i != PROTOCOL_QUAKE && i != PROTOCOL_DARKPLACES1 && i != PROTOCOL_DARKPLACES2 && i != PROTOCOL_DARKPLACES3 && i != PROTOCOL_DARKPLACES4 && i != PROTOCOL_DARKPLACES5 && i != PROTOCOL_NEHAHRAMOVIE)
1545 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);
1549 case svc_disconnect:
1550 Host_EndGame ("Server disconnected\n");
1553 Con_Printf ("%s", MSG_ReadString ());
1556 case svc_centerprint:
1557 SCR_CenterPrint (MSG_ReadString ());
1561 Cbuf_AddText (MSG_ReadString ());
1568 case svc_serverinfo:
1569 CL_ParseServerInfo ();
1573 for (i=0 ; i<3 ; i++)
1574 cl.viewangles[i] = MSG_ReadAngle ();
1578 cl.viewentity = (unsigned short)MSG_ReadShort ();
1579 if (cl.viewentity >= MAX_EDICTS)
1580 Host_Error("svc_setview >= MAX_EDICTS\n");
1581 // LordHavoc: assume first setview recieved is the real player entity
1582 if (!cl.playerentity)
1583 cl.playerentity = cl.viewentity;
1586 case svc_lightstyle:
1587 i = MSG_ReadByte ();
1588 if (i >= MAX_LIGHTSTYLES)
1589 Host_Error ("svc_lightstyle >= MAX_LIGHTSTYLES");
1590 strlcpy (cl_lightstyle[i].map, MSG_ReadString(), sizeof (cl_lightstyle[i].map));
1591 cl_lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
1592 cl_lightstyle[i].length = strlen(cl_lightstyle[i].map);
1596 CL_ParseStartSoundPacket(false);
1600 CL_ParseStartSoundPacket(true);
1604 i = MSG_ReadShort();
1605 S_StopSound(i>>3, i&7);
1608 case svc_updatename:
1609 i = MSG_ReadByte ();
1610 if (i >= cl.maxclients)
1611 Host_Error ("CL_ParseServerMessage: svc_updatename >= cl.maxclients");
1612 strlcpy (cl.scores[i].name, MSG_ReadString (), sizeof (cl.scores[i].name));
1615 case svc_updatefrags:
1616 i = MSG_ReadByte ();
1617 if (i >= cl.maxclients)
1618 Host_Error ("CL_ParseServerMessage: svc_updatefrags >= cl.maxclients");
1619 cl.scores[i].frags = MSG_ReadShort ();
1622 case svc_updatecolors:
1623 i = MSG_ReadByte ();
1624 if (i >= cl.maxclients)
1625 Host_Error ("CL_ParseServerMessage: svc_updatecolors >= cl.maxclients");
1626 cl.scores[i].colors = MSG_ReadByte ();
1630 CL_ParseParticleEffect ();
1641 case svc_spawnbaseline:
1642 i = MSG_ReadShort ();
1643 if (i < 0 || i >= MAX_EDICTS)
1644 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i);
1645 CL_ParseBaseline (cl_entities + i, false);
1647 case svc_spawnbaseline2:
1648 i = MSG_ReadShort ();
1649 if (i < 0 || i >= MAX_EDICTS)
1650 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline2: invalid entity number %i", i);
1651 CL_ParseBaseline (cl_entities + i, true);
1653 case svc_spawnstatic:
1654 CL_ParseStatic (false);
1656 case svc_spawnstatic2:
1657 CL_ParseStatic (true);
1659 case svc_temp_entity:
1660 CL_ParseTempEntity ();
1664 cl.paused = MSG_ReadByte ();
1672 i = MSG_ReadByte ();
1673 if (i <= cls.signon)
1674 Host_Error ("Received signon %i when at %i", i, cls.signon);
1679 case svc_killedmonster:
1680 cl.stats[STAT_MONSTERS]++;
1683 case svc_foundsecret:
1684 cl.stats[STAT_SECRETS]++;
1687 case svc_updatestat:
1688 i = MSG_ReadByte ();
1689 if (i < 0 || i >= MAX_CL_STATS)
1690 Host_Error ("svc_updatestat: %i is invalid", i);
1691 cl.stats[i] = MSG_ReadLong ();
1694 case svc_spawnstaticsound:
1695 CL_ParseStaticSound (false);
1698 case svc_spawnstaticsound2:
1699 CL_ParseStaticSound (true);
1703 cl.cdtrack = MSG_ReadByte ();
1704 cl.looptrack = MSG_ReadByte ();
1705 if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )
1706 CDAudio_Play ((qbyte)cls.forcetrack, true);
1708 CDAudio_Play ((qbyte)cl.cdtrack, true);
1711 case svc_intermission:
1712 cl.intermission = 1;
1713 cl.completed_time = cl.time;
1717 cl.intermission = 2;
1718 cl.completed_time = cl.time;
1719 SCR_CenterPrint (MSG_ReadString ());
1723 cl.intermission = 3;
1724 cl.completed_time = cl.time;
1725 SCR_CenterPrint (MSG_ReadString ());
1728 case svc_sellscreen:
1729 Cmd_ExecuteString ("help", src_command);
1732 if (gamemode == GAME_TENEBRAE)
1734 // repeating particle effect
1747 SHOWLMP_decodehide();
1750 if (gamemode == GAME_TENEBRAE)
1760 SHOWLMP_decodeshow();
1763 R_SetSkyBox(MSG_ReadString());
1768 length = (int) ((unsigned short) MSG_ReadShort());
1769 for (i = 0;i < length;i++)
1770 cgamenetbuffer[i] = MSG_ReadByte();
1772 CL_CGVM_ParseNetwork(cgamenetbuffer, length);
1776 if (cls.signon == SIGNONS - 1)
1778 // first update is the final signon stage
1779 cls.signon = SIGNONS;
1782 CL_ReadEntityFrame();
1787 if (entitiesupdated)
1788 CL_EntityUpdateEnd();
1790 parsingerror = false;
1793 void CL_Parse_DumpPacket(void)
1797 Con_Printf("Packet dump:\n");
1798 SZ_HexDumpToConsole(&net_message);
1799 parsingerror = false;
1802 void CL_Parse_Init(void)
1804 // LordHavoc: added demo_nehahra cvar
1805 cl_scores_mempool = Mem_AllocPool("client player info");
1806 Cvar_RegisterVariable (&demo_nehahra);
1807 if (gamemode == GAME_NEHAHRA)
1808 Cvar_SetValue("demo_nehahra", 1);
1809 Cvar_RegisterVariable(&developer_networkentities);