cl_main.c 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845
  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. // cl_main.c -- client main loop
  16. #include "client.h"
  17. cvar_t *freelook;
  18. cvar_t *adr0;
  19. cvar_t *adr1;
  20. cvar_t *adr2;
  21. cvar_t *adr3;
  22. cvar_t *adr4;
  23. cvar_t *adr5;
  24. cvar_t *adr6;
  25. cvar_t *adr7;
  26. cvar_t *adr8;
  27. cvar_t *cl_stereo_separation;
  28. cvar_t *cl_stereo;
  29. cvar_t *rcon_client_password;
  30. cvar_t *rcon_address;
  31. cvar_t *cl_noskins;
  32. cvar_t *cl_autoskins;
  33. cvar_t *cl_footsteps;
  34. cvar_t *cl_timeout;
  35. cvar_t *cl_predict;
  36. //cvar_t *cl_minfps;
  37. cvar_t *cl_maxfps;
  38. cvar_t *cl_gun;
  39. cvar_t *cl_add_particles;
  40. cvar_t *cl_add_lights;
  41. cvar_t *cl_add_entities;
  42. cvar_t *cl_add_blend;
  43. cvar_t *cl_shownet;
  44. cvar_t *cl_showmiss;
  45. cvar_t *cl_showclamp;
  46. cvar_t *cl_paused;
  47. cvar_t *cl_timedemo;
  48. cvar_t *lookspring;
  49. cvar_t *lookstrafe;
  50. cvar_t *sensitivity;
  51. cvar_t *m_pitch;
  52. cvar_t *m_yaw;
  53. cvar_t *m_forward;
  54. cvar_t *m_side;
  55. cvar_t *cl_lightlevel;
  56. //
  57. // userinfo
  58. //
  59. cvar_t *info_password;
  60. cvar_t *info_spectator;
  61. cvar_t *name;
  62. cvar_t *skin;
  63. cvar_t *rate;
  64. cvar_t *fov;
  65. cvar_t *msg;
  66. cvar_t *hand;
  67. cvar_t *gender;
  68. cvar_t *gender_auto;
  69. cvar_t *cl_vwep;
  70. client_static_t cls;
  71. client_state_t cl;
  72. centity_t cl_entities[MAX_EDICTS];
  73. entity_state_t cl_parse_entities[MAX_PARSE_ENTITIES];
  74. extern cvar_t *allow_download;
  75. extern cvar_t *allow_download_players;
  76. extern cvar_t *allow_download_models;
  77. extern cvar_t *allow_download_sounds;
  78. extern cvar_t *allow_download_maps;
  79. //======================================================================
  80. /*
  81. ====================
  82. CL_WriteDemoMessage
  83. Dumps the current net message, prefixed by the length
  84. ====================
  85. */
  86. void CL_WriteDemoMessage (void)
  87. {
  88. int len, swlen;
  89. // the first eight bytes are just packet sequencing stuff
  90. len = net_message.cursize-8;
  91. swlen = LittleLong(len);
  92. fwrite (&swlen, 4, 1, cls.demofile);
  93. fwrite (net_message.data+8, len, 1, cls.demofile);
  94. }
  95. /*
  96. ====================
  97. CL_Stop_f
  98. stop recording a demo
  99. ====================
  100. */
  101. void CL_Stop_f (void)
  102. {
  103. int len;
  104. if (!cls.demorecording)
  105. {
  106. Com_Printf ("Not recording a demo.\n");
  107. return;
  108. }
  109. // finish up
  110. len = -1;
  111. fwrite (&len, 4, 1, cls.demofile);
  112. fclose (cls.demofile);
  113. cls.demofile = NULL;
  114. cls.demorecording = false;
  115. Com_Printf ("Stopped demo.\n");
  116. }
  117. /*
  118. ====================
  119. CL_Record_f
  120. record <demoname>
  121. Begins recording a demo from the current position
  122. ====================
  123. */
  124. void CL_Record_f (void)
  125. {
  126. char name[MAX_OSPATH];
  127. char buf_data[MAX_MSGLEN];
  128. sizebuf_t buf;
  129. int i;
  130. int len;
  131. entity_state_t *ent;
  132. entity_state_t nullstate;
  133. if (Cmd_Argc() != 2)
  134. {
  135. Com_Printf ("record <demoname>\n");
  136. return;
  137. }
  138. if (cls.demorecording)
  139. {
  140. Com_Printf ("Already recording.\n");
  141. return;
  142. }
  143. if (cls.state != ca_active)
  144. {
  145. Com_Printf ("You must be in a level to record.\n");
  146. return;
  147. }
  148. //
  149. // open the demo file
  150. //
  151. Com_sprintf (name, sizeof(name), "%s/demos/%s.dm2", FS_Gamedir(), Cmd_Argv(1));
  152. Com_Printf ("recording to %s.\n", name);
  153. FS_CreatePath (name);
  154. cls.demofile = fopen (name, "wb");
  155. if (!cls.demofile)
  156. {
  157. Com_Printf ("ERROR: couldn't open.\n");
  158. return;
  159. }
  160. cls.demorecording = true;
  161. // don't start saving messages until a non-delta compressed message is received
  162. cls.demowaiting = true;
  163. //
  164. // write out messages to hold the startup information
  165. //
  166. SZ_Init (&buf, buf_data, sizeof(buf_data));
  167. // send the serverdata
  168. MSG_WriteByte (&buf, svc_serverdata);
  169. MSG_WriteLong (&buf, PROTOCOL_VERSION);
  170. MSG_WriteLong (&buf, 0x10000 + cl.servercount);
  171. MSG_WriteByte (&buf, 1); // demos are always attract loops
  172. MSG_WriteString (&buf, cl.gamedir);
  173. MSG_WriteShort (&buf, cl.playernum);
  174. MSG_WriteString (&buf, cl.configstrings[CS_NAME]);
  175. // configstrings
  176. for (i=0 ; i<MAX_CONFIGSTRINGS ; i++)
  177. {
  178. if (cl.configstrings[i][0])
  179. {
  180. if (buf.cursize + strlen (cl.configstrings[i]) + 32 > buf.maxsize)
  181. { // write it out
  182. len = LittleLong (buf.cursize);
  183. fwrite (&len, 4, 1, cls.demofile);
  184. fwrite (buf.data, buf.cursize, 1, cls.demofile);
  185. buf.cursize = 0;
  186. }
  187. MSG_WriteByte (&buf, svc_configstring);
  188. MSG_WriteShort (&buf, i);
  189. MSG_WriteString (&buf, cl.configstrings[i]);
  190. }
  191. }
  192. // baselines
  193. memset (&nullstate, 0, sizeof(nullstate));
  194. for (i=0; i<MAX_EDICTS ; i++)
  195. {
  196. ent = &cl_entities[i].baseline;
  197. if (!ent->modelindex)
  198. continue;
  199. if (buf.cursize + 64 > buf.maxsize)
  200. { // write it out
  201. len = LittleLong (buf.cursize);
  202. fwrite (&len, 4, 1, cls.demofile);
  203. fwrite (buf.data, buf.cursize, 1, cls.demofile);
  204. buf.cursize = 0;
  205. }
  206. MSG_WriteByte (&buf, svc_spawnbaseline);
  207. MSG_WriteDeltaEntity (&nullstate, &cl_entities[i].baseline, &buf, true, true);
  208. }
  209. MSG_WriteByte (&buf, svc_stufftext);
  210. MSG_WriteString (&buf, "precache\n");
  211. // write it to the demo file
  212. len = LittleLong (buf.cursize);
  213. fwrite (&len, 4, 1, cls.demofile);
  214. fwrite (buf.data, buf.cursize, 1, cls.demofile);
  215. // the rest of the demo file will be individual frames
  216. }
  217. //======================================================================
  218. /*
  219. ===================
  220. Cmd_ForwardToServer
  221. adds the current command line as a clc_stringcmd to the client message.
  222. things like godmode, noclip, etc, are commands directed to the server,
  223. so when they are typed in at the console, they will need to be forwarded.
  224. ===================
  225. */
  226. void Cmd_ForwardToServer (void)
  227. {
  228. char *cmd;
  229. cmd = Cmd_Argv(0);
  230. if (cls.state <= ca_connected || *cmd == '-' || *cmd == '+')
  231. {
  232. Com_Printf ("Unknown command \"%s\"\n", cmd);
  233. return;
  234. }
  235. MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
  236. SZ_Print (&cls.netchan.message, cmd);
  237. if (Cmd_Argc() > 1)
  238. {
  239. SZ_Print (&cls.netchan.message, " ");
  240. SZ_Print (&cls.netchan.message, Cmd_Args());
  241. }
  242. }
  243. void CL_Setenv_f( void )
  244. {
  245. int argc = Cmd_Argc();
  246. if ( argc > 2 )
  247. {
  248. char buffer[1000];
  249. int i;
  250. strcpy( buffer, Cmd_Argv(1) );
  251. strcat( buffer, "=" );
  252. for ( i = 2; i < argc; i++ )
  253. {
  254. strcat( buffer, Cmd_Argv( i ) );
  255. strcat( buffer, " " );
  256. }
  257. putenv( buffer );
  258. }
  259. else if ( argc == 2 )
  260. {
  261. char *env = getenv( Cmd_Argv(1) );
  262. if ( env )
  263. {
  264. Com_Printf( "%s=%s\n", Cmd_Argv(1), env );
  265. }
  266. else
  267. {
  268. Com_Printf( "%s undefined\n", Cmd_Argv(1), env );
  269. }
  270. }
  271. }
  272. /*
  273. ==================
  274. CL_ForwardToServer_f
  275. ==================
  276. */
  277. void CL_ForwardToServer_f (void)
  278. {
  279. if (cls.state != ca_connected && cls.state != ca_active)
  280. {
  281. Com_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0));
  282. return;
  283. }
  284. // don't forward the first argument
  285. if (Cmd_Argc() > 1)
  286. {
  287. MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
  288. SZ_Print (&cls.netchan.message, Cmd_Args());
  289. }
  290. }
  291. /*
  292. ==================
  293. CL_Pause_f
  294. ==================
  295. */
  296. void CL_Pause_f (void)
  297. {
  298. // never pause in multiplayer
  299. if (Cvar_VariableValue ("maxclients") > 1 || !Com_ServerState ())
  300. {
  301. Cvar_SetValue ("paused", 0);
  302. return;
  303. }
  304. Cvar_SetValue ("paused", !cl_paused->value);
  305. }
  306. /*
  307. ==================
  308. CL_Quit_f
  309. ==================
  310. */
  311. void CL_Quit_f (void)
  312. {
  313. CL_Disconnect ();
  314. Com_Quit ();
  315. }
  316. /*
  317. ================
  318. CL_Drop
  319. Called after an ERR_DROP was thrown
  320. ================
  321. */
  322. void CL_Drop (void)
  323. {
  324. if (cls.state == ca_uninitialized)
  325. return;
  326. if (cls.state == ca_disconnected)
  327. return;
  328. CL_Disconnect ();
  329. // drop loading plaque unless this is the initial game start
  330. if (cls.disable_servercount != -1)
  331. SCR_EndLoadingPlaque (); // get rid of loading plaque
  332. }
  333. /*
  334. =======================
  335. CL_SendConnectPacket
  336. We have gotten a challenge from the server, so try and
  337. connect.
  338. ======================
  339. */
  340. void CL_SendConnectPacket (void)
  341. {
  342. netadr_t adr;
  343. int port;
  344. if (!NET_StringToAdr (cls.servername, &adr))
  345. {
  346. Com_Printf ("Bad server address\n");
  347. cls.connect_time = 0;
  348. return;
  349. }
  350. if (adr.port == 0)
  351. adr.port = BigShort (PORT_SERVER);
  352. port = Cvar_VariableValue ("qport");
  353. userinfo_modified = false;
  354. Netchan_OutOfBandPrint (NS_CLIENT, adr, "connect %i %i %i \"%s\"\n",
  355. PROTOCOL_VERSION, port, cls.challenge, Cvar_Userinfo() );
  356. }
  357. /*
  358. =================
  359. CL_CheckForResend
  360. Resend a connect message if the last one has timed out
  361. =================
  362. */
  363. void CL_CheckForResend (void)
  364. {
  365. netadr_t adr;
  366. // if the local server is running and we aren't
  367. // then connect
  368. if (cls.state == ca_disconnected && Com_ServerState() )
  369. {
  370. cls.state = ca_connecting;
  371. strncpy (cls.servername, "localhost", sizeof(cls.servername)-1);
  372. // we don't need a challenge on the localhost
  373. CL_SendConnectPacket ();
  374. return;
  375. // cls.connect_time = -99999; // CL_CheckForResend() will fire immediately
  376. }
  377. // resend if we haven't gotten a reply yet
  378. if (cls.state != ca_connecting)
  379. return;
  380. if (cls.realtime - cls.connect_time < 3000)
  381. return;
  382. if (!NET_StringToAdr (cls.servername, &adr))
  383. {
  384. Com_Printf ("Bad server address\n");
  385. cls.state = ca_disconnected;
  386. return;
  387. }
  388. if (adr.port == 0)
  389. adr.port = BigShort (PORT_SERVER);
  390. cls.connect_time = cls.realtime; // for retransmit requests
  391. Com_Printf ("Connecting to %s...\n", cls.servername);
  392. Netchan_OutOfBandPrint (NS_CLIENT, adr, "getchallenge\n");
  393. }
  394. /*
  395. ================
  396. CL_Connect_f
  397. ================
  398. */
  399. void CL_Connect_f (void)
  400. {
  401. char *server;
  402. if (Cmd_Argc() != 2)
  403. {
  404. Com_Printf ("usage: connect <server>\n");
  405. return;
  406. }
  407. if (Com_ServerState ())
  408. { // if running a local server, kill it and reissue
  409. SV_Shutdown (va("Server quit\n", msg), false);
  410. }
  411. else
  412. {
  413. CL_Disconnect ();
  414. }
  415. server = Cmd_Argv (1);
  416. NET_Config (true); // allow remote
  417. CL_Disconnect ();
  418. cls.state = ca_connecting;
  419. strncpy (cls.servername, server, sizeof(cls.servername)-1);
  420. cls.connect_time = -99999; // CL_CheckForResend() will fire immediately
  421. }
  422. /*
  423. =====================
  424. CL_Rcon_f
  425. Send the rest of the command line over as
  426. an unconnected command.
  427. =====================
  428. */
  429. void CL_Rcon_f (void)
  430. {
  431. char message[1024];
  432. int i;
  433. netadr_t to;
  434. if (!rcon_client_password->string)
  435. {
  436. Com_Printf ("You must set 'rcon_password' before\n"
  437. "issuing an rcon command.\n");
  438. return;
  439. }
  440. message[0] = (char)255;
  441. message[1] = (char)255;
  442. message[2] = (char)255;
  443. message[3] = (char)255;
  444. message[4] = 0;
  445. NET_Config (true); // allow remote
  446. strcat (message, "rcon ");
  447. strcat (message, rcon_client_password->string);
  448. strcat (message, " ");
  449. for (i=1 ; i<Cmd_Argc() ; i++)
  450. {
  451. strcat (message, Cmd_Argv(i));
  452. strcat (message, " ");
  453. }
  454. if (cls.state >= ca_connected)
  455. to = cls.netchan.remote_address;
  456. else
  457. {
  458. if (!strlen(rcon_address->string))
  459. {
  460. Com_Printf ("You must either be connected,\n"
  461. "or set the 'rcon_address' cvar\n"
  462. "to issue rcon commands\n");
  463. return;
  464. }
  465. NET_StringToAdr (rcon_address->string, &to);
  466. if (to.port == 0)
  467. to.port = BigShort (PORT_SERVER);
  468. }
  469. NET_SendPacket (NS_CLIENT, strlen(message)+1, message, to);
  470. }
  471. /*
  472. =====================
  473. CL_ClearState
  474. =====================
  475. */
  476. void CL_ClearState (void)
  477. {
  478. S_StopAllSounds ();
  479. CL_ClearEffects ();
  480. CL_ClearTEnts ();
  481. // wipe the entire cl structure
  482. memset (&cl, 0, sizeof(cl));
  483. memset (&cl_entities, 0, sizeof(cl_entities));
  484. SZ_Clear (&cls.netchan.message);
  485. }
  486. /*
  487. =====================
  488. CL_Disconnect
  489. Goes from a connected state to full screen console state
  490. Sends a disconnect message to the server
  491. This is also called on Com_Error, so it shouldn't cause any errors
  492. =====================
  493. */
  494. void CL_Disconnect (void)
  495. {
  496. byte final[32];
  497. if (cls.state == ca_disconnected)
  498. return;
  499. if (cl_timedemo && cl_timedemo->value)
  500. {
  501. int time;
  502. time = Sys_Milliseconds () - cl.timedemo_start;
  503. if (time > 0)
  504. Com_Printf ("%i frames, %3.1f seconds: %3.1f fps\n", cl.timedemo_frames,
  505. time/1000.0, cl.timedemo_frames*1000.0 / time);
  506. }
  507. VectorClear (cl.refdef.blend);
  508. re.CinematicSetPalette(NULL);
  509. M_ForceMenuOff ();
  510. cls.connect_time = 0;
  511. SCR_StopCinematic ();
  512. if (cls.demorecording)
  513. CL_Stop_f ();
  514. // send a disconnect message to the server
  515. final[0] = clc_stringcmd;
  516. strcpy ((char *)final+1, "disconnect");
  517. Netchan_Transmit (&cls.netchan, strlen(final), final);
  518. Netchan_Transmit (&cls.netchan, strlen(final), final);
  519. Netchan_Transmit (&cls.netchan, strlen(final), final);
  520. CL_ClearState ();
  521. // stop download
  522. if (cls.download) {
  523. fclose(cls.download);
  524. cls.download = NULL;
  525. }
  526. cls.state = ca_disconnected;
  527. }
  528. void CL_Disconnect_f (void)
  529. {
  530. Com_Error (ERR_DROP, "Disconnected from server");
  531. }
  532. /*
  533. ====================
  534. CL_Packet_f
  535. packet <destination> <contents>
  536. Contents allows \n escape character
  537. ====================
  538. */
  539. void CL_Packet_f (void)
  540. {
  541. char send[2048];
  542. int i, l;
  543. char *in, *out;
  544. netadr_t adr;
  545. if (Cmd_Argc() != 3)
  546. {
  547. Com_Printf ("packet <destination> <contents>\n");
  548. return;
  549. }
  550. NET_Config (true); // allow remote
  551. if (!NET_StringToAdr (Cmd_Argv(1), &adr))
  552. {
  553. Com_Printf ("Bad address\n");
  554. return;
  555. }
  556. if (!adr.port)
  557. adr.port = BigShort (PORT_SERVER);
  558. in = Cmd_Argv(2);
  559. out = send+4;
  560. send[0] = send[1] = send[2] = send[3] = (char)0xff;
  561. l = strlen (in);
  562. for (i=0 ; i<l ; i++)
  563. {
  564. if (in[i] == '\\' && in[i+1] == 'n')
  565. {
  566. *out++ = '\n';
  567. i++;
  568. }
  569. else
  570. *out++ = in[i];
  571. }
  572. *out = 0;
  573. NET_SendPacket (NS_CLIENT, out-send, send, adr);
  574. }
  575. /*
  576. =================
  577. CL_Changing_f
  578. Just sent as a hint to the client that they should
  579. drop to full console
  580. =================
  581. */
  582. void CL_Changing_f (void)
  583. {
  584. //ZOID
  585. //if we are downloading, we don't change! This so we don't suddenly stop downloading a map
  586. if (cls.download)
  587. return;
  588. SCR_BeginLoadingPlaque ();
  589. cls.state = ca_connected; // not active anymore, but not disconnected
  590. Com_Printf ("\nChanging map...\n");
  591. }
  592. /*
  593. =================
  594. CL_Reconnect_f
  595. The server is changing levels
  596. =================
  597. */
  598. void CL_Reconnect_f (void)
  599. {
  600. //ZOID
  601. //if we are downloading, we don't change! This so we don't suddenly stop downloading a map
  602. if (cls.download)
  603. return;
  604. S_StopAllSounds ();
  605. if (cls.state == ca_connected) {
  606. Com_Printf ("reconnecting...\n");
  607. cls.state = ca_connected;
  608. MSG_WriteChar (&cls.netchan.message, clc_stringcmd);
  609. MSG_WriteString (&cls.netchan.message, "new");
  610. return;
  611. }
  612. if (*cls.servername) {
  613. if (cls.state >= ca_connected) {
  614. CL_Disconnect();
  615. cls.connect_time = cls.realtime - 1500;
  616. } else
  617. cls.connect_time = -99999; // fire immediately
  618. cls.state = ca_connecting;
  619. Com_Printf ("reconnecting...\n");
  620. }
  621. }
  622. /*
  623. =================
  624. CL_ParseStatusMessage
  625. Handle a reply from a ping
  626. =================
  627. */
  628. void CL_ParseStatusMessage (void)
  629. {
  630. char *s;
  631. s = MSG_ReadString(&net_message);
  632. Com_Printf ("%s\n", s);
  633. M_AddToServerList (net_from, s);
  634. }
  635. /*
  636. =================
  637. CL_PingServers_f
  638. =================
  639. */
  640. void CL_PingServers_f (void)
  641. {
  642. int i;
  643. netadr_t adr;
  644. char name[32];
  645. char *adrstring;
  646. cvar_t *noudp;
  647. cvar_t *noipx;
  648. NET_Config (true); // allow remote
  649. // send a broadcast packet
  650. Com_Printf ("pinging broadcast...\n");
  651. noudp = Cvar_Get ("noudp", "0", CVAR_NOSET);
  652. if (!noudp->value)
  653. {
  654. adr.type = NA_BROADCAST;
  655. adr.port = BigShort(PORT_SERVER);
  656. Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
  657. }
  658. noipx = Cvar_Get ("noipx", "0", CVAR_NOSET);
  659. if (!noipx->value)
  660. {
  661. adr.type = NA_BROADCAST_IPX;
  662. adr.port = BigShort(PORT_SERVER);
  663. Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
  664. }
  665. // send a packet to each address book entry
  666. for (i=0 ; i<16 ; i++)
  667. {
  668. Com_sprintf (name, sizeof(name), "adr%i", i);
  669. adrstring = Cvar_VariableString (name);
  670. if (!adrstring || !adrstring[0])
  671. continue;
  672. Com_Printf ("pinging %s...\n", adrstring);
  673. if (!NET_StringToAdr (adrstring, &adr))
  674. {
  675. Com_Printf ("Bad address: %s\n", adrstring);
  676. continue;
  677. }
  678. if (!adr.port)
  679. adr.port = BigShort(PORT_SERVER);
  680. Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
  681. }
  682. }
  683. /*
  684. =================
  685. CL_Skins_f
  686. Load or download any custom player skins and models
  687. =================
  688. */
  689. void CL_Skins_f (void)
  690. {
  691. int i;
  692. for (i=0 ; i<MAX_CLIENTS ; i++)
  693. {
  694. if (!cl.configstrings[CS_PLAYERSKINS+i][0])
  695. continue;
  696. Com_Printf ("client %i: %s\n", i, cl.configstrings[CS_PLAYERSKINS+i]);
  697. SCR_UpdateScreen ();
  698. Sys_SendKeyEvents (); // pump message loop
  699. CL_ParseClientinfo (i);
  700. }
  701. }
  702. /*
  703. =================
  704. CL_ConnectionlessPacket
  705. Responses to broadcasts, etc
  706. =================
  707. */
  708. void CL_ConnectionlessPacket (void)
  709. {
  710. char *s;
  711. char *c;
  712. MSG_BeginReading (&net_message);
  713. MSG_ReadLong (&net_message); // skip the -1
  714. s = MSG_ReadStringLine (&net_message);
  715. Cmd_TokenizeString (s, false);
  716. c = Cmd_Argv(0);
  717. Com_Printf ("%s: %s\n", NET_AdrToString (net_from), c);
  718. // server connection
  719. if (!strcmp(c, "client_connect"))
  720. {
  721. if (cls.state == ca_connected)
  722. {
  723. Com_Printf ("Dup connect received. Ignored.\n");
  724. return;
  725. }
  726. Netchan_Setup (NS_CLIENT, &cls.netchan, net_from, cls.quakePort);
  727. MSG_WriteChar (&cls.netchan.message, clc_stringcmd);
  728. MSG_WriteString (&cls.netchan.message, "new");
  729. cls.state = ca_connected;
  730. return;
  731. }
  732. // server responding to a status broadcast
  733. if (!strcmp(c, "info"))
  734. {
  735. CL_ParseStatusMessage ();
  736. return;
  737. }
  738. // remote command from gui front end
  739. if (!strcmp(c, "cmd"))
  740. {
  741. if (!NET_IsLocalAddress(net_from))
  742. {
  743. Com_Printf ("Command packet from remote host. Ignored.\n");
  744. return;
  745. }
  746. Sys_AppActivate ();
  747. s = MSG_ReadString (&net_message);
  748. Cbuf_AddText (s);
  749. Cbuf_AddText ("\n");
  750. return;
  751. }
  752. // print command from somewhere
  753. if (!strcmp(c, "print"))
  754. {
  755. s = MSG_ReadString (&net_message);
  756. Com_Printf ("%s", s);
  757. return;
  758. }
  759. // ping from somewhere
  760. if (!strcmp(c, "ping"))
  761. {
  762. Netchan_OutOfBandPrint (NS_CLIENT, net_from, "ack");
  763. return;
  764. }
  765. // challenge from the server we are connecting to
  766. if (!strcmp(c, "challenge"))
  767. {
  768. cls.challenge = atoi(Cmd_Argv(1));
  769. CL_SendConnectPacket ();
  770. return;
  771. }
  772. // echo request from server
  773. if (!strcmp(c, "echo"))
  774. {
  775. Netchan_OutOfBandPrint (NS_CLIENT, net_from, "%s", Cmd_Argv(1) );
  776. return;
  777. }
  778. Com_Printf ("Unknown command.\n");
  779. }
  780. /*
  781. =================
  782. CL_DumpPackets
  783. A vain attempt to help bad TCP stacks that cause problems
  784. when they overflow
  785. =================
  786. */
  787. void CL_DumpPackets (void)
  788. {
  789. while (NET_GetPacket (NS_CLIENT, &net_from, &net_message))
  790. {
  791. Com_Printf ("dumnping a packet\n");
  792. }
  793. }
  794. /*
  795. =================
  796. CL_ReadPackets
  797. =================
  798. */
  799. void CL_ReadPackets (void)
  800. {
  801. while (NET_GetPacket (NS_CLIENT, &net_from, &net_message))
  802. {
  803. // Com_Printf ("packet\n");
  804. //
  805. // remote command packet
  806. //
  807. if (*(int *)net_message.data == -1)
  808. {
  809. CL_ConnectionlessPacket ();
  810. continue;
  811. }
  812. if (cls.state == ca_disconnected || cls.state == ca_connecting)
  813. continue; // dump it if not connected
  814. if (net_message.cursize < 8)
  815. {
  816. Com_Printf ("%s: Runt packet\n",NET_AdrToString(net_from));
  817. continue;
  818. }
  819. //
  820. // packet from server
  821. //
  822. if (!NET_CompareAdr (net_from, cls.netchan.remote_address))
  823. {
  824. Com_DPrintf ("%s:sequenced packet without connection\n"
  825. ,NET_AdrToString(net_from));
  826. continue;
  827. }
  828. if (!Netchan_Process(&cls.netchan, &net_message))
  829. continue; // wasn't accepted for some reason
  830. CL_ParseServerMessage ();
  831. }
  832. //
  833. // check timeout
  834. //
  835. if (cls.state >= ca_connected
  836. && cls.realtime - cls.netchan.last_received > cl_timeout->value*1000)
  837. {
  838. if (++cl.timeoutcount > 5) // timeoutcount saves debugger
  839. {
  840. Com_Printf ("\nServer connection timed out.\n");
  841. CL_Disconnect ();
  842. return;
  843. }
  844. }
  845. else
  846. cl.timeoutcount = 0;
  847. }
  848. //=============================================================================
  849. /*
  850. ==============
  851. CL_FixUpGender_f
  852. ==============
  853. */
  854. void CL_FixUpGender(void)
  855. {
  856. char *p;
  857. char sk[80];
  858. if (gender_auto->value) {
  859. if (gender->modified) {
  860. // was set directly, don't override the user
  861. gender->modified = false;
  862. return;
  863. }
  864. strncpy(sk, skin->string, sizeof(sk) - 1);
  865. if ((p = strchr(sk, '/')) != NULL)
  866. *p = 0;
  867. if (Q_stricmp(sk, "male") == 0 || Q_stricmp(sk, "cyborg") == 0)
  868. Cvar_Set ("gender", "male");
  869. else if (Q_stricmp(sk, "female") == 0 || Q_stricmp(sk, "crackhor") == 0)
  870. Cvar_Set ("gender", "female");
  871. else
  872. Cvar_Set ("gender", "none");
  873. gender->modified = false;
  874. }
  875. }
  876. /*
  877. ==============
  878. CL_Userinfo_f
  879. ==============
  880. */
  881. void CL_Userinfo_f (void)
  882. {
  883. Com_Printf ("User info settings:\n");
  884. Info_Print (Cvar_Userinfo());
  885. }
  886. /*
  887. =================
  888. CL_Snd_Restart_f
  889. Restart the sound subsystem so it can pick up
  890. new parameters and flush all sounds
  891. =================
  892. */
  893. void CL_Snd_Restart_f (void)
  894. {
  895. S_Shutdown ();
  896. S_Init ();
  897. CL_RegisterSounds ();
  898. }
  899. int precache_check; // for autodownload of precache items
  900. int precache_spawncount;
  901. int precache_tex;
  902. int precache_model_skin;
  903. byte *precache_model; // used for skin checking in alias models
  904. #define PLAYER_MULT 5
  905. // ENV_CNT is map load, ENV_CNT+1 is first env map
  906. #define ENV_CNT (CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT)
  907. #define TEXTURE_CNT (ENV_CNT+13)
  908. static const char *env_suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
  909. void CL_RequestNextDownload (void)
  910. {
  911. unsigned map_checksum; // for detecting cheater maps
  912. char fn[MAX_OSPATH];
  913. dmdl_t *pheader;
  914. if (cls.state != ca_connected)
  915. return;
  916. if (!allow_download->value && precache_check < ENV_CNT)
  917. precache_check = ENV_CNT;
  918. //ZOID
  919. if (precache_check == CS_MODELS) { // confirm map
  920. precache_check = CS_MODELS+2; // 0 isn't used
  921. if (allow_download_maps->value)
  922. if (!CL_CheckOrDownloadFile(cl.configstrings[CS_MODELS+1]))
  923. return; // started a download
  924. }
  925. if (precache_check >= CS_MODELS && precache_check < CS_MODELS+MAX_MODELS) {
  926. if (allow_download_models->value) {
  927. while (precache_check < CS_MODELS+MAX_MODELS &&
  928. cl.configstrings[precache_check][0]) {
  929. if (cl.configstrings[precache_check][0] == '*' ||
  930. cl.configstrings[precache_check][0] == '#') {
  931. precache_check++;
  932. continue;
  933. }
  934. if (precache_model_skin == 0) {
  935. if (!CL_CheckOrDownloadFile(cl.configstrings[precache_check])) {
  936. precache_model_skin = 1;
  937. return; // started a download
  938. }
  939. precache_model_skin = 1;
  940. }
  941. // checking for skins in the model
  942. if (!precache_model) {
  943. FS_LoadFile (cl.configstrings[precache_check], (void **)&precache_model);
  944. if (!precache_model) {
  945. precache_model_skin = 0;
  946. precache_check++;
  947. continue; // couldn't load it
  948. }
  949. if (LittleLong(*(unsigned *)precache_model) != IDALIASHEADER) {
  950. // not an alias model
  951. FS_FreeFile(precache_model);
  952. precache_model = 0;
  953. precache_model_skin = 0;
  954. precache_check++;
  955. continue;
  956. }
  957. pheader = (dmdl_t *)precache_model;
  958. if (LittleLong (pheader->version) != ALIAS_VERSION) {
  959. precache_check++;
  960. precache_model_skin = 0;
  961. continue; // couldn't load it
  962. }
  963. }
  964. pheader = (dmdl_t *)precache_model;
  965. while (precache_model_skin - 1 < LittleLong(pheader->num_skins)) {
  966. if (!CL_CheckOrDownloadFile((char *)precache_model +
  967. LittleLong(pheader->ofs_skins) +
  968. (precache_model_skin - 1)*MAX_SKINNAME)) {
  969. precache_model_skin++;
  970. return; // started a download
  971. }
  972. precache_model_skin++;
  973. }
  974. if (precache_model) {
  975. FS_FreeFile(precache_model);
  976. precache_model = 0;
  977. }
  978. precache_model_skin = 0;
  979. precache_check++;
  980. }
  981. }
  982. precache_check = CS_SOUNDS;
  983. }
  984. if (precache_check >= CS_SOUNDS && precache_check < CS_SOUNDS+MAX_SOUNDS) {
  985. if (allow_download_sounds->value) {
  986. if (precache_check == CS_SOUNDS)
  987. precache_check++; // zero is blank
  988. while (precache_check < CS_SOUNDS+MAX_SOUNDS &&
  989. cl.configstrings[precache_check][0]) {
  990. if (cl.configstrings[precache_check][0] == '*') {
  991. precache_check++;
  992. continue;
  993. }
  994. Com_sprintf(fn, sizeof(fn), "sound/%s", cl.configstrings[precache_check++]);
  995. if (!CL_CheckOrDownloadFile(fn))
  996. return; // started a download
  997. }
  998. }
  999. precache_check = CS_IMAGES;
  1000. }
  1001. if (precache_check >= CS_IMAGES && precache_check < CS_IMAGES+MAX_IMAGES) {
  1002. if (precache_check == CS_IMAGES)
  1003. precache_check++; // zero is blank
  1004. while (precache_check < CS_IMAGES+MAX_IMAGES &&
  1005. cl.configstrings[precache_check][0]) {
  1006. Com_sprintf(fn, sizeof(fn), "pics/%s.pcx", cl.configstrings[precache_check++]);
  1007. if (!CL_CheckOrDownloadFile(fn))
  1008. return; // started a download
  1009. }
  1010. precache_check = CS_PLAYERSKINS;
  1011. }
  1012. // skins are special, since a player has three things to download:
  1013. // model, weapon model and skin
  1014. // so precache_check is now *3
  1015. if (precache_check >= CS_PLAYERSKINS && precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT) {
  1016. if (allow_download_players->value) {
  1017. while (precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT) {
  1018. int i, n;
  1019. char model[MAX_QPATH], skin[MAX_QPATH], *p;
  1020. i = (precache_check - CS_PLAYERSKINS)/PLAYER_MULT;
  1021. n = (precache_check - CS_PLAYERSKINS)%PLAYER_MULT;
  1022. if (!cl.configstrings[CS_PLAYERSKINS+i][0]) {
  1023. precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT;
  1024. continue;
  1025. }
  1026. if ((p = strchr(cl.configstrings[CS_PLAYERSKINS+i], '\\')) != NULL)
  1027. p++;
  1028. else
  1029. p = cl.configstrings[CS_PLAYERSKINS+i];
  1030. strcpy(model, p);
  1031. p = strchr(model, '/');
  1032. if (!p)
  1033. p = strchr(model, '\\');
  1034. if (p) {
  1035. *p++ = 0;
  1036. strcpy(skin, p);
  1037. } else
  1038. *skin = 0;
  1039. switch (n) {
  1040. case 0: // model
  1041. Com_sprintf(fn, sizeof(fn), "players/%s/tris.md2", model);
  1042. if (!CL_CheckOrDownloadFile(fn)) {
  1043. precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 1;
  1044. return; // started a download
  1045. }
  1046. n++;
  1047. /*FALL THROUGH*/
  1048. case 1: // weapon model
  1049. Com_sprintf(fn, sizeof(fn), "players/%s/weapon.md2", model);
  1050. if (!CL_CheckOrDownloadFile(fn)) {
  1051. precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 2;
  1052. return; // started a download
  1053. }
  1054. n++;
  1055. /*FALL THROUGH*/
  1056. case 2: // weapon skin
  1057. Com_sprintf(fn, sizeof(fn), "players/%s/weapon.pcx", model);
  1058. if (!CL_CheckOrDownloadFile(fn)) {
  1059. precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 3;
  1060. return; // started a download
  1061. }
  1062. n++;
  1063. /*FALL THROUGH*/
  1064. case 3: // skin
  1065. Com_sprintf(fn, sizeof(fn), "players/%s/%s.pcx", model, skin);
  1066. if (!CL_CheckOrDownloadFile(fn)) {
  1067. precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 4;
  1068. return; // started a download
  1069. }
  1070. n++;
  1071. /*FALL THROUGH*/
  1072. case 4: // skin_i
  1073. Com_sprintf(fn, sizeof(fn), "players/%s/%s_i.pcx", model, skin);
  1074. if (!CL_CheckOrDownloadFile(fn)) {
  1075. precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 5;
  1076. return; // started a download
  1077. }
  1078. // move on to next model
  1079. precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT;
  1080. }
  1081. }
  1082. }
  1083. // precache phase completed
  1084. precache_check = ENV_CNT;
  1085. }
  1086. if (precache_check == ENV_CNT) {
  1087. precache_check = ENV_CNT + 1;
  1088. CM_LoadMap (cl.configstrings[CS_MODELS+1], true, &map_checksum);
  1089. if (map_checksum != atoi(cl.configstrings[CS_MAPCHECKSUM])) {
  1090. Com_Error (ERR_DROP, "Local map version differs from server: %i != '%s'\n",
  1091. map_checksum, cl.configstrings[CS_MAPCHECKSUM]);
  1092. return;
  1093. }
  1094. }
  1095. if (precache_check > ENV_CNT && precache_check < TEXTURE_CNT) {
  1096. if (allow_download->value && allow_download_maps->value) {
  1097. while (precache_check < TEXTURE_CNT) {
  1098. int n = precache_check++ - ENV_CNT - 1;
  1099. if (n & 1)
  1100. Com_sprintf(fn, sizeof(fn), "env/%s%s.pcx",
  1101. cl.configstrings[CS_SKY], env_suf[n/2]);
  1102. else
  1103. Com_sprintf(fn, sizeof(fn), "env/%s%s.tga",
  1104. cl.configstrings[CS_SKY], env_suf[n/2]);
  1105. if (!CL_CheckOrDownloadFile(fn))
  1106. return; // started a download
  1107. }
  1108. }
  1109. precache_check = TEXTURE_CNT;
  1110. }
  1111. if (precache_check == TEXTURE_CNT) {
  1112. precache_check = TEXTURE_CNT+1;
  1113. precache_tex = 0;
  1114. }
  1115. // confirm existance of textures, download any that don't exist
  1116. if (precache_check == TEXTURE_CNT+1) {
  1117. // from qcommon/cmodel.c
  1118. extern int numtexinfo;
  1119. extern mapsurface_t map_surfaces[];
  1120. if (allow_download->value && allow_download_maps->value) {
  1121. while (precache_tex < numtexinfo) {
  1122. char fn[MAX_OSPATH];
  1123. sprintf(fn, "textures/%s.wal", map_surfaces[precache_tex++].rname);
  1124. if (!CL_CheckOrDownloadFile(fn))
  1125. return; // started a download
  1126. }
  1127. }
  1128. precache_check = TEXTURE_CNT+999;
  1129. }
  1130. //ZOID
  1131. CL_RegisterSounds ();
  1132. CL_PrepRefresh ();
  1133. MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
  1134. MSG_WriteString (&cls.netchan.message, va("begin %i\n", precache_spawncount) );
  1135. }
  1136. /*
  1137. =================
  1138. CL_Precache_f
  1139. The server will send this command right
  1140. before allowing the client into the server
  1141. =================
  1142. */
  1143. void CL_Precache_f (void)
  1144. {
  1145. //Yet another hack to let old demos work
  1146. //the old precache sequence
  1147. if (Cmd_Argc() < 2) {
  1148. unsigned map_checksum; // for detecting cheater maps
  1149. CM_LoadMap (cl.configstrings[CS_MODELS+1], true, &map_checksum);
  1150. CL_RegisterSounds ();
  1151. CL_PrepRefresh ();
  1152. return;
  1153. }
  1154. precache_check = CS_MODELS;
  1155. precache_spawncount = atoi(Cmd_Argv(1));
  1156. precache_model = 0;
  1157. precache_model_skin = 0;
  1158. CL_RequestNextDownload();
  1159. }
  1160. /*
  1161. =================
  1162. CL_InitLocal
  1163. =================
  1164. */
  1165. void CL_InitLocal (void)
  1166. {
  1167. cls.state = ca_disconnected;
  1168. cls.realtime = Sys_Milliseconds ();
  1169. CL_InitInput ();
  1170. adr0 = Cvar_Get( "adr0", "", CVAR_ARCHIVE );
  1171. adr1 = Cvar_Get( "adr1", "", CVAR_ARCHIVE );
  1172. adr2 = Cvar_Get( "adr2", "", CVAR_ARCHIVE );
  1173. adr3 = Cvar_Get( "adr3", "", CVAR_ARCHIVE );
  1174. adr4 = Cvar_Get( "adr4", "", CVAR_ARCHIVE );
  1175. adr5 = Cvar_Get( "adr5", "", CVAR_ARCHIVE );
  1176. adr6 = Cvar_Get( "adr6", "", CVAR_ARCHIVE );
  1177. adr7 = Cvar_Get( "adr7", "", CVAR_ARCHIVE );
  1178. adr8 = Cvar_Get( "adr8", "", CVAR_ARCHIVE );
  1179. //
  1180. // register our variables
  1181. //
  1182. cl_stereo_separation = Cvar_Get( "cl_stereo_separation", "0.4", CVAR_ARCHIVE );
  1183. cl_stereo = Cvar_Get( "cl_stereo", "0", 0 );
  1184. cl_add_blend = Cvar_Get ("cl_blend", "1", 0);
  1185. cl_add_lights = Cvar_Get ("cl_lights", "1", 0);
  1186. cl_add_particles = Cvar_Get ("cl_particles", "1", 0);
  1187. cl_add_entities = Cvar_Get ("cl_entities", "1", 0);
  1188. cl_gun = Cvar_Get ("cl_gun", "1", 0);
  1189. cl_footsteps = Cvar_Get ("cl_footsteps", "1", 0);
  1190. cl_noskins = Cvar_Get ("cl_noskins", "0", 0);
  1191. cl_autoskins = Cvar_Get ("cl_autoskins", "0", 0);
  1192. cl_predict = Cvar_Get ("cl_predict", "1", 0);
  1193. // cl_minfps = Cvar_Get ("cl_minfps", "5", 0);
  1194. cl_maxfps = Cvar_Get ("cl_maxfps", "90", 0);
  1195. cl_upspeed = Cvar_Get ("cl_upspeed", "200", 0);
  1196. cl_forwardspeed = Cvar_Get ("cl_forwardspeed", "200", 0);
  1197. cl_sidespeed = Cvar_Get ("cl_sidespeed", "200", 0);
  1198. cl_yawspeed = Cvar_Get ("cl_yawspeed", "140", 0);
  1199. cl_pitchspeed = Cvar_Get ("cl_pitchspeed", "150", 0);
  1200. cl_anglespeedkey = Cvar_Get ("cl_anglespeedkey", "1.5", 0);
  1201. cl_run = Cvar_Get ("cl_run", "0", CVAR_ARCHIVE);
  1202. freelook = Cvar_Get( "freelook", "0", CVAR_ARCHIVE );
  1203. lookspring = Cvar_Get ("lookspring", "0", CVAR_ARCHIVE);
  1204. lookstrafe = Cvar_Get ("lookstrafe", "0", CVAR_ARCHIVE);
  1205. sensitivity = Cvar_Get ("sensitivity", "3", CVAR_ARCHIVE);
  1206. m_pitch = Cvar_Get ("m_pitch", "0.022", CVAR_ARCHIVE);
  1207. m_yaw = Cvar_Get ("m_yaw", "0.022", 0);
  1208. m_forward = Cvar_Get ("m_forward", "1", 0);
  1209. m_side = Cvar_Get ("m_side", "1", 0);
  1210. cl_shownet = Cvar_Get ("cl_shownet", "0", 0);
  1211. cl_showmiss = Cvar_Get ("cl_showmiss", "0", 0);
  1212. cl_showclamp = Cvar_Get ("showclamp", "0", 0);
  1213. cl_timeout = Cvar_Get ("cl_timeout", "120", 0);
  1214. cl_paused = Cvar_Get ("paused", "0", 0);
  1215. cl_timedemo = Cvar_Get ("timedemo", "0", 0);
  1216. rcon_client_password = Cvar_Get ("rcon_password", "", 0);
  1217. rcon_address = Cvar_Get ("rcon_address", "", 0);
  1218. cl_lightlevel = Cvar_Get ("r_lightlevel", "0", 0);
  1219. //
  1220. // userinfo
  1221. //
  1222. info_password = Cvar_Get ("password", "", CVAR_USERINFO);
  1223. info_spectator = Cvar_Get ("spectator", "0", CVAR_USERINFO);
  1224. name = Cvar_Get ("name", "unnamed", CVAR_USERINFO | CVAR_ARCHIVE);
  1225. skin = Cvar_Get ("skin", "male/grunt", CVAR_USERINFO | CVAR_ARCHIVE);
  1226. rate = Cvar_Get ("rate", "25000", CVAR_USERINFO | CVAR_ARCHIVE); // FIXME
  1227. msg = Cvar_Get ("msg", "1", CVAR_USERINFO | CVAR_ARCHIVE);
  1228. hand = Cvar_Get ("hand", "0", CVAR_USERINFO | CVAR_ARCHIVE);
  1229. fov = Cvar_Get ("fov", "90", CVAR_USERINFO | CVAR_ARCHIVE);
  1230. gender = Cvar_Get ("gender", "male", CVAR_USERINFO | CVAR_ARCHIVE);
  1231. gender_auto = Cvar_Get ("gender_auto", "1", CVAR_ARCHIVE);
  1232. gender->modified = false; // clear this so we know when user sets it manually
  1233. cl_vwep = Cvar_Get ("cl_vwep", "1", CVAR_ARCHIVE);
  1234. //
  1235. // register our commands
  1236. //
  1237. Cmd_AddCommand ("cmd", CL_ForwardToServer_f);
  1238. Cmd_AddCommand ("pause", CL_Pause_f);
  1239. Cmd_AddCommand ("pingservers", CL_PingServers_f);
  1240. Cmd_AddCommand ("skins", CL_Skins_f);
  1241. Cmd_AddCommand ("userinfo", CL_Userinfo_f);
  1242. Cmd_AddCommand ("snd_restart", CL_Snd_Restart_f);
  1243. Cmd_AddCommand ("changing", CL_Changing_f);
  1244. Cmd_AddCommand ("disconnect", CL_Disconnect_f);
  1245. Cmd_AddCommand ("record", CL_Record_f);
  1246. Cmd_AddCommand ("stop", CL_Stop_f);
  1247. Cmd_AddCommand ("quit", CL_Quit_f);
  1248. Cmd_AddCommand ("connect", CL_Connect_f);
  1249. Cmd_AddCommand ("reconnect", CL_Reconnect_f);
  1250. Cmd_AddCommand ("rcon", CL_Rcon_f);
  1251. // Cmd_AddCommand ("packet", CL_Packet_f); // this is dangerous to leave in
  1252. Cmd_AddCommand ("setenv", CL_Setenv_f );
  1253. Cmd_AddCommand ("precache", CL_Precache_f);
  1254. Cmd_AddCommand ("download", CL_Download_f);
  1255. //
  1256. // forward to server commands
  1257. //
  1258. // the only thing this does is allow command completion
  1259. // to work -- all unknown commands are automatically
  1260. // forwarded to the server
  1261. Cmd_AddCommand ("wave", NULL);
  1262. Cmd_AddCommand ("inven", NULL);
  1263. Cmd_AddCommand ("kill", NULL);
  1264. Cmd_AddCommand ("use", NULL);
  1265. Cmd_AddCommand ("drop", NULL);
  1266. Cmd_AddCommand ("say", NULL);
  1267. Cmd_AddCommand ("say_team", NULL);
  1268. Cmd_AddCommand ("info", NULL);
  1269. Cmd_AddCommand ("prog", NULL);
  1270. Cmd_AddCommand ("give", NULL);
  1271. Cmd_AddCommand ("god", NULL);
  1272. Cmd_AddCommand ("notarget", NULL);
  1273. Cmd_AddCommand ("noclip", NULL);
  1274. Cmd_AddCommand ("invuse", NULL);
  1275. Cmd_AddCommand ("invprev", NULL);
  1276. Cmd_AddCommand ("invnext", NULL);
  1277. Cmd_AddCommand ("invdrop", NULL);
  1278. Cmd_AddCommand ("weapnext", NULL);
  1279. Cmd_AddCommand ("weapprev", NULL);
  1280. }
  1281. /*
  1282. ===============
  1283. CL_WriteConfiguration
  1284. Writes key bindings and archived cvars to config.cfg
  1285. ===============
  1286. */
  1287. void CL_WriteConfiguration (void)
  1288. {
  1289. FILE *f;
  1290. char path[MAX_QPATH];
  1291. if (cls.state == ca_uninitialized)
  1292. return;
  1293. Com_sprintf (path, sizeof(path),"%s/config.cfg",FS_Gamedir());
  1294. f = fopen (path, "w");
  1295. if (!f)
  1296. {
  1297. Com_Printf ("Couldn't write config.cfg.\n");
  1298. return;
  1299. }
  1300. fprintf (f, "// generated by quake, do not modify\n");
  1301. Key_WriteBindings (f);
  1302. fclose (f);
  1303. Cvar_WriteVariables (path);
  1304. }
  1305. /*
  1306. ==================
  1307. CL_FixCvarCheats
  1308. ==================
  1309. */
  1310. typedef struct
  1311. {
  1312. char *name;
  1313. char *value;
  1314. cvar_t *var;
  1315. } cheatvar_t;
  1316. cheatvar_t cheatvars[] = {
  1317. {"timescale", "1"},
  1318. {"timedemo", "0"},
  1319. {"r_drawworld", "1"},
  1320. {"cl_testlights", "0"},
  1321. {"r_fullbright", "0"},
  1322. {"r_drawflat", "0"},
  1323. {"paused", "0"},
  1324. {"fixedtime", "0"},
  1325. {"sw_draworder", "0"},
  1326. {"gl_lightmap", "0"},
  1327. {"gl_saturatelighting", "0"},
  1328. {NULL, NULL}
  1329. };
  1330. int numcheatvars;
  1331. void CL_FixCvarCheats (void)
  1332. {
  1333. int i;
  1334. cheatvar_t *var;
  1335. if ( !strcmp(cl.configstrings[CS_MAXCLIENTS], "1")
  1336. || !cl.configstrings[CS_MAXCLIENTS][0] )
  1337. return; // single player can cheat
  1338. // find all the cvars if we haven't done it yet
  1339. if (!numcheatvars)
  1340. {
  1341. while (cheatvars[numcheatvars].name)
  1342. {
  1343. cheatvars[numcheatvars].var = Cvar_Get (cheatvars[numcheatvars].name,
  1344. cheatvars[numcheatvars].value, 0);
  1345. numcheatvars++;
  1346. }
  1347. }
  1348. // make sure they are all set to the proper values
  1349. for (i=0, var = cheatvars ; i<numcheatvars ; i++, var++)
  1350. {
  1351. if ( strcmp (var->var->string, var->value) )
  1352. {
  1353. Cvar_Set (var->name, var->value);
  1354. }
  1355. }
  1356. }
  1357. //============================================================================
  1358. /*
  1359. ==================
  1360. CL_SendCommand
  1361. ==================
  1362. */
  1363. void CL_SendCommand (void)
  1364. {
  1365. // get new key events
  1366. Sys_SendKeyEvents ();
  1367. // allow mice or other external controllers to add commands
  1368. IN_Commands ();
  1369. // process console commands
  1370. Cbuf_Execute ();
  1371. // fix any cheating cvars
  1372. CL_FixCvarCheats ();
  1373. // send intentions now
  1374. CL_SendCmd ();
  1375. // resend a connection request if necessary
  1376. CL_CheckForResend ();
  1377. }
  1378. /*
  1379. ==================
  1380. CL_Frame
  1381. ==================
  1382. */
  1383. void CL_Frame (int msec)
  1384. {
  1385. static int extratime;
  1386. static int lasttimecalled;
  1387. if (dedicated->value)
  1388. return;
  1389. extratime += msec;
  1390. if (!cl_timedemo->value)
  1391. {
  1392. if (cls.state == ca_connected && extratime < 100)
  1393. return; // don't flood packets out while connecting
  1394. if (extratime < 1000/cl_maxfps->value)
  1395. return; // framerate is too high
  1396. }
  1397. // let the mouse activate or deactivate
  1398. IN_Frame ();
  1399. // decide the simulation time
  1400. cls.frametime = extratime/1000.0;
  1401. cl.time += extratime;
  1402. cls.realtime = curtime;
  1403. extratime = 0;
  1404. #if 0
  1405. if (cls.frametime > (1.0 / cl_minfps->value))
  1406. cls.frametime = (1.0 / cl_minfps->value);
  1407. #else
  1408. if (cls.frametime > (1.0 / 5))
  1409. cls.frametime = (1.0 / 5);
  1410. #endif
  1411. // if in the debugger last frame, don't timeout
  1412. if (msec > 5000)
  1413. cls.netchan.last_received = Sys_Milliseconds ();
  1414. // fetch results from server
  1415. CL_ReadPackets ();
  1416. // send a new command message to the server
  1417. CL_SendCommand ();
  1418. // predict all unacknowledged movements
  1419. CL_PredictMovement ();
  1420. // allow rendering DLL change
  1421. VID_CheckChanges ();
  1422. if (!cl.refresh_prepped && cls.state == ca_active)
  1423. CL_PrepRefresh ();
  1424. // update the screen
  1425. if (host_speeds->value)
  1426. time_before_ref = Sys_Milliseconds ();
  1427. SCR_UpdateScreen ();
  1428. if (host_speeds->value)
  1429. time_after_ref = Sys_Milliseconds ();
  1430. // update audio
  1431. S_Update (cl.refdef.vieworg, cl.v_forward, cl.v_right, cl.v_up);
  1432. CDAudio_Update();
  1433. // advance local effects for next frame
  1434. CL_RunDLights ();
  1435. CL_RunLightStyles ();
  1436. SCR_RunCinematic ();
  1437. SCR_RunConsole ();
  1438. cls.framecount++;
  1439. if ( log_stats->value )
  1440. {
  1441. if ( cls.state == ca_active )
  1442. {
  1443. if ( !lasttimecalled )
  1444. {
  1445. lasttimecalled = Sys_Milliseconds();
  1446. if ( log_stats_file )
  1447. fprintf( log_stats_file, "0\n" );
  1448. }
  1449. else
  1450. {
  1451. int now = Sys_Milliseconds();
  1452. if ( log_stats_file )
  1453. fprintf( log_stats_file, "%d\n", now - lasttimecalled );
  1454. lasttimecalled = now;
  1455. }
  1456. }
  1457. }
  1458. }
  1459. //============================================================================
  1460. /*
  1461. ====================
  1462. CL_Init
  1463. ====================
  1464. */
  1465. void CL_Init (void)
  1466. {
  1467. if (dedicated->value)
  1468. return; // nothing running on the client
  1469. // all archived variables will now be loaded
  1470. Con_Init ();
  1471. #if defined __linux__ || defined __sgi
  1472. S_Init ();
  1473. VID_Init ();
  1474. #else
  1475. VID_Init ();
  1476. S_Init (); // sound must be initialized after window is created
  1477. #endif
  1478. V_Init ();
  1479. net_message.data = net_message_buffer;
  1480. net_message.maxsize = sizeof(net_message_buffer);
  1481. M_Init ();
  1482. SCR_Init ();
  1483. cls.disable_screen = true; // don't draw yet
  1484. CDAudio_Init ();
  1485. CL_InitLocal ();
  1486. IN_Init ();
  1487. // Cbuf_AddText ("exec autoexec.cfg\n");
  1488. FS_ExecAutoexec ();
  1489. Cbuf_Execute ();
  1490. }
  1491. /*
  1492. ===============
  1493. CL_Shutdown
  1494. FIXME: this is a callback from Sys_Quit and Com_Error. It would be better
  1495. to run quit through here before the final handoff to the sys code.
  1496. ===============
  1497. */
  1498. void CL_Shutdown(void)
  1499. {
  1500. static qboolean isdown = false;
  1501. if (isdown)
  1502. {
  1503. printf ("recursive shutdown\n");
  1504. return;
  1505. }
  1506. isdown = true;
  1507. CL_WriteConfiguration ();
  1508. CDAudio_Shutdown ();
  1509. S_Shutdown();
  1510. IN_Shutdown ();
  1511. VID_Shutdown();
  1512. }