mirror of
https://github.com/blendogames/thirtyflightsofloving.git
synced 2024-11-15 00:41:21 +00:00
911 lines
22 KiB
C
911 lines
22 KiB
C
|
/*
|
||
|
Copyright (C) 1997-2001 Id Software, Inc.
|
||
|
|
||
|
This program is free software; you can redistribute it and/or
|
||
|
modify it under the terms of the GNU General Public License
|
||
|
as published by the Free Software Foundation; either version 2
|
||
|
of the License, or (at your option) any later version.
|
||
|
|
||
|
This program is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||
|
|
||
|
See the GNU General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License
|
||
|
along with this program; if not, write to the Free Software
|
||
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||
|
|
||
|
*/
|
||
|
// cl_parse.c -- parse a message received from the server
|
||
|
|
||
|
#include "client.h"
|
||
|
|
||
|
char *svc_strings[256] =
|
||
|
{
|
||
|
"svc_bad",
|
||
|
|
||
|
"svc_muzzleflash",
|
||
|
"svc_muzzlflash2",
|
||
|
"svc_temp_entity",
|
||
|
"svc_layout",
|
||
|
"svc_inventory",
|
||
|
|
||
|
"svc_nop",
|
||
|
"svc_disconnect",
|
||
|
"svc_reconnect",
|
||
|
"svc_sound",
|
||
|
"svc_print",
|
||
|
"svc_stufftext",
|
||
|
"svc_serverdata",
|
||
|
"svc_configstring",
|
||
|
"svc_spawnbaseline",
|
||
|
"svc_centerprint",
|
||
|
"svc_download",
|
||
|
"svc_playerinfo",
|
||
|
"svc_packetentities",
|
||
|
"svc_deltapacketentities",
|
||
|
"svc_frame"
|
||
|
};
|
||
|
|
||
|
//=============================================================================
|
||
|
|
||
|
/*
|
||
|
======================
|
||
|
CL_RegisterSounds
|
||
|
======================
|
||
|
*/
|
||
|
void CL_RegisterSounds (void)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
S_BeginRegistration ();
|
||
|
CL_RegisterTEntSounds ();
|
||
|
|
||
|
// Knightmare- 1/2/2002- ULTRA-CHEESY HACK for old demos or
|
||
|
// connected to server using old protocol
|
||
|
// Changed config strings require different offsets
|
||
|
if ( LegacyProtocol() )
|
||
|
{
|
||
|
for (i=1; i < OLD_MAX_SOUNDS; i++)
|
||
|
{
|
||
|
if (!cl.configstrings[OLD_CS_SOUNDS+i][0])
|
||
|
break;
|
||
|
cl.sound_precache[i] = S_RegisterSound (cl.configstrings[OLD_CS_SOUNDS+i]);
|
||
|
Sys_SendKeyEvents (); // pump message loop
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for (i=1; i < MAX_SOUNDS; i++)
|
||
|
{
|
||
|
if (!cl.configstrings[CS_SOUNDS+i][0])
|
||
|
break;
|
||
|
cl.sound_precache[i] = S_RegisterSound (cl.configstrings[CS_SOUNDS+i]);
|
||
|
Sys_SendKeyEvents (); // pump message loop
|
||
|
}
|
||
|
}
|
||
|
//end Knightmare
|
||
|
S_EndRegistration ();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
=====================================================================
|
||
|
|
||
|
SERVER CONNECTING MESSAGES
|
||
|
|
||
|
=====================================================================
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
==================
|
||
|
LegacyProtocol
|
||
|
A utility function that determines
|
||
|
if parsing of old protocol should be used.
|
||
|
==================
|
||
|
*/
|
||
|
qboolean LegacyProtocol (void)
|
||
|
{
|
||
|
//if (dedicated->value) // Server always uses new protocol
|
||
|
// return false;
|
||
|
if ( (Com_ServerState() && cls.serverProtocol <= OLD_PROTOCOL_VERSION)
|
||
|
|| (cls.serverProtocol == OLD_PROTOCOL_VERSION) )
|
||
|
return true;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
==================
|
||
|
R1Q2Protocol
|
||
|
A utility function that determines
|
||
|
if parsing of R1Q2 protocol should be used.
|
||
|
==================
|
||
|
*/
|
||
|
qboolean R1Q2Protocol (void)
|
||
|
{
|
||
|
//if (dedicated->value) // Server always uses new protocol
|
||
|
// return false;
|
||
|
if ( cls.serverProtocol == R1Q2_PROTOCOL_VERSION )
|
||
|
return true;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
==================
|
||
|
CL_ParseServerData
|
||
|
==================
|
||
|
*/
|
||
|
void CL_ParseServerData (void)
|
||
|
{
|
||
|
extern cvar_t *fs_gamedirvar;
|
||
|
char *str;
|
||
|
int i;
|
||
|
|
||
|
Com_DPrintf ("Serverdata packet received.\n");
|
||
|
//
|
||
|
// wipe the client_state_t struct
|
||
|
//
|
||
|
CL_ClearState ();
|
||
|
cls.state = ca_connected;
|
||
|
|
||
|
// parse protocol version number
|
||
|
i = MSG_ReadLong (&net_message);
|
||
|
cls.serverProtocol = i;
|
||
|
|
||
|
// BIG HACK to let demos from release work with the 3.0x patch!!!
|
||
|
// Knightmare- also allow connectivity with servers using the old protocol
|
||
|
// if (Com_ServerState() && (i < PROTOCOL_VERSION) /*== 35*/)
|
||
|
if ( LegacyProtocol() ) {} // do nothing
|
||
|
/* else if (i == OLD_PROTOCOL_VERSION)
|
||
|
Cvar_ForceSet ("cl_servertrick", "1");
|
||
|
else if (i == PROTOCOL_VERSION)
|
||
|
Cvar_ForceSet ("cl_servertrick", "0"); // force this off for local games
|
||
|
else if (i != PROTOCOL_VERSION) */
|
||
|
else if ( (i != PROTOCOL_VERSION) && (i != OLD_PROTOCOL_VERSION) )
|
||
|
Com_Error (ERR_DROP,"Server returned version %i, not %i", i, PROTOCOL_VERSION);
|
||
|
|
||
|
cl.servercount = MSG_ReadLong (&net_message);
|
||
|
cl.attractloop = MSG_ReadByte (&net_message);
|
||
|
|
||
|
// game directory
|
||
|
str = MSG_ReadString (&net_message);
|
||
|
strncpy (cl.gamedir, str, sizeof(cl.gamedir)-1);
|
||
|
|
||
|
// set gamedir
|
||
|
if ( ( (*str && (!fs_gamedirvar->string || !*fs_gamedirvar->string || strcmp(fs_gamedirvar->string, str)))
|
||
|
|| (!*str && (fs_gamedirvar->string && *fs_gamedirvar->string)) ) // was fs_gamedirvar->string || *fs_gamedirvar->string
|
||
|
&& !cl.attractloop ) // Knightmare- don't allow demos to change this
|
||
|
Cvar_Set("game", str);
|
||
|
|
||
|
// parse player entity number
|
||
|
cl.playernum = MSG_ReadShort (&net_message);
|
||
|
|
||
|
// get the full level name
|
||
|
str = MSG_ReadString (&net_message);
|
||
|
|
||
|
if (cl.playernum == -1)
|
||
|
{ // playing a cinematic or showing a pic, not a level
|
||
|
SCR_PlayCinematic (str);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// seperate the printfs so the server message can have a color
|
||
|
Com_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");
|
||
|
con.ormask = 128;
|
||
|
Com_Printf ("%c"S_COLOR_SHADOW S_COLOR_ALT"%s\n", 2, str);
|
||
|
con.ormask = 0;
|
||
|
|
||
|
// need to prep refresh at next oportunity
|
||
|
cl.refresh_prepped = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
==================
|
||
|
CL_ParseBaseline
|
||
|
==================
|
||
|
*/
|
||
|
void CL_ParseBaseline (void)
|
||
|
{
|
||
|
entity_state_t *es;
|
||
|
int bits;
|
||
|
int newnum;
|
||
|
entity_state_t nullstate;
|
||
|
|
||
|
memset (&nullstate, 0, sizeof(nullstate));
|
||
|
|
||
|
newnum = CL_ParseEntityBits (&bits);
|
||
|
es = &cl_entities[newnum].baseline;
|
||
|
CL_ParseDelta (&nullstate, es, newnum, bits);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
CL_LoadClientinfo
|
||
|
|
||
|
================
|
||
|
*/
|
||
|
void CL_LoadClientinfo (clientinfo_t *ci, char *s)
|
||
|
{
|
||
|
int i;
|
||
|
char *t;
|
||
|
char model_name[MAX_QPATH];
|
||
|
char skin_name[MAX_QPATH];
|
||
|
char model_filename[MAX_QPATH];
|
||
|
char skin_filename[MAX_QPATH];
|
||
|
char weapon_filename[MAX_QPATH];
|
||
|
|
||
|
strncpy(ci->cinfo, s, sizeof(ci->cinfo));
|
||
|
ci->cinfo[sizeof(ci->cinfo)-1] = 0;
|
||
|
|
||
|
// isolate the player's name
|
||
|
strncpy(ci->name, s, sizeof(ci->name));
|
||
|
ci->name[sizeof(ci->name)-1] = 0;
|
||
|
t = strstr (s, "\\");
|
||
|
if (t)
|
||
|
{
|
||
|
ci->name[t-s] = 0;
|
||
|
s = t+1;
|
||
|
}
|
||
|
|
||
|
if (cl_noskins->value || *s == 0)
|
||
|
{
|
||
|
Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
|
||
|
Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/male/weapon.md2");
|
||
|
Com_sprintf (skin_filename, sizeof(skin_filename), "players/male/grunt.pcx");
|
||
|
Com_sprintf (ci->iconname, sizeof(ci->iconname), "/players/male/grunt_i.pcx");
|
||
|
ci->model = R_RegisterModel (model_filename);
|
||
|
memset(ci->weaponmodel, 0, sizeof(ci->weaponmodel));
|
||
|
ci->weaponmodel[0] = R_RegisterModel (weapon_filename);
|
||
|
ci->skin = R_RegisterSkin (skin_filename);
|
||
|
ci->icon = R_DrawFindPic (ci->iconname);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// isolate the model name
|
||
|
// strncpy (model_name, s);
|
||
|
Q_strncpyz (model_name, s, sizeof(model_name));
|
||
|
t = strstr(model_name, "/");
|
||
|
if (!t)
|
||
|
t = strstr(model_name, "\\");
|
||
|
if (!t)
|
||
|
t = model_name;
|
||
|
*t = 0;
|
||
|
|
||
|
// isolate the skin name
|
||
|
// strncpy (skin_name, s + strlen(model_name) + 1);
|
||
|
Q_strncpyz (skin_name, s + strlen(model_name) + 1, sizeof(skin_name));
|
||
|
|
||
|
// model file
|
||
|
Com_sprintf (model_filename, sizeof(model_filename), "players/%s/tris.md2", model_name);
|
||
|
ci->model = R_RegisterModel (model_filename);
|
||
|
if (!ci->model)
|
||
|
{
|
||
|
// strncpy(model_name, "male");
|
||
|
Q_strncpyz(model_name, "male", sizeof(model_name));
|
||
|
Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
|
||
|
ci->model = R_RegisterModel (model_filename);
|
||
|
}
|
||
|
|
||
|
// skin file
|
||
|
Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/%s.pcx", model_name, skin_name);
|
||
|
ci->skin = R_RegisterSkin (skin_filename);
|
||
|
|
||
|
// if we don't have the skin and the model wasn't male,
|
||
|
// see if the male has it (this is for CTF's skins)
|
||
|
if (!ci->skin && Q_stricmp(model_name, "male"))
|
||
|
{
|
||
|
// change model to male
|
||
|
// strncpy(model_name, "male");
|
||
|
Q_strncpyz(model_name, "male", sizeof(model_name));
|
||
|
Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
|
||
|
ci->model = R_RegisterModel (model_filename);
|
||
|
|
||
|
// see if the skin exists for the male model
|
||
|
Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/%s.pcx", model_name, skin_name);
|
||
|
ci->skin = R_RegisterSkin (skin_filename);
|
||
|
}
|
||
|
|
||
|
// if we still don't have a skin, it means that the male model didn't have
|
||
|
// it, so default to grunt
|
||
|
if (!ci->skin) {
|
||
|
// see if the skin exists for the male model
|
||
|
Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/grunt.pcx", model_name, skin_name);
|
||
|
ci->skin = R_RegisterSkin (skin_filename);
|
||
|
}
|
||
|
|
||
|
// weapon file
|
||
|
for (i = 0; i < num_cl_weaponmodels; i++) {
|
||
|
Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/%s/%s", model_name, cl_weaponmodels[i]);
|
||
|
ci->weaponmodel[i] = R_RegisterModel(weapon_filename);
|
||
|
if (!ci->weaponmodel[i] && strcmp(model_name, "cyborg") == 0) {
|
||
|
// try male
|
||
|
Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/male/%s", cl_weaponmodels[i]);
|
||
|
ci->weaponmodel[i] = R_RegisterModel(weapon_filename);
|
||
|
}
|
||
|
if (!cl_vwep->value)
|
||
|
break; // only one when vwep is off
|
||
|
}
|
||
|
|
||
|
// icon file
|
||
|
Com_sprintf (ci->iconname, sizeof(ci->iconname), "/players/%s/%s_i.pcx", model_name, skin_name);
|
||
|
ci->icon = R_DrawFindPic (ci->iconname);
|
||
|
}
|
||
|
|
||
|
// must have loaded all data types to be valud
|
||
|
if (!ci->skin || !ci->icon || !ci->model || !ci->weaponmodel[0])
|
||
|
{
|
||
|
ci->skin = NULL;
|
||
|
ci->icon = NULL;
|
||
|
ci->model = NULL;
|
||
|
ci->weaponmodel[0] = NULL;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
CL_ParseClientinfo
|
||
|
|
||
|
Load the skin, icon, and model for a client
|
||
|
================
|
||
|
*/
|
||
|
void CL_ParseClientinfo (int player)
|
||
|
{
|
||
|
char *s;
|
||
|
clientinfo_t *ci;
|
||
|
|
||
|
// Knightmare- 1/2/2002- GROSS HACK for old demos or
|
||
|
// connected to server using old protocol
|
||
|
// Changed config strings require different offsets
|
||
|
if ( LegacyProtocol() )
|
||
|
s = cl.configstrings[player+OLD_CS_PLAYERSKINS];
|
||
|
else
|
||
|
s = cl.configstrings[player+CS_PLAYERSKINS];
|
||
|
//end Knightmare
|
||
|
|
||
|
ci = &cl.clientinfo[player];
|
||
|
|
||
|
CL_LoadClientinfo (ci, s);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
CL_MissionPackCDTrack
|
||
|
Returns correct OGG track number for mission packs.
|
||
|
This assumes that the standard Q2 CD was ripped
|
||
|
as track02-track11, and the Rogue CD as track12-track21.
|
||
|
================
|
||
|
*/
|
||
|
int CL_MissionPackCDTrack (int tracknum)
|
||
|
{
|
||
|
if (modType("rogue") || cl_rogue_music->value)
|
||
|
{
|
||
|
if (tracknum >= 2 && tracknum <= 11)
|
||
|
return tracknum + 10;
|
||
|
else
|
||
|
return tracknum;
|
||
|
}
|
||
|
// an out-of-order mix from Q2 and Rogue CDs
|
||
|
else if (modType("xatrix") || cl_xatrix_music->value)
|
||
|
{
|
||
|
switch(tracknum)
|
||
|
{
|
||
|
case 2: return 9; break;
|
||
|
case 3: return 13; break;
|
||
|
case 4: return 14; break;
|
||
|
case 5: return 7; break;
|
||
|
case 6: return 16; break;
|
||
|
case 7: return 2; break;
|
||
|
case 8: return 15; break;
|
||
|
case 9: return 3; break;
|
||
|
case 10: return 4; break;
|
||
|
case 11: return 18; break;
|
||
|
default: return tracknum; break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
return tracknum;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
=================
|
||
|
CL_PlayBackgroundTrack
|
||
|
=================
|
||
|
*/
|
||
|
#ifdef OGG_SUPPORT
|
||
|
|
||
|
#include "snd_ogg.h"
|
||
|
|
||
|
void CL_PlayBackgroundTrack (void)
|
||
|
{
|
||
|
char name[MAX_QPATH];
|
||
|
int track;
|
||
|
|
||
|
if (!cl.refresh_prepped)
|
||
|
return;
|
||
|
|
||
|
// using a named audio track intead of numbered
|
||
|
if (strlen(cl.configstrings[CS_CDTRACK]) > 2)
|
||
|
{
|
||
|
Com_sprintf (name, sizeof(name), "music/%s.ogg", cl.configstrings[CS_CDTRACK]);
|
||
|
if (FS_LoadFile(name, NULL) != -1)
|
||
|
{
|
||
|
CDAudio_Stop();
|
||
|
S_StartBackgroundTrack(name, name);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
track = atoi(cl.configstrings[CS_CDTRACK]);
|
||
|
|
||
|
if (track == 0)
|
||
|
{ // Stop any playing track
|
||
|
CDAudio_Stop();
|
||
|
S_StopBackgroundTrack();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// If an OGG file exists play it, otherwise fall back to CD audio
|
||
|
Com_sprintf (name, sizeof(name), "music/track%02i.ogg", CL_MissionPackCDTrack(track));
|
||
|
if ( (FS_LoadFile(name, NULL) != -1) && cl_ogg_music->value )
|
||
|
S_StartBackgroundTrack(name, name);
|
||
|
else
|
||
|
CDAudio_Play(track, true);
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
|
||
|
void CL_PlayBackgroundTrack (void)
|
||
|
{
|
||
|
CDAudio_Play (atoi(cl.configstrings[CS_CDTRACK]), true);
|
||
|
}
|
||
|
|
||
|
#endif // OGG_SUPPORT
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
CL_ParseConfigString
|
||
|
================
|
||
|
*/
|
||
|
void CL_ParseConfigString (void)
|
||
|
{
|
||
|
int i;
|
||
|
int max_models, max_sounds, max_images, cs_lights, cs_sounds, cs_images, cs_playerskins;
|
||
|
char *s;
|
||
|
char olds[MAX_QPATH];
|
||
|
size_t length;
|
||
|
|
||
|
// Knightmare- hack for connected to server using old protocol
|
||
|
// Changed config strings require different parsing
|
||
|
if ( LegacyProtocol() )
|
||
|
{
|
||
|
max_models = OLD_MAX_MODELS;
|
||
|
max_sounds = OLD_MAX_SOUNDS;
|
||
|
max_images = OLD_MAX_IMAGES;
|
||
|
cs_lights = OLD_CS_LIGHTS;
|
||
|
cs_sounds = OLD_CS_SOUNDS;
|
||
|
cs_images = OLD_CS_IMAGES;
|
||
|
cs_playerskins = OLD_CS_PLAYERSKINS;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
max_models = MAX_MODELS;
|
||
|
max_sounds = MAX_SOUNDS;
|
||
|
max_images = MAX_IMAGES;
|
||
|
cs_lights = CS_LIGHTS;
|
||
|
cs_sounds = CS_SOUNDS;
|
||
|
cs_images = CS_IMAGES;
|
||
|
cs_playerskins = CS_PLAYERSKINS;
|
||
|
}
|
||
|
|
||
|
i = MSG_ReadShort (&net_message);
|
||
|
if (i < 0 || i >= MAX_CONFIGSTRINGS)
|
||
|
Com_Error (ERR_DROP, "configstring > MAX_CONFIGSTRINGS");
|
||
|
s = MSG_ReadString(&net_message);
|
||
|
|
||
|
// strncpy (olds, cl.configstrings[i], sizeof(olds));
|
||
|
// olds[sizeof(olds) - 1] = 0;
|
||
|
Q_strncpyz (olds, cl.configstrings[i], sizeof(olds));
|
||
|
|
||
|
// check length
|
||
|
length = strlen(s);
|
||
|
if ( length >= (sizeof(cl.configstrings[0]) * (MAX_CONFIGSTRINGS - i)) - 1 )
|
||
|
Com_Error (ERR_DROP, "CL_ParseConfigString: string %d exceeds available buffer space!", i);
|
||
|
|
||
|
// Don't use a null-terminated strncpy here!!
|
||
|
// strcpy (cl.configstrings[i], s);
|
||
|
if (i >= CS_STATUSBAR && i < CS_AIRACCEL) { // allow writes to statusbar strings to overflow
|
||
|
strncpy (cl.configstrings[i], s, (sizeof(cl.configstrings[i]) * (CS_AIRACCEL - i))-1 );
|
||
|
cl.configstrings[CS_AIRACCEL-1][MAX_QPATH-1] = 0; // null terminate end of section
|
||
|
}
|
||
|
else if ( LegacyProtocol() && (i >= OLD_CS_GENERAL && i < OLD_MAX_CONFIGSTRINGS) ) { // allow writes to general strings to overflow
|
||
|
strncpy (cl.configstrings[i], s, (sizeof(cl.configstrings[i]) * (OLD_MAX_CONFIGSTRINGS - i))-1 );
|
||
|
cl.configstrings[OLD_MAX_CONFIGSTRINGS-1][MAX_QPATH-1] = 0; // null terminate end of section
|
||
|
}
|
||
|
else if ( !LegacyProtocol() && (i >= CS_GENERAL && i < CS_PAKFILE) ) { // allow writes to general strings to overflow
|
||
|
strncpy (cl.configstrings[i], s, (sizeof(cl.configstrings[i]) * (CS_PAKFILE - i))-1 );
|
||
|
cl.configstrings[CS_PAKFILE-1][MAX_QPATH-1] = 0; // null terminate end of section
|
||
|
}
|
||
|
else {
|
||
|
if (length >= MAX_PATH)
|
||
|
Com_Printf(S_COLOR_YELLOW"CL_ParseConfigString: string %d of length %d exceeds MAX_QPATH.\n", i, (int)length);
|
||
|
Q_strncpyz (cl.configstrings[i], s, sizeof(cl.configstrings[i]));
|
||
|
}
|
||
|
|
||
|
// do something apropriate
|
||
|
if (i >= cs_lights && i < cs_lights+MAX_LIGHTSTYLES)
|
||
|
CL_SetLightstyle (i - cs_lights);
|
||
|
else if (i == CS_CDTRACK)
|
||
|
{
|
||
|
if (cl.refresh_prepped)
|
||
|
CL_PlayBackgroundTrack ();
|
||
|
}
|
||
|
else if (i == CS_MAXCLIENTS) // from R1Q2
|
||
|
{
|
||
|
if (!cl.attractloop)
|
||
|
cl.maxclients = atoi(cl.configstrings[CS_MAXCLIENTS]);
|
||
|
}
|
||
|
else if (i >= CS_MODELS && i < CS_MODELS+max_models)
|
||
|
{
|
||
|
if (cl.refresh_prepped)
|
||
|
{
|
||
|
cl.model_draw[i-CS_MODELS] = R_RegisterModel (cl.configstrings[i]);
|
||
|
if (cl.configstrings[i][0] == '*')
|
||
|
cl.model_clip[i-CS_MODELS] = CM_InlineModel (cl.configstrings[i]);
|
||
|
else
|
||
|
cl.model_clip[i-CS_MODELS] = NULL;
|
||
|
}
|
||
|
}
|
||
|
else if (i >= cs_sounds && i < cs_sounds+max_sounds) // Knightmare- was MAX_MODELS
|
||
|
{
|
||
|
if (cl.refresh_prepped)
|
||
|
cl.sound_precache[i-cs_sounds] = S_RegisterSound (cl.configstrings[i]);
|
||
|
}
|
||
|
else if (i >= cs_images && i < cs_images+max_images) // Knightmare- was MAX_IMAGES
|
||
|
{
|
||
|
if (cl.refresh_prepped)
|
||
|
cl.image_precache[i-cs_images] = R_DrawFindPic (cl.configstrings[i]);
|
||
|
}
|
||
|
else if (i >= cs_playerskins && i < cs_playerskins+MAX_CLIENTS)
|
||
|
{
|
||
|
// from R1Q2- a hack to avoid parsing non-skins from mods that overload CS_PLAYERSKINS
|
||
|
if ( (i-cs_playerskins) < cl.maxclients ) {
|
||
|
if (cl.refresh_prepped && strcmp(olds, s))
|
||
|
CL_ParseClientinfo (i-cs_playerskins);
|
||
|
}
|
||
|
else {
|
||
|
Com_DPrintf ("CL_ParseConfigString: Ignoring out-of-range playerskin %d (%s)\n", i, MakePrintable(s, 0));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
=====================================================================
|
||
|
|
||
|
ACTION MESSAGES
|
||
|
|
||
|
=====================================================================
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
==================
|
||
|
CL_ParseStartSoundPacket
|
||
|
==================
|
||
|
*/
|
||
|
void CL_ParseStartSoundPacket(void)
|
||
|
{
|
||
|
vec3_t pos_v;
|
||
|
float *pos;
|
||
|
int channel, ent;
|
||
|
int sound_num;
|
||
|
float volume;
|
||
|
float attenuation;
|
||
|
int flags;
|
||
|
float ofs;
|
||
|
|
||
|
flags = MSG_ReadByte (&net_message);
|
||
|
|
||
|
// Knightmare- 12/23/2001
|
||
|
// read sound indices as bytes only if playing old demos or
|
||
|
// connected to server using old protocol; otherwise, read as shorts
|
||
|
if ( LegacyProtocol() )
|
||
|
sound_num = MSG_ReadByte (&net_message);
|
||
|
else
|
||
|
sound_num = MSG_ReadShort (&net_message);
|
||
|
//end Knightmare
|
||
|
|
||
|
if (flags & SND_VOLUME)
|
||
|
volume = MSG_ReadByte (&net_message) / 255.0;
|
||
|
else
|
||
|
volume = DEFAULT_SOUND_PACKET_VOLUME;
|
||
|
|
||
|
if (flags & SND_ATTENUATION)
|
||
|
attenuation = MSG_ReadByte (&net_message) / 64.0;
|
||
|
else
|
||
|
attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;
|
||
|
|
||
|
if (flags & SND_OFFSET)
|
||
|
ofs = MSG_ReadByte (&net_message) / 1000.0;
|
||
|
else
|
||
|
ofs = 0;
|
||
|
|
||
|
if (flags & SND_ENT)
|
||
|
{ // entity reletive
|
||
|
channel = MSG_ReadShort(&net_message);
|
||
|
ent = channel>>3;
|
||
|
if (ent > MAX_EDICTS)
|
||
|
Com_Error (ERR_DROP,"CL_ParseStartSoundPacket: ent = %i", ent);
|
||
|
|
||
|
channel &= 7;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ent = 0;
|
||
|
channel = 0;
|
||
|
}
|
||
|
|
||
|
if (flags & SND_POS)
|
||
|
{ // positioned in space
|
||
|
MSG_ReadPos (&net_message, pos_v);
|
||
|
|
||
|
pos = pos_v;
|
||
|
}
|
||
|
else // use entity number
|
||
|
pos = NULL;
|
||
|
|
||
|
if (!cl.sound_precache[sound_num])
|
||
|
return;
|
||
|
|
||
|
S_StartSound (pos, ent, channel, cl.sound_precache[sound_num], volume, attenuation, ofs);
|
||
|
}
|
||
|
|
||
|
|
||
|
void SHOWNET(char *s)
|
||
|
{
|
||
|
if (cl_shownet->value>=2)
|
||
|
Com_Printf ("%3i:%s\n", net_message.readcount-1, s);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
=====================
|
||
|
CL_ParseStuffText
|
||
|
Catches stuffed quit or error commands from the server.
|
||
|
Shutting down suddenly in this way can hang some SMP systems.
|
||
|
This simply disconnects, same effect as kicking player.
|
||
|
=====================
|
||
|
*/
|
||
|
/*qboolean CL_ParseStuffText (char *stufftext)
|
||
|
{
|
||
|
char *parsetext = stufftext;
|
||
|
|
||
|
// skip leading spaces
|
||
|
while (*parsetext == ' ') parsetext++;
|
||
|
if (strncmp(parsetext, "quit", 4))
|
||
|
{
|
||
|
Com_Printf("server stuffed quit command, disconnecting...\n");
|
||
|
CL_Disconnect ();
|
||
|
return false;
|
||
|
}
|
||
|
if (strncmp(parsetext, "error", 5))
|
||
|
{
|
||
|
Com_Printf("server stuffed error command, disconnecting...\n");
|
||
|
CL_Disconnect ();
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}*/
|
||
|
|
||
|
|
||
|
// Knightmare- server-controlled fog
|
||
|
/*
|
||
|
=====================
|
||
|
CL_ParseFog
|
||
|
=====================
|
||
|
*/
|
||
|
// Fog is sent like this:
|
||
|
// gi.WriteByte (svc_fog); // svc_fog = 21
|
||
|
// gi.WriteByte (fog_enable); // 1 = on, 0 = off
|
||
|
// gi.WriteByte (fog_model); // 0, 1, or 2
|
||
|
// gi.WriteByte (fog_density); // 1-100
|
||
|
// gi.WriteShort (fog_near); // >0, <fog_far
|
||
|
// gi.WriteShort (fog_far); // >fog_near-64, <5000
|
||
|
// gi.WriteByte (fog_red); // 0-255
|
||
|
// gi.WriteByte (fog_green); // 0-255
|
||
|
// gi.WriteByte (fog_blue); // 0-255
|
||
|
// gi.unicast (player_ent, true);
|
||
|
|
||
|
void CL_ParseFog (void)
|
||
|
{
|
||
|
qboolean fogenable;
|
||
|
int model, density, start, end,
|
||
|
red, green, blue, temp;
|
||
|
|
||
|
temp = MSG_ReadByte (&net_message);
|
||
|
fogenable = (temp > 0) ? true:false;
|
||
|
model = MSG_ReadByte (&net_message);
|
||
|
density = MSG_ReadByte (&net_message);
|
||
|
start = MSG_ReadShort (&net_message);
|
||
|
end = MSG_ReadShort (&net_message);
|
||
|
red = MSG_ReadByte (&net_message);
|
||
|
green = MSG_ReadByte (&net_message);
|
||
|
blue = MSG_ReadByte (&net_message);
|
||
|
|
||
|
// R_SetFogVars (fogenable, model, density, start, end, red, green, blue);
|
||
|
V_SetFogInfo (fogenable, model, density, start, end, red, green, blue);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
=====================
|
||
|
CL_ParseServerMessage
|
||
|
=====================
|
||
|
*/
|
||
|
void CL_ParseServerMessage (void)
|
||
|
{
|
||
|
int cmd;
|
||
|
char *s;
|
||
|
int i;
|
||
|
|
||
|
//
|
||
|
// if recording demos, copy the message out
|
||
|
//
|
||
|
if (cl_shownet->value == 1)
|
||
|
Com_Printf ("%i ",net_message.cursize);
|
||
|
else if (cl_shownet->value >= 2)
|
||
|
Com_Printf ("------------------\n");
|
||
|
|
||
|
|
||
|
//
|
||
|
// parse the message
|
||
|
//
|
||
|
while (1)
|
||
|
{
|
||
|
if (net_message.readcount > net_message.cursize)
|
||
|
{
|
||
|
Com_Error (ERR_DROP,"CL_ParseServerMessage: Bad server message");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
cmd = MSG_ReadByte (&net_message);
|
||
|
|
||
|
if (cmd == -1)
|
||
|
{
|
||
|
SHOWNET("END OF MESSAGE");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (cl_shownet->value>=2)
|
||
|
{
|
||
|
if (!svc_strings[cmd])
|
||
|
Com_Printf ("%3i:BAD CMD %i\n", net_message.readcount-1,cmd);
|
||
|
else
|
||
|
SHOWNET(svc_strings[cmd]);
|
||
|
}
|
||
|
|
||
|
// other commands
|
||
|
switch (cmd)
|
||
|
{
|
||
|
default:
|
||
|
Com_Error (ERR_DROP,"CL_ParseServerMessage: Illegible server message\n");
|
||
|
break;
|
||
|
|
||
|
case svc_nop:
|
||
|
// Com_Printf ("svc_nop\n");
|
||
|
break;
|
||
|
|
||
|
case svc_disconnect:
|
||
|
Com_Error (ERR_DISCONNECT,"Server disconnected\n");
|
||
|
break;
|
||
|
|
||
|
case svc_reconnect:
|
||
|
Com_Printf ("Server disconnected, reconnecting\n");
|
||
|
if (cls.download) {
|
||
|
//ZOID, close download
|
||
|
fclose (cls.download);
|
||
|
cls.download = NULL;
|
||
|
}
|
||
|
cls.state = ca_connecting;
|
||
|
cls.connect_time = -99999; // CL_CheckForResend() will fire immediately
|
||
|
break;
|
||
|
|
||
|
case svc_print:
|
||
|
i = MSG_ReadByte (&net_message);
|
||
|
if (i == PRINT_CHAT)
|
||
|
{
|
||
|
S_StartLocalSound ("misc/talk.wav");
|
||
|
con.ormask = 128;
|
||
|
Com_Printf (S_COLOR_ALT"%s", MSG_ReadString (&net_message)); // Knightmare- add green flag
|
||
|
}
|
||
|
else
|
||
|
Com_Printf ("%s", MSG_ReadString (&net_message));
|
||
|
con.ormask = 0;
|
||
|
break;
|
||
|
|
||
|
case svc_centerprint:
|
||
|
SCR_CenterPrint (MSG_ReadString (&net_message));
|
||
|
break;
|
||
|
|
||
|
case svc_stufftext:
|
||
|
s = MSG_ReadString (&net_message);
|
||
|
Com_DPrintf ("stufftext: %s\n", s);
|
||
|
Cbuf_AddText (s);
|
||
|
break;
|
||
|
|
||
|
case svc_serverdata:
|
||
|
Cbuf_Execute (); // make sure any stuffed commands are done
|
||
|
CL_ParseServerData ();
|
||
|
break;
|
||
|
|
||
|
case svc_configstring:
|
||
|
CL_ParseConfigString ();
|
||
|
break;
|
||
|
|
||
|
case svc_sound:
|
||
|
CL_ParseStartSoundPacket();
|
||
|
break;
|
||
|
|
||
|
case svc_spawnbaseline:
|
||
|
CL_ParseBaseline ();
|
||
|
break;
|
||
|
|
||
|
case svc_temp_entity:
|
||
|
CL_ParseTEnt ();
|
||
|
break;
|
||
|
|
||
|
case svc_muzzleflash:
|
||
|
CL_ParseMuzzleFlash ();
|
||
|
break;
|
||
|
|
||
|
case svc_muzzleflash2:
|
||
|
CL_ParseMuzzleFlash2 ();
|
||
|
break;
|
||
|
|
||
|
case svc_download:
|
||
|
CL_ParseDownload ();
|
||
|
break;
|
||
|
|
||
|
case svc_frame:
|
||
|
CL_ParseFrame ();
|
||
|
break;
|
||
|
|
||
|
case svc_inventory:
|
||
|
CL_ParseInventory ();
|
||
|
break;
|
||
|
|
||
|
case svc_fog: // Knightmare added
|
||
|
CL_ParseFog ();
|
||
|
break;
|
||
|
|
||
|
case svc_layout:
|
||
|
s = MSG_ReadString (&net_message);
|
||
|
strncpy (cl.layout, s, sizeof(cl.layout)-1);
|
||
|
break;
|
||
|
|
||
|
case svc_playerinfo:
|
||
|
case svc_packetentities:
|
||
|
case svc_deltapacketentities:
|
||
|
Com_Error (ERR_DROP, "Out of place frame data");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CL_AddNetgraph ();
|
||
|
|
||
|
//
|
||
|
// we don't know if it is ok to save a demo message until
|
||
|
// after we have parsed the frame
|
||
|
//
|
||
|
if (cls.demorecording && !cls.demowaiting)
|
||
|
CL_WriteDemoMessage ();
|
||
|
|
||
|
}
|
||
|
|
||
|
|