mirror of
https://git.code.sf.net/p/quake/quakeforge-old
synced 2024-11-29 15:12:17 +00:00
e468985ee1
there, more will be added later as needed.. Added -Wall to the cflags on a few things, may have missed some stuff.. Changed the tests on HAVE_GL_COLOR_INDEX8_EXT to actually function.. (Fixes the GL texture problem..) Added tests for GLAPIENTRY and APIENTRY, there will alweys be something.. Fixed the check for the 3dfxgl lib.. Some makefile tweaking.. Changed VERSION into a string so it can easily be 0.1.0.. Removed the generated configure script, does not merge sanely..
1552 lines
31 KiB
C
1552 lines
31 KiB
C
/*
|
||
Copyright (C) 1996-1997 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
|
||
|
||
#include <ctype.h>
|
||
|
||
#include "quakedef.h"
|
||
#include "winquake.h"
|
||
|
||
#ifdef __sun__
|
||
/* Sun's model_t in sys/model.h conflicts w/ Quake's model_t */
|
||
#define model_t sunmodel_t
|
||
#endif
|
||
|
||
#ifdef _WIN32
|
||
#include "winsock.h"
|
||
#else
|
||
#include <netinet/in.h>
|
||
#endif
|
||
|
||
#ifdef __sun__
|
||
#undef model_t
|
||
#endif
|
||
|
||
|
||
// we need to declare some mouse variables here, because the menu system
|
||
// references them even when on a unix system.
|
||
|
||
qboolean noclip_anglehack; // remnant from old quake
|
||
|
||
|
||
cvar_t rcon_password = {"rcon_password", "", false};
|
||
|
||
cvar_t rcon_address = {"rcon_address", ""};
|
||
|
||
cvar_t cl_timeout = {"cl_timeout", "60"};
|
||
|
||
cvar_t cl_shownet = {"cl_shownet","0"}; // can be 0, 1, or 2
|
||
|
||
cvar_t cl_sbar = {"cl_sbar", "0", true};
|
||
cvar_t cl_hudswap = {"cl_hudswap", "0", true};
|
||
cvar_t cl_maxfps = {"cl_maxfps", "0", true};
|
||
|
||
cvar_t lookspring = {"lookspring","0", true};
|
||
cvar_t lookstrafe = {"lookstrafe","0", true};
|
||
cvar_t sensitivity = {"sensitivity","3", true};
|
||
|
||
cvar_t m_pitch = {"m_pitch","0.022", true};
|
||
cvar_t m_yaw = {"m_yaw","0.022"};
|
||
cvar_t m_forward = {"m_forward","1"};
|
||
cvar_t m_side = {"m_side","0.8"};
|
||
|
||
cvar_t entlatency = {"entlatency", "20"};
|
||
cvar_t cl_predict_players = {"cl_predict_players", "1"};
|
||
cvar_t cl_predict_players2 = {"cl_predict_players2", "1"};
|
||
cvar_t cl_solid_players = {"cl_solid_players", "1"};
|
||
|
||
cvar_t localid = {"localid", ""};
|
||
|
||
static qboolean allowremotecmd = true;
|
||
|
||
//
|
||
// info mirrors
|
||
//
|
||
cvar_t password = {"password", "", false, true};
|
||
cvar_t spectator = {"spectator", "", false, true};
|
||
cvar_t name = {"name","unnamed", true, true};
|
||
cvar_t team = {"team","", true, true};
|
||
cvar_t skin = {"skin","", true, true};
|
||
cvar_t topcolor = {"topcolor","0", true, true};
|
||
cvar_t bottomcolor = {"bottomcolor","0", true, true};
|
||
cvar_t rate = {"rate","2500", true, true};
|
||
cvar_t noaim = {"noaim","0", true, true};
|
||
cvar_t msg = {"msg","1", true, true};
|
||
|
||
extern cvar_t cl_hightrack;
|
||
|
||
|
||
client_static_t cls;
|
||
client_state_t cl;
|
||
|
||
entity_state_t cl_baselines[MAX_EDICTS];
|
||
efrag_t cl_efrags[MAX_EFRAGS];
|
||
entity_t cl_static_entities[MAX_STATIC_ENTITIES];
|
||
lightstyle_t cl_lightstyle[MAX_LIGHTSTYLES];
|
||
dlight_t cl_dlights[MAX_DLIGHTS];
|
||
|
||
// refresh list
|
||
// this is double buffered so the last frame
|
||
// can be scanned for oldorigins of trailing objects
|
||
int cl_numvisedicts, cl_oldnumvisedicts;
|
||
entity_t *cl_visedicts, *cl_oldvisedicts;
|
||
entity_t cl_visedicts_list[2][MAX_VISEDICTS];
|
||
|
||
double connect_time = -1; // for connection retransmits
|
||
|
||
quakeparms_t host_parms;
|
||
|
||
qboolean host_initialized; // true if into command execution
|
||
qboolean nomaster;
|
||
|
||
double host_frametime;
|
||
double realtime; // without any filtering or bounding
|
||
double oldrealtime; // last frame run
|
||
int host_framecount;
|
||
|
||
int host_hunklevel;
|
||
|
||
byte *host_basepal;
|
||
byte *host_colormap;
|
||
|
||
netadr_t master_adr; // address of the master server
|
||
|
||
cvar_t host_speeds = {"host_speeds","0"}; // set for running times
|
||
cvar_t show_fps = {"show_fps","0"}; // set for running times
|
||
cvar_t developer = {"developer","0"};
|
||
|
||
int fps_count;
|
||
|
||
jmp_buf host_abort;
|
||
|
||
void Master_Connect_f (void);
|
||
|
||
float server_version = 0; // version of server we connected to
|
||
|
||
char emodel_name[] =
|
||
{ 'e' ^ 0xff, 'm' ^ 0xff, 'o' ^ 0xff, 'd' ^ 0xff, 'e' ^ 0xff, 'l' ^ 0xff, 0 };
|
||
char pmodel_name[] =
|
||
{ 'p' ^ 0xff, 'm' ^ 0xff, 'o' ^ 0xff, 'd' ^ 0xff, 'e' ^ 0xff, 'l' ^ 0xff, 0 };
|
||
char prespawn_name[] =
|
||
{ 'p'^0xff, 'r'^0xff, 'e'^0xff, 's'^0xff, 'p'^0xff, 'a'^0xff, 'w'^0xff, 'n'^0xff,
|
||
' '^0xff, '%'^0xff, 'i'^0xff, ' '^0xff, '0'^0xff, ' '^0xff, '%'^0xff, 'i'^0xff, 0 };
|
||
char modellist_name[] =
|
||
{ 'm'^0xff, 'o'^0xff, 'd'^0xff, 'e'^0xff, 'l'^0xff, 'l'^0xff, 'i'^0xff, 's'^0xff, 't'^0xff,
|
||
' '^0xff, '%'^0xff, 'i'^0xff, ' '^0xff, '%'^0xff, 'i'^0xff, 0 };
|
||
char soundlist_name[] =
|
||
{ 's'^0xff, 'o'^0xff, 'u'^0xff, 'n'^0xff, 'd'^0xff, 'l'^0xff, 'i'^0xff, 's'^0xff, 't'^0xff,
|
||
' '^0xff, '%'^0xff, 'i'^0xff, ' '^0xff, '%'^0xff, 'i'^0xff, 0 };
|
||
|
||
/*
|
||
==================
|
||
CL_Quit_f
|
||
==================
|
||
*/
|
||
void CL_Quit_f (void)
|
||
{
|
||
if (1 /* key_dest != key_console */ /* && cls.state != ca_dedicated */)
|
||
{
|
||
M_Menu_Quit_f ();
|
||
return;
|
||
}
|
||
CL_Disconnect ();
|
||
Sys_Quit ();
|
||
}
|
||
|
||
/*
|
||
=======================
|
||
CL_Version_f
|
||
======================
|
||
*/
|
||
void CL_Version_f (void)
|
||
{
|
||
Con_Printf ("Version %s\n", VERSION);
|
||
Con_Printf ("Exe: "__TIME__" "__DATE__"\n");
|
||
}
|
||
|
||
|
||
/*
|
||
=======================
|
||
CL_SendConnectPacket
|
||
|
||
called by CL_Connect_f and CL_CheckResend
|
||
======================
|
||
*/
|
||
void CL_SendConnectPacket (void)
|
||
{
|
||
netadr_t adr;
|
||
char data[2048];
|
||
double t1, t2;
|
||
// JACK: Fixed bug where DNS lookups would cause two connects real fast
|
||
// Now, adds lookup time to the connect time.
|
||
// Should I add it to realtime instead?!?!
|
||
|
||
if (cls.state != ca_disconnected)
|
||
return;
|
||
|
||
t1 = Sys_DoubleTime ();
|
||
|
||
if (!NET_StringToAdr (cls.servername, &adr))
|
||
{
|
||
Con_Printf ("Bad server address\n");
|
||
connect_time = -1;
|
||
return;
|
||
}
|
||
|
||
if (!NET_IsClientLegal(&adr))
|
||
{
|
||
Con_Printf ("Illegal server address\n");
|
||
connect_time = -1;
|
||
return;
|
||
}
|
||
|
||
if (adr.port == 0)
|
||
adr.port = BigShort (27500);
|
||
t2 = Sys_DoubleTime ();
|
||
|
||
connect_time = realtime+t2-t1; // for retransmit requests
|
||
|
||
cls.qport = Cvar_VariableValue("qport");
|
||
|
||
// Arrgh, this was not in the old binary only release, and eats up
|
||
// far too much of the 196 chars in the userinfo space, leaving nothing
|
||
// for player use, thus, its commented out for the moment..
|
||
//
|
||
//Info_SetValueForStarKey (cls.userinfo, "*ip", NET_AdrToString(adr), MAX_INFO_STRING);
|
||
|
||
// Con_Printf ("Connecting to %s...\n", cls.servername);
|
||
sprintf (data, "%c%c%c%cconnect %i %i %i \"%s\"\n",
|
||
255, 255, 255, 255, PROTOCOL_VERSION, cls.qport, cls.challenge, cls.userinfo);
|
||
NET_SendPacket (strlen(data), data, adr);
|
||
}
|
||
|
||
/*
|
||
=================
|
||
CL_CheckForResend
|
||
|
||
Resend a connect message if the last one has timed out
|
||
|
||
=================
|
||
*/
|
||
void CL_CheckForResend (void)
|
||
{
|
||
netadr_t adr;
|
||
char data[2048];
|
||
double t1, t2;
|
||
|
||
if (connect_time == -1)
|
||
return;
|
||
if (cls.state != ca_disconnected)
|
||
return;
|
||
if (connect_time && realtime - connect_time < 5.0)
|
||
return;
|
||
|
||
t1 = Sys_DoubleTime ();
|
||
if (!NET_StringToAdr (cls.servername, &adr))
|
||
{
|
||
Con_Printf ("Bad server address\n");
|
||
connect_time = -1;
|
||
return;
|
||
}
|
||
if (!NET_IsClientLegal(&adr))
|
||
{
|
||
Con_Printf ("Illegal server address\n");
|
||
connect_time = -1;
|
||
return;
|
||
}
|
||
|
||
if (adr.port == 0)
|
||
adr.port = BigShort (27500);
|
||
t2 = Sys_DoubleTime ();
|
||
|
||
connect_time = realtime+t2-t1; // for retransmit requests
|
||
|
||
Con_Printf ("Connecting to %s...\n", cls.servername);
|
||
sprintf (data, "%c%c%c%cgetchallenge\n", 255, 255, 255, 255);
|
||
NET_SendPacket (strlen(data), data, adr);
|
||
}
|
||
|
||
void CL_BeginServerConnect(void)
|
||
{
|
||
connect_time = 0;
|
||
CL_CheckForResend();
|
||
}
|
||
|
||
/*
|
||
================
|
||
CL_Connect_f
|
||
|
||
================
|
||
*/
|
||
void CL_Connect_f (void)
|
||
{
|
||
char *server;
|
||
|
||
if (Cmd_Argc() != 2)
|
||
{
|
||
Con_Printf ("usage: connect <server>\n");
|
||
return;
|
||
}
|
||
|
||
server = Cmd_Argv (1);
|
||
|
||
CL_Disconnect ();
|
||
|
||
strncpy (cls.servername, server, sizeof(cls.servername)-1);
|
||
CL_BeginServerConnect();
|
||
}
|
||
|
||
|
||
/*
|
||
=====================
|
||
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_password.string)
|
||
{
|
||
Con_Printf ("You must set 'rcon_password' before\n"
|
||
"issuing an rcon command.\n");
|
||
return;
|
||
}
|
||
|
||
message[0] = 255;
|
||
message[1] = 255;
|
||
message[2] = 255;
|
||
message[3] = 255;
|
||
message[4] = 0;
|
||
|
||
strcat (message, "rcon ");
|
||
|
||
strcat (message, rcon_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))
|
||
{
|
||
Con_Printf ("You must either be connected,\n"
|
||
"or set the 'rcon_address' cvar\n"
|
||
"to issue rcon commands\n");
|
||
|
||
return;
|
||
}
|
||
NET_StringToAdr (rcon_address.string, &to);
|
||
}
|
||
|
||
NET_SendPacket (strlen(message)+1, message
|
||
, to);
|
||
}
|
||
|
||
|
||
/*
|
||
=====================
|
||
CL_ClearState
|
||
|
||
=====================
|
||
*/
|
||
void CL_ClearState (void)
|
||
{
|
||
int i;
|
||
|
||
S_StopAllSounds (true);
|
||
|
||
Con_DPrintf ("Clearing memory\n");
|
||
D_FlushCaches ();
|
||
Mod_ClearAll ();
|
||
if (host_hunklevel) // FIXME: check this...
|
||
Hunk_FreeToLowMark (host_hunklevel);
|
||
|
||
CL_ClearTEnts ();
|
||
|
||
// wipe the entire cl structure
|
||
memset (&cl, 0, sizeof(cl));
|
||
|
||
SZ_Clear (&cls.netchan.message);
|
||
|
||
// clear other arrays
|
||
memset (cl_efrags, 0, sizeof(cl_efrags));
|
||
memset (cl_dlights, 0, sizeof(cl_dlights));
|
||
memset (cl_lightstyle, 0, sizeof(cl_lightstyle));
|
||
|
||
//
|
||
// allocate the efrags and chain together into a free list
|
||
//
|
||
cl.free_efrags = cl_efrags;
|
||
for (i=0 ; i<MAX_EFRAGS-1 ; i++)
|
||
cl.free_efrags[i].entnext = &cl.free_efrags[i+1];
|
||
cl.free_efrags[i].entnext = NULL;
|
||
}
|
||
|
||
/*
|
||
=====================
|
||
CL_Disconnect
|
||
|
||
Sends a disconnect message to the server
|
||
This is also called on Host_Error, so it shouldn't cause any errors
|
||
=====================
|
||
*/
|
||
void CL_Disconnect (void)
|
||
{
|
||
byte final[10];
|
||
|
||
connect_time = -1;
|
||
|
||
#ifdef _WIN32
|
||
SetWindowText (mainwindow, "QuakeWorld: disconnected");
|
||
#endif
|
||
|
||
// stop sounds (especially looping!)
|
||
S_StopAllSounds (true);
|
||
|
||
// if running a local server, shut it down
|
||
if (cls.demoplayback)
|
||
CL_StopPlayback ();
|
||
else if (cls.state != ca_disconnected)
|
||
{
|
||
if (cls.demorecording)
|
||
CL_Stop_f ();
|
||
|
||
final[0] = clc_stringcmd;
|
||
strcpy (final+1, "drop");
|
||
Netchan_Transmit (&cls.netchan, 6, final);
|
||
Netchan_Transmit (&cls.netchan, 6, final);
|
||
Netchan_Transmit (&cls.netchan, 6, final);
|
||
|
||
cls.state = ca_disconnected;
|
||
|
||
cls.demoplayback = cls.demorecording = cls.timedemo = false;
|
||
}
|
||
Cam_Reset();
|
||
|
||
if (cls.download) {
|
||
fclose(cls.download);
|
||
cls.download = NULL;
|
||
}
|
||
|
||
CL_StopUpload();
|
||
|
||
}
|
||
|
||
void CL_Disconnect_f (void)
|
||
{
|
||
CL_Disconnect ();
|
||
}
|
||
|
||
/*
|
||
====================
|
||
CL_User_f
|
||
|
||
user <name or userid>
|
||
|
||
Dump userdata / masterdata for a user
|
||
====================
|
||
*/
|
||
void CL_User_f (void)
|
||
{
|
||
int uid;
|
||
int i;
|
||
|
||
if (Cmd_Argc() != 2)
|
||
{
|
||
Con_Printf ("Usage: user <username / userid>\n");
|
||
return;
|
||
}
|
||
|
||
uid = atoi(Cmd_Argv(1));
|
||
|
||
for (i=0 ; i<MAX_CLIENTS ; i++)
|
||
{
|
||
if (!cl.players[i].name[0])
|
||
continue;
|
||
if (cl.players[i].userid == uid
|
||
|| !strcmp(cl.players[i].name, Cmd_Argv(1)) )
|
||
{
|
||
Info_Print (cl.players[i].userinfo);
|
||
return;
|
||
}
|
||
}
|
||
Con_Printf ("User not in server.\n");
|
||
}
|
||
|
||
/*
|
||
====================
|
||
CL_Users_f
|
||
|
||
Dump userids for all current players
|
||
====================
|
||
*/
|
||
void CL_Users_f (void)
|
||
{
|
||
int i;
|
||
int c;
|
||
|
||
c = 0;
|
||
Con_Printf ("userid frags name\n");
|
||
Con_Printf ("------ ----- ----\n");
|
||
for (i=0 ; i<MAX_CLIENTS ; i++)
|
||
{
|
||
if (cl.players[i].name[0])
|
||
{
|
||
Con_Printf ("%6i %4i %s\n", cl.players[i].userid, cl.players[i].frags, cl.players[i].name);
|
||
c++;
|
||
}
|
||
}
|
||
|
||
Con_Printf ("%i total users\n", c);
|
||
}
|
||
|
||
void CL_Color_f (void)
|
||
{
|
||
// just for quake compatability...
|
||
int top, bottom;
|
||
char num[16];
|
||
|
||
if (Cmd_Argc() == 1)
|
||
{
|
||
Con_Printf ("\"color\" is \"%s %s\"\n",
|
||
Info_ValueForKey (cls.userinfo, "topcolor"),
|
||
Info_ValueForKey (cls.userinfo, "bottomcolor") );
|
||
Con_Printf ("color <0-13> [0-13]\n");
|
||
return;
|
||
}
|
||
|
||
if (Cmd_Argc() == 2)
|
||
top = bottom = atoi(Cmd_Argv(1));
|
||
else
|
||
{
|
||
top = atoi(Cmd_Argv(1));
|
||
bottom = atoi(Cmd_Argv(2));
|
||
}
|
||
|
||
top &= 15;
|
||
if (top > 13)
|
||
top = 13;
|
||
bottom &= 15;
|
||
if (bottom > 13)
|
||
bottom = 13;
|
||
|
||
sprintf (num, "%i", top);
|
||
Cvar_Set ("topcolor", num);
|
||
sprintf (num, "%i", bottom);
|
||
Cvar_Set ("bottomcolor", num);
|
||
}
|
||
|
||
/*
|
||
==================
|
||
CL_FullServerinfo_f
|
||
|
||
Sent by server when serverinfo changes
|
||
==================
|
||
*/
|
||
void CL_FullServerinfo_f (void)
|
||
{
|
||
char *p;
|
||
float v;
|
||
|
||
if (Cmd_Argc() != 2)
|
||
{
|
||
Con_Printf ("usage: fullserverinfo <complete info string>\n");
|
||
return;
|
||
}
|
||
|
||
strcpy (cl.serverinfo, Cmd_Argv(1));
|
||
|
||
if ((p = Info_ValueForKey(cl.serverinfo, "*vesion")) && *p) {
|
||
v = Q_atof(p);
|
||
if (v) {
|
||
if (!server_version)
|
||
Con_Printf("Version %1.2f Server\n", v);
|
||
server_version = v;
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
==================
|
||
CL_FullInfo_f
|
||
|
||
Allow clients to change userinfo
|
||
==================
|
||
Casey was here :)
|
||
*/
|
||
void CL_FullInfo_f (void)
|
||
{
|
||
char key[512];
|
||
char value[512];
|
||
char *o;
|
||
char *s;
|
||
|
||
if (Cmd_Argc() != 2)
|
||
{
|
||
Con_Printf ("fullinfo <complete info string>\n");
|
||
return;
|
||
}
|
||
|
||
s = Cmd_Argv(1);
|
||
if (*s == '\\')
|
||
s++;
|
||
while (*s)
|
||
{
|
||
o = key;
|
||
while (*s && *s != '\\')
|
||
*o++ = *s++;
|
||
*o = 0;
|
||
|
||
if (!*s)
|
||
{
|
||
Con_Printf ("MISSING VALUE\n");
|
||
return;
|
||
}
|
||
|
||
o = value;
|
||
s++;
|
||
while (*s && *s != '\\')
|
||
*o++ = *s++;
|
||
*o = 0;
|
||
|
||
if (*s)
|
||
s++;
|
||
|
||
if (!stricmp(key, pmodel_name) || !stricmp(key, emodel_name))
|
||
continue;
|
||
|
||
Info_SetValueForKey (cls.userinfo, key, value, MAX_INFO_STRING);
|
||
}
|
||
}
|
||
|
||
/*
|
||
==================
|
||
CL_SetInfo_f
|
||
|
||
Allow clients to change userinfo
|
||
==================
|
||
*/
|
||
void CL_SetInfo_f (void)
|
||
{
|
||
if (Cmd_Argc() == 1)
|
||
{
|
||
Info_Print (cls.userinfo);
|
||
return;
|
||
}
|
||
if (Cmd_Argc() != 3)
|
||
{
|
||
Con_Printf ("usage: setinfo [ <key> <value> ]\n");
|
||
return;
|
||
}
|
||
if (!stricmp(Cmd_Argv(1), pmodel_name) || !strcmp(Cmd_Argv(1), emodel_name))
|
||
return;
|
||
|
||
Info_SetValueForKey (cls.userinfo, Cmd_Argv(1), Cmd_Argv(2), MAX_INFO_STRING);
|
||
if (cls.state >= ca_connected)
|
||
Cmd_ForwardToServer ();
|
||
}
|
||
|
||
/*
|
||
====================
|
||
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)
|
||
{
|
||
Con_Printf ("packet <destination> <contents>\n");
|
||
return;
|
||
}
|
||
|
||
if (!NET_StringToAdr (Cmd_Argv(1), &adr))
|
||
{
|
||
Con_Printf ("Bad address\n");
|
||
return;
|
||
}
|
||
|
||
in = Cmd_Argv(2);
|
||
out = send+4;
|
||
send[0] = send[1] = send[2] = send[3] = 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 (out-send, send, adr);
|
||
}
|
||
|
||
|
||
/*
|
||
=====================
|
||
CL_NextDemo
|
||
|
||
Called to play the next demo in the demo loop
|
||
=====================
|
||
*/
|
||
void CL_NextDemo (void)
|
||
{
|
||
char str[1024];
|
||
|
||
if (cls.demonum == -1)
|
||
return; // don't play demos
|
||
|
||
if (!cls.demos[cls.demonum][0] || cls.demonum == MAX_DEMOS)
|
||
{
|
||
cls.demonum = 0;
|
||
if (!cls.demos[cls.demonum][0])
|
||
{
|
||
// Con_Printf ("No demos listed with startdemos\n");
|
||
cls.demonum = -1;
|
||
return;
|
||
}
|
||
}
|
||
|
||
sprintf (str,"playdemo %s\n", cls.demos[cls.demonum]);
|
||
Cbuf_InsertText (str);
|
||
cls.demonum++;
|
||
}
|
||
|
||
|
||
/*
|
||
=================
|
||
CL_Changing_f
|
||
|
||
Just sent as a hint to the client that they should
|
||
drop to full console
|
||
=================
|
||
*/
|
||
void CL_Changing_f (void)
|
||
{
|
||
if (cls.download) // don't change when downloading
|
||
return;
|
||
|
||
S_StopAllSounds (true);
|
||
cl.intermission = 0;
|
||
cls.state = ca_connected; // not active anymore, but not disconnected
|
||
Con_Printf ("\nChanging map...\n");
|
||
}
|
||
|
||
|
||
/*
|
||
=================
|
||
CL_Reconnect_f
|
||
|
||
The server is changing levels
|
||
=================
|
||
*/
|
||
void CL_Reconnect_f (void)
|
||
{
|
||
if (cls.download) // don't change when downloading
|
||
return;
|
||
|
||
S_StopAllSounds (true);
|
||
|
||
if (cls.state == ca_connected) {
|
||
Con_Printf ("reconnecting...\n");
|
||
MSG_WriteChar (&cls.netchan.message, clc_stringcmd);
|
||
MSG_WriteString (&cls.netchan.message, "new");
|
||
return;
|
||
}
|
||
|
||
if (!*cls.servername) {
|
||
Con_Printf("No server to reconnect to...\n");
|
||
return;
|
||
}
|
||
|
||
CL_Disconnect();
|
||
CL_BeginServerConnect();
|
||
}
|
||
|
||
/*
|
||
=================
|
||
CL_ConnectionlessPacket
|
||
|
||
Responses to broadcasts, etc
|
||
=================
|
||
*/
|
||
void CL_ConnectionlessPacket (void)
|
||
{
|
||
char *s;
|
||
int c;
|
||
|
||
MSG_BeginReading ();
|
||
MSG_ReadLong (); // skip the -1
|
||
|
||
c = MSG_ReadByte ();
|
||
if (!cls.demoplayback)
|
||
Con_Printf ("%s: ", NET_AdrToString (net_from));
|
||
// Con_DPrintf ("%s", net_message.data + 5);
|
||
if (c == S2C_CONNECTION)
|
||
{
|
||
Con_Printf ("connection\n");
|
||
if (cls.state >= ca_connected)
|
||
{
|
||
if (!cls.demoplayback)
|
||
Con_Printf ("Dup connect received. Ignored.\n");
|
||
return;
|
||
}
|
||
Netchan_Setup (&cls.netchan, net_from, cls.qport);
|
||
MSG_WriteChar (&cls.netchan.message, clc_stringcmd);
|
||
MSG_WriteString (&cls.netchan.message, "new");
|
||
cls.state = ca_connected;
|
||
Con_Printf ("Connected.\n");
|
||
allowremotecmd = false; // localid required now for remote cmds
|
||
return;
|
||
}
|
||
// remote command from gui front end
|
||
if (c == A2C_CLIENT_COMMAND)
|
||
{
|
||
char cmdtext[2048];
|
||
|
||
Con_Printf ("client command\n");
|
||
|
||
if ((*(unsigned *)net_from.ip != *(unsigned *)net_local_adr.ip
|
||
&& *(unsigned *)net_from.ip != htonl(INADDR_LOOPBACK)) )
|
||
{
|
||
Con_Printf ("Command packet from remote host. Ignored.\n");
|
||
return;
|
||
}
|
||
#ifdef _WIN32
|
||
ShowWindow (mainwindow, SW_RESTORE);
|
||
SetForegroundWindow (mainwindow);
|
||
#endif
|
||
s = MSG_ReadString ();
|
||
|
||
strncpy(cmdtext, s, sizeof(cmdtext) - 1);
|
||
cmdtext[sizeof(cmdtext) - 1] = 0;
|
||
|
||
s = MSG_ReadString ();
|
||
|
||
while (*s && isspace(*s))
|
||
s++;
|
||
while (*s && isspace(s[strlen(s) - 1]))
|
||
s[strlen(s) - 1] = 0;
|
||
|
||
if (!allowremotecmd && (!*localid.string || strcmp(localid.string, s))) {
|
||
if (!*localid.string) {
|
||
Con_Printf("===========================\n");
|
||
Con_Printf("Command packet received from local host, but no "
|
||
"localid has been set. You may need to upgrade your server "
|
||
"browser.\n");
|
||
Con_Printf("===========================\n");
|
||
return;
|
||
}
|
||
Con_Printf("===========================\n");
|
||
Con_Printf("Invalid localid on command packet received from local host. "
|
||
"\n|%s| != |%s|\n"
|
||
"You may need to reload your server browser and QuakeWorld.\n",
|
||
s, localid.string);
|
||
Con_Printf("===========================\n");
|
||
Cvar_Set("localid", "");
|
||
return;
|
||
}
|
||
|
||
Cbuf_AddText (cmdtext);
|
||
allowremotecmd = false;
|
||
return;
|
||
}
|
||
// print command from somewhere
|
||
if (c == A2C_PRINT)
|
||
{
|
||
Con_Printf ("print\n");
|
||
|
||
s = MSG_ReadString ();
|
||
Con_Print (s);
|
||
return;
|
||
}
|
||
|
||
// ping from somewhere
|
||
if (c == A2A_PING)
|
||
{
|
||
char data[6];
|
||
|
||
Con_Printf ("ping\n");
|
||
|
||
data[0] = 0xff;
|
||
data[1] = 0xff;
|
||
data[2] = 0xff;
|
||
data[3] = 0xff;
|
||
data[4] = A2A_ACK;
|
||
data[5] = 0;
|
||
|
||
NET_SendPacket (6, &data, net_from);
|
||
return;
|
||
}
|
||
|
||
if (c == S2C_CHALLENGE) {
|
||
Con_Printf ("challenge\n");
|
||
|
||
s = MSG_ReadString ();
|
||
cls.challenge = atoi(s);
|
||
CL_SendConnectPacket ();
|
||
return;
|
||
}
|
||
|
||
#if 0
|
||
if (c == svc_disconnect) {
|
||
Con_Printf ("disconnect\n");
|
||
|
||
Host_EndGame ("Server disconnected");
|
||
return;
|
||
}
|
||
#endif
|
||
|
||
Con_Printf ("unknown: %c\n", c);
|
||
}
|
||
|
||
|
||
/*
|
||
=================
|
||
CL_ReadPackets
|
||
=================
|
||
*/
|
||
void CL_ReadPackets (void)
|
||
{
|
||
// while (NET_GetPacket ())
|
||
while (CL_GetMessage())
|
||
{
|
||
//
|
||
// remote command packet
|
||
//
|
||
if (*(int *)net_message.data == -1)
|
||
{
|
||
CL_ConnectionlessPacket ();
|
||
continue;
|
||
}
|
||
|
||
if (net_message.cursize < 8)
|
||
{
|
||
Con_Printf ("%s: Runt packet\n",NET_AdrToString(net_from));
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// packet from server
|
||
//
|
||
if (!cls.demoplayback &&
|
||
!NET_CompareAdr (net_from, cls.netchan.remote_address))
|
||
{
|
||
Con_DPrintf ("%s:sequenced packet without connection\n"
|
||
,NET_AdrToString(net_from));
|
||
continue;
|
||
}
|
||
if (!Netchan_Process(&cls.netchan))
|
||
continue; // wasn't accepted for some reason
|
||
CL_ParseServerMessage ();
|
||
|
||
// if (cls.demoplayback && cls.state >= ca_active && !CL_DemoBehind())
|
||
// return;
|
||
}
|
||
|
||
//
|
||
// check timeout
|
||
//
|
||
if (cls.state >= ca_connected
|
||
&& realtime - cls.netchan.last_received > cl_timeout.value)
|
||
{
|
||
Con_Printf ("\nServer connection timed out.\n");
|
||
CL_Disconnect ();
|
||
return;
|
||
}
|
||
|
||
}
|
||
|
||
//=============================================================================
|
||
|
||
/*
|
||
=====================
|
||
CL_Download_f
|
||
=====================
|
||
*/
|
||
void CL_Download_f (void)
|
||
{
|
||
char *p, *q;
|
||
|
||
if (cls.state == ca_disconnected)
|
||
{
|
||
Con_Printf ("Must be connected.\n");
|
||
return;
|
||
}
|
||
|
||
if (Cmd_Argc() != 2)
|
||
{
|
||
Con_Printf ("Usage: download <datafile>\n");
|
||
return;
|
||
}
|
||
|
||
sprintf (cls.downloadname, "%s/%s", com_gamedir, Cmd_Argv(1));
|
||
|
||
p = cls.downloadname;
|
||
for (;;) {
|
||
if ((q = strchr(p, '/')) != NULL) {
|
||
*q = 0;
|
||
Sys_mkdir(cls.downloadname);
|
||
*q = '/';
|
||
p = q + 1;
|
||
} else
|
||
break;
|
||
}
|
||
|
||
strcpy(cls.downloadtempname, cls.downloadname);
|
||
cls.download = fopen (cls.downloadname, "wb");
|
||
cls.downloadtype = dl_single;
|
||
|
||
MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
|
||
SZ_Print (&cls.netchan.message, va("download %s\n",Cmd_Argv(1)));
|
||
}
|
||
|
||
#ifdef _WINDOWS
|
||
#include <windows.h>
|
||
/*
|
||
=================
|
||
CL_Minimize_f
|
||
=================
|
||
*/
|
||
void CL_Windows_f (void) {
|
||
// if (modestate == MS_WINDOWED)
|
||
// ShowWindow(mainwindow, SW_MINIMIZE);
|
||
// else
|
||
SendMessage(mainwindow, WM_SYSKEYUP, VK_TAB, 1 | (0x0F << 16) | (1<<29));
|
||
}
|
||
#endif
|
||
|
||
/*
|
||
=================
|
||
CL_Init
|
||
=================
|
||
*/
|
||
void CL_Init (void)
|
||
{
|
||
extern cvar_t baseskin;
|
||
extern cvar_t noskins;
|
||
char st[80];
|
||
|
||
cls.state = ca_disconnected;
|
||
|
||
Info_SetValueForKey (cls.userinfo, "name", "unnamed", MAX_INFO_STRING);
|
||
Info_SetValueForKey (cls.userinfo, "topcolor", "0", MAX_INFO_STRING);
|
||
Info_SetValueForKey (cls.userinfo, "bottomcolor", "0", MAX_INFO_STRING);
|
||
Info_SetValueForKey (cls.userinfo, "rate", "2500", MAX_INFO_STRING);
|
||
Info_SetValueForKey (cls.userinfo, "msg", "1", MAX_INFO_STRING);
|
||
//sprintf (st, "%4.2f-%04d", VERSION, build_number());
|
||
sprintf (st, "%s", VERSION);
|
||
Info_SetValueForStarKey (cls.userinfo, "*ver", st, MAX_INFO_STRING);
|
||
|
||
CL_InitInput ();
|
||
CL_InitTEnts ();
|
||
CL_InitPrediction ();
|
||
CL_InitCam ();
|
||
Pmove_Init ();
|
||
|
||
//
|
||
// register our commands
|
||
//
|
||
Cvar_RegisterVariable (&show_fps);
|
||
Cvar_RegisterVariable (&host_speeds);
|
||
Cvar_RegisterVariable (&developer);
|
||
|
||
Cvar_RegisterVariable (&cl_warncmd);
|
||
Cvar_RegisterVariable (&cl_upspeed);
|
||
Cvar_RegisterVariable (&cl_forwardspeed);
|
||
Cvar_RegisterVariable (&cl_backspeed);
|
||
Cvar_RegisterVariable (&cl_sidespeed);
|
||
Cvar_RegisterVariable (&cl_movespeedkey);
|
||
Cvar_RegisterVariable (&cl_yawspeed);
|
||
Cvar_RegisterVariable (&cl_pitchspeed);
|
||
Cvar_RegisterVariable (&cl_anglespeedkey);
|
||
Cvar_RegisterVariable (&cl_shownet);
|
||
Cvar_RegisterVariable (&cl_sbar);
|
||
Cvar_RegisterVariable (&cl_hudswap);
|
||
Cvar_RegisterVariable (&cl_maxfps);
|
||
Cvar_RegisterVariable (&cl_timeout);
|
||
Cvar_RegisterVariable (&lookspring);
|
||
Cvar_RegisterVariable (&lookstrafe);
|
||
Cvar_RegisterVariable (&sensitivity);
|
||
|
||
Cvar_RegisterVariable (&m_pitch);
|
||
Cvar_RegisterVariable (&m_yaw);
|
||
Cvar_RegisterVariable (&m_forward);
|
||
Cvar_RegisterVariable (&m_side);
|
||
|
||
Cvar_RegisterVariable (&rcon_password);
|
||
Cvar_RegisterVariable (&rcon_address);
|
||
|
||
Cvar_RegisterVariable (&entlatency);
|
||
Cvar_RegisterVariable (&cl_predict_players2);
|
||
Cvar_RegisterVariable (&cl_predict_players);
|
||
Cvar_RegisterVariable (&cl_solid_players);
|
||
|
||
Cvar_RegisterVariable (&localid);
|
||
|
||
Cvar_RegisterVariable (&baseskin);
|
||
Cvar_RegisterVariable (&noskins);
|
||
|
||
//
|
||
// info mirrors
|
||
//
|
||
Cvar_RegisterVariable (&name);
|
||
Cvar_RegisterVariable (&password);
|
||
Cvar_RegisterVariable (&spectator);
|
||
Cvar_RegisterVariable (&skin);
|
||
Cvar_RegisterVariable (&team);
|
||
Cvar_RegisterVariable (&topcolor);
|
||
Cvar_RegisterVariable (&bottomcolor);
|
||
Cvar_RegisterVariable (&rate);
|
||
Cvar_RegisterVariable (&msg);
|
||
Cvar_RegisterVariable (&noaim);
|
||
|
||
|
||
Cmd_AddCommand ("version", CL_Version_f);
|
||
|
||
Cmd_AddCommand ("changing", CL_Changing_f);
|
||
Cmd_AddCommand ("disconnect", CL_Disconnect_f);
|
||
Cmd_AddCommand ("record", CL_Record_f);
|
||
Cmd_AddCommand ("rerecord", CL_ReRecord_f);
|
||
Cmd_AddCommand ("stop", CL_Stop_f);
|
||
Cmd_AddCommand ("playdemo", CL_PlayDemo_f);
|
||
Cmd_AddCommand ("timedemo", CL_TimeDemo_f);
|
||
|
||
Cmd_AddCommand ("skins", Skin_Skins_f);
|
||
Cmd_AddCommand ("allskins", Skin_AllSkins_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);
|
||
Cmd_AddCommand ("user", CL_User_f);
|
||
Cmd_AddCommand ("users", CL_Users_f);
|
||
|
||
Cmd_AddCommand ("setinfo", CL_SetInfo_f);
|
||
Cmd_AddCommand ("fullinfo", CL_FullInfo_f);
|
||
Cmd_AddCommand ("fullserverinfo", CL_FullServerinfo_f);
|
||
|
||
Cmd_AddCommand ("color", CL_Color_f);
|
||
Cmd_AddCommand ("download", CL_Download_f);
|
||
|
||
Cmd_AddCommand ("nextul", CL_NextUpload);
|
||
Cmd_AddCommand ("stopul", CL_StopUpload);
|
||
|
||
//
|
||
// forward to server commands
|
||
//
|
||
Cmd_AddCommand ("kill", NULL);
|
||
Cmd_AddCommand ("pause", NULL);
|
||
Cmd_AddCommand ("say", NULL);
|
||
Cmd_AddCommand ("say_team", NULL);
|
||
Cmd_AddCommand ("serverinfo", NULL);
|
||
|
||
//
|
||
// Windows commands
|
||
//
|
||
#ifdef _WINDOWS
|
||
Cmd_AddCommand ("windows", CL_Windows_f);
|
||
#endif
|
||
}
|
||
|
||
|
||
/*
|
||
================
|
||
Host_EndGame
|
||
|
||
Call this to drop to a console without exiting the qwcl
|
||
================
|
||
*/
|
||
void Host_EndGame (char *message, ...)
|
||
{
|
||
va_list argptr;
|
||
char string[1024];
|
||
|
||
va_start (argptr,message);
|
||
vsprintf (string,message,argptr);
|
||
va_end (argptr);
|
||
Con_Printf ("\n===========================\n");
|
||
Con_Printf ("Host_EndGame: %s\n",string);
|
||
Con_Printf ("===========================\n\n");
|
||
|
||
CL_Disconnect ();
|
||
|
||
longjmp (host_abort, 1);
|
||
}
|
||
|
||
/*
|
||
================
|
||
Host_Error
|
||
|
||
This shuts down the client and exits qwcl
|
||
================
|
||
*/
|
||
void Host_Error (char *error, ...)
|
||
{
|
||
va_list argptr;
|
||
char string[1024];
|
||
static qboolean inerror = false;
|
||
|
||
if (inerror)
|
||
Sys_Error ("Host_Error: recursively entered");
|
||
inerror = true;
|
||
|
||
va_start (argptr,error);
|
||
vsprintf (string,error,argptr);
|
||
va_end (argptr);
|
||
Con_Printf ("Host_Error: %s\n",string);
|
||
|
||
CL_Disconnect ();
|
||
cls.demonum = -1;
|
||
|
||
inerror = false;
|
||
|
||
// FIXME
|
||
Sys_Error ("Host_Error: %s\n",string);
|
||
}
|
||
|
||
|
||
/*
|
||
===============
|
||
Host_WriteConfiguration
|
||
|
||
Writes key bindings and archived cvars to config.cfg
|
||
===============
|
||
*/
|
||
void Host_WriteConfiguration (void)
|
||
{
|
||
FILE *f;
|
||
|
||
if (host_initialized)
|
||
{
|
||
f = fopen (va("%s/config.cfg",com_gamedir), "w");
|
||
if (!f)
|
||
{
|
||
Con_Printf ("Couldn't write config.cfg.\n");
|
||
return;
|
||
}
|
||
|
||
Key_WriteBindings (f);
|
||
Cvar_WriteVariables (f);
|
||
|
||
fclose (f);
|
||
}
|
||
}
|
||
|
||
|
||
//============================================================================
|
||
|
||
#if 0
|
||
/*
|
||
==================
|
||
Host_SimulationTime
|
||
|
||
This determines if enough time has passed to run a simulation frame
|
||
==================
|
||
*/
|
||
qboolean Host_SimulationTime(float time)
|
||
{
|
||
float fps;
|
||
|
||
if (oldrealtime > realtime)
|
||
oldrealtime = 0;
|
||
|
||
if (cl_maxfps.value)
|
||
fps = max(30.0, min(cl_maxfps.value, 72.0));
|
||
else
|
||
fps = max(30.0, min(rate.value/80.0, 72.0));
|
||
|
||
if (!cls.timedemo && (realtime + time) - oldrealtime < 1.0/fps)
|
||
return false; // framerate is too high
|
||
return true;
|
||
}
|
||
#endif
|
||
|
||
|
||
/*
|
||
==================
|
||
Host_Frame
|
||
|
||
Runs all active servers
|
||
==================
|
||
*/
|
||
int nopacketcount;
|
||
void Host_Frame (float time)
|
||
{
|
||
static double time1 = 0;
|
||
static double time2 = 0;
|
||
static double time3 = 0;
|
||
int pass1, pass2, pass3;
|
||
float fps;
|
||
if (setjmp (host_abort) )
|
||
return; // something bad happened, or the server disconnected
|
||
|
||
// decide the simulation time
|
||
realtime += time;
|
||
if (oldrealtime > realtime)
|
||
oldrealtime = 0;
|
||
|
||
if (cl_maxfps.value)
|
||
fps = max(30.0, min(cl_maxfps.value, 72.0));
|
||
else
|
||
fps = max(30.0, min(rate.value/80.0, 72.0));
|
||
|
||
if (!cls.timedemo && realtime - oldrealtime < 1.0/fps)
|
||
return; // framerate is too high
|
||
|
||
host_frametime = realtime - oldrealtime;
|
||
oldrealtime = realtime;
|
||
if (host_frametime > 0.2)
|
||
host_frametime = 0.2;
|
||
|
||
// get new key events
|
||
Sys_SendKeyEvents ();
|
||
|
||
// allow mice or other external controllers to add commands
|
||
IN_Commands ();
|
||
|
||
// process console commands
|
||
Cbuf_Execute ();
|
||
|
||
// fetch results from server
|
||
CL_ReadPackets ();
|
||
|
||
// send intentions now
|
||
// resend a connection request if necessary
|
||
if (cls.state == ca_disconnected) {
|
||
CL_CheckForResend ();
|
||
} else
|
||
CL_SendCmd ();
|
||
|
||
// Set up prediction for other players
|
||
CL_SetUpPlayerPrediction(false);
|
||
|
||
// do client side motion prediction
|
||
CL_PredictMove ();
|
||
|
||
// Set up prediction for other players
|
||
CL_SetUpPlayerPrediction(true);
|
||
|
||
// build a refresh entity list
|
||
CL_EmitEntities ();
|
||
|
||
// update video
|
||
if (host_speeds.value)
|
||
time1 = Sys_DoubleTime ();
|
||
|
||
SCR_UpdateScreen ();
|
||
|
||
if (host_speeds.value)
|
||
time2 = Sys_DoubleTime ();
|
||
|
||
// update audio
|
||
if (cls.state == ca_active)
|
||
{
|
||
S_Update (r_origin, vpn, vright, vup);
|
||
CL_DecayLights ();
|
||
}
|
||
else
|
||
S_Update (vec3_origin, vec3_origin, vec3_origin, vec3_origin);
|
||
|
||
CDAudio_Update();
|
||
|
||
if (host_speeds.value)
|
||
{
|
||
pass1 = (time1 - time3)*1000;
|
||
time3 = Sys_DoubleTime ();
|
||
pass2 = (time2 - time1)*1000;
|
||
pass3 = (time3 - time2)*1000;
|
||
Con_Printf ("%3i tot %3i server %3i gfx %3i snd\n",
|
||
pass1+pass2+pass3, pass1, pass2, pass3);
|
||
}
|
||
|
||
host_framecount++;
|
||
fps_count++;
|
||
}
|
||
|
||
static void simple_crypt(char *buf, int len)
|
||
{
|
||
while (len--)
|
||
*buf++ ^= 0xff;
|
||
}
|
||
|
||
void Host_FixupModelNames(void)
|
||
{
|
||
simple_crypt(emodel_name, sizeof(emodel_name) - 1);
|
||
simple_crypt(pmodel_name, sizeof(pmodel_name) - 1);
|
||
simple_crypt(prespawn_name, sizeof(prespawn_name) - 1);
|
||
simple_crypt(modellist_name, sizeof(modellist_name) - 1);
|
||
simple_crypt(soundlist_name, sizeof(soundlist_name) - 1);
|
||
}
|
||
|
||
//============================================================================
|
||
|
||
/*
|
||
====================
|
||
Host_Init
|
||
====================
|
||
*/
|
||
void Host_Init (quakeparms_t *parms)
|
||
{
|
||
COM_InitArgv (parms->argc, parms->argv);
|
||
COM_AddParm ("-game");
|
||
COM_AddParm ("qw");
|
||
|
||
Sys_mkdir("qw");
|
||
|
||
if (COM_CheckParm ("-minmemory"))
|
||
parms->memsize = MINIMUM_MEMORY;
|
||
|
||
host_parms = *parms;
|
||
|
||
if (parms->memsize < MINIMUM_MEMORY)
|
||
Sys_Error ("Only %4.1f megs of memory reported, can't execute game", parms->memsize / (float)0x100000);
|
||
|
||
Memory_Init (parms->membase, parms->memsize);
|
||
Cbuf_Init ();
|
||
Cmd_Init ();
|
||
V_Init ();
|
||
|
||
COM_Init ();
|
||
|
||
Host_FixupModelNames();
|
||
|
||
NET_Init (PORT_CLIENT);
|
||
Netchan_Init ();
|
||
|
||
W_LoadWadFile ("gfx.wad");
|
||
Key_Init ();
|
||
Con_Init ();
|
||
M_Init ();
|
||
Mod_Init ();
|
||
|
||
// Con_Printf ("Exe: "__TIME__" "__DATE__"\n");
|
||
Con_Printf ("%4.1f megs RAM used.\n",parms->memsize/ (1024*1024.0));
|
||
|
||
R_InitTextures ();
|
||
|
||
host_basepal = (byte *)COM_LoadHunkFile ("gfx/palette.lmp");
|
||
if (!host_basepal)
|
||
Sys_Error ("Couldn't load gfx/palette.lmp");
|
||
host_colormap = (byte *)COM_LoadHunkFile ("gfx/colormap.lmp");
|
||
if (!host_colormap)
|
||
Sys_Error ("Couldn't load gfx/colormap.lmp");
|
||
#ifdef __linux__
|
||
IN_Init ();
|
||
CDAudio_Init ();
|
||
VID_Init (host_basepal);
|
||
Draw_Init ();
|
||
SCR_Init ();
|
||
R_Init ();
|
||
|
||
// S_Init (); // S_Init is now done as part of VID. Sigh.
|
||
|
||
cls.state = ca_disconnected;
|
||
Sbar_Init ();
|
||
CL_Init ();
|
||
#else
|
||
VID_Init (host_basepal);
|
||
Draw_Init ();
|
||
SCR_Init ();
|
||
R_Init ();
|
||
// S_Init (); // S_Init is now done as part of VID. Sigh.
|
||
#ifdef GLQUAKE
|
||
S_Init();
|
||
#endif
|
||
|
||
cls.state = ca_disconnected;
|
||
CDAudio_Init ();
|
||
Sbar_Init ();
|
||
CL_Init ();
|
||
IN_Init ();
|
||
#endif
|
||
|
||
Cbuf_InsertText ("exec quake.rc\n");
|
||
Cbuf_AddText ("echo Type connect <internet address> or use GameSpy to connect to a game.\n");
|
||
Cbuf_AddText ("cl_warncmd 1\n");
|
||
|
||
Hunk_AllocName (0, "-HOST_HUNKLEVEL-");
|
||
host_hunklevel = Hunk_LowMark ();
|
||
|
||
host_initialized = true;
|
||
|
||
Con_Printf ("\nClient Version %s (Build %04d)\n\n", VERSION, build_number());
|
||
|
||
Con_Printf ("<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> QuakeWorld Initialized <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>\n");
|
||
}
|
||
|
||
|
||
/*
|
||
===============
|
||
Host_Shutdown
|
||
|
||
FIXME: this is a callback from Sys_Quit and Sys_Error. It would be better
|
||
to run quit through here before the final handoff to the sys code.
|
||
===============
|
||
*/
|
||
void Host_Shutdown(void)
|
||
{
|
||
static qboolean isdown = false;
|
||
|
||
if (isdown)
|
||
{
|
||
printf ("recursive shutdown\n");
|
||
return;
|
||
}
|
||
isdown = true;
|
||
|
||
Host_WriteConfiguration ();
|
||
|
||
CDAudio_Shutdown ();
|
||
NET_Shutdown ();
|
||
S_Shutdown();
|
||
IN_Shutdown ();
|
||
if (host_basepal)
|
||
VID_Shutdown();
|
||
}
|
||
|