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