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