This repository has been archived on 2022-06-27. You can view files and clone it, but cannot push or open issues or pull requests.
Xash3DArchive/engine/client/cl_main.c

1769 lines
39 KiB
C
Raw Normal View History

2007-06-21 22:00:00 +02:00
/*
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_main.c -- client main loop
2007-09-11 22:00:00 +02:00
#include <windows.h>
2007-06-21 22:00:00 +02:00
#include "client.h"
cvar_t *freelook;
cvar_t *adr0;
cvar_t *adr1;
cvar_t *adr2;
cvar_t *adr3;
cvar_t *adr4;
cvar_t *adr5;
cvar_t *adr6;
cvar_t *adr7;
cvar_t *adr8;
cvar_t *rcon_client_password;
cvar_t *rcon_address;
cvar_t *cl_noskins;
cvar_t *cl_autoskins;
cvar_t *cl_footsteps;
cvar_t *cl_timeout;
cvar_t *cl_predict;
//cvar_t *cl_minfps;
cvar_t *cl_maxfps;
cvar_t *cl_gun;
cvar_t *cl_add_particles;
cvar_t *cl_add_lights;
cvar_t *cl_add_entities;
cvar_t *cl_add_blend;
cvar_t *cl_shownet;
cvar_t *cl_showmiss;
cvar_t *cl_showclamp;
cvar_t *cl_paused;
cvar_t *cl_timedemo;
cvar_t *lookspring;
cvar_t *lookstrafe;
cvar_t *sensitivity;
cvar_t *m_pitch;
cvar_t *m_yaw;
cvar_t *m_forward;
cvar_t *m_side;
cvar_t *cl_lightlevel;
//
// userinfo
//
cvar_t *info_password;
cvar_t *info_spectator;
cvar_t *name;
cvar_t *skin;
cvar_t *rate;
cvar_t *fov;
cvar_t *msg;
cvar_t *hand;
cvar_t *gender;
cvar_t *gender_auto;
cvar_t *cl_vwep;
client_static_t cls;
2007-11-04 22:00:00 +01:00
client_t cl;
2007-06-21 22:00:00 +02:00
centity_t cl_entities[MAX_EDICTS];
entity_state_t cl_parse_entities[MAX_PARSE_ENTITIES];
extern cvar_t *allow_download;
extern cvar_t *allow_download_players;
extern cvar_t *allow_download_models;
extern cvar_t *allow_download_sounds;
extern cvar_t *allow_download_maps;
2007-09-11 22:00:00 +02:00
extern HWND cl_hwnd;
2007-06-21 22:00:00 +02:00
//======================================================================
/*
====================
CL_WriteDemoMessage
Dumps the current net message, prefixed by the length
====================
*/
void CL_WriteDemoMessage (void)
{
int len, swlen;
// the first eight bytes are just packet sequencing stuff
len = net_message.cursize-8;
swlen = LittleLong(len);
FS_Write (cls.demofile, &swlen, 4);
FS_Write (cls.demofile, net_message.data + 8, len );
}
/*
====================
CL_Stop_f
stop recording a demo
====================
*/
void CL_Stop_f (void)
{
int len;
if (!cls.demorecording)
{
2007-07-28 22:00:00 +02:00
Msg ("Not recording a demo.\n");
2007-06-21 22:00:00 +02:00
return;
}
// finish up
len = -1;
FS_Write (cls.demofile, &len, 4 );
FS_Close (cls.demofile);
cls.demofile = NULL;
cls.demorecording = false;
2007-07-28 22:00:00 +02:00
Msg ("Stopped demo.\n");
2007-06-21 22:00:00 +02:00
}
/*
====================
CL_Record_f
record <demoname>
Begins recording a demo from the current position
====================
*/
void CL_Record_f (void)
{
char name[MAX_OSPATH];
char buf_data[MAX_MSGLEN];
sizebuf_t buf;
int i;
int len;
entity_state_t *ent;
entity_state_t nullstate;
if (Cmd_Argc() != 2)
{
2007-07-28 22:00:00 +02:00
Msg ("record <demoname>\n");
2007-06-21 22:00:00 +02:00
return;
}
if (cls.demorecording)
{
2007-07-28 22:00:00 +02:00
Msg ("Already recording.\n");
2007-06-21 22:00:00 +02:00
return;
}
if (cls.state != ca_active)
{
2007-07-28 22:00:00 +02:00
Msg ("You must be in a level to record.\n");
2007-06-21 22:00:00 +02:00
return;
}
// open the demo file
2007-08-11 22:00:00 +02:00
sprintf (name, "demos/%s.dm2", Cmd_Argv(1));
2007-06-21 22:00:00 +02:00
2007-07-28 22:00:00 +02:00
Msg ("recording to %s.\n", name);
2007-06-21 22:00:00 +02:00
cls.demofile = FS_Open (name, "wb");
if (!cls.demofile)
{
2007-07-28 22:00:00 +02:00
Msg ("ERROR: couldn't open.\n");
2007-06-21 22:00:00 +02:00
return;
}
cls.demorecording = true;
// don't start saving messages until a non-delta compressed message is received
cls.demowaiting = true;
//
// write out messages to hold the startup information
//
SZ_Init (&buf, buf_data, sizeof(buf_data));
// send the serverdata
MSG_WriteByte (&buf, svc_serverdata);
MSG_WriteLong (&buf, PROTOCOL_VERSION);
MSG_WriteLong (&buf, 0x10000 + cl.servercount);
MSG_WriteByte (&buf, 1); // demos are always attract loops
MSG_WriteString (&buf, cl.gamedir);
MSG_WriteShort (&buf, cl.playernum);
MSG_WriteString (&buf, cl.configstrings[CS_NAME]);
// configstrings
for (i=0 ; i<MAX_CONFIGSTRINGS ; i++)
{
if (cl.configstrings[i][0])
{
if (buf.cursize + strlen (cl.configstrings[i]) + 32 > buf.maxsize)
{ // write it out
len = LittleLong (buf.cursize);
FS_Write (cls.demofile, &len, 4 );
FS_Write (cls.demofile, buf.data, buf.cursize );
buf.cursize = 0;
}
MSG_WriteByte (&buf, svc_configstring);
MSG_WriteShort (&buf, i);
MSG_WriteString (&buf, cl.configstrings[i]);
}
}
// baselines
memset (&nullstate, 0, sizeof(nullstate));
for (i=0; i<MAX_EDICTS ; i++)
{
ent = &cl_entities[i].baseline;
if (!ent->modelindex)
continue;
if (buf.cursize + 64 > buf.maxsize)
{ // write it out
len = LittleLong (buf.cursize);
FS_Write(cls.demofile, &len, 4 );
FS_Write(cls.demofile, buf.data, buf.cursize );
buf.cursize = 0;
}
MSG_WriteByte (&buf, svc_spawnbaseline);
MSG_WriteDeltaEntity (&nullstate, &cl_entities[i].baseline, &buf, true, true);
}
MSG_WriteByte (&buf, svc_stufftext);
MSG_WriteString (&buf, "precache\n");
// write it to the demo file
len = LittleLong (buf.cursize);
FS_Write (cls.demofile, &len, 4 );
FS_Write (cls.demofile, buf.data, buf.cursize );
// the rest of the demo file will be individual frames
}
//======================================================================
/*
===================
Cmd_ForwardToServer
adds the current command line as a clc_stringcmd to the client message.
things like godmode, noclip, etc, are commands directed to the server,
so when they are typed in at the console, they will need to be forwarded.
===================
*/
void Cmd_ForwardToServer (void)
{
char *cmd;
cmd = Cmd_Argv(0);
if (cls.state <= ca_connected || *cmd == '-' || *cmd == '+')
{
2007-07-28 22:00:00 +02:00
Msg ("Unknown command \"%s\"\n", cmd);
2007-06-21 22:00:00 +02:00
return;
}
MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
SZ_Print (&cls.netchan.message, cmd);
if (Cmd_Argc() > 1)
{
SZ_Print (&cls.netchan.message, " ");
SZ_Print (&cls.netchan.message, Cmd_Args());
}
}
void CL_Setenv_f( void )
{
int argc = Cmd_Argc();
if ( argc > 2 )
{
char buffer[1000];
int i;
strcpy( buffer, Cmd_Argv(1) );
strcat( buffer, "=" );
for ( i = 2; i < argc; i++ )
{
strcat( buffer, Cmd_Argv( i ) );
strcat( buffer, " " );
}
putenv( buffer );
}
else if ( argc == 2 )
{
char *env = getenv( Cmd_Argv(1) );
if ( env )
{
2007-07-28 22:00:00 +02:00
Msg( "%s=%s\n", Cmd_Argv(1), env );
2007-06-21 22:00:00 +02:00
}
else
{
2007-07-28 22:00:00 +02:00
Msg( "%s undefined\n", Cmd_Argv(1), env );
2007-06-21 22:00:00 +02:00
}
}
}
/*
==================
CL_ForwardToServer_f
==================
*/
void CL_ForwardToServer_f (void)
{
if (cls.state != ca_connected && cls.state != ca_active)
{
2007-07-28 22:00:00 +02:00
Msg ("Can't \"%s\", not connected\n", Cmd_Argv(0));
2007-06-21 22:00:00 +02:00
return;
}
// don't forward the first argument
if (Cmd_Argc() > 1)
{
MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
SZ_Print (&cls.netchan.message, Cmd_Args());
}
}
/*
==================
CL_Pause_f
==================
*/
void CL_Pause_f (void)
{
// never pause in multiplayer
2007-09-06 22:00:00 +02:00
if (Cvar_VariableValue ("maxclients") > 1 || !Com_ServerState ())
2007-06-21 22:00:00 +02:00
{
Cvar_SetValue ("paused", 0);
return;
}
Cvar_SetValue ("paused", !cl_paused->value);
}
/*
==================
CL_Quit_f
==================
*/
void CL_Quit_f (void)
{
CL_Disconnect ();
2007-09-22 22:00:00 +02:00
host.type = HOST_OFFLINE;
2007-06-21 22:00:00 +02:00
}
/*
================
CL_Drop
2007-09-10 22:00:00 +02:00
Called after an Host_Error was thrown
2007-06-21 22:00:00 +02:00
================
*/
void CL_Drop (void)
{
if (cls.state == ca_uninitialized)
return;
if (cls.state == ca_disconnected)
return;
CL_Disconnect ();
// drop loading plaque unless this is the initial game start
if (cls.disable_servercount != -1)
2007-09-10 22:00:00 +02:00
SCR_EndLoadingPlaque (); // get rid of loading plaque
2007-06-21 22:00:00 +02:00
}
/*
=======================
CL_SendConnectPacket
We have gotten a challenge from the server, so try and
connect.
======================
*/
void CL_SendConnectPacket (void)
{
netadr_t adr;
int port;
if (!NET_StringToAdr (cls.servername, &adr))
{
2007-07-28 22:00:00 +02:00
Msg ("Bad server address\n");
2007-06-21 22:00:00 +02:00
cls.connect_time = 0;
return;
}
if (adr.port == 0)
adr.port = BigShort (PORT_SERVER);
port = Cvar_VariableValue ("qport");
userinfo_modified = false;
Netchan_OutOfBandPrint (NS_CLIENT, adr, "connect %i %i %i \"%s\"\n",
PROTOCOL_VERSION, port, cls.challenge, Cvar_Userinfo() );
}
/*
=================
CL_CheckForResend
Resend a connect message if the last one has timed out
=================
*/
void CL_CheckForResend (void)
{
netadr_t adr;
// if the local server is running and we aren't
// then connect
if (cls.state == ca_disconnected && Com_ServerState() )
{
cls.state = ca_connecting;
strncpy (cls.servername, "localhost", sizeof(cls.servername)-1);
// we don't need a challenge on the localhost
CL_SendConnectPacket ();
return;
// cls.connect_time = -99999; // CL_CheckForResend() will fire immediately
}
// resend if we haven't gotten a reply yet
if (cls.state != ca_connecting)
return;
2007-09-07 22:00:00 +02:00
if (cls.realtime - cls.connect_time < 3.0f)
2007-06-21 22:00:00 +02:00
return;
if (!NET_StringToAdr (cls.servername, &adr))
{
2007-07-28 22:00:00 +02:00
Msg ("Bad server address\n");
2007-06-21 22:00:00 +02:00
cls.state = ca_disconnected;
return;
}
if (adr.port == 0)
adr.port = BigShort (PORT_SERVER);
cls.connect_time = cls.realtime; // for retransmit requests
2007-07-28 22:00:00 +02:00
Msg ("Connecting to %s...\n", cls.servername);
2007-06-21 22:00:00 +02:00
Netchan_OutOfBandPrint (NS_CLIENT, adr, "getchallenge\n");
}
/*
================
CL_Connect_f
================
*/
void CL_Connect_f (void)
{
char *server;
if (Cmd_Argc() != 2)
{
2007-07-28 22:00:00 +02:00
Msg ("usage: connect <server>\n");
2007-06-21 22:00:00 +02:00
return;
}
if (Com_ServerState ())
{ // if running a local server, kill it and reissue
SV_Shutdown (va("Server quit\n", msg), false);
}
else
{
CL_Disconnect ();
}
server = Cmd_Argv (1);
NET_Config (true); // allow remote
CL_Disconnect ();
cls.state = ca_connecting;
strncpy (cls.servername, server, sizeof(cls.servername)-1);
cls.connect_time = -99999; // CL_CheckForResend() will fire immediately
}
/*
=====================
CL_Rcon_f
Send the rest of the command line over as
an unconnected command.
=====================
*/
void CL_Rcon_f (void)
{
char message[1024];
int i;
netadr_t to;
if (!rcon_client_password->string)
{
2007-07-28 22:00:00 +02:00
Msg ("You must set 'rcon_password' before\n"
2007-06-21 22:00:00 +02:00
"issuing an rcon command.\n");
return;
}
message[0] = (char)255;
message[1] = (char)255;
message[2] = (char)255;
message[3] = (char)255;
message[4] = 0;
NET_Config (true); // allow remote
strcat (message, "rcon ");
strcat (message, rcon_client_password->string);
strcat (message, " ");
for (i=1 ; i<Cmd_Argc() ; i++)
{
strcat (message, Cmd_Argv(i));
strcat (message, " ");
}
if (cls.state >= ca_connected)
to = cls.netchan.remote_address;
else
{
if (!strlen(rcon_address->string))
{
2007-07-28 22:00:00 +02:00
Msg ("You must either be connected,\n"
2007-06-21 22:00:00 +02:00
"or set the 'rcon_address' cvar\n"
"to issue rcon commands\n");
return;
}
NET_StringToAdr (rcon_address->string, &to);
if (to.port == 0)
to.port = BigShort (PORT_SERVER);
}
NET_SendPacket (NS_CLIENT, strlen(message)+1, message, to);
}
/*
=====================
CL_ClearState
=====================
*/
void CL_ClearState (void)
{
S_StopAllSounds ();
CL_ClearEffects ();
CL_ClearTEnts ();
// wipe the entire cl structure
memset (&cl, 0, sizeof(cl));
memset (&cl_entities, 0, sizeof(cl_entities));
SZ_Clear (&cls.netchan.message);
}
/*
=====================
CL_Disconnect
Goes from a connected state to full screen console state
Sends a disconnect message to the server
2007-09-10 22:00:00 +02:00
This is also called on Host_Error, so it shouldn't cause any errors
2007-06-21 22:00:00 +02:00
=====================
*/
void CL_Disconnect (void)
{
byte final[32];
if (cls.state == ca_disconnected)
return;
2007-09-06 22:00:00 +02:00
if (cl_timedemo && cl_timedemo->value)
{
2007-09-07 22:00:00 +02:00
float time;
2007-09-06 22:00:00 +02:00
2007-09-07 22:00:00 +02:00
time = Sys_DoubleTime() - cl.timedemo_start;
2007-09-06 22:00:00 +02:00
if (time > 0)
Msg ("%i frames, %3.1f seconds: %3.1f fps\n", cl.timedemo_frames,
2007-09-07 22:00:00 +02:00
time, cl.timedemo_frames / time);
2007-09-06 22:00:00 +02:00
}
2007-06-21 22:00:00 +02:00
VectorClear (cl.refdef.blend);
2007-08-17 22:00:00 +02:00
re->CinematicSetPalette(NULL);
2007-06-21 22:00:00 +02:00
M_ForceMenuOff ();
cls.connect_time = 0;
SCR_StopCinematic ();
if (cls.demorecording)
CL_Stop_f ();
// send a disconnect message to the server
final[0] = clc_stringcmd;
strcpy ((char *)final+1, "disconnect");
Netchan_Transmit (&cls.netchan, strlen(final), final);
Netchan_Transmit (&cls.netchan, strlen(final), final);
Netchan_Transmit (&cls.netchan, strlen(final), final);
CL_ClearState ();
// stop download
if (cls.download)
{
FS_Close(cls.download);
cls.download = NULL;
}
cls.state = ca_disconnected;
}
void CL_Disconnect_f (void)
{
2007-09-10 22:00:00 +02:00
Host_Error("Disconnected from server\n");
2007-06-21 22:00:00 +02:00
}
/*
====================
CL_Packet_f
packet <destination> <contents>
Contents allows \n escape character
====================
*/
void CL_Packet_f (void)
{
char send[2048];
int i, l;
char *in, *out;
netadr_t adr;
if (Cmd_Argc() != 3)
{
2007-07-28 22:00:00 +02:00
Msg ("packet <destination> <contents>\n");
2007-06-21 22:00:00 +02:00
return;
}
NET_Config (true); // allow remote
if (!NET_StringToAdr (Cmd_Argv(1), &adr))
{
2007-07-28 22:00:00 +02:00
Msg ("Bad address\n");
2007-06-21 22:00:00 +02:00
return;
}
if (!adr.port)
adr.port = BigShort (PORT_SERVER);
in = Cmd_Argv(2);
out = send+4;
send[0] = send[1] = send[2] = send[3] = (char)0xff;
l = strlen (in);
for (i=0 ; i<l ; i++)
{
if (in[i] == '\\' && in[i+1] == 'n')
{
*out++ = '\n';
i++;
}
else
*out++ = in[i];
}
*out = 0;
NET_SendPacket (NS_CLIENT, out-send, send, adr);
}
/*
=================
CL_Changing_f
Just sent as a hint to the client that they should
drop to full console
=================
*/
void CL_Changing_f (void)
{
//ZOID
//if we are downloading, we don't change! This so we don't suddenly stop downloading a map
2007-09-06 22:00:00 +02:00
if (cls.download)
return;
2007-06-21 22:00:00 +02:00
SCR_BeginLoadingPlaque ();
cls.state = ca_connected; // not active anymore, but not disconnected
2007-07-28 22:00:00 +02:00
Msg ("\nChanging map...\n");
2007-06-21 22:00:00 +02:00
}
/*
=================
CL_Reconnect_f
The server is changing levels
=================
*/
void CL_Reconnect_f (void)
{
//ZOID
//if we are downloading, we don't change! This so we don't suddenly stop downloading a map
2007-09-07 22:00:00 +02:00
if (cls.download) return;
2007-06-21 22:00:00 +02:00
S_StopAllSounds ();
2007-09-07 22:00:00 +02:00
if (cls.state == ca_connected)
{
2007-07-28 22:00:00 +02:00
Msg ("reconnecting...\n");
2007-06-21 22:00:00 +02:00
cls.state = ca_connected;
MSG_WriteChar (&cls.netchan.message, clc_stringcmd);
MSG_WriteString (&cls.netchan.message, "new");
return;
}
2007-09-07 22:00:00 +02:00
if (*cls.servername)
{
if (cls.state >= ca_connected)
{
2007-06-21 22:00:00 +02:00
CL_Disconnect();
2007-09-07 22:00:00 +02:00
cls.connect_time = cls.realtime - 1.5f;
}
else cls.connect_time = -99999; // fire immediately
2007-06-21 22:00:00 +02:00
cls.state = ca_connecting;
2007-07-28 22:00:00 +02:00
Msg ("reconnecting...\n");
2007-06-21 22:00:00 +02:00
}
}
/*
=================
CL_ParseStatusMessage
Handle a reply from a ping
=================
*/
void CL_ParseStatusMessage (void)
{
char *s;
s = MSG_ReadString(&net_message);
2007-07-28 22:00:00 +02:00
Msg ("%s\n", s);
2007-06-21 22:00:00 +02:00
M_AddToServerList (net_from, s);
}
/*
=================
CL_PingServers_f
=================
*/
void CL_PingServers_f (void)
{
int i;
netadr_t adr;
char name[32];
char *adrstring;
cvar_t *noudp;
cvar_t *noipx;
NET_Config (true); // allow remote
// send a broadcast packet
2007-07-28 22:00:00 +02:00
Msg ("pinging broadcast...\n");
2007-06-21 22:00:00 +02:00
2007-11-04 22:00:00 +01:00
noudp = Cvar_Get ("noudp", "0", CVAR_INIT);
2007-06-21 22:00:00 +02:00
if (!noudp->value)
{
adr.type = NA_BROADCAST;
adr.port = BigShort(PORT_SERVER);
Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
}
2007-11-04 22:00:00 +01:00
noipx = Cvar_Get ("noipx", "0", CVAR_INIT);
2007-06-21 22:00:00 +02:00
if (!noipx->value)
{
adr.type = NA_BROADCAST_IPX;
adr.port = BigShort(PORT_SERVER);
Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
}
// send a packet to each address book entry
2007-08-11 22:00:00 +02:00
for (i = 0; i < 16; i++)
2007-06-21 22:00:00 +02:00
{
2007-08-11 22:00:00 +02:00
sprintf (name, "adr%i", i);
2007-06-21 22:00:00 +02:00
adrstring = Cvar_VariableString (name);
if (!adrstring || !adrstring[0])
continue;
2007-07-28 22:00:00 +02:00
Msg ("pinging %s...\n", adrstring);
2007-06-21 22:00:00 +02:00
if (!NET_StringToAdr (adrstring, &adr))
{
2007-07-28 22:00:00 +02:00
Msg ("Bad address: %s\n", adrstring);
2007-06-21 22:00:00 +02:00
continue;
}
if (!adr.port)
adr.port = BigShort(PORT_SERVER);
Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
}
}
/*
=================
CL_Skins_f
Load or download any custom player skins and models
=================
*/
void CL_Skins_f (void)
{
int i;
for (i=0 ; i<MAX_CLIENTS ; i++)
{
if (!cl.configstrings[CS_PLAYERSKINS+i][0])
continue;
2007-07-28 22:00:00 +02:00
Msg ("client %i: %s\n", i, cl.configstrings[CS_PLAYERSKINS+i]);
2007-06-21 22:00:00 +02:00
SCR_UpdateScreen ();
Sys_SendKeyEvents (); // pump message loop
CL_ParseClientinfo (i);
}
}
/*
=================
CL_ConnectionlessPacket
Responses to broadcasts, etc
=================
*/
void CL_ConnectionlessPacket (void)
{
char *s;
char *c;
MSG_BeginReading (&net_message);
2007-11-04 22:00:00 +01:00
MSG_ReadLong (&net_message); // skip the -1
2007-06-21 22:00:00 +02:00
s = MSG_ReadStringLine (&net_message);
2007-11-04 22:00:00 +01:00
Cmd_TokenizeString(s);
2007-06-21 22:00:00 +02:00
c = Cmd_Argv(0);
2007-07-28 22:00:00 +02:00
Msg ("%s: %s\n", NET_AdrToString (net_from), c);
2007-06-21 22:00:00 +02:00
// server connection
if (!strcmp(c, "client_connect"))
{
if (cls.state == ca_connected)
{
2007-07-28 22:00:00 +02:00
Msg ("Dup connect received. Ignored.\n");
2007-06-21 22:00:00 +02:00
return;
}
Netchan_Setup (NS_CLIENT, &cls.netchan, net_from, cls.quakePort);
MSG_WriteChar (&cls.netchan.message, clc_stringcmd);
MSG_WriteString (&cls.netchan.message, "new");
cls.state = ca_connected;
return;
}
// server responding to a status broadcast
if (!strcmp(c, "info"))
{
CL_ParseStatusMessage ();
return;
}
// remote command from gui front end
if (!strcmp(c, "cmd"))
{
if (!NET_IsLocalAddress(net_from))
{
2007-07-28 22:00:00 +02:00
Msg ("Command packet from remote host. Ignored.\n");
2007-06-21 22:00:00 +02:00
return;
}
2007-09-11 22:00:00 +02:00
ShowWindow ( cl_hwnd, SW_RESTORE);
SetForegroundWindow ( cl_hwnd );
2007-06-21 22:00:00 +02:00
s = MSG_ReadString (&net_message);
Cbuf_AddText (s);
Cbuf_AddText ("\n");
return;
}
// print command from somewhere
if (!strcmp(c, "print"))
{
s = MSG_ReadString (&net_message);
2007-07-28 22:00:00 +02:00
Msg ("%s", s);
2007-06-21 22:00:00 +02:00
return;
}
// ping from somewhere
if (!strcmp(c, "ping"))
{
Netchan_OutOfBandPrint (NS_CLIENT, net_from, "ack");
return;
}
// challenge from the server we are connecting to
if (!strcmp(c, "challenge"))
{
cls.challenge = atoi(Cmd_Argv(1));
CL_SendConnectPacket ();
return;
}
// echo request from server
if (!strcmp(c, "echo"))
{
Netchan_OutOfBandPrint (NS_CLIENT, net_from, "%s", Cmd_Argv(1) );
return;
}
2007-07-28 22:00:00 +02:00
Msg ("Unknown command.\n");
2007-06-21 22:00:00 +02:00
}
/*
=================
CL_DumpPackets
A vain attempt to help bad TCP stacks that cause problems
when they overflow
=================
*/
void CL_DumpPackets (void)
{
while (NET_GetPacket (NS_CLIENT, &net_from, &net_message))
{
2007-07-28 22:00:00 +02:00
Msg ("dumnping a packet\n");
2007-06-21 22:00:00 +02:00
}
}
/*
=================
CL_ReadPackets
=================
*/
void CL_ReadPackets (void)
{
while (NET_GetPacket (NS_CLIENT, &net_from, &net_message))
{
2007-10-19 22:00:00 +02:00
//Msg ("packet\n");
2007-06-21 22:00:00 +02:00
//
// remote command packet
//
if (*(int *)net_message.data == -1)
{
CL_ConnectionlessPacket ();
continue;
}
if (cls.state == ca_disconnected || cls.state == ca_connecting)
continue; // dump it if not connected
if (net_message.cursize < 8)
{
2007-07-28 22:00:00 +02:00
Msg ("%s: Runt packet\n",NET_AdrToString(net_from));
2007-06-21 22:00:00 +02:00
continue;
}
//
// packet from server
//
if (!NET_CompareAdr (net_from, cls.netchan.remote_address))
{
2007-08-17 22:00:00 +02:00
MsgWarn("CL_ReadPackets: %s:sequenced packet without connection\n",NET_AdrToString(net_from));
2007-06-21 22:00:00 +02:00
continue;
}
if (!Netchan_Process(&cls.netchan, &net_message))
2007-10-19 22:00:00 +02:00
continue; // wasn't accepted for some reason
2007-06-21 22:00:00 +02:00
CL_ParseServerMessage ();
}
//
// check timeout
//
2007-09-09 22:00:00 +02:00
if (cls.state >= ca_connected && cls.realtime - cls.netchan.last_received > cl_timeout->value)
2007-06-21 22:00:00 +02:00
{
2007-10-19 22:00:00 +02:00
if (++cl.timeoutcount > 5) // timeoutcount saves debugger
2007-06-21 22:00:00 +02:00
{
2007-07-28 22:00:00 +02:00
Msg ("\nServer connection timed out.\n");
2007-06-21 22:00:00 +02:00
CL_Disconnect ();
return;
}
}
2007-09-07 22:00:00 +02:00
else cl.timeoutcount = 0;
2007-06-21 22:00:00 +02:00
}
//=============================================================================
/*
==============
CL_FixUpGender_f
==============
*/
void CL_FixUpGender(void)
{
char *p;
char sk[80];
if (gender_auto->value) {
if (gender->modified) {
// was set directly, don't override the user
gender->modified = false;
return;
}
strncpy(sk, skin->string, sizeof(sk) - 1);
if ((p = strchr(sk, '/')) != NULL)
*p = 0;
2007-08-01 22:00:00 +02:00
if (strcasecmp(sk, "male") == 0 || strcasecmp(sk, "cyborg") == 0)
2007-06-21 22:00:00 +02:00
Cvar_Set ("gender", "male");
2007-08-01 22:00:00 +02:00
else if (strcasecmp(sk, "female") == 0 || strcasecmp(sk, "crackhor") == 0)
2007-06-21 22:00:00 +02:00
Cvar_Set ("gender", "female");
else
Cvar_Set ("gender", "none");
gender->modified = false;
}
}
/*
==============
CL_Userinfo_f
==============
*/
void CL_Userinfo_f (void)
{
2007-07-28 22:00:00 +02:00
Msg ("User info settings:\n");
2007-06-21 22:00:00 +02:00
Info_Print (Cvar_Userinfo());
}
/*
=================
CL_Snd_Restart_f
Restart the sound subsystem so it can pick up
new parameters and flush all sounds
=================
*/
void CL_Snd_Restart_f (void)
{
2007-11-01 22:00:00 +01:00
S_Shutdown();
S_Init();
CL_RegisterSounds();
2007-06-21 22:00:00 +02:00
}
int precache_check; // for autodownload of precache items
int precache_spawncount;
int precache_tex;
int precache_model_skin;
byte *precache_model; // used for skin checking in alias models
#define PLAYER_MULT 5
// ENV_CNT is map load, ENV_CNT+1 is first env map
#define ENV_CNT (CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT)
#define TEXTURE_CNT (ENV_CNT+13)
static const char *env_suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
void CL_RequestNextDownload (void)
{
unsigned map_checksum; // for detecting cheater maps
char fn[MAX_OSPATH];
2007-09-14 22:00:00 +02:00
studiohdr_t *pheader;
2007-06-21 22:00:00 +02:00
if (cls.state != ca_connected)
return;
if (!allow_download->value && precache_check < ENV_CNT)
precache_check = ENV_CNT;
//ZOID
2007-09-14 22:00:00 +02:00
if (precache_check == CS_MODELS)
{
// confirm map
2007-06-21 22:00:00 +02:00
precache_check = CS_MODELS+2; // 0 isn't used
if (allow_download_maps->value)
if (!CL_CheckOrDownloadFile(cl.configstrings[CS_MODELS+1]))
return; // started a download
}
2007-09-14 22:00:00 +02:00
if (precache_check >= CS_MODELS && precache_check < CS_MODELS+MAX_MODELS)
{
if (allow_download_models->value)
{
2007-06-21 22:00:00 +02:00
while (precache_check < CS_MODELS+MAX_MODELS &&
cl.configstrings[precache_check][0]) {
if (cl.configstrings[precache_check][0] == '*' ||
cl.configstrings[precache_check][0] == '#') {
precache_check++;
continue;
}
if (precache_model_skin == 0) {
if (!CL_CheckOrDownloadFile(cl.configstrings[precache_check])) {
precache_model_skin = 1;
return; // started a download
}
precache_model_skin = 1;
}
// checking for skins in the model
if (!precache_model) {
precache_model = FS_LoadFile (cl.configstrings[precache_check], NULL);
if (!precache_model)
{
precache_model_skin = 0;
precache_check++;
continue; // couldn't load it
}
2007-09-14 22:00:00 +02:00
if (LittleLong(*(uint *)precache_model) != IDSTUDIOHEADER)
{
// not an studio model
2007-06-21 22:00:00 +02:00
precache_model = 0;
precache_model_skin = 0;
precache_check++;
continue;
}
2007-09-14 22:00:00 +02:00
pheader = (studiohdr_t *)precache_model;
if (LittleLong (pheader->version) != STUDIO_VERSION)
{
2007-06-21 22:00:00 +02:00
precache_check++;
precache_model_skin = 0;
continue; // couldn't load it
}
}
2007-09-14 22:00:00 +02:00
pheader = (studiohdr_t *)precache_model;
2007-06-21 22:00:00 +02:00
2007-09-14 22:00:00 +02:00
if (precache_model)
{
2007-06-21 22:00:00 +02:00
precache_model = 0;
}
precache_model_skin = 0;
precache_check++;
}
}
precache_check = CS_SOUNDS;
}
2007-08-11 22:00:00 +02:00
if (precache_check >= CS_SOUNDS && precache_check < CS_SOUNDS+MAX_SOUNDS)
{
if (allow_download_sounds->value)
{
if (precache_check == CS_SOUNDS) precache_check++; // zero is blank
while (precache_check < CS_SOUNDS+MAX_SOUNDS && cl.configstrings[precache_check][0])
{
if (cl.configstrings[precache_check][0] == '*')
{
2007-06-21 22:00:00 +02:00
precache_check++;
continue;
}
2007-08-11 22:00:00 +02:00
sprintf(fn, "sound/%s", cl.configstrings[precache_check++]);
if (!CL_CheckOrDownloadFile(fn)) return; // started a download
2007-06-21 22:00:00 +02:00
}
}
precache_check = CS_IMAGES;
}
2007-08-11 22:00:00 +02:00
if (precache_check >= CS_IMAGES && precache_check < CS_IMAGES+MAX_IMAGES)
{
if (precache_check == CS_IMAGES) precache_check++; // zero is blank
while (precache_check < CS_IMAGES+MAX_IMAGES && cl.configstrings[precache_check][0])
{
sprintf(fn, "pics/%s.pcx", cl.configstrings[precache_check++]);
if (!CL_CheckOrDownloadFile(fn)) return; // started a download
2007-06-21 22:00:00 +02:00
}
precache_check = CS_PLAYERSKINS;
}
// skins are special, since a player has three things to download:
// model, weapon model and skin
// so precache_check is now *3
2007-08-11 22:00:00 +02:00
if (precache_check >= CS_PLAYERSKINS && precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT)
{
if (allow_download_players->value)
{
while (precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT)
{
2007-06-21 22:00:00 +02:00
int i, n;
char model[MAX_QPATH], skin[MAX_QPATH], *p;
i = (precache_check - CS_PLAYERSKINS)/PLAYER_MULT;
n = (precache_check - CS_PLAYERSKINS)%PLAYER_MULT;
if (!cl.configstrings[CS_PLAYERSKINS+i][0]) {
precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT;
continue;
}
if ((p = strchr(cl.configstrings[CS_PLAYERSKINS+i], '\\')) != NULL)
p++;
2007-08-11 22:00:00 +02:00
else p = cl.configstrings[CS_PLAYERSKINS+i];
2007-06-21 22:00:00 +02:00
strcpy(model, p);
p = strchr(model, '/');
if (!p)
p = strchr(model, '\\');
2007-08-11 22:00:00 +02:00
if (p)
{
2007-06-21 22:00:00 +02:00
*p++ = 0;
strcpy(skin, p);
2007-08-11 22:00:00 +02:00
}
else *skin = 0;
2007-06-21 22:00:00 +02:00
2007-08-11 22:00:00 +02:00
switch (n)
{
2007-06-21 22:00:00 +02:00
case 0: // model
2007-09-14 22:00:00 +02:00
sprintf(fn, "models/players/%s/player.mdl", model);
2007-08-11 22:00:00 +02:00
if (!CL_CheckOrDownloadFile(fn))
{
2007-06-21 22:00:00 +02:00
precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 1;
return; // started a download
}
n++;
/*FALL THROUGH*/
case 1: // weapon model
2007-09-14 22:00:00 +02:00
sprintf(fn, "weapons/%s.mdl", model);
2007-08-11 22:00:00 +02:00
if (!CL_CheckOrDownloadFile(fn))
{
2007-06-21 22:00:00 +02:00
precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 2;
return; // started a download
}
n++;
/*FALL THROUGH*/
2007-09-14 22:00:00 +02:00
default:
break;
2007-06-21 22:00:00 +02:00
}
}
}
// precache phase completed
precache_check = ENV_CNT;
}
2007-08-11 22:00:00 +02:00
if (precache_check == ENV_CNT)
{
2007-06-21 22:00:00 +02:00
precache_check = ENV_CNT + 1;
CM_LoadMap (cl.configstrings[CS_MODELS+1], true, &map_checksum);
2007-08-11 22:00:00 +02:00
if (map_checksum != atoi(cl.configstrings[CS_MAPCHECKSUM]))
{
2007-09-10 22:00:00 +02:00
Host_Error("Local map version differs from server: %i != '%s'\n", map_checksum, cl.configstrings[CS_MAPCHECKSUM]);
2007-06-21 22:00:00 +02:00
return;
}
}
2007-08-11 22:00:00 +02:00
if (precache_check > ENV_CNT && precache_check < TEXTURE_CNT)
{
if (allow_download->value && allow_download_maps->value)
{
while (precache_check < TEXTURE_CNT)
{
2007-06-21 22:00:00 +02:00
int n = precache_check++ - ENV_CNT - 1;
2007-08-11 22:00:00 +02:00
if (n & 1) sprintf(fn, "env/%s%s.pcx", cl.configstrings[CS_SKY], env_suf[n/2]);
else sprintf(fn, "env/%s%s.tga", cl.configstrings[CS_SKY], env_suf[n/2]);
if (!CL_CheckOrDownloadFile(fn)) return; // started a download
2007-06-21 22:00:00 +02:00
}
}
precache_check = TEXTURE_CNT;
}
2007-08-11 22:00:00 +02:00
if (precache_check == TEXTURE_CNT)
{
2007-06-21 22:00:00 +02:00
precache_check = TEXTURE_CNT+1;
precache_tex = 0;
}
// confirm existance of textures, download any that don't exist
2007-08-11 22:00:00 +02:00
if (precache_check == TEXTURE_CNT+1)
{
2007-06-21 22:00:00 +02:00
// from common/cmodel.c
2007-08-11 22:00:00 +02:00
extern int numtexinfo;
2007-06-21 22:00:00 +02:00
extern mapsurface_t map_surfaces[];
2007-08-11 22:00:00 +02:00
if (allow_download->value && allow_download_maps->value)
{
while (precache_tex < numtexinfo)
{
2007-06-21 22:00:00 +02:00
char fn[MAX_OSPATH];
sprintf(fn, "textures/%s.jpg", map_surfaces[precache_tex++].rname);
2007-08-11 22:00:00 +02:00
if (!CL_CheckOrDownloadFile(fn)) return; // started a download
2007-06-21 22:00:00 +02:00
}
}
precache_check = TEXTURE_CNT+999;
}
//ZOID
CL_RegisterSounds ();
CL_PrepRefresh ();
MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
MSG_WriteString (&cls.netchan.message, va("begin %i\n", precache_spawncount) );
}
/*
=================
CL_Precache_f
The server will send this command right
before allowing the client into the server
=================
*/
void CL_Precache_f (void)
{
//Yet another hack to let old demos work
//the old precache sequence
if (Cmd_Argc() < 2) {
unsigned map_checksum; // for detecting cheater maps
CM_LoadMap (cl.configstrings[CS_MODELS+1], true, &map_checksum);
CL_RegisterSounds ();
CL_PrepRefresh ();
return;
}
precache_check = CS_MODELS;
precache_spawncount = atoi(Cmd_Argv(1));
precache_model = 0;
precache_model_skin = 0;
CL_RequestNextDownload();
}
/*
=================
CL_InitLocal
=================
*/
void CL_InitLocal (void)
{
cls.state = ca_disconnected;
2007-09-07 22:00:00 +02:00
cls.realtime = 1.0f;
2007-06-21 22:00:00 +02:00
CL_InitInput ();
adr0 = Cvar_Get( "adr0", "", CVAR_ARCHIVE );
adr1 = Cvar_Get( "adr1", "", CVAR_ARCHIVE );
adr2 = Cvar_Get( "adr2", "", CVAR_ARCHIVE );
adr3 = Cvar_Get( "adr3", "", CVAR_ARCHIVE );
adr4 = Cvar_Get( "adr4", "", CVAR_ARCHIVE );
adr5 = Cvar_Get( "adr5", "", CVAR_ARCHIVE );
adr6 = Cvar_Get( "adr6", "", CVAR_ARCHIVE );
adr7 = Cvar_Get( "adr7", "", CVAR_ARCHIVE );
adr8 = Cvar_Get( "adr8", "", CVAR_ARCHIVE );
2007-11-05 22:00:00 +01:00
// register our variables
2007-06-21 22:00:00 +02:00
cl_add_blend = Cvar_Get ("cl_blend", "1", 0);
cl_add_lights = Cvar_Get ("cl_lights", "1", 0);
cl_add_particles = Cvar_Get ("cl_particles", "1", 0);
cl_add_entities = Cvar_Get ("cl_entities", "1", 0);
cl_gun = Cvar_Get ("cl_gun", "1", 0);
cl_footsteps = Cvar_Get ("cl_footsteps", "1", 0);
cl_noskins = Cvar_Get ("cl_noskins", "0", 0);
cl_autoskins = Cvar_Get ("cl_autoskins", "0", 0);
2007-09-05 22:00:00 +02:00
cl_predict = Cvar_Get ("cl_predict", "1", 0);
2007-06-21 22:00:00 +02:00
// cl_minfps = Cvar_Get ("cl_minfps", "5", 0);
2007-10-29 22:00:00 +01:00
cl_maxfps = Cvar_Get ("cl_maxfps", "1000", 0);
2007-06-21 22:00:00 +02:00
cl_upspeed = Cvar_Get ("cl_upspeed", "200", 0);
cl_forwardspeed = Cvar_Get ("cl_forwardspeed", "200", 0);
cl_sidespeed = Cvar_Get ("cl_sidespeed", "200", 0);
cl_yawspeed = Cvar_Get ("cl_yawspeed", "140", 0);
cl_pitchspeed = Cvar_Get ("cl_pitchspeed", "150", 0);
cl_anglespeedkey = Cvar_Get ("cl_anglespeedkey", "1.5", 0);
cl_run = Cvar_Get ("cl_run", "0", CVAR_ARCHIVE);
freelook = Cvar_Get( "freelook", "0", CVAR_ARCHIVE );
lookspring = Cvar_Get ("lookspring", "0", CVAR_ARCHIVE);
lookstrafe = Cvar_Get ("lookstrafe", "0", CVAR_ARCHIVE);
sensitivity = Cvar_Get ("sensitivity", "3", CVAR_ARCHIVE);
m_pitch = Cvar_Get ("m_pitch", "0.022", CVAR_ARCHIVE);
m_yaw = Cvar_Get ("m_yaw", "0.022", 0);
m_forward = Cvar_Get ("m_forward", "1", 0);
m_side = Cvar_Get ("m_side", "1", 0);
cl_shownet = Cvar_Get ("cl_shownet", "0", 0);
cl_showmiss = Cvar_Get ("cl_showmiss", "0", 0);
cl_showclamp = Cvar_Get ("showclamp", "0", 0);
cl_timeout = Cvar_Get ("cl_timeout", "120", 0);
cl_paused = Cvar_Get ("paused", "0", 0);
cl_timedemo = Cvar_Get ("timedemo", "0", 0);
rcon_client_password = Cvar_Get ("rcon_password", "", 0);
rcon_address = Cvar_Get ("rcon_address", "", 0);
cl_lightlevel = Cvar_Get ("r_lightlevel", "0", 0);
//
// userinfo
//
info_password = Cvar_Get ("password", "", CVAR_USERINFO);
info_spectator = Cvar_Get ("spectator", "0", CVAR_USERINFO);
name = Cvar_Get ("name", "unnamed", CVAR_USERINFO | CVAR_ARCHIVE);
skin = Cvar_Get ("skin", "male/grunt", CVAR_USERINFO | CVAR_ARCHIVE);
rate = Cvar_Get ("rate", "25000", CVAR_USERINFO | CVAR_ARCHIVE); // FIXME
msg = Cvar_Get ("msg", "1", CVAR_USERINFO | CVAR_ARCHIVE);
hand = Cvar_Get ("hand", "0", CVAR_USERINFO | CVAR_ARCHIVE);
fov = Cvar_Get ("fov", "90", CVAR_USERINFO | CVAR_ARCHIVE);
gender = Cvar_Get ("gender", "male", CVAR_USERINFO | CVAR_ARCHIVE);
gender_auto = Cvar_Get ("gender_auto", "1", CVAR_ARCHIVE);
gender->modified = false; // clear this so we know when user sets it manually
cl_vwep = Cvar_Get ("cl_vwep", "1", CVAR_ARCHIVE);
//
// register our commands
//
Cmd_AddCommand ("cmd", CL_ForwardToServer_f);
Cmd_AddCommand ("pause", CL_Pause_f);
Cmd_AddCommand ("pingservers", CL_PingServers_f);
Cmd_AddCommand ("skins", CL_Skins_f);
Cmd_AddCommand ("userinfo", CL_Userinfo_f);
Cmd_AddCommand ("snd_restart", CL_Snd_Restart_f);
Cmd_AddCommand ("changing", CL_Changing_f);
Cmd_AddCommand ("disconnect", CL_Disconnect_f);
Cmd_AddCommand ("record", CL_Record_f);
Cmd_AddCommand ("stop", CL_Stop_f);
Cmd_AddCommand ("quit", CL_Quit_f);
Cmd_AddCommand ("connect", CL_Connect_f);
Cmd_AddCommand ("reconnect", CL_Reconnect_f);
Cmd_AddCommand ("rcon", CL_Rcon_f);
// Cmd_AddCommand ("packet", CL_Packet_f); // this is dangerous to leave in
Cmd_AddCommand ("setenv", CL_Setenv_f );
Cmd_AddCommand ("precache", CL_Precache_f);
Cmd_AddCommand ("download", CL_Download_f);
//
// forward to server commands
//
// the only thing this does is allow command completion
// to work -- all unknown commands are automatically
// forwarded to the server
Cmd_AddCommand ("wave", NULL);
Cmd_AddCommand ("inven", NULL);
Cmd_AddCommand ("kill", NULL);
Cmd_AddCommand ("use", NULL);
Cmd_AddCommand ("drop", NULL);
Cmd_AddCommand ("say", NULL);
Cmd_AddCommand ("say_team", NULL);
Cmd_AddCommand ("info", NULL);
Cmd_AddCommand ("prog", NULL);
Cmd_AddCommand ("give", NULL);
Cmd_AddCommand ("god", NULL);
Cmd_AddCommand ("notarget", NULL);
Cmd_AddCommand ("noclip", NULL);
Cmd_AddCommand ("invuse", NULL);
Cmd_AddCommand ("invprev", NULL);
Cmd_AddCommand ("invnext", NULL);
Cmd_AddCommand ("invdrop", NULL);
Cmd_AddCommand ("weapnext", NULL);
Cmd_AddCommand ("weapprev", NULL);
}
/*
===============
CL_WriteConfiguration
Writes key bindings and archived cvars to config.cfg
===============
*/
void CL_WriteConfiguration (void)
{
file_t *f;
2007-11-04 22:00:00 +01:00
if (cls.state == ca_uninitialized) return;
2007-06-21 22:00:00 +02:00
2007-11-04 22:00:00 +01:00
f = FS_Open("scripts/config/keys.rc", "w");
if(f)
2007-06-21 22:00:00 +02:00
{
2007-11-04 22:00:00 +01:00
FS_Printf (f, "//=======================================================================\n");
FS_Printf (f, "//\t\t\tCopyright XashXT Group 2007 <20>\n");
FS_Printf (f, "//\t\t\tkeys.rc - current key bindings\n");
FS_Printf (f, "//=======================================================================\n");
Key_WriteBindings(f);
FS_Close (f);
2007-06-21 22:00:00 +02:00
}
2007-11-04 22:00:00 +01:00
else Msg("Couldn't write keys.rc.\n");
2007-06-21 22:00:00 +02:00
2007-11-04 22:00:00 +01:00
f = FS_Open("scripts/config/vars.rc", "w");
if(f)
{
FS_Printf (f, "//=======================================================================\n");
FS_Printf (f, "//\t\t\tCopyright XashXT Group 2007 <20>\n");
FS_Printf (f, "//\t\t\tvars.rc - archive of cvars\n");
FS_Printf (f, "//=======================================================================\n");
Cvar_WriteVariables(f);
FS_Close (f);
}
else Msg("Couldn't write vars.rc.\n");
2007-06-21 22:00:00 +02:00
}
/*
==================
CL_FixCvarCheats
==================
*/
typedef struct
{
char *name;
char *value;
cvar_t *var;
} cheatvar_t;
cheatvar_t cheatvars[] = {
{"timescale", "1"},
{"timedemo", "0"},
{"r_drawworld", "1"},
{"cl_testlights", "0"},
{"r_fullbright", "0"},
{"r_drawflat", "0"},
{"paused", "0"},
{"fixedtime", "0"},
{"sw_draworder", "0"},
{"gl_lightmap", "0"},
{"gl_saturatelighting", "0"},
{NULL, NULL}
};
int numcheatvars;
void CL_FixCvarCheats (void)
{
int i;
cheatvar_t *var;
2007-09-06 22:00:00 +02:00
if ( !strcmp(cl.configstrings[CS_MAXCLIENTS], "1")
|| !cl.configstrings[CS_MAXCLIENTS][0] )
return; // single player can cheat
2007-06-21 22:00:00 +02:00
// find all the cvars if we haven't done it yet
if (!numcheatvars)
{
while (cheatvars[numcheatvars].name)
{
cheatvars[numcheatvars].var = Cvar_Get (cheatvars[numcheatvars].name,
cheatvars[numcheatvars].value, 0);
numcheatvars++;
}
}
// make sure they are all set to the proper values
for (i=0, var = cheatvars ; i<numcheatvars ; i++, var++)
{
if ( strcmp (var->var->string, var->value) )
{
Cvar_Set (var->name, var->value);
}
}
}
//============================================================================
/*
==================
CL_SendCommand
==================
*/
void CL_SendCommand (void)
{
// get new key events
Sys_SendKeyEvents ();
// process console commands
Cbuf_Execute ();
// fix any cheating cvars
CL_FixCvarCheats ();
// send intentions now
CL_SendCmd ();
// resend a connection request if necessary
CL_CheckForResend ();
}
/*
==================
CL_Frame
==================
*/
2007-09-07 22:00:00 +02:00
void CL_Frame (float time)
2007-06-21 22:00:00 +02:00
{
2007-09-07 22:00:00 +02:00
static float extratime;
static float lasttimecalled;
2007-06-21 22:00:00 +02:00
2007-10-29 22:00:00 +01:00
if (dedicated->value) return;
2007-06-21 22:00:00 +02:00
2007-09-07 22:00:00 +02:00
extratime += time;
2007-06-21 22:00:00 +02:00
if (!cl_timedemo->value)
{
2007-10-29 22:00:00 +01:00
if (cls.state == ca_connected && extratime < 0.01f)
return; // don't flood packets out while connecting
2007-09-07 22:00:00 +02:00
if (extratime < 1.0f / cl_maxfps->value)
2007-09-06 22:00:00 +02:00
return; // framerate is too high
2007-06-21 22:00:00 +02:00
}
// let the mouse activate or deactivate
IN_Frame ();
// decide the simulation time
2007-09-07 22:00:00 +02:00
cls.frametime = extratime;
2007-06-21 22:00:00 +02:00
cl.time += extratime;
2007-09-09 22:00:00 +02:00
cls.realtime = host.realtime;
2007-06-21 22:00:00 +02:00
extratime = 0;
// if in the debugger last frame, don't timeout
2007-09-09 22:00:00 +02:00
if (time > 5.0f) cls.netchan.last_received = host.realtime;
2007-06-21 22:00:00 +02:00
// fetch results from server
CL_ReadPackets ();
// send a new command message to the server
CL_SendCommand ();
// predict all unacknowledged movements
CL_PredictMovement ();
// allow rendering DLL change
VID_CheckChanges ();
if (!cl.refresh_prepped && cls.state == ca_active)
CL_PrepRefresh ();
// update the screen
2007-11-01 22:00:00 +01:00
if (host_speeds->value) time_before_ref = Sys_DoubleTime();
2007-06-21 22:00:00 +02:00
SCR_UpdateScreen ();
2007-11-01 22:00:00 +01:00
if (host_speeds->value) time_after_ref = Sys_DoubleTime();
2007-06-21 22:00:00 +02:00
// update audio
2007-11-01 22:00:00 +01:00
S_Update();
2007-11-04 22:00:00 +01:00
S_Respatialize( cl.playernum + 1, cl.refdef.vieworg, cl.v_forward, cl.v_left, cl.v_up );
2007-06-21 22:00:00 +02:00
// advance local effects for next frame
CL_RunDLights ();
CL_RunLightStyles ();
2007-11-05 22:00:00 +01:00
2007-06-21 22:00:00 +02:00
SCR_RunCinematic ();
2007-11-04 22:00:00 +01:00
Con_RunConsole ();
2007-06-21 22:00:00 +02:00
cls.framecount++;
}
//============================================================================
/*
====================
CL_Init
====================
*/
void CL_Init (void)
{
2007-09-06 22:00:00 +02:00
if (dedicated->value)
return; // nothing running on the client
2007-06-21 22:00:00 +02:00
// all archived variables will now be loaded
Con_Init ();
VID_Init ();
S_Init (); // sound must be initialized after window is created
V_Init ();
net_message.data = net_message_buffer;
net_message.maxsize = sizeof(net_message_buffer);
M_Init ();
SCR_Init ();
cls.disable_screen = true; // don't draw yet
CL_InitLocal ();
IN_Init ();
Cbuf_AddText ("exec autoexec.cfg\n");
Cbuf_Execute ();
}
/*
===============
CL_Shutdown
2007-09-10 22:00:00 +02:00
FIXME: this is a callback from Sys_Quit and Host_Error. It would be better
2007-06-21 22:00:00 +02:00
to run quit through here before the final handoff to the sys code.
===============
*/
void CL_Shutdown(void)
{
2007-10-29 22:00:00 +01:00
// already freed
if(host.state == HOST_ERROR) return;
2007-06-21 22:00:00 +02:00
CL_WriteConfiguration ();
S_Shutdown();
IN_Shutdown ();
2007-09-13 22:00:00 +02:00
VID_FreeRender();
2007-06-21 22:00:00 +02:00
}