1/* 2Copyright (C) 1996-1997 Id Software, Inc. 3 4This program is free software; you can redistribute it and/or 5modify it under the terms of the GNU General Public License 6as published by the Free Software Foundation; either version 2 7of the License, or (at your option) any later version. 8 9This program is distributed in the hope that it will be useful, 10but WITHOUT ANY WARRANTY; without even the implied warranty of 11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13See the GNU General Public License for more details. 14 15You should have received a copy of the GNU General Public License 16along with this program; if not, write to the Free Software 17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 19*/ 20 21#include "qwsvdef.h" 22 23qboolean sv_allow_cheats; 24 25int fp_messages=4, fp_persecond=4, fp_secondsdead=10; 26char fp_msg[255] = { 0 }; 27extern cvar_t cl_warncmd; 28 extern redirect_t sv_redirected; 29 30 31/* 32=============================================================================== 33 34OPERATOR CONSOLE ONLY COMMANDS 35 36These commands can only be entered from stdin or by a remote operator datagram 37=============================================================================== 38*/ 39 40/* 41==================== 42SV_SetMaster_f 43 44Make a master server current 45==================== 46*/ 47void SV_SetMaster_f (void) 48{ 49 char data[2]; 50 int i; 51 52 memset (&master_adr, 0, sizeof(master_adr)); 53 54 for (i=1 ; i<Cmd_Argc() ; i++) 55 { 56 if (!strcmp(Cmd_Argv(i), "none") || !NET_StringToAdr (Cmd_Argv(i), &master_adr[i-1])) 57 { 58 Con_Printf ("Setting nomaster mode.\n"); 59 return; 60 } 61 if (master_adr[i-1].port == 0) 62 master_adr[i-1].port = BigShort (27000); 63 64 Con_Printf ("Master server at %s\n", NET_AdrToString (master_adr[i-1])); 65 66 Con_Printf ("Sending a ping.\n"); 67 68 data[0] = A2A_PING; 69 data[1] = 0; 70 NET_SendPacket (2, data, master_adr[i-1]); 71 } 72 73 svs.last_heartbeat = -99999; 74} 75 76 77/* 78================== 79SV_Quit_f 80================== 81*/ 82void SV_Quit_f (void) 83{ 84 SV_FinalMessage ("server shutdown\n"); 85 Con_Printf ("Shutting down.\n"); 86 SV_Shutdown (); 87 Sys_Quit (); 88} 89 90/* 91============ 92SV_Logfile_f 93============ 94*/ 95void SV_Logfile_f (void) 96{ 97 char name[MAX_OSPATH]; 98 99 if (sv_logfile) 100 { 101 Con_Printf ("File logging off.\n"); 102 fclose (sv_logfile); 103 sv_logfile = NULL; 104 return; 105 } 106 107 sprintf (name, "%s/qconsole.log", com_gamedir); 108 Con_Printf ("Logging text to %s.\n", name); 109 sv_logfile = fopen (name, "w"); 110 if (!sv_logfile) 111 Con_Printf ("failed.\n"); 112} 113 114 115/* 116============ 117SV_Fraglogfile_f 118============ 119*/ 120void SV_Fraglogfile_f (void) 121{ 122 char name[MAX_OSPATH]; 123 int i; 124 125 if (sv_fraglogfile) 126 { 127 Con_Printf ("Frag file logging off.\n"); 128 fclose (sv_fraglogfile); 129 sv_fraglogfile = NULL; 130 return; 131 } 132 133 // find an unused name 134 for (i=0 ; i<1000 ; i++) 135 { 136 sprintf (name, "%s/frag_%i.log", com_gamedir, i); 137 sv_fraglogfile = fopen (name, "r"); 138 if (!sv_fraglogfile) 139 { // can't read it, so create this one 140 sv_fraglogfile = fopen (name, "w"); 141 if (!sv_fraglogfile) 142 i=1000; // give error 143 break; 144 } 145 fclose (sv_fraglogfile); 146 } 147 if (i==1000) 148 { 149 Con_Printf ("Can't open any logfiles.\n"); 150 sv_fraglogfile = NULL; 151 return; 152 } 153 154 Con_Printf ("Logging frags to %s.\n", name); 155} 156 157 158/* 159================== 160SV_SetPlayer 161 162Sets host_client and sv_player to the player with idnum Cmd_Argv(1) 163================== 164*/ 165qboolean SV_SetPlayer (void) 166{ 167 client_t *cl; 168 int i; 169 int idnum; 170 171 idnum = atoi(Cmd_Argv(1)); 172 173 for (i=0,cl=svs.clients ; i<MAX_CLIENTS ; i++,cl++) 174 { 175 if (!cl->state) 176 continue; 177 if (cl->userid == idnum) 178 { 179 host_client = cl; 180 sv_player = host_client->edict; 181 return true; 182 } 183 } 184 Con_Printf ("Userid %i is not on the server\n", idnum); 185 return false; 186} 187 188 189/* 190================== 191SV_God_f 192 193Sets client to godmode 194================== 195*/ 196void SV_God_f (void) 197{ 198 if (!sv_allow_cheats) 199 { 200 Con_Printf ("You must run the server with -cheats to enable this command.\n"); 201 return; 202 } 203 204 if (!SV_SetPlayer ()) 205 return; 206 207 sv_player->v.flags = (int)sv_player->v.flags ^ FL_GODMODE; 208 if (!((int)sv_player->v.flags & FL_GODMODE) ) 209 SV_ClientPrintf (host_client, PRINT_HIGH, "godmode OFF\n"); 210 else 211 SV_ClientPrintf (host_client, PRINT_HIGH, "godmode ON\n"); 212} 213 214 215void SV_Noclip_f (void) 216{ 217 if (!sv_allow_cheats) 218 { 219 Con_Printf ("You must run the server with -cheats to enable this command.\n"); 220 return; 221 } 222 223 if (!SV_SetPlayer ()) 224 return; 225 226 if (sv_player->v.movetype != MOVETYPE_NOCLIP) 227 { 228 sv_player->v.movetype = MOVETYPE_NOCLIP; 229 SV_ClientPrintf (host_client, PRINT_HIGH, "noclip ON\n"); 230 } 231 else 232 { 233 sv_player->v.movetype = MOVETYPE_WALK; 234 SV_ClientPrintf (host_client, PRINT_HIGH, "noclip OFF\n"); 235 } 236} 237 238 239/* 240================== 241SV_Give_f 242================== 243*/ 244void SV_Give_f (void) 245{ 246 char *t; 247 int v; 248 249 if (!sv_allow_cheats) 250 { 251 Con_Printf ("You must run the server with -cheats to enable this command.\n"); 252 return; 253 } 254 255 if (!SV_SetPlayer ()) 256 return; 257 258 t = Cmd_Argv(2); 259 v = atoi (Cmd_Argv(3)); 260 261 switch (t[0]) 262 { 263 case '2': 264 case '3': 265 case '4': 266 case '5': 267 case '6': 268 case '7': 269 case '8': 270 case '9': 271 sv_player->v.items = (int)sv_player->v.items | IT_SHOTGUN<< (t[0] - '2'); 272 break; 273 274 case 's': 275 sv_player->v.ammo_shells = v; 276 break; 277 case 'n': 278 sv_player->v.ammo_nails = v; 279 break; 280 case 'r': 281 sv_player->v.ammo_rockets = v; 282 break; 283 case 'h': 284 sv_player->v.health = v; 285 break; 286 case 'c': 287 sv_player->v.ammo_cells = v; 288 break; 289 } 290} 291 292 293/* 294====================== 295SV_Map_f 296 297handle a 298map <mapname> 299command from the console or progs. 300====================== 301*/ 302void SV_Map_f (void) 303{ 304 char level[MAX_QPATH]; 305 char expanded[MAX_QPATH]; 306 FILE *f; 307 308 if (Cmd_Argc() != 2) 309 { 310 Con_Printf ("map <levelname> : continue game on a new level\n"); 311 return; 312 } 313 strcpy (level, Cmd_Argv(1)); 314 315#if 0 316 if (!strcmp (level, "e1m8")) 317 { // QuakeWorld can't go to e1m8 318 SV_BroadcastPrintf (PRINT_HIGH, "can't go to low grav level in QuakeWorld...\n"); 319 strcpy (level, "e1m5"); 320 } 321#endif 322 323 // check to make sure the level exists 324 sprintf (expanded, "maps/%s.bsp", level); 325 COM_FOpenFile (expanded, &f); 326 if (!f) 327 { 328 Con_Printf ("Can't find %s\n", expanded); 329 return; 330 } 331 fclose (f); 332 333 SV_BroadcastCommand ("changing\n"); 334 SV_SendMessagesToAll (); 335 336 SV_SpawnServer (level); 337 338 SV_BroadcastCommand ("reconnect\n"); 339} 340 341 342/* 343================== 344SV_Kick_f 345 346Kick a user off of the server 347================== 348*/ 349void SV_Kick_f (void) 350{ 351 int i; 352 client_t *cl; 353 int uid; 354 355 uid = atoi(Cmd_Argv(1)); 356 357 for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++) 358 { 359 if (!cl->state) 360 continue; 361 if (cl->userid == uid) 362 { 363 SV_BroadcastPrintf (PRINT_HIGH, "%s was kicked\n", cl->name); 364 // print directly, because the dropped client won't get the 365 // SV_BroadcastPrintf message 366 SV_ClientPrintf (cl, PRINT_HIGH, "You were kicked from the game\n"); 367 SV_DropClient (cl); 368 return; 369 } 370 } 371 372 Con_Printf ("Couldn't find user number %i\n", uid); 373} 374 375 376/* 377================ 378SV_Status_f 379================ 380*/ 381void SV_Status_f (void) 382{ 383 int i, j, l; 384 client_t *cl; 385 float cpu, avg, pak; 386 char *s; 387 388 389 cpu = (svs.stats.latched_active+svs.stats.latched_idle); 390 if (cpu) 391 cpu = 100*svs.stats.latched_active/cpu; 392 avg = 1000*svs.stats.latched_active / STATFRAMES; 393 pak = (float)svs.stats.latched_packets/ STATFRAMES; 394 395 Con_Printf ("net address : %s\n",NET_AdrToString (net_local_adr)); 396 Con_Printf ("cpu utilization : %3i%%\n",(int)cpu); 397 Con_Printf ("avg response time: %i ms\n",(int)avg); 398 Con_Printf ("packets/frame : %5.2f (%d)\n", pak, num_prstr); 399 400// min fps lat drp 401 if (sv_redirected != RD_NONE) { 402 // most remote clients are 40 columns 403 // 0123456789012345678901234567890123456789 404 Con_Printf ("name userid frags\n"); 405 Con_Printf (" address rate ping drop\n"); 406 Con_Printf (" ---------------- ---- ---- -----\n"); 407 for (i=0,cl=svs.clients ; i<MAX_CLIENTS ; i++,cl++) 408 { 409 if (!cl->state) 410 continue; 411 412 Con_Printf ("%-16.16s ", cl->name); 413 414 Con_Printf ("%6i %5i", cl->userid, (int)cl->edict->v.frags); 415 if (cl->spectator) 416 Con_Printf(" (s)\n"); 417 else 418 Con_Printf("\n"); 419 420 s = NET_BaseAdrToString ( cl->netchan.remote_address); 421 Con_Printf (" %-16.16s", s); 422 if (cl->state == cs_connected) 423 { 424 Con_Printf ("CONNECTING\n"); 425 continue; 426 } 427 if (cl->state == cs_zombie) 428 { 429 Con_Printf ("ZOMBIE\n"); 430 continue; 431 } 432 Con_Printf ("%4i %4i %5.2f\n" 433 , (int)(1000*cl->netchan.frame_rate) 434 , (int)SV_CalcPing (cl) 435 , 100.0*cl->netchan.drop_count / cl->netchan.incoming_sequence); 436 } 437 } else { 438 Con_Printf ("frags userid address name rate ping drop qport\n"); 439 Con_Printf ("----- ------ --------------- --------------- ---- ---- ----- -----\n"); 440 for (i=0,cl=svs.clients ; i<MAX_CLIENTS ; i++,cl++) 441 { 442 if (!cl->state) 443 continue; 444 Con_Printf ("%5i %6i ", (int)cl->edict->v.frags, cl->userid); 445 446 s = NET_BaseAdrToString ( cl->netchan.remote_address); 447 Con_Printf ("%s", s); 448 l = 16 - strlen(s); 449 for (j=0 ; j<l ; j++) 450 Con_Printf (" "); 451 452 Con_Printf ("%s", cl->name); 453 l = 16 - strlen(cl->name); 454 for (j=0 ; j<l ; j++) 455 Con_Printf (" "); 456 if (cl->state == cs_connected) 457 { 458 Con_Printf ("CONNECTING\n"); 459 continue; 460 } 461 if (cl->state == cs_zombie) 462 { 463 Con_Printf ("ZOMBIE\n"); 464 continue; 465 } 466 Con_Printf ("%4i %4i %3.1f %4i" 467 , (int)(1000*cl->netchan.frame_rate) 468 , (int)SV_CalcPing (cl) 469 , 100.0*cl->netchan.drop_count / cl->netchan.incoming_sequence 470 , cl->netchan.qport); 471 if (cl->spectator) 472 Con_Printf(" (s)\n"); 473 else 474 Con_Printf("\n"); 475 476 477 } 478 } 479 Con_Printf ("\n"); 480} 481 482/* 483================== 484SV_ConSay_f 485================== 486*/ 487void SV_ConSay_f(void) 488{ 489 client_t *client; 490 int j; 491 char *p; 492 char text[1024]; 493 494 if (Cmd_Argc () < 2) 495 return; 496 497 Q_strcpy (text, "console: "); 498 p = Cmd_Args(); 499 500 if (*p == '"') 501 { 502 p++; 503 p[Q_strlen(p)-1] = 0; 504 } 505 506 Q_strcat(text, p); 507 508 for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++) 509 { 510 if (client->state != cs_spawned) 511 continue; 512 SV_ClientPrintf(client, PRINT_CHAT, "%s\n", text); 513 } 514} 515 516 517/* 518================== 519SV_Heartbeat_f 520================== 521*/ 522void SV_Heartbeat_f (void) 523{ 524 svs.last_heartbeat = -9999; 525} 526 527void SV_SendServerInfoChange(char *key, char *value) 528{ 529 if (!sv.state) 530 return; 531 532 MSG_WriteByte (&sv.reliable_datagram, svc_serverinfo); 533 MSG_WriteString (&sv.reliable_datagram, key); 534 MSG_WriteString (&sv.reliable_datagram, value); 535} 536 537/* 538=========== 539SV_Serverinfo_f 540 541 Examine or change the serverinfo string 542=========== 543*/ 544char *CopyString(char *s); 545void SV_Serverinfo_f (void) 546{ 547 cvar_t *var; 548 549 if (Cmd_Argc() == 1) 550 { 551 Con_Printf ("Server info settings:\n"); 552 Info_Print (svs.info); 553 return; 554 } 555 556 if (Cmd_Argc() != 3) 557 { 558 Con_Printf ("usage: serverinfo [ <key> <value> ]\n"); 559 return; 560 } 561 562 if (Cmd_Argv(1)[0] == '*') 563 { 564 Con_Printf ("Star variables cannot be changed.\n"); 565 return; 566 } 567 Info_SetValueForKey (svs.info, Cmd_Argv(1), Cmd_Argv(2), MAX_SERVERINFO_STRING); 568 569 // if this is a cvar, change it too 570 var = Cvar_FindVar (Cmd_Argv(1)); 571 if (var) 572 { 573 Z_Free (var->string); // free the old value string 574 var->string = CopyString (Cmd_Argv(2)); 575 var->value = Q_atof (var->string); 576 } 577 578 SV_SendServerInfoChange(Cmd_Argv(1), Cmd_Argv(2)); 579} 580 581 582/* 583=========== 584SV_Serverinfo_f 585 586 Examine or change the serverinfo string 587=========== 588*/ 589char *CopyString(char *s); 590void SV_Localinfo_f (void) 591{ 592 if (Cmd_Argc() == 1) 593 { 594 Con_Printf ("Local info settings:\n"); 595 Info_Print (localinfo); 596 return; 597 } 598 599 if (Cmd_Argc() != 3) 600 { 601 Con_Printf ("usage: localinfo [ <key> <value> ]\n"); 602 return; 603 } 604 605 if (Cmd_Argv(1)[0] == '*') 606 { 607 Con_Printf ("Star variables cannot be changed.\n"); 608 return; 609 } 610 Info_SetValueForKey (localinfo, Cmd_Argv(1), Cmd_Argv(2), MAX_LOCALINFO_STRING); 611} 612 613 614/* 615=========== 616SV_User_f 617 618Examine a users info strings 619=========== 620*/ 621void SV_User_f (void) 622{ 623 if (Cmd_Argc() != 2) 624 { 625 Con_Printf ("Usage: info <userid>\n"); 626 return; 627 } 628 629 if (!SV_SetPlayer ()) 630 return; 631 632 Info_Print (host_client->userinfo); 633} 634 635/* 636================ 637SV_Gamedir 638 639Sets the fake *gamedir to a different directory. 640================ 641*/ 642void SV_Gamedir (void) 643{ 644 char *dir; 645 646 if (Cmd_Argc() == 1) 647 { 648 Con_Printf ("Current *gamedir: %s\n", Info_ValueForKey (svs.info, "*gamedir")); 649 return; 650 } 651 652 if (Cmd_Argc() != 2) 653 { 654 Con_Printf ("Usage: sv_gamedir <newgamedir>\n"); 655 return; 656 } 657 658 dir = Cmd_Argv(1); 659 660 if (strstr(dir, "..") || strstr(dir, "/") 661 || strstr(dir, "\\") || strstr(dir, ":") ) 662 { 663 Con_Printf ("*Gamedir should be a single filename, not a path\n"); 664 return; 665 } 666 667 Info_SetValueForStarKey (svs.info, "*gamedir", dir, MAX_SERVERINFO_STRING); 668} 669 670/* 671================ 672SV_Floodport_f 673 674Sets the gamedir and path to a different directory. 675================ 676*/ 677 678void SV_Floodprot_f (void) 679{ 680 int arg1, arg2, arg3; 681 682 if (Cmd_Argc() == 1) 683 { 684 if (fp_messages) { 685 Con_Printf ("Current floodprot settings: \nAfter %d msgs per %d seconds, silence for %d seconds\n", 686 fp_messages, fp_persecond, fp_secondsdead); 687 return; 688 } else 689 Con_Printf ("No floodprots enabled.\n"); 690 } 691 692 if (Cmd_Argc() != 4) 693 { 694 Con_Printf ("Usage: floodprot <# of messages> <per # of seconds> <seconds to silence>\n"); 695 Con_Printf ("Use floodprotmsg to set a custom message to say to the flooder.\n"); 696 return; 697 } 698 699 arg1 = atoi(Cmd_Argv(1)); 700 arg2 = atoi(Cmd_Argv(2)); 701 arg3 = atoi(Cmd_Argv(3)); 702 703 if (arg1<=0 || arg2 <= 0 || arg3<=0) { 704 Con_Printf ("All values must be positive numbers\n"); 705 return; 706 } 707 708 if (arg1 > 10) { 709 Con_Printf ("Can only track up to 10 messages.\n"); 710 return; 711 } 712 713 fp_messages = arg1; 714 fp_persecond = arg2; 715 fp_secondsdead = arg3; 716} 717 718void SV_Floodprotmsg_f (void) 719{ 720 if (Cmd_Argc() == 1) { 721 Con_Printf("Current msg: %s\n", fp_msg); 722 return; 723 } else if (Cmd_Argc() != 2) { 724 Con_Printf("Usage: floodprotmsg \"<message>\"\n"); 725 return; 726 } 727 sprintf(fp_msg, "%s", Cmd_Argv(1)); 728} 729 730/* 731================ 732SV_Gamedir_f 733 734Sets the gamedir and path to a different directory. 735================ 736*/ 737char gamedirfile[MAX_OSPATH]; 738void SV_Gamedir_f (void) 739{ 740 char *dir; 741 742 if (Cmd_Argc() == 1) 743 { 744 Con_Printf ("Current gamedir: %s\n", com_gamedir); 745 return; 746 } 747 748 if (Cmd_Argc() != 2) 749 { 750 Con_Printf ("Usage: gamedir <newdir>\n"); 751 return; 752 } 753 754 dir = Cmd_Argv(1); 755 756 if (strstr(dir, "..") || strstr(dir, "/") 757 || strstr(dir, "\\") || strstr(dir, ":") ) 758 { 759 Con_Printf ("Gamedir should be a single filename, not a path\n"); 760 return; 761 } 762 763 COM_Gamedir (dir); 764 Info_SetValueForStarKey (svs.info, "*gamedir", dir, MAX_SERVERINFO_STRING); 765} 766 767/* 768================ 769SV_Snap 770================ 771*/ 772void SV_Snap (int uid) 773{ 774 client_t *cl; 775 char pcxname[80]; 776 char checkname[MAX_OSPATH]; 777 int i; 778 779 for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++) 780 { 781 if (!cl->state) 782 continue; 783 if (cl->userid == uid) 784 break; 785 } 786 if (i >= MAX_CLIENTS) { 787 Con_Printf ("userid not found\n"); 788 return; 789 } 790 791 sprintf(pcxname, "%d-00.pcx", uid); 792 793 sprintf(checkname, "%s/snap", gamedirfile); 794 Sys_mkdir(gamedirfile); 795 Sys_mkdir(checkname); 796 797 for (i=0 ; i<=99 ; i++) 798 { 799 pcxname[strlen(pcxname) - 6] = i/10 + '0'; 800 pcxname[strlen(pcxname) - 5] = i%10 + '0'; 801 sprintf (checkname, "%s/snap/%s", gamedirfile, pcxname); 802 if (Sys_FileTime(checkname) == -1) 803 break; // file doesn't exist 804 } 805 if (i==100) 806 { 807 Con_Printf ("Snap: Couldn't create a file, clean some out.\n"); 808 return; 809 } 810 strcpy(cl->uploadfn, checkname); 811 812 memcpy(&cl->snap_from, &net_from, sizeof(net_from)); 813 if (sv_redirected != RD_NONE) 814 cl->remote_snap = true; 815 else 816 cl->remote_snap = false; 817 818 ClientReliableWrite_Begin (cl, svc_stufftext, 24); 819 ClientReliableWrite_String (cl, "cmd snap"); 820 Con_Printf ("Requesting snap from user %d...\n", uid); 821} 822 823/* 824================ 825SV_Snap_f 826================ 827*/ 828void SV_Snap_f (void) 829{ 830 int uid; 831 832 if (Cmd_Argc() != 2) 833 { 834 Con_Printf ("Usage: snap <userid>\n"); 835 return; 836 } 837 838 uid = atoi(Cmd_Argv(1)); 839 840 SV_Snap(uid); 841} 842 843/* 844================ 845SV_Snap 846================ 847*/ 848void SV_SnapAll_f (void) 849{ 850 client_t *cl; 851 int i; 852 853 for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++) 854 { 855 if (cl->state < cs_connected || cl->spectator) 856 continue; 857 SV_Snap(cl->userid); 858 } 859} 860 861/* 862================== 863SV_InitOperatorCommands 864================== 865*/ 866void SV_InitOperatorCommands (void) 867{ 868 if (COM_CheckParm ("-cheats")) 869 { 870 sv_allow_cheats = true; 871 Info_SetValueForStarKey (svs.info, "*cheats", "ON", MAX_SERVERINFO_STRING); 872 } 873 874 Cmd_AddCommand ("logfile", SV_Logfile_f); 875 Cmd_AddCommand ("fraglogfile", SV_Fraglogfile_f); 876 877 Cmd_AddCommand ("snap", SV_Snap_f); 878 Cmd_AddCommand ("snapall", SV_SnapAll_f); 879 Cmd_AddCommand ("kick", SV_Kick_f); 880 Cmd_AddCommand ("status", SV_Status_f); 881 882 Cmd_AddCommand ("map", SV_Map_f); 883 Cmd_AddCommand ("setmaster", SV_SetMaster_f); 884 885 Cmd_AddCommand ("say", SV_ConSay_f); 886 Cmd_AddCommand ("heartbeat", SV_Heartbeat_f); 887 Cmd_AddCommand ("quit", SV_Quit_f); 888 Cmd_AddCommand ("god", SV_God_f); 889 Cmd_AddCommand ("give", SV_Give_f); 890 Cmd_AddCommand ("noclip", SV_Noclip_f); 891 Cmd_AddCommand ("serverinfo", SV_Serverinfo_f); 892 Cmd_AddCommand ("localinfo", SV_Localinfo_f); 893 Cmd_AddCommand ("user", SV_User_f); 894 Cmd_AddCommand ("gamedir", SV_Gamedir_f); 895 Cmd_AddCommand ("sv_gamedir", SV_Gamedir); 896 Cmd_AddCommand ("floodprot", SV_Floodprot_f); 897 Cmd_AddCommand ("floodprotmsg", SV_Floodprotmsg_f); 898 899 cl_warncmd.value = 1; 900} 901