+ Con_Printf("svc_updateuserinfo >= cl.maxclients\n");
+ MSG_ReadLong();
+ MSG_ReadString();
+ return;
+ }
+ cl.scores[slot].qw_userid = MSG_ReadLong();
+ strlcpy(cl.scores[slot].qw_userinfo, MSG_ReadString(), sizeof(cl.scores[slot].qw_userinfo));
+
+ QW_CL_ProcessUserInfo(slot);
+}
+
+static void QW_CL_SetInfo(void)
+{
+ int slot;
+ char key[2048];
+ char value[2048];
+ slot = MSG_ReadByte();
+ strlcpy(key, MSG_ReadString(), sizeof(key));
+ strlcpy(value, MSG_ReadString(), sizeof(value));
+ if (slot >= cl.maxclients)
+ {
+ Con_Printf("svc_setinfo >= cl.maxclients\n");
+ return;
+ }
+ InfoString_SetValue(cl.scores[slot].qw_userinfo, sizeof(cl.scores[slot].qw_userinfo), key, value);
+
+ QW_CL_ProcessUserInfo(slot);
+}
+
+static void QW_CL_ServerInfo(void)
+{
+ char key[2048];
+ char value[2048];
+ char temp[32];
+ strlcpy(key, MSG_ReadString(), sizeof(key));
+ strlcpy(value, MSG_ReadString(), sizeof(value));
+ Con_DPrintf("SERVERINFO: %s=%s\n", key, value);
+ InfoString_SetValue(cl.qw_serverinfo, sizeof(cl.qw_serverinfo), key, value);
+ InfoString_GetValue(cl.qw_serverinfo, "teamplay", temp, sizeof(temp));
+ cl.qw_teamplay = atoi(temp);
+}
+
+static void QW_CL_ParseNails(void)
+{
+ int i, j;
+ int numnails = MSG_ReadByte();
+ vec_t *v;
+ unsigned char bits[6];
+ for (i = 0;i < numnails;i++)
+ {
+ for (j = 0;j < 6;j++)
+ bits[j] = MSG_ReadByte();
+ if (cl.qw_num_nails > 255)
+ continue;
+ v = cl.qw_nails[cl.qw_num_nails++];
+ v[0] = ( ( bits[0] + ((bits[1]&15)<<8) ) <<1) - 4096;
+ v[1] = ( ( (bits[1]>>4) + (bits[2]<<4) ) <<1) - 4096;
+ v[2] = ( ( bits[3] + ((bits[4]&15)<<8) ) <<1) - 4096;
+ v[3] = -360*(bits[4]>>4)/16;
+ v[4] = 360*bits[5]/256;
+ v[5] = 0;
+ }
+}
+
+static void CL_UpdateItemsAndWeapon(void)
+{
+ int j;
+ // check for important changes
+
+ // set flash times
+ if (cl.olditems != cl.stats[STAT_ITEMS])
+ for (j = 0;j < 32;j++)
+ if ((cl.stats[STAT_ITEMS] & (1<<j)) && !(cl.olditems & (1<<j)))
+ cl.item_gettime[j] = cl.time;
+ cl.olditems = cl.stats[STAT_ITEMS];
+
+ // GAME_NEXUIZ hud needs weapon change time
+ if (cl.activeweapon != cl.stats[STAT_ACTIVEWEAPON])
+ cl.weapontime = cl.time;
+ cl.activeweapon = cl.stats[STAT_ACTIVEWEAPON];
+}
+
+/*
+=====================
+CL_SignonReply
+
+An svc_signonnum has been received, perform a client side setup
+=====================
+*/
+static void CL_SignonReply (void)
+{
+ Con_DPrintf("CL_SignonReply: %i\n", cls.signon);
+
+ switch (cls.signon)
+ {
+ case 1:
+ if (cls.netcon)
+ {
+ MSG_WriteByte (&cls.netcon->message, clc_stringcmd);
+ MSG_WriteString (&cls.netcon->message, "prespawn");
+ }
+ break;
+
+ case 2:
+ if (cls.netcon)
+ {
+ MSG_WriteByte (&cls.netcon->message, clc_stringcmd);
+ MSG_WriteString (&cls.netcon->message, va("name \"%s\"", cl_name.string));
+
+ MSG_WriteByte (&cls.netcon->message, clc_stringcmd);
+ MSG_WriteString (&cls.netcon->message, va("color %i %i", cl_color.integer >> 4, cl_color.integer & 15));
+
+ if (cl_pmodel.integer)
+ {
+ MSG_WriteByte (&cls.netcon->message, clc_stringcmd);
+ MSG_WriteString (&cls.netcon->message, va("pmodel %i", cl_pmodel.integer));
+ }
+ if (*cl_playermodel.string)
+ {
+ MSG_WriteByte (&cls.netcon->message, clc_stringcmd);
+ MSG_WriteString (&cls.netcon->message, va("playermodel %s", cl_playermodel.string));
+ }
+ if (*cl_playerskin.string)
+ {
+ MSG_WriteByte (&cls.netcon->message, clc_stringcmd);
+ MSG_WriteString (&cls.netcon->message, va("playerskin %s", cl_playerskin.string));
+ }
+
+ MSG_WriteByte (&cls.netcon->message, clc_stringcmd);
+ MSG_WriteString (&cls.netcon->message, va("rate %i", cl_rate.integer));
+
+ MSG_WriteByte (&cls.netcon->message, clc_stringcmd);
+ MSG_WriteString (&cls.netcon->message, "spawn");
+ }
+ break;
+
+ case 3:
+ if (cls.netcon)
+ {
+ MSG_WriteByte (&cls.netcon->message, clc_stringcmd);
+ MSG_WriteString (&cls.netcon->message, "begin");
+ }
+ break;
+
+ case 4:
+ Con_ClearNotify();
+ break;
+ }
+}
+
+/*
+==================
+CL_ParseServerInfo
+==================
+*/
+void CL_ParseServerInfo (void)
+{
+ char *str;
+ int i;
+ protocolversion_t protocol;
+ int nummodels, numsounds;
+
+ Con_DPrint("Serverinfo packet received.\n");
+
+ // if server is active, we already began a loading plaque
+ if (!sv.active)
+ SCR_BeginLoadingPlaque();
+
+ // check memory integrity
+ Mem_CheckSentinelsGlobal();
+
+//
+// wipe the client_state_t struct
+//
+ CL_ClearState ();
+
+// parse protocol version number
+ i = MSG_ReadLong ();
+ protocol = Protocol_EnumForNumber(i);
+ if (protocol == PROTOCOL_UNKNOWN)
+ {
+ Host_Error("CL_ParseServerInfo: Server is unrecognized protocol number (%i)", i);
+ return;
+ }
+ // hack for unmarked Nehahra movie demos which had a custom protocol
+ if (protocol == PROTOCOL_QUAKEDP && cls.demoplayback && demo_nehahra.integer)
+ protocol = PROTOCOL_NEHAHRAMOVIE;
+ cls.protocol = protocol;
+ Con_DPrintf("Server protocol is %s\n", Protocol_NameForEnum(cls.protocol));
+
+ cl.num_entities = 1;
+
+ if (protocol == PROTOCOL_QUAKEWORLD)
+ {
+ cl.qw_servercount = MSG_ReadLong();
+
+ str = MSG_ReadString();
+ Con_Printf("server gamedir is %s\n", str);
+#if 0
+ // FIXME: change gamedir if needed!
+ if (strcasecmp(gamedirfile, str))
+ {
+ Host_SaveConfig_f();
+ cflag = 1;
+ }
+
+ Com_Gamedir(str); // change gamedir
+
+ if (cflag)
+ {
+ // exec the new config stuff
+ }
+#endif
+
+ cl.gametype = GAME_DEATHMATCH;
+ cl.maxclients = 32;
+
+ // parse player number
+ i = MSG_ReadByte();
+ cl.qw_spectator = (i & 128) != 0;
+ cl.playerentity = cl.viewentity = (i & 127) + 1;
+ cl.scores = (scoreboard_t *)Mem_Alloc(cls.levelmempool, cl.maxclients*sizeof(*cl.scores));
+
+ // get the full level name
+ str = MSG_ReadString ();
+ strlcpy (cl.levelname, str, sizeof(cl.levelname));
+
+ // get the movevars
+ cl.qw_movevars_gravity = MSG_ReadFloat();
+ cl.qw_movevars_stopspeed = MSG_ReadFloat();
+ cl.qw_movevars_maxspeed = MSG_ReadFloat();
+ cl.qw_movevars_spectatormaxspeed = MSG_ReadFloat();
+ cl.qw_movevars_accelerate = MSG_ReadFloat();
+ cl.qw_movevars_airaccelerate = MSG_ReadFloat();
+ cl.qw_movevars_wateraccelerate = MSG_ReadFloat();
+ cl.qw_movevars_friction = MSG_ReadFloat();
+ cl.qw_movevars_waterfriction = MSG_ReadFloat();
+ cl.qw_movevars_entgravity = MSG_ReadFloat();
+
+ // seperate the printfs so the server message can have a color
+ 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);
+
+ // check memory integrity
+ Mem_CheckSentinelsGlobal();
+
+ if (cls.netcon)
+ {
+ MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
+ MSG_WriteString(&cls.netcon->message, va("soundlist %i %i", cl.qw_servercount, 0));
+ }
+
+ cls.state = ca_connected;
+ cls.signon = 1;
+
+ // note: on QW protocol we can't set up the gameworld until after
+ // downloads finish...
+ // (we don't even know the name of the map yet)
+ }
+ else
+ {
+ // parse maxclients
+ cl.maxclients = MSG_ReadByte ();
+ if (cl.maxclients < 1 || cl.maxclients > MAX_SCOREBOARD)
+ {
+ Host_Error("Bad maxclients (%u) from server", cl.maxclients);
+ return;
+ }
+ cl.scores = (scoreboard_t *)Mem_Alloc(cls.levelmempool, cl.maxclients*sizeof(*cl.scores));
+
+ // parse gametype
+ cl.gametype = MSG_ReadByte ();
+
+ // parse signon message
+ str = MSG_ReadString ();
+ strlcpy (cl.levelname, str, sizeof(cl.levelname));
+
+ // seperate the printfs so the server message can have a color
+ if (cls.protocol != PROTOCOL_NEHAHRAMOVIE) // no messages when playing the Nehahra movie
+ 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);
+
+ // check memory integrity
+ Mem_CheckSentinelsGlobal();
+
+ // parse model precache list
+ for (nummodels=1 ; ; nummodels++)