1 /* 2 Copyright (C) 1996-1997 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 */ 20 21 #include "quakedef.h" 22 23 extern cvar_t pausable; 24 25 int current_skill; 26 27 void Mod_Print (void); 28 29 /* 30 ================== 31 Host_Quit_f 32 ================== 33 */ 34 35 extern void M_Menu_Quit_f (void); 36 37 void Host_Quit(); 38 39 void Host_Quit_f (void) 40 { 41 if (key_dest != key_console && cls.state != ca_dedicated) 42 { 43 M_Menu_Quit_f (); 44 return; 45 } 46 Host_Quit(); 47 } 48 49 void Host_Quit() 50 { 51 CL_Disconnect (); 52 Host_ShutdownServer(false); 53 54 Sys_Quit (); 55 } 56 57 58 /* 59 ================== 60 Host_Status_f 61 ================== 62 */ 63 void Host_Status_f (void) 64 { 65 client_t *client; 66 int seconds; 67 int minutes; 68 int hours = 0; 69 int j; 70 void (*print) (const char *fmt, ...); 71 72 if (cmd_source == src_command) 73 { 74 if (!sv.active) 75 { 76 Cmd_ForwardToServer (); 77 return; 78 } 79 print = Con_Printf; 80 } 81 else 82 print = SV_ClientPrintf; 83 84 print ("host: %s\n", Cvar_VariableString ("hostname")); 85 print ("version: %4.2f\n", VERSION); 86 if (tcpipAvailable) 87 print ("tcp/ip: %s\n", my_tcpip_address); 88 if (ipxAvailable) 89 print ("ipx: %s\n", my_ipx_address); 90 print ("map: %s\n", sv.name); 91 print ("players: %i active (%i max)\n\n", net_activeconnections, svs.maxclients); 92 for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++) 93 { 94 if (!client->active) 95 continue; 96 seconds = (int)(net_time - client->netconnection->connecttime); 97 minutes = seconds / 60; 98 if (minutes) 99 { 100 seconds -= (minutes * 60); 101 hours = minutes / 60; 102 if (hours) 103 minutes -= (hours * 60); 104 } 105 else 106 hours = 0; 107 print ("#%-2u %-16.16s %3i %2i:%02i:%02i\n", j+1, client->name, (int)client->edict->u.v.frags, hours, minutes, seconds); 108 print (" %s\n", client->netconnection->address); 109 } 110 } 111 112 113 /* 114 ================== 115 Host_God_f 116 117 Sets client to godmode 118 ================== 119 */ 120 void Host_God_f (void) 121 { 122 if (cmd_source == src_command) 123 { 124 Cmd_ForwardToServer (); 125 return; 126 } 127 128 if (pr_global_struct->deathmatch && !host_client->privileged) 129 return; 130 131 sv_player->u.v.flags = (int)sv_player->u.v.flags ^ FL_GODMODE; 132 if (!((int)sv_player->u.v.flags & FL_GODMODE) ) 133 SV_ClientPrintf ("godmode OFF\n"); 134 else 135 SV_ClientPrintf ("godmode ON\n"); 136 } 137 138 void Host_Notarget_f (void) 139 { 140 if (cmd_source == src_command) 141 { 142 Cmd_ForwardToServer (); 143 return; 144 } 145 146 if (pr_global_struct->deathmatch && !host_client->privileged) 147 return; 148 149 sv_player->u.v.flags = (int)sv_player->u.v.flags ^ FL_NOTARGET; 150 if (!((int)sv_player->u.v.flags & FL_NOTARGET) ) 151 SV_ClientPrintf ("notarget OFF\n"); 152 else 153 SV_ClientPrintf ("notarget ON\n"); 154 } 155 156 qboolean noclip_anglehack; 157 158 void Host_Noclip_f (void) 159 { 160 if (cmd_source == src_command) 161 { 162 Cmd_ForwardToServer (); 163 return; 164 } 165 166 if (pr_global_struct->deathmatch && !host_client->privileged) 167 return; 168 169 if (sv_player->u.v.movetype != MOVETYPE_NOCLIP) 170 { 171 noclip_anglehack = true; 172 sv_player->u.v.movetype = MOVETYPE_NOCLIP; 173 SV_ClientPrintf ("noclip ON\n"); 174 } 175 else 176 { 177 noclip_anglehack = false; 178 sv_player->u.v.movetype = MOVETYPE_WALK; 179 SV_ClientPrintf ("noclip OFF\n"); 180 } 181 } 182 183 /* 184 ================== 185 Host_Fly_f 186 187 Sets client to flymode 188 ================== 189 */ 190 void Host_Fly_f (void) 191 { 192 if (cmd_source == src_command) 193 { 194 Cmd_ForwardToServer (); 195 return; 196 } 197 198 if (pr_global_struct->deathmatch && !host_client->privileged) 199 return; 200 201 if (sv_player->u.v.movetype != MOVETYPE_FLY) 202 { 203 sv_player->u.v.movetype = MOVETYPE_FLY; 204 SV_ClientPrintf ("flymode ON\n"); 205 } 206 else 207 { 208 sv_player->u.v.movetype = MOVETYPE_WALK; 209 SV_ClientPrintf ("flymode OFF\n"); 210 } 211 } 212 213 214 /* 215 ================== 216 Host_Ping_f 217 218 ================== 219 */ 220 void Host_Ping_f (void) 221 { 222 int i, j; 223 float total; 224 client_t *client; 225 226 if (cmd_source == src_command) 227 { 228 Cmd_ForwardToServer (); 229 return; 230 } 231 232 SV_ClientPrintf ("Client ping times:\n"); 233 for (i=0, client = svs.clients ; i<svs.maxclients ; i++, client++) 234 { 235 if (!client->active) 236 continue; 237 total = 0; 238 for (j=0 ; j<NUM_PING_TIMES ; j++) 239 total+=client->ping_times[j]; 240 total /= NUM_PING_TIMES; 241 SV_ClientPrintf ("%4i %s\n", (int)(total*1000), client->name); 242 } 243 } 244 245 /* 246 =============================================================================== 247 248 SERVER TRANSITIONS 249 250 =============================================================================== 251 */ 252 253 254 /* 255 ====================== 256 Host_Map_f 257 258 handle a 259 map <servername> 260 command from the console. Active clients are kicked off. 261 ====================== 262 */ 263 void Host_Map_f (void) 264 { 265 int i; 266 char name[MAX_QPATH]; 267 268 if (cmd_source != src_command) 269 return; 270 271 cls.demonum = -1; // stop demo loop in case this fails 272 273 CL_Disconnect (); 274 Host_ShutdownServer(false); 275 276 key_dest = key_game; // remove console or menu 277 SCR_BeginLoadingPlaque (); 278 279 cls.mapstring[0] = 0; 280 for (i=0 ; i<Cmd_Argc() ; i++) 281 { 282 strcat (cls.mapstring, Cmd_Argv(i)); 283 strcat (cls.mapstring, " "); 284 } 285 strcat (cls.mapstring, "\n"); 286 287 svs.serverflags = 0; // haven't completed an episode yet 288 strcpy (name, Cmd_Argv(1)); 289 #ifdef QUAKE2 290 SV_SpawnServer (name, NULL); 291 #else 292 SV_SpawnServer (name); 293 #endif 294 if (!sv.active) 295 return; 296 297 if (cls.state != ca_dedicated) 298 { 299 strcpy (cls.spawnparms, ""); 300 301 for (i=2 ; i<Cmd_Argc() ; i++) 302 { 303 strcat (cls.spawnparms, Cmd_Argv(i)); 304 strcat (cls.spawnparms, " "); 305 } 306 307 Cmd_ExecuteString2 ("connect local", src_command); 308 } 309 } 310 311 /* 312 ================== 313 Host_Changelevel_f 314 315 Goes to a new map, taking all clients along 316 ================== 317 */ 318 void Host_Changelevel_f (void) 319 { 320 #ifdef QUAKE2 321 char level[MAX_QPATH]; 322 char _startspot[MAX_QPATH]; 323 char *startspot; 324 325 if (Cmd_Argc() < 2) 326 { 327 Con_Printf ("changelevel <levelname> : continue game on a new level\n"); 328 return; 329 } 330 if (!sv.active || cls.demoplayback) 331 { 332 Con_Printf ("Only the server may changelevel\n"); 333 return; 334 } 335 336 strcpy (level, Cmd_Argv(1)); 337 if (Cmd_Argc() == 2) 338 startspot = NULL; 339 else 340 { 341 strcpy (_startspot, Cmd_Argv(2)); 342 startspot = _startspot; 343 } 344 345 SV_SaveSpawnparms (); 346 SV_SpawnServer (level, startspot); 347 #else 348 char level[MAX_QPATH]; 349 350 if (Cmd_Argc() != 2) 351 { 352 Con_Printf ("changelevel <levelname> : continue game on a new level\n"); 353 return; 354 } 355 if (!sv.active || cls.demoplayback) 356 { 357 Con_Printf ("Only the server may changelevel\n"); 358 return; 359 } 360 SV_SaveSpawnparms (); 361 strcpy (level, Cmd_Argv(1)); 362 SV_SpawnServer (level); 363 #endif 364 } 365 366 /* 367 ================== 368 Host_Restart_f 369 370 Restarts the current server for a dead player 371 ================== 372 */ 373 void Host_Restart_f (void) 374 { 375 char mapname[MAX_QPATH]; 376 #ifdef QUAKE2 377 char startspot[MAX_QPATH]; 378 #endif 379 380 if (cls.demoplayback || !sv.active) 381 return; 382 383 if (cmd_source != src_command) 384 return; 385 strcpy (mapname, sv.name); // must copy out, because it gets cleared 386 // in sv_spawnserver 387 #ifdef QUAKE2 388 strcpy(startspot, sv.startspot); 389 SV_SpawnServer (mapname, startspot); 390 #else 391 SV_SpawnServer (mapname); 392 #endif 393 } 394 395 /* 396 ================== 397 Host_Reconnect_f 398 399 This command causes the client to wait for the signon messages again. 400 This is sent just before a server changes levels 401 ================== 402 */ 403 void Host_Reconnect_f (void) 404 { 405 SCR_BeginLoadingPlaque (); 406 cls.signon = 0; // need new connection messages 407 } 408 409 /* 410 ===================== 411 Host_Connect_f 412 413 User command to connect to server 414 ===================== 415 */ 416 void Host_Connect_f (void) 417 { 418 char name[MAX_QPATH]; 419 420 cls.demonum = -1; // stop demo loop in case this fails 421 if (cls.demoplayback) 422 { 423 CL_StopPlayback (); 424 CL_Disconnect (); 425 } 426 strcpy (name, Cmd_Argv(1)); 427 CL_EstablishConnection (name); 428 Host_Reconnect_f (); 429 } 430 431 432 /* 433 =============================================================================== 434 435 LOAD / SAVE GAME 436 437 =============================================================================== 438 */ 439 440 #define SAVEGAME_VERSION 5 441 442 /* 443 =============== 444 Host_SavegameComment 445 446 Writes a SAVEGAME_COMMENT_LENGTH character comment describing the current 447 =============== 448 */ 449 void Host_SavegameComment (char *text) 450 { 451 int i; 452 char kills[20]; 453 454 for (i=0 ; i<SAVEGAME_COMMENT_LENGTH ; i++) 455 text[i] = ' '; 456 memcpy (text, cl.levelname, strlen(cl.levelname)); 457 sprintf (kills,"kills:%3i/%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]); 458 memcpy (text+22, kills, strlen(kills)); 459 // convert space to _ to make stdio happy 460 for (i=0 ; i<SAVEGAME_COMMENT_LENGTH ; i++) 461 if (text[i] == ' ') 462 text[i] = '_'; 463 text[SAVEGAME_COMMENT_LENGTH] = '\0'; 464 } 465 466 467 /* 468 =============== 469 Host_Savegame_f 470 =============== 471 */ 472 void Host_Savegame_f (void) 473 { 474 char name[256]; 475 FILE *f; 476 int i; 477 char comment[SAVEGAME_COMMENT_LENGTH+1]; 478 479 if (cmd_source != src_command) 480 return; 481 482 if (!sv.active) 483 { 484 Con_Printf ("Not playing a local game.\n"); 485 return; 486 } 487 488 if (cl.intermission) 489 { 490 Con_Printf ("Can't save in intermission.\n"); 491 return; 492 } 493 494 if (svs.maxclients != 1) 495 { 496 Con_Printf ("Can't save multiplayer games.\n"); 497 return; 498 } 499 500 if (Cmd_Argc() != 2) 501 { 502 Con_Printf ("save <savename> : save a game\n"); 503 return; 504 } 505 506 if (strstr(Cmd_Argv(1), "..")) 507 { 508 Con_Printf ("Relative pathnames are not allowed.\n"); 509 return; 510 } 511 512 for (i=0 ; i<svs.maxclients ; i++) 513 { 514 if (svs.clients[i].active && (svs.clients[i].edict->u.v.health <= 0) ) 515 { 516 Con_Printf ("Can't savegame with a dead player\n"); 517 return; 518 } 519 } 520 521 sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1)); 522 COM_DefaultExtension (name, ".sav"); 523 524 Con_Printf ("Saving game to %s...\n", name); 525 f = fopen (name, "w"); 526 if (!f) 527 { 528 Con_Printf ("ERROR: couldn't open.\n"); 529 return; 530 } 531 532 fprintf (f, "%i\n", SAVEGAME_VERSION); 533 Host_SavegameComment (comment); 534 fprintf (f, "%s\n", comment); 535 for (i=0 ; i<NUM_SPAWN_PARMS ; i++) 536 fprintf (f, "%f\n", svs.clients->spawn_parms[i]); 537 fprintf (f, "%d\n", current_skill); 538 fprintf (f, "%s\n", sv.name); 539 fprintf (f, "%f\n",sv.time); 540 541 // write the light styles 542 543 for (i=0 ; i<MAX_LIGHTSTYLES ; i++) 544 { 545 if (sv.lightstyles[i]) 546 fprintf (f, "%s\n", sv.lightstyles[i]); 547 else 548 fprintf (f,"m\n"); 549 } 550 551 552 ED_WriteGlobals (f); 553 for (i=0 ; i<sv.num_edicts ; i++) 554 { 555 ED_Write (f, EDICT_NUM(i)); 556 fflush (f); 557 } 558 fclose (f); 559 Con_Printf ("done.\n"); 560 } 561 562 563 /* 564 =============== 565 Host_Loadgame_f 566 =============== 567 */ 568 void Host_Loadgame_f (void) 569 { 570 char name[MAX_OSPATH]; 571 FILE *f; 572 char mapname[MAX_QPATH]; 573 float time, tfloat; 574 char str[32768], *start; 575 int i, r; 576 edict_t *ent; 577 int entnum; 578 int version; 579 float spawn_parms[NUM_SPAWN_PARMS]; 580 581 if (cmd_source != src_command) 582 return; 583 584 if (Cmd_Argc() != 2) 585 { 586 Con_Printf ("load <savename> : load a game\n"); 587 return; 588 } 589 590 cls.demonum = -1; // stop demo loop in case this fails 591 592 sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1)); 593 COM_DefaultExtension (name, ".sav"); 594 595 // we can't call SCR_BeginLoadingPlaque, because too much stack space has 596 // been used. The menu calls it before stuffing loadgame command 597 // SCR_BeginLoadingPlaque (); 598 599 Con_Printf ("Loading game from %s...\n", name); 600 f = fopen (name, "r"); 601 if (!f) 602 { 603 Con_Printf ("ERROR: couldn't open.\n"); 604 return; 605 } 606 607 fscanf (f, "%i\n", &version); 608 if (version != SAVEGAME_VERSION) 609 { 610 fclose (f); 611 Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION); 612 return; 613 } 614 fscanf (f, "%s\n", str); 615 for (i=0 ; i<NUM_SPAWN_PARMS ; i++) 616 fscanf (f, "%f\n", &spawn_parms[i]); 617 // this silliness is so we can load 1.06 save files, which have float skill values 618 fscanf (f, "%f\n", &tfloat); 619 current_skill = (int)(tfloat + 0.1); 620 Cvar_SetValue ("skill", (float)current_skill); 621 622 #ifdef QUAKE2 623 Cvar_SetValue ("deathmatch", 0); 624 Cvar_SetValue ("coop", 0); 625 Cvar_SetValue ("teamplay", 0); 626 #endif 627 628 fscanf (f, "%s\n",mapname); 629 fscanf (f, "%f\n",&time); 630 631 CL_Disconnect_f (); 632 633 #ifdef QUAKE2 634 SV_SpawnServer (mapname, NULL); 635 #else 636 SV_SpawnServer (mapname); 637 #endif 638 if (!sv.active) 639 { 640 Con_Printf ("Couldn't load map\n"); 641 return; 642 } 643 sv.paused = true; // pause until all clients connect 644 sv.loadgame = true; 645 646 // load the light styles 647 648 for (i=0 ; i<MAX_LIGHTSTYLES ; i++) 649 { 650 fscanf (f, "%s\n", str); 651 sv.lightstyles[i] = (char*) Hunk_Alloc (strlen(str)+1); 652 strcpy (sv.lightstyles[i], str); 653 } 654 655 // load the edicts out of the savegame file 656 entnum = -1; // -1 is the globals 657 while (!feof(f)) 658 { 659 for (i=0 ; i< (int) (sizeof(str)-1) ; i++) 660 { 661 r = fgetc (f); 662 if (r == EOF || !r) 663 break; 664 str[i] = r; 665 if (r == '}') 666 { 667 i++; 668 break; 669 } 670 } 671 if (i == sizeof(str)-1) 672 Sys_Error ("Loadgame buffer overflow"); 673 str[i] = 0; 674 start = str; 675 start = COM_Parse(str); 676 if (!com_token[0]) 677 break; // end of file 678 if (strcmp(com_token,"{")) 679 Sys_Error ("First token isn't a brace"); 680 681 if (entnum == -1) 682 { // parse the global vars 683 ED_ParseGlobals (start); 684 } 685 else 686 { // parse an edict 687 688 ent = EDICT_NUM(entnum); 689 memset (&ent->u.v, 0, progs->entityfields * 4); 690 ent->free = false; 691 ED_ParseEdict (start, ent); 692 693 // link it into the bsp tree 694 if (!ent->free) 695 SV_LinkEdict (ent, false); 696 } 697 698 entnum++; 699 } 700 701 sv.num_edicts = entnum; 702 sv.time = time; 703 704 fclose (f); 705 706 for (i=0 ; i<NUM_SPAWN_PARMS ; i++) 707 svs.clients->spawn_parms[i] = spawn_parms[i]; 708 709 if (cls.state != ca_dedicated) 710 { 711 CL_EstablishConnection ("local"); 712 Host_Reconnect_f (); 713 } 714 } 715 716 #ifdef QUAKE2 717 void SaveGamestate() 718 { 719 char name[256]; 720 FILE *f; 721 int i; 722 char comment[SAVEGAME_COMMENT_LENGTH+1]; 723 edict_t *ent; 724 725 sprintf (name, "%s/%s.gip", com_gamedir, sv.name); 726 727 Con_Printf ("Saving game to %s...\n", name); 728 f = fopen (name, "w"); 729 if (!f) 730 { 731 Con_Printf ("ERROR: couldn't open.\n"); 732 return; 733 } 734 735 fprintf (f, "%i\n", SAVEGAME_VERSION); 736 Host_SavegameComment (comment); 737 fprintf (f, "%s\n", comment); 738 // for (i=0 ; i<NUM_SPAWN_PARMS ; i++) 739 // fprintf (f, "%f\n", svs.clients->spawn_parms[i]); 740 fprintf (f, "%f\n", skill.value); 741 fprintf (f, "%s\n", sv.name); 742 fprintf (f, "%f\n", sv.time); 743 744 // write the light styles 745 746 for (i=0 ; i<MAX_LIGHTSTYLES ; i++) 747 { 748 if (sv.lightstyles[i]) 749 fprintf (f, "%s\n", sv.lightstyles[i]); 750 else 751 fprintf (f,"m\n"); 752 } 753 754 755 for (i=svs.maxclients+1 ; i<sv.num_edicts ; i++) 756 { 757 ent = EDICT_NUM(i); 758 if ((int)ent->u.v.flags & FL_ARCHIVE_OVERRIDE) 759 continue; 760 fprintf (f, "%i\n",i); 761 ED_Write (f, ent); 762 fflush (f); 763 } 764 fclose (f); 765 Con_Printf ("done.\n"); 766 } 767 768 int LoadGamestate(char *level, char *startspot) 769 { 770 char name[MAX_OSPATH]; 771 FILE *f; 772 char mapname[MAX_QPATH]; 773 float time, sk; 774 char str[32768], *start; 775 int i, r; 776 edict_t *ent; 777 int entnum; 778 int version; 779 // float spawn_parms[NUM_SPAWN_PARMS]; 780 781 sprintf (name, "%s/%s.gip", com_gamedir, level); 782 783 Con_Printf ("Loading game from %s...\n", name); 784 f = fopen (name, "r"); 785 if (!f) 786 { 787 Con_Printf ("ERROR: couldn't open.\n"); 788 return -1; 789 } 790 791 fscanf (f, "%i\n", &version); 792 if (version != SAVEGAME_VERSION) 793 { 794 fclose (f); 795 Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION); 796 return -1; 797 } 798 fscanf (f, "%s\n", str); 799 // for (i=0 ; i<NUM_SPAWN_PARMS ; i++) 800 // fscanf (f, "%f\n", &spawn_parms[i]); 801 fscanf (f, "%f\n", &sk); 802 Cvar_SetValue ("skill", sk); 803 804 fscanf (f, "%s\n",mapname); 805 fscanf (f, "%f\n",&time); 806 807 SV_SpawnServer (mapname, startspot); 808 809 if (!sv.active) 810 { 811 Con_Printf ("Couldn't load map\n"); 812 return -1; 813 } 814 815 // load the light styles 816 for (i=0 ; i<MAX_LIGHTSTYLES ; i++) 817 { 818 fscanf (f, "%s\n", str); 819 sv.lightstyles[i] = Hunk_Alloc (strlen(str)+1); 820 strcpy (sv.lightstyles[i], str); 821 } 822 823 // load the edicts out of the savegame file 824 while (!feof(f)) 825 { 826 fscanf (f, "%i\n",&entnum); 827 for (i=0 ; i<sizeof(str)-1 ; i++) 828 { 829 r = fgetc (f); 830 if (r == EOF || !r) 831 break; 832 str[i] = r; 833 if (r == '}') 834 { 835 i++; 836 break; 837 } 838 } 839 if (i == sizeof(str)-1) 840 Sys_Error ("Loadgame buffer overflow"); 841 str[i] = 0; 842 start = str; 843 start = COM_Parse(str); 844 if (!com_token[0]) 845 break; // end of file 846 if (strcmp(com_token,"{")) 847 Sys_Error ("First token isn't a brace"); 848 849 // parse an edict 850 851 ent = EDICT_NUM(entnum); 852 memset (&ent->v, 0, progs->entityfields * 4); 853 ent->free = false; 854 ED_ParseEdict (start, ent); 855 856 // link it into the bsp tree 857 if (!ent->free) 858 SV_LinkEdict (ent, false); 859 } 860 861 // sv.num_edicts = entnum; 862 sv.time = time; 863 fclose (f); 864 865 // for (i=0 ; i<NUM_SPAWN_PARMS ; i++) 866 // svs.clients->spawn_parms[i] = spawn_parms[i]; 867 868 return 0; 869 } 870 871 // changing levels within a unit 872 void Host_Changelevel2_f (void) 873 { 874 char level[MAX_QPATH]; 875 char _startspot[MAX_QPATH]; 876 char *startspot; 877 878 if (Cmd_Argc() < 2) 879 { 880 Con_Printf ("changelevel2 <levelname> : continue game on a new level in the unit\n"); 881 return; 882 } 883 if (!sv.active || cls.demoplayback) 884 { 885 Con_Printf ("Only the server may changelevel\n"); 886 return; 887 } 888 889 strcpy (level, Cmd_Argv(1)); 890 if (Cmd_Argc() == 2) 891 startspot = NULL; 892 else 893 { 894 strcpy (_startspot, Cmd_Argv(2)); 895 startspot = _startspot; 896 } 897 898 SV_SaveSpawnparms (); 899 900 // save the current level's state 901 SaveGamestate (); 902 903 // try to restore the new level 904 if (LoadGamestate (level, startspot)) 905 SV_SpawnServer (level, startspot); 906 } 907 #endif 908 909 910 //============================================================================ 911 912 /* 913 ====================== 914 Host_Name_f 915 ====================== 916 */ 917 void Host_Name_f (void) 918 { 919 char *newName; 920 921 if (Cmd_Argc () == 1) 922 { 923 Con_Printf ("\"name\" is \"%s\"\n", cl_name.string); 924 return; 925 } 926 if (Cmd_Argc () == 2) 927 newName = Cmd_Argv(1); 928 else 929 newName = Cmd_Args(); 930 newName[15] = 0; 931 932 if (cmd_source == src_command) 933 { 934 if (Q_strcmp(cl_name.string, newName) == 0) 935 return; 936 Cvar_Set ("_cl_name", newName); 937 if (cls.state == ca_connected) 938 Cmd_ForwardToServer (); 939 return; 940 } 941 942 if (host_client->name[0] && strcmp(host_client->name, "unconnected") ) 943 if (Q_strcmp(host_client->name, newName) != 0) 944 Con_Printf ("%s renamed to %s\n", host_client->name, newName); 945 Q_strcpy (host_client->name, newName); 946 host_client->edict->u.v.netname = host_client->name - pr_strings; 947 948 // send notification to all clients 949 950 MSG_WriteByte (&sv.reliable_datagram, svc_updatename); 951 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients); 952 MSG_WriteString (&sv.reliable_datagram, host_client->name); 953 } 954 955 956 void Host_Version_f (void) 957 { 958 Con_Printf ("Version %4.2f\n", VERSION); 959 Con_Printf ("Exe: " __TIME__ " " __DATE__ "\n"); 960 } 961 962 #ifdef IDGODS 963 void Host_Please_f (void) 964 { 965 client_t *cl; 966 int j; 967 968 if (cmd_source != src_command) 969 return; 970 971 if ((Cmd_Argc () == 3) && Q_strcmp(Cmd_Argv(1), "#") == 0) 972 { 973 j = Q_atof(Cmd_Argv(2)) - 1; 974 if (j < 0 || j >= svs.maxclients) 975 return; 976 if (!svs.clients[j].active) 977 return; 978 cl = &svs.clients[j]; 979 if (cl->privileged) 980 { 981 cl->privileged = false; 982 cl->edict->u.v.flags = (int)cl->edict->u.v.flags & ~(FL_GODMODE|FL_NOTARGET); 983 cl->edict->u.v.movetype = MOVETYPE_WALK; 984 noclip_anglehack = false; 985 } 986 else 987 cl->privileged = true; 988 } 989 990 if (Cmd_Argc () != 2) 991 return; 992 993 for (j=0, cl = svs.clients ; j<svs.maxclients ; j++, cl++) 994 { 995 if (!cl->active) 996 continue; 997 if (Q_strcasecmp(cl->name, Cmd_Argv(1)) == 0) 998 { 999 if (cl->privileged) 1000 { 1001 cl->privileged = false; 1002 cl->edict->u.v.flags = (int)cl->edict->u.v.flags & ~(FL_GODMODE|FL_NOTARGET); 1003 cl->edict->u.v.movetype = MOVETYPE_WALK; 1004 noclip_anglehack = false; 1005 } 1006 else 1007 cl->privileged = true; 1008 break; 1009 } 1010 } 1011 } 1012 #endif 1013 1014 1015 void Host_Say(qboolean teamonly) 1016 { 1017 client_t *client; 1018 client_t *save; 1019 int j; 1020 char *p; 1021 unsigned char text[64]; 1022 qboolean fromServer = false; 1023 1024 if (cmd_source == src_command) 1025 { 1026 if (cls.state == ca_dedicated) 1027 { 1028 fromServer = true; 1029 teamonly = false; 1030 } 1031 else 1032 { 1033 Cmd_ForwardToServer (); 1034 return; 1035 } 1036 } 1037 1038 if (Cmd_Argc () < 2) 1039 return; 1040 1041 save = host_client; 1042 1043 p = Cmd_Args(); 1044 // remove quotes if present 1045 if (*p == '"') 1046 { 1047 p++; 1048 p[Q_strlen(p)-1] = 0; 1049 } 1050 1051 // turn on color set 1 1052 if (!fromServer) 1053 sprintf ((char*) text, "%c%s: ", 1, save->name); 1054 else 1055 sprintf ((char*) text, "%c<%s> ", 1, hostname.string); 1056 1057 j = sizeof(text) - 2 - Q_strlen((char*) text); // -2 for /n and null terminator 1058 if (Q_strlen((char*) p) > j) 1059 p[j] = 0; 1060 1061 strcat ((char*) text, p); 1062 strcat ((char*) text, "\n"); 1063 1064 for (j = 0, client = svs.clients; j < svs.maxclients; j++, client++) 1065 { 1066 if (!client || !client->active || !client->spawned) 1067 continue; 1068 if (teamplay.value && teamonly && client->edict->u.v.team != save->edict->u.v.team) 1069 continue; 1070 host_client = client; 1071 SV_ClientPrintf("%s", text); 1072 } 1073 host_client = save; 1074 1075 Sys_Printf("%s", &text[1]); 1076 } 1077 1078 1079 void Host_Say_f(void) 1080 { 1081 Host_Say(false); 1082 } 1083 1084 1085 void Host_Say_Team_f(void) 1086 { 1087 Host_Say(true); 1088 } 1089 1090 1091 void Host_Tell_f(void) 1092 { 1093 client_t *client; 1094 client_t *save; 1095 int j; 1096 char *p; 1097 char text[64]; 1098 1099 if (cmd_source == src_command) 1100 { 1101 Cmd_ForwardToServer (); 1102 return; 1103 } 1104 1105 if (Cmd_Argc () < 3) 1106 return; 1107 1108 Q_strcpy(text, host_client->name); 1109 Q_strcat(text, ": "); 1110 1111 p = Cmd_Args(); 1112 1113 // remove quotes if present 1114 if (*p == '"') 1115 { 1116 p++; 1117 p[Q_strlen(p)-1] = 0; 1118 } 1119 1120 // check length & truncate if necessary 1121 j = sizeof(text) - 2 - Q_strlen(text); // -2 for /n and null terminator 1122 if (Q_strlen(p) > j) 1123 p[j] = 0; 1124 1125 strcat (text, p); 1126 strcat (text, "\n"); 1127 1128 save = host_client; 1129 for (j = 0, client = svs.clients; j < svs.maxclients; j++, client++) 1130 { 1131 if (!client->active || !client->spawned) 1132 continue; 1133 if (Q_strcasecmp(client->name, Cmd_Argv(1))) 1134 continue; 1135 host_client = client; 1136 SV_ClientPrintf("%s", text); 1137 break; 1138 } 1139 host_client = save; 1140 } 1141 1142 1143 /* 1144 ================== 1145 Host_Color_f 1146 ================== 1147 */ 1148 void Host_Color_f(void) 1149 { 1150 int top, bottom; 1151 int playercolor; 1152 1153 if (Cmd_Argc() == 1) 1154 { 1155 Con_Printf ("\"color\" is \"%i %i\"\n", ((int)cl_color.value) >> 4, ((int)cl_color.value) & 0x0f); 1156 Con_Printf ("color <0-13> [0-13]\n"); 1157 return; 1158 } 1159 1160 if (Cmd_Argc() == 2) 1161 top = bottom = atoi(Cmd_Argv(1)); 1162 else 1163 { 1164 top = atoi(Cmd_Argv(1)); 1165 bottom = atoi(Cmd_Argv(2)); 1166 } 1167 1168 top &= 15; 1169 if (top > 13) 1170 top = 13; 1171 bottom &= 15; 1172 if (bottom > 13) 1173 bottom = 13; 1174 1175 playercolor = top*16 + bottom; 1176 1177 if (cmd_source == src_command) 1178 { 1179 Cvar_SetValue ("_cl_color", playercolor); 1180 if (cls.state == ca_connected) 1181 Cmd_ForwardToServer (); 1182 return; 1183 } 1184 1185 host_client->colors = playercolor; 1186 host_client->edict->u.v.team = bottom + 1; 1187 1188 // send notification to all clients 1189 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors); 1190 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients); 1191 MSG_WriteByte (&sv.reliable_datagram, host_client->colors); 1192 } 1193 1194 /* 1195 ================== 1196 Host_Kill_f 1197 ================== 1198 */ 1199 void Host_Kill_f (void) 1200 { 1201 if (cmd_source == src_command) 1202 { 1203 Cmd_ForwardToServer (); 1204 return; 1205 } 1206 1207 if (sv_player->u.v.health <= 0) 1208 { 1209 SV_ClientPrintf ("Can't suicide -- allready dead!\n"); 1210 return; 1211 } 1212 1213 pr_global_struct->time = sv.time; 1214 pr_global_struct->self = EDICT_TO_PROG(sv_player); 1215 PR_ExecuteProgram (pr_global_struct->ClientKill); 1216 } 1217 1218 1219 /* 1220 ================== 1221 Host_Pause_f 1222 ================== 1223 */ 1224 void Host_Pause_f (void) 1225 { 1226 1227 if (cmd_source == src_command) 1228 { 1229 Cmd_ForwardToServer (); 1230 return; 1231 } 1232 if (!pausable.value) 1233 SV_ClientPrintf ("Pause not allowed.\n"); 1234 else 1235 { 1236 sv.paused ^= 1; 1237 1238 if (sv.paused) 1239 { 1240 SV_BroadcastPrintf ("%s paused the game\n", pr_strings + sv_player->u.v.netname); 1241 } 1242 else 1243 { 1244 SV_BroadcastPrintf ("%s unpaused the game\n",pr_strings + sv_player->u.v.netname); 1245 } 1246 1247 // send notification to all clients 1248 MSG_WriteByte (&sv.reliable_datagram, svc_setpause); 1249 MSG_WriteByte (&sv.reliable_datagram, sv.paused); 1250 } 1251 } 1252 1253 //=========================================================================== 1254 1255 1256 /* 1257 ================== 1258 Host_PreSpawn_f 1259 ================== 1260 */ 1261 void Host_PreSpawn_f (void) 1262 { 1263 if (cmd_source == src_command) 1264 { 1265 Con_Printf ("prespawn is not valid from the console\n"); 1266 return; 1267 } 1268 1269 if (host_client->spawned) 1270 { 1271 Con_Printf ("prespawn not valid -- allready spawned\n"); 1272 return; 1273 } 1274 1275 SZ_Write (&host_client->message, sv.signon.data, sv.signon.cursize); 1276 MSG_WriteByte (&host_client->message, svc_signonnum); 1277 MSG_WriteByte (&host_client->message, 2); 1278 host_client->sendsignon = true; 1279 } 1280 1281 /* 1282 ================== 1283 Host_Spawn_f 1284 ================== 1285 */ 1286 void Host_Spawn_f (void) 1287 { 1288 int i; 1289 client_t *client; 1290 edict_t *ent; 1291 1292 if (cmd_source == src_command) 1293 { 1294 Con_Printf ("spawn is not valid from the console\n"); 1295 return; 1296 } 1297 1298 if (host_client->spawned) 1299 { 1300 Con_Printf ("Spawn not valid -- allready spawned\n"); 1301 return; 1302 } 1303 1304 // run the entrance script 1305 if (sv.loadgame) 1306 { // loaded games are fully inited allready 1307 // if this is the last client to be connected, unpause 1308 sv.paused = false; 1309 } 1310 else 1311 { 1312 // set up the edict 1313 ent = host_client->edict; 1314 1315 memset (&ent->u.v, 0, progs->entityfields * 4); 1316 ent->u.v.colormap = NUM_FOR_EDICT(ent); 1317 ent->u.v.team = (host_client->colors & 15) + 1; 1318 ent->u.v.netname = host_client->name - pr_strings; 1319 1320 // copy spawn parms out of the client_t 1321 1322 for (i=0 ; i< NUM_SPAWN_PARMS ; i++) 1323 (&pr_global_struct->parm1)[i] = host_client->spawn_parms[i]; 1324 1325 // call the spawn function 1326 1327 pr_global_struct->time = sv.time; 1328 pr_global_struct->self = EDICT_TO_PROG(sv_player); 1329 PR_ExecuteProgram (pr_global_struct->ClientConnect); 1330 1331 if ((Sys_FloatTime() - host_client->netconnection->connecttime) <= sv.time) 1332 Sys_Printf ("%s entered the game\n", host_client->name); 1333 1334 PR_ExecuteProgram (pr_global_struct->PutClientInServer); 1335 } 1336 1337 1338 // send all current names, colors, and frag counts 1339 SZ_Clear (&host_client->message); 1340 1341 // send time of update 1342 MSG_WriteByte (&host_client->message, svc_time); 1343 MSG_WriteFloat (&host_client->message, sv.time); 1344 1345 for (i=0, client = svs.clients ; i<svs.maxclients ; i++, client++) 1346 { 1347 MSG_WriteByte (&host_client->message, svc_updatename); 1348 MSG_WriteByte (&host_client->message, i); 1349 MSG_WriteString (&host_client->message, client->name); 1350 MSG_WriteByte (&host_client->message, svc_updatefrags); 1351 MSG_WriteByte (&host_client->message, i); 1352 MSG_WriteShort (&host_client->message, client->old_frags); 1353 MSG_WriteByte (&host_client->message, svc_updatecolors); 1354 MSG_WriteByte (&host_client->message, i); 1355 MSG_WriteByte (&host_client->message, client->colors); 1356 } 1357 1358 // send all current light styles 1359 for (i=0 ; i<MAX_LIGHTSTYLES ; i++) 1360 { 1361 MSG_WriteByte (&host_client->message, svc_lightstyle); 1362 MSG_WriteByte (&host_client->message, (char)i); 1363 MSG_WriteString (&host_client->message, sv.lightstyles[i]); 1364 } 1365 1366 // 1367 // send some stats 1368 // 1369 MSG_WriteByte (&host_client->message, svc_updatestat); 1370 MSG_WriteByte (&host_client->message, STAT_TOTALSECRETS); 1371 MSG_WriteLong (&host_client->message, (int) pr_global_struct->total_secrets); 1372 1373 MSG_WriteByte (&host_client->message, svc_updatestat); 1374 MSG_WriteByte (&host_client->message, STAT_TOTALMONSTERS); 1375 MSG_WriteLong (&host_client->message, (int) pr_global_struct->total_monsters); 1376 1377 MSG_WriteByte (&host_client->message, svc_updatestat); 1378 MSG_WriteByte (&host_client->message, STAT_SECRETS); 1379 MSG_WriteLong (&host_client->message, (int) pr_global_struct->found_secrets); 1380 1381 MSG_WriteByte (&host_client->message, svc_updatestat); 1382 MSG_WriteByte (&host_client->message, STAT_MONSTERS); 1383 MSG_WriteLong (&host_client->message, (int) pr_global_struct->killed_monsters); 1384 1385 1386 // 1387 // send a fixangle 1388 // Never send a roll angle, because savegames can catch the server 1389 // in a state where it is expecting the client to correct the angle 1390 // and it won't happen if the game was just loaded, so you wind up 1391 // with a permanent head tilt 1392 ent = EDICT_NUM( 1 + (host_client - svs.clients) ); 1393 MSG_WriteByte (&host_client->message, svc_setangle); 1394 for (i=0 ; i < 2 ; i++) 1395 MSG_WriteAngle (&host_client->message, ent->u.v.angles[i] ); 1396 MSG_WriteAngle (&host_client->message, 0 ); 1397 1398 SV_WriteClientdataToMessage (sv_player, &host_client->message); 1399 1400 MSG_WriteByte (&host_client->message, svc_signonnum); 1401 MSG_WriteByte (&host_client->message, 3); 1402 host_client->sendsignon = true; 1403 } 1404 1405 /* 1406 ================== 1407 Host_Begin_f 1408 ================== 1409 */ 1410 void Host_Begin_f (void) 1411 { 1412 if (cmd_source == src_command) 1413 { 1414 Con_Printf ("begin is not valid from the console\n"); 1415 return; 1416 } 1417 1418 host_client->spawned = true; 1419 } 1420 1421 //=========================================================================== 1422 1423 1424 /* 1425 ================== 1426 Host_Kick_f 1427 1428 Kicks a user off of the server 1429 ================== 1430 */ 1431 void Host_Kick_f (void) 1432 { 1433 const char *who; 1434 const char *message = NULL; 1435 client_t *save; 1436 int i; 1437 qboolean byNumber = false; 1438 1439 if (cmd_source == src_command) 1440 { 1441 if (!sv.active) 1442 { 1443 Cmd_ForwardToServer (); 1444 return; 1445 } 1446 } 1447 else if (pr_global_struct->deathmatch && !host_client->privileged) 1448 return; 1449 1450 save = host_client; 1451 1452 if (Cmd_Argc() > 2 && Q_strcmp(Cmd_Argv(1), "#") == 0) 1453 { 1454 i = (int) Q_atof(Cmd_Argv(2)) - 1; 1455 if (i < 0 || i >= svs.maxclients) 1456 return; 1457 if (!svs.clients[i].active) 1458 return; 1459 host_client = &svs.clients[i]; 1460 byNumber = true; 1461 } 1462 else 1463 { 1464 for (i = 0, host_client = svs.clients; i < svs.maxclients; i++, host_client++) 1465 { 1466 if (!host_client->active) 1467 continue; 1468 if (Q_strcasecmp(host_client->name, Cmd_Argv(1)) == 0) 1469 break; 1470 } 1471 } 1472 1473 if (i < svs.maxclients) 1474 { 1475 if (cmd_source == src_command) 1476 if (cls.state == ca_dedicated) 1477 who = "Console"; 1478 else 1479 who = cl_name.string; 1480 else 1481 who = save->name; 1482 1483 // can't kick yourself! 1484 if (host_client == save) 1485 return; 1486 1487 if (Cmd_Argc() > 2) 1488 { 1489 message = COM_Parse(Cmd_Args()); 1490 if (byNumber) 1491 { 1492 message++; // skip the # 1493 while (*message == ' ') // skip white space 1494 message++; 1495 message += Q_strlen(Cmd_Argv(2)); // skip the number 1496 } 1497 while (*message && *message == ' ') 1498 message++; 1499 } 1500 if (message) 1501 SV_ClientPrintf ("Kicked by %s: %s\n", who, message); 1502 else 1503 SV_ClientPrintf ("Kicked by %s\n", who); 1504 SV_DropClient (false); 1505 } 1506 1507 host_client = save; 1508 } 1509 1510 /* 1511 =============================================================================== 1512 1513 DEBUGGING TOOLS 1514 1515 =============================================================================== 1516 */ 1517 1518 /* 1519 ================== 1520 Host_Give_f 1521 ================== 1522 */ 1523 void Host_Give_f (void) 1524 { 1525 char *t; 1526 int v, w; 1527 eval_t *val; 1528 1529 if (cmd_source == src_command) 1530 { 1531 Cmd_ForwardToServer (); 1532 return; 1533 } 1534 1535 if (pr_global_struct->deathmatch && !host_client->privileged) 1536 return; 1537 1538 t = Cmd_Argv(1); 1539 v = atoi (Cmd_Argv(2)); 1540 1541 switch (t[0]) 1542 { 1543 case '0': 1544 case '1': 1545 case '2': 1546 case '3': 1547 case '4': 1548 case '5': 1549 case '6': 1550 case '7': 1551 case '8': 1552 case '9': 1553 // MED 01/04/97 added hipnotic give stuff 1554 if (hipnotic) 1555 { 1556 if (t[0] == '6') 1557 { 1558 if (t[1] == 'a') 1559 sv_player->u.v.items = (int)sv_player->u.v.items | HIT_PROXIMITY_GUN; 1560 else 1561 sv_player->u.v.items = (int)sv_player->u.v.items | IT_GRENADE_LAUNCHER; 1562 } 1563 else if (t[0] == '9') 1564 sv_player->u.v.items = (int)sv_player->u.v.items | HIT_LASER_CANNON; 1565 else if (t[0] == '0') 1566 sv_player->u.v.items = (int)sv_player->u.v.items | HIT_MJOLNIR; 1567 else if (t[0] >= '2') 1568 sv_player->u.v.items = (int)sv_player->u.v.items | (IT_SHOTGUN << (t[0] - '2')); 1569 } 1570 else 1571 { 1572 if (t[0] >= '2') 1573 sv_player->u.v.items = (int)sv_player->u.v.items | (IT_SHOTGUN << (t[0] - '2')); 1574 } 1575 break; 1576 1577 case 's': 1578 if (rogue) 1579 { 1580 val = GetEdictFieldValue(sv_player, "ammo_shells1"); 1581 if (val) 1582 val->_float = v; 1583 } 1584 1585 sv_player->u.v.ammo_shells = v; 1586 break; 1587 case 'n': 1588 if (rogue) 1589 { 1590 val = GetEdictFieldValue(sv_player, "ammo_nails1"); 1591 if (val) 1592 { 1593 val->_float = v; 1594 if (sv_player->u.v.weapon <= IT_LIGHTNING) 1595 sv_player->u.v.ammo_nails = v; 1596 } 1597 } 1598 else 1599 { 1600 sv_player->u.v.ammo_nails = v; 1601 } 1602 break; 1603 case 'l': 1604 if (rogue) 1605 { 1606 val = GetEdictFieldValue(sv_player, "ammo_lava_nails"); 1607 if (val) 1608 { 1609 val->_float = v; 1610 if (sv_player->u.v.weapon > IT_LIGHTNING) 1611 sv_player->u.v.ammo_nails = v; 1612 } 1613 } 1614 break; 1615 case 'r': 1616 if (rogue) 1617 { 1618 val = GetEdictFieldValue(sv_player, "ammo_rockets1"); 1619 if (val) 1620 { 1621 val->_float = v; 1622 if (sv_player->u.v.weapon <= IT_LIGHTNING) 1623 sv_player->u.v.ammo_rockets = v; 1624 } 1625 } 1626 else 1627 { 1628 sv_player->u.v.ammo_rockets = v; 1629 } 1630 break; 1631 case 'm': 1632 if (rogue) 1633 { 1634 val = GetEdictFieldValue(sv_player, "ammo_multi_rockets"); 1635 if (val) 1636 { 1637 val->_float = v; 1638 if (sv_player->u.v.weapon > IT_LIGHTNING) 1639 sv_player->u.v.ammo_rockets = v; 1640 } 1641 } 1642 break; 1643 case 'h': 1644 sv_player->u.v.health = v; 1645 break; 1646 case 'c': 1647 if (rogue) 1648 { 1649 val = GetEdictFieldValue(sv_player, "ammo_cells1"); 1650 if (val) 1651 { 1652 val->_float = v; 1653 if (sv_player->u.v.weapon <= IT_LIGHTNING) 1654 sv_player->u.v.ammo_cells = v; 1655 } 1656 } 1657 else 1658 { 1659 sv_player->u.v.ammo_cells = v; 1660 } 1661 break; 1662 case 'p': 1663 if (rogue) 1664 { 1665 val = GetEdictFieldValue(sv_player, "ammo_plasma"); 1666 if (val) 1667 { 1668 val->_float = v; 1669 if (sv_player->u.v.weapon > IT_LIGHTNING) 1670 sv_player->u.v.ammo_cells = v; 1671 } 1672 } 1673 break; 1674 } 1675 } 1676 1677 edict_t *FindViewthing (void) 1678 { 1679 int i; 1680 edict_t *e; 1681 1682 for (i=0 ; i<sv.num_edicts ; i++) 1683 { 1684 e = EDICT_NUM(i); 1685 if ( !strcmp (pr_strings + e->u.v.classname, "viewthing") ) 1686 return e; 1687 } 1688 Con_Printf ("No viewthing on map\n"); 1689 return NULL; 1690 } 1691 1692 /* 1693 ================== 1694 Host_Viewmodel_f 1695 ================== 1696 */ 1697 void Host_Viewmodel_f (void) 1698 { 1699 edict_t *e; 1700 model_t *m; 1701 1702 e = FindViewthing (); 1703 if (!e) 1704 return; 1705 1706 m = Mod_ForName (Cmd_Argv(1), false); 1707 if (!m) 1708 { 1709 Con_Printf ("Can't load %s\n", Cmd_Argv(1)); 1710 return; 1711 } 1712 1713 e->u.v.frame = 0; 1714 cl.model_precache[(int)e->u.v.modelindex] = m; 1715 } 1716 1717 /* 1718 ================== 1719 Host_Viewframe_f 1720 ================== 1721 */ 1722 void Host_Viewframe_f (void) 1723 { 1724 edict_t *e; 1725 int f; 1726 model_t *m; 1727 1728 e = FindViewthing (); 1729 if (!e) 1730 return; 1731 m = cl.model_precache[(int)e->u.v.modelindex]; 1732 1733 f = atoi(Cmd_Argv(1)); 1734 if (f >= m->numframes) 1735 f = m->numframes-1; 1736 1737 e->u.v.frame = f; 1738 } 1739 1740 1741 void PrintFrameName (model_t *m, int frame) 1742 { 1743 aliashdr_t *hdr; 1744 maliasframedesc_t *pframedesc; 1745 1746 hdr = (aliashdr_t *)Mod_Extradata (m); 1747 if (!hdr) 1748 return; 1749 pframedesc = &hdr->frames[frame]; 1750 1751 Con_Printf ("frame %i: %s\n", frame, pframedesc->name); 1752 } 1753 1754 /* 1755 ================== 1756 Host_Viewnext_f 1757 ================== 1758 */ 1759 void Host_Viewnext_f (void) 1760 { 1761 edict_t *e; 1762 model_t *m; 1763 1764 e = FindViewthing (); 1765 if (!e) 1766 return; 1767 m = cl.model_precache[(int)e->u.v.modelindex]; 1768 1769 e->u.v.frame = e->u.v.frame + 1; 1770 if (e->u.v.frame >= m->numframes) 1771 e->u.v.frame = m->numframes - 1; 1772 1773 PrintFrameName (m, (int) e->u.v.frame); 1774 } 1775 1776 /* 1777 ================== 1778 Host_Viewprev_f 1779 ================== 1780 */ 1781 void Host_Viewprev_f (void) 1782 { 1783 edict_t *e; 1784 model_t *m; 1785 1786 e = FindViewthing (); 1787 if (!e) 1788 return; 1789 1790 m = cl.model_precache[(int)e->u.v.modelindex]; 1791 1792 e->u.v.frame = e->u.v.frame - 1; 1793 if (e->u.v.frame < 0) 1794 e->u.v.frame = 0; 1795 1796 PrintFrameName (m, (int) e->u.v.frame); 1797 } 1798 1799 /* 1800 =============================================================================== 1801 1802 DEMO LOOP CONTROL 1803 1804 =============================================================================== 1805 */ 1806 1807 1808 /* 1809 ================== 1810 Host_Startdemos_f 1811 ================== 1812 */ 1813 void Host_Startdemos_f (void) 1814 { 1815 int i, c; 1816 1817 if (cls.state == ca_dedicated) 1818 { 1819 if (!sv.active) 1820 Cbuf_AddText ("map start\n"); 1821 return; 1822 } 1823 1824 c = Cmd_Argc() - 1; 1825 if (c > MAX_DEMOS) 1826 { 1827 Con_Printf ("Max %i demos in demoloop\n", MAX_DEMOS); 1828 c = MAX_DEMOS; 1829 } 1830 Con_Printf ("%i demo(s) in loop\n", c); 1831 1832 for (i=1 ; i<c+1 ; i++) 1833 strncpy (cls.demos[i-1], Cmd_Argv(i), sizeof(cls.demos[0])-1); 1834 1835 if (!sv.active && cls.demonum != -1 && !cls.demoplayback) 1836 { 1837 cls.demonum = 0; 1838 CL_NextDemo (); 1839 } 1840 else 1841 cls.demonum = -1; 1842 } 1843 1844 1845 /* 1846 ================== 1847 Host_Demos_f 1848 1849 Return to looping demos 1850 ================== 1851 */ 1852 void Host_Demos_f (void) 1853 { 1854 if (cls.state == ca_dedicated) 1855 return; 1856 if (cls.demonum == -1) 1857 cls.demonum = 1; 1858 CL_Disconnect_f (); 1859 CL_NextDemo (); 1860 } 1861 1862 /* 1863 ================== 1864 Host_Stopdemo_f 1865 1866 Return to looping demos 1867 ================== 1868 */ 1869 void Host_Stopdemo_f (void) 1870 { 1871 if (cls.state == ca_dedicated) 1872 return; 1873 if (!cls.demoplayback) 1874 return; 1875 CL_StopPlayback (); 1876 CL_Disconnect (); 1877 } 1878 1879 //============================================================================= 1880 1881 /* 1882 ================== 1883 Host_InitCommands 1884 ================== 1885 */ 1886 void Host_InitCommands (void) 1887 { 1888 Cmd_AddCommand ("status", Host_Status_f); 1889 Cmd_AddCommand ("quit", Host_Quit_f); 1890 Cmd_AddCommand ("god", Host_God_f); 1891 Cmd_AddCommand ("notarget", Host_Notarget_f); 1892 Cmd_AddCommand ("fly", Host_Fly_f); 1893 Cmd_AddCommand ("map", Host_Map_f); 1894 Cmd_AddCommand ("restart", Host_Restart_f); 1895 Cmd_AddCommand ("changelevel", Host_Changelevel_f); 1896 #ifdef QUAKE2 1897 Cmd_AddCommand ("changelevel2", Host_Changelevel2_f); 1898 #endif 1899 Cmd_AddCommand ("connect", Host_Connect_f); 1900 Cmd_AddCommand ("reconnect", Host_Reconnect_f); 1901 Cmd_AddCommand ("name", Host_Name_f); 1902 Cmd_AddCommand ("noclip", Host_Noclip_f); 1903 Cmd_AddCommand ("version", Host_Version_f); 1904 #ifdef IDGODS 1905 Cmd_AddCommand ("please", Host_Please_f); 1906 #endif 1907 Cmd_AddCommand ("say", Host_Say_f); 1908 Cmd_AddCommand ("say_team", Host_Say_Team_f); 1909 Cmd_AddCommand ("tell", Host_Tell_f); 1910 Cmd_AddCommand ("color", Host_Color_f); 1911 Cmd_AddCommand ("kill", Host_Kill_f); 1912 Cmd_AddCommand ("pause", Host_Pause_f); 1913 Cmd_AddCommand ("spawn", Host_Spawn_f); 1914 Cmd_AddCommand ("begin", Host_Begin_f); 1915 Cmd_AddCommand ("prespawn", Host_PreSpawn_f); 1916 Cmd_AddCommand ("kick", Host_Kick_f); 1917 Cmd_AddCommand ("ping", Host_Ping_f); 1918 Cmd_AddCommand ("load", Host_Loadgame_f); 1919 Cmd_AddCommand ("save", Host_Savegame_f); 1920 Cmd_AddCommand ("give", Host_Give_f); 1921 1922 Cmd_AddCommand ("startdemos", Host_Startdemos_f); 1923 Cmd_AddCommand ("demos", Host_Demos_f); 1924 Cmd_AddCommand ("stopdemo", Host_Stopdemo_f); 1925 1926 Cmd_AddCommand ("viewmodel", Host_Viewmodel_f); 1927 Cmd_AddCommand ("viewframe", Host_Viewframe_f); 1928 Cmd_AddCommand ("viewnext", Host_Viewnext_f); 1929 Cmd_AddCommand ("viewprev", Host_Viewprev_f); 1930 1931 Cmd_AddCommand ("mcache", Mod_Print); 1932 } 1933