123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845 |
- /*
- 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
- #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 *cl_stereo_separation;
- cvar_t *cl_stereo;
- 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;
- client_state_t cl;
- 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;
- //======================================================================
- /*
- ====================
- 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);
- fwrite (&swlen, 4, 1, cls.demofile);
- fwrite (net_message.data+8, len, 1, cls.demofile);
- }
- /*
- ====================
- CL_Stop_f
- stop recording a demo
- ====================
- */
- void CL_Stop_f (void)
- {
- int len;
- if (!cls.demorecording)
- {
- Com_Printf ("Not recording a demo.\n");
- return;
- }
- // finish up
- len = -1;
- fwrite (&len, 4, 1, cls.demofile);
- fclose (cls.demofile);
- cls.demofile = NULL;
- cls.demorecording = false;
- Com_Printf ("Stopped demo.\n");
- }
- /*
- ====================
- 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)
- {
- Com_Printf ("record <demoname>\n");
- return;
- }
- if (cls.demorecording)
- {
- Com_Printf ("Already recording.\n");
- return;
- }
- if (cls.state != ca_active)
- {
- Com_Printf ("You must be in a level to record.\n");
- return;
- }
- //
- // open the demo file
- //
- Com_sprintf (name, sizeof(name), "%s/demos/%s.dm2", FS_Gamedir(), Cmd_Argv(1));
- Com_Printf ("recording to %s.\n", name);
- FS_CreatePath (name);
- cls.demofile = fopen (name, "wb");
- if (!cls.demofile)
- {
- Com_Printf ("ERROR: couldn't open.\n");
- 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);
- fwrite (&len, 4, 1, cls.demofile);
- fwrite (buf.data, buf.cursize, 1, cls.demofile);
- 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);
- fwrite (&len, 4, 1, cls.demofile);
- fwrite (buf.data, buf.cursize, 1, cls.demofile);
- 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);
- fwrite (&len, 4, 1, cls.demofile);
- fwrite (buf.data, buf.cursize, 1, cls.demofile);
- // 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 == '+')
- {
- Com_Printf ("Unknown command \"%s\"\n", cmd);
- 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 )
- {
- Com_Printf( "%s=%s\n", Cmd_Argv(1), env );
- }
- else
- {
- Com_Printf( "%s undefined\n", Cmd_Argv(1), env );
- }
- }
- }
- /*
- ==================
- CL_ForwardToServer_f
- ==================
- */
- void CL_ForwardToServer_f (void)
- {
- if (cls.state != ca_connected && cls.state != ca_active)
- {
- Com_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0));
- 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
- if (Cvar_VariableValue ("maxclients") > 1 || !Com_ServerState ())
- {
- Cvar_SetValue ("paused", 0);
- return;
- }
- Cvar_SetValue ("paused", !cl_paused->value);
- }
- /*
- ==================
- CL_Quit_f
- ==================
- */
- void CL_Quit_f (void)
- {
- CL_Disconnect ();
- Com_Quit ();
- }
- /*
- ================
- CL_Drop
- Called after an ERR_DROP was thrown
- ================
- */
- 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)
- SCR_EndLoadingPlaque (); // get rid of loading plaque
- }
- /*
- =======================
- 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))
- {
- Com_Printf ("Bad server address\n");
- 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;
- if (cls.realtime - cls.connect_time < 3000)
- return;
- if (!NET_StringToAdr (cls.servername, &adr))
- {
- Com_Printf ("Bad server address\n");
- cls.state = ca_disconnected;
- return;
- }
- if (adr.port == 0)
- adr.port = BigShort (PORT_SERVER);
- cls.connect_time = cls.realtime; // for retransmit requests
- Com_Printf ("Connecting to %s...\n", cls.servername);
- Netchan_OutOfBandPrint (NS_CLIENT, adr, "getchallenge\n");
- }
- /*
- ================
- CL_Connect_f
- ================
- */
- void CL_Connect_f (void)
- {
- char *server;
- if (Cmd_Argc() != 2)
- {
- Com_Printf ("usage: connect <server>\n");
- 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)
- {
- Com_Printf ("You must set 'rcon_password' before\n"
- "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))
- {
- Com_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);
- 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
- This is also called on Com_Error, so it shouldn't cause any errors
- =====================
- */
- void CL_Disconnect (void)
- {
- byte final[32];
- if (cls.state == ca_disconnected)
- return;
- if (cl_timedemo && cl_timedemo->value)
- {
- int time;
-
- time = Sys_Milliseconds () - cl.timedemo_start;
- if (time > 0)
- Com_Printf ("%i frames, %3.1f seconds: %3.1f fps\n", cl.timedemo_frames,
- time/1000.0, cl.timedemo_frames*1000.0 / time);
- }
- VectorClear (cl.refdef.blend);
- re.CinematicSetPalette(NULL);
- 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) {
- fclose(cls.download);
- cls.download = NULL;
- }
- cls.state = ca_disconnected;
- }
- void CL_Disconnect_f (void)
- {
- Com_Error (ERR_DROP, "Disconnected from server");
- }
- /*
- ====================
- 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)
- {
- Com_Printf ("packet <destination> <contents>\n");
- return;
- }
- NET_Config (true); // allow remote
- if (!NET_StringToAdr (Cmd_Argv(1), &adr))
- {
- Com_Printf ("Bad address\n");
- 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
- if (cls.download)
- return;
- SCR_BeginLoadingPlaque ();
- cls.state = ca_connected; // not active anymore, but not disconnected
- Com_Printf ("\nChanging map...\n");
- }
- /*
- =================
- 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
- if (cls.download)
- return;
- S_StopAllSounds ();
- if (cls.state == ca_connected) {
- Com_Printf ("reconnecting...\n");
- cls.state = ca_connected;
- MSG_WriteChar (&cls.netchan.message, clc_stringcmd);
- MSG_WriteString (&cls.netchan.message, "new");
- return;
- }
- if (*cls.servername) {
- if (cls.state >= ca_connected) {
- CL_Disconnect();
- cls.connect_time = cls.realtime - 1500;
- } else
- cls.connect_time = -99999; // fire immediately
- cls.state = ca_connecting;
- Com_Printf ("reconnecting...\n");
- }
- }
- /*
- =================
- CL_ParseStatusMessage
- Handle a reply from a ping
- =================
- */
- void CL_ParseStatusMessage (void)
- {
- char *s;
- s = MSG_ReadString(&net_message);
- Com_Printf ("%s\n", s);
- 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
- Com_Printf ("pinging broadcast...\n");
- noudp = Cvar_Get ("noudp", "0", CVAR_NOSET);
- if (!noudp->value)
- {
- adr.type = NA_BROADCAST;
- adr.port = BigShort(PORT_SERVER);
- Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
- }
- noipx = Cvar_Get ("noipx", "0", CVAR_NOSET);
- 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
- for (i=0 ; i<16 ; i++)
- {
- Com_sprintf (name, sizeof(name), "adr%i", i);
- adrstring = Cvar_VariableString (name);
- if (!adrstring || !adrstring[0])
- continue;
- Com_Printf ("pinging %s...\n", adrstring);
- if (!NET_StringToAdr (adrstring, &adr))
- {
- Com_Printf ("Bad address: %s\n", adrstring);
- 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;
- Com_Printf ("client %i: %s\n", i, cl.configstrings[CS_PLAYERSKINS+i]);
- 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);
- MSG_ReadLong (&net_message); // skip the -1
- s = MSG_ReadStringLine (&net_message);
- Cmd_TokenizeString (s, false);
- c = Cmd_Argv(0);
- Com_Printf ("%s: %s\n", NET_AdrToString (net_from), c);
- // server connection
- if (!strcmp(c, "client_connect"))
- {
- if (cls.state == ca_connected)
- {
- Com_Printf ("Dup connect received. Ignored.\n");
- 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))
- {
- Com_Printf ("Command packet from remote host. Ignored.\n");
- return;
- }
- Sys_AppActivate ();
- 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);
- Com_Printf ("%s", s);
- 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;
- }
- Com_Printf ("Unknown command.\n");
- }
- /*
- =================
- 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))
- {
- Com_Printf ("dumnping a packet\n");
- }
- }
- /*
- =================
- CL_ReadPackets
- =================
- */
- void CL_ReadPackets (void)
- {
- while (NET_GetPacket (NS_CLIENT, &net_from, &net_message))
- {
- // Com_Printf ("packet\n");
- //
- // 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)
- {
- Com_Printf ("%s: Runt packet\n",NET_AdrToString(net_from));
- continue;
- }
- //
- // packet from server
- //
- if (!NET_CompareAdr (net_from, cls.netchan.remote_address))
- {
- Com_DPrintf ("%s:sequenced packet without connection\n"
- ,NET_AdrToString(net_from));
- continue;
- }
- if (!Netchan_Process(&cls.netchan, &net_message))
- continue; // wasn't accepted for some reason
- CL_ParseServerMessage ();
- }
- //
- // check timeout
- //
- if (cls.state >= ca_connected
- && cls.realtime - cls.netchan.last_received > cl_timeout->value*1000)
- {
- if (++cl.timeoutcount > 5) // timeoutcount saves debugger
- {
- Com_Printf ("\nServer connection timed out.\n");
- CL_Disconnect ();
- return;
- }
- }
- else
- cl.timeoutcount = 0;
-
- }
- //=============================================================================
- /*
- ==============
- 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;
- if (Q_stricmp(sk, "male") == 0 || Q_stricmp(sk, "cyborg") == 0)
- Cvar_Set ("gender", "male");
- else if (Q_stricmp(sk, "female") == 0 || Q_stricmp(sk, "crackhor") == 0)
- Cvar_Set ("gender", "female");
- else
- Cvar_Set ("gender", "none");
- gender->modified = false;
- }
- }
- /*
- ==============
- CL_Userinfo_f
- ==============
- */
- void CL_Userinfo_f (void)
- {
- Com_Printf ("User info settings:\n");
- 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)
- {
- S_Shutdown ();
- S_Init ();
- CL_RegisterSounds ();
- }
- 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];
- dmdl_t *pheader;
- if (cls.state != ca_connected)
- return;
- if (!allow_download->value && precache_check < ENV_CNT)
- precache_check = ENV_CNT;
- //ZOID
- if (precache_check == CS_MODELS) { // confirm map
- 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
- }
- if (precache_check >= CS_MODELS && precache_check < CS_MODELS+MAX_MODELS) {
- if (allow_download_models->value) {
- 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) {
- FS_LoadFile (cl.configstrings[precache_check], (void **)&precache_model);
- if (!precache_model) {
- precache_model_skin = 0;
- precache_check++;
- continue; // couldn't load it
- }
- if (LittleLong(*(unsigned *)precache_model) != IDALIASHEADER) {
- // not an alias model
- FS_FreeFile(precache_model);
- precache_model = 0;
- precache_model_skin = 0;
- precache_check++;
- continue;
- }
- pheader = (dmdl_t *)precache_model;
- if (LittleLong (pheader->version) != ALIAS_VERSION) {
- precache_check++;
- precache_model_skin = 0;
- continue; // couldn't load it
- }
- }
- pheader = (dmdl_t *)precache_model;
- while (precache_model_skin - 1 < LittleLong(pheader->num_skins)) {
- if (!CL_CheckOrDownloadFile((char *)precache_model +
- LittleLong(pheader->ofs_skins) +
- (precache_model_skin - 1)*MAX_SKINNAME)) {
- precache_model_skin++;
- return; // started a download
- }
- precache_model_skin++;
- }
- if (precache_model) {
- FS_FreeFile(precache_model);
- precache_model = 0;
- }
- precache_model_skin = 0;
- precache_check++;
- }
- }
- precache_check = CS_SOUNDS;
- }
- 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] == '*') {
- precache_check++;
- continue;
- }
- Com_sprintf(fn, sizeof(fn), "sound/%s", cl.configstrings[precache_check++]);
- if (!CL_CheckOrDownloadFile(fn))
- return; // started a download
- }
- }
- precache_check = CS_IMAGES;
- }
- 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]) {
- Com_sprintf(fn, sizeof(fn), "pics/%s.pcx", cl.configstrings[precache_check++]);
- if (!CL_CheckOrDownloadFile(fn))
- return; // started a download
- }
- 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
- 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) {
- 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++;
- else
- p = cl.configstrings[CS_PLAYERSKINS+i];
- strcpy(model, p);
- p = strchr(model, '/');
- if (!p)
- p = strchr(model, '\\');
- if (p) {
- *p++ = 0;
- strcpy(skin, p);
- } else
- *skin = 0;
- switch (n) {
- case 0: // model
- Com_sprintf(fn, sizeof(fn), "players/%s/tris.md2", model);
- if (!CL_CheckOrDownloadFile(fn)) {
- precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 1;
- return; // started a download
- }
- n++;
- /*FALL THROUGH*/
- case 1: // weapon model
- Com_sprintf(fn, sizeof(fn), "players/%s/weapon.md2", model);
- if (!CL_CheckOrDownloadFile(fn)) {
- precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 2;
- return; // started a download
- }
- n++;
- /*FALL THROUGH*/
- case 2: // weapon skin
- Com_sprintf(fn, sizeof(fn), "players/%s/weapon.pcx", model);
- if (!CL_CheckOrDownloadFile(fn)) {
- precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 3;
- return; // started a download
- }
- n++;
- /*FALL THROUGH*/
- case 3: // skin
- Com_sprintf(fn, sizeof(fn), "players/%s/%s.pcx", model, skin);
- if (!CL_CheckOrDownloadFile(fn)) {
- precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 4;
- return; // started a download
- }
- n++;
- /*FALL THROUGH*/
- case 4: // skin_i
- Com_sprintf(fn, sizeof(fn), "players/%s/%s_i.pcx", model, skin);
- if (!CL_CheckOrDownloadFile(fn)) {
- precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 5;
- return; // started a download
- }
- // move on to next model
- precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT;
- }
- }
- }
- // precache phase completed
- precache_check = ENV_CNT;
- }
- if (precache_check == ENV_CNT) {
- precache_check = ENV_CNT + 1;
- CM_LoadMap (cl.configstrings[CS_MODELS+1], true, &map_checksum);
- if (map_checksum != atoi(cl.configstrings[CS_MAPCHECKSUM])) {
- Com_Error (ERR_DROP, "Local map version differs from server: %i != '%s'\n",
- map_checksum, cl.configstrings[CS_MAPCHECKSUM]);
- return;
- }
- }
- if (precache_check > ENV_CNT && precache_check < TEXTURE_CNT) {
- if (allow_download->value && allow_download_maps->value) {
- while (precache_check < TEXTURE_CNT) {
- int n = precache_check++ - ENV_CNT - 1;
- if (n & 1)
- Com_sprintf(fn, sizeof(fn), "env/%s%s.pcx",
- cl.configstrings[CS_SKY], env_suf[n/2]);
- else
- Com_sprintf(fn, sizeof(fn), "env/%s%s.tga",
- cl.configstrings[CS_SKY], env_suf[n/2]);
- if (!CL_CheckOrDownloadFile(fn))
- return; // started a download
- }
- }
- precache_check = TEXTURE_CNT;
- }
- if (precache_check == TEXTURE_CNT) {
- precache_check = TEXTURE_CNT+1;
- precache_tex = 0;
- }
- // confirm existance of textures, download any that don't exist
- if (precache_check == TEXTURE_CNT+1) {
- // from qcommon/cmodel.c
- extern int numtexinfo;
- extern mapsurface_t map_surfaces[];
- if (allow_download->value && allow_download_maps->value) {
- while (precache_tex < numtexinfo) {
- char fn[MAX_OSPATH];
- sprintf(fn, "textures/%s.wal", map_surfaces[precache_tex++].rname);
- if (!CL_CheckOrDownloadFile(fn))
- return; // started a download
- }
- }
- 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;
- cls.realtime = Sys_Milliseconds ();
- 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 );
- //
- // register our variables
- //
- cl_stereo_separation = Cvar_Get( "cl_stereo_separation", "0.4", CVAR_ARCHIVE );
- cl_stereo = Cvar_Get( "cl_stereo", "0", 0 );
- 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);
- cl_predict = Cvar_Get ("cl_predict", "1", 0);
- // cl_minfps = Cvar_Get ("cl_minfps", "5", 0);
- cl_maxfps = Cvar_Get ("cl_maxfps", "90", 0);
- 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 *f;
- char path[MAX_QPATH];
- if (cls.state == ca_uninitialized)
- return;
- Com_sprintf (path, sizeof(path),"%s/config.cfg",FS_Gamedir());
- f = fopen (path, "w");
- if (!f)
- {
- Com_Printf ("Couldn't write config.cfg.\n");
- return;
- }
- fprintf (f, "// generated by quake, do not modify\n");
- Key_WriteBindings (f);
- fclose (f);
- Cvar_WriteVariables (path);
- }
- /*
- ==================
- 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;
- if ( !strcmp(cl.configstrings[CS_MAXCLIENTS], "1")
- || !cl.configstrings[CS_MAXCLIENTS][0] )
- return; // single player can cheat
- // 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 ();
- // allow mice or other external controllers to add commands
- IN_Commands ();
- // 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
- ==================
- */
- void CL_Frame (int msec)
- {
- static int extratime;
- static int lasttimecalled;
- if (dedicated->value)
- return;
- extratime += msec;
- if (!cl_timedemo->value)
- {
- if (cls.state == ca_connected && extratime < 100)
- return; // don't flood packets out while connecting
- if (extratime < 1000/cl_maxfps->value)
- return; // framerate is too high
- }
- // let the mouse activate or deactivate
- IN_Frame ();
- // decide the simulation time
- cls.frametime = extratime/1000.0;
- cl.time += extratime;
- cls.realtime = curtime;
- extratime = 0;
- #if 0
- if (cls.frametime > (1.0 / cl_minfps->value))
- cls.frametime = (1.0 / cl_minfps->value);
- #else
- if (cls.frametime > (1.0 / 5))
- cls.frametime = (1.0 / 5);
- #endif
- // if in the debugger last frame, don't timeout
- if (msec > 5000)
- cls.netchan.last_received = Sys_Milliseconds ();
- // 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
- if (host_speeds->value)
- time_before_ref = Sys_Milliseconds ();
- SCR_UpdateScreen ();
- if (host_speeds->value)
- time_after_ref = Sys_Milliseconds ();
- // update audio
- S_Update (cl.refdef.vieworg, cl.v_forward, cl.v_right, cl.v_up);
-
- CDAudio_Update();
- // advance local effects for next frame
- CL_RunDLights ();
- CL_RunLightStyles ();
- SCR_RunCinematic ();
- SCR_RunConsole ();
- cls.framecount++;
- if ( log_stats->value )
- {
- if ( cls.state == ca_active )
- {
- if ( !lasttimecalled )
- {
- lasttimecalled = Sys_Milliseconds();
- if ( log_stats_file )
- fprintf( log_stats_file, "0\n" );
- }
- else
- {
- int now = Sys_Milliseconds();
- if ( log_stats_file )
- fprintf( log_stats_file, "%d\n", now - lasttimecalled );
- lasttimecalled = now;
- }
- }
- }
- }
- //============================================================================
- /*
- ====================
- CL_Init
- ====================
- */
- void CL_Init (void)
- {
- if (dedicated->value)
- return; // nothing running on the client
- // all archived variables will now be loaded
- Con_Init ();
- #if defined __linux__ || defined __sgi
- S_Init ();
- VID_Init ();
- #else
- VID_Init ();
- S_Init (); // sound must be initialized after window is created
- #endif
-
- 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
- CDAudio_Init ();
- CL_InitLocal ();
- IN_Init ();
- // Cbuf_AddText ("exec autoexec.cfg\n");
- FS_ExecAutoexec ();
- Cbuf_Execute ();
- }
- /*
- ===============
- CL_Shutdown
- FIXME: this is a callback from Sys_Quit and Com_Error. It would be better
- to run quit through here before the final handoff to the sys code.
- ===============
- */
- void CL_Shutdown(void)
- {
- static qboolean isdown = false;
-
- if (isdown)
- {
- printf ("recursive shutdown\n");
- return;
- }
- isdown = true;
- CL_WriteConfiguration ();
- CDAudio_Shutdown ();
- S_Shutdown();
- IN_Shutdown ();
- VID_Shutdown();
- }
|