menu.c (106717B)
1 /* 2 Copyright (C) 1997-2001 Id Software, Inc. 3 4 This program is free software; you can redistribute it and/or 5 modify it under the terms of the GNU General Public License 6 as published by the Free Software Foundation; either version 2 7 of the License, or (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13 See the GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 19 */ 20 #include <ctype.h> 21 #ifdef _WIN32 22 #include <io.h> 23 #endif 24 #include "client.h" 25 #include "../client/qmenu.h" 26 27 static int m_main_cursor; 28 29 #define NUM_CURSOR_FRAMES 15 30 31 static char *menu_in_sound = "misc/menu1.wav"; 32 static char *menu_move_sound = "misc/menu2.wav"; 33 static char *menu_out_sound = "misc/menu3.wav"; 34 35 void M_Menu_Main_f (void); 36 void M_Menu_Game_f (void); 37 void M_Menu_LoadGame_f (void); 38 void M_Menu_SaveGame_f (void); 39 void M_Menu_PlayerConfig_f (void); 40 void M_Menu_DownloadOptions_f (void); 41 void M_Menu_Credits_f( void ); 42 void M_Menu_Multiplayer_f( void ); 43 void M_Menu_JoinServer_f (void); 44 void M_Menu_AddressBook_f( void ); 45 void M_Menu_StartServer_f (void); 46 void M_Menu_DMOptions_f (void); 47 void M_Menu_Video_f (void); 48 void M_Menu_Options_f (void); 49 void M_Menu_Keys_f (void); 50 void M_Menu_Quit_f (void); 51 52 void M_Menu_Credits( void ); 53 54 qboolean m_entersound; // play after drawing a frame, so caching 55 // won't disrupt the sound 56 57 void (*m_drawfunc) (void); 58 const char *(*m_keyfunc) (int key); 59 60 //============================================================================= 61 /* Support Routines */ 62 63 #define MAX_MENU_DEPTH 8 64 65 66 typedef struct 67 { 68 void (*draw) (void); 69 const char *(*key) (int k); 70 } menulayer_t; 71 72 menulayer_t m_layers[MAX_MENU_DEPTH]; 73 int m_menudepth; 74 75 static void M_Banner( char *name ) 76 { 77 int w, h; 78 79 re.DrawGetPicSize (&w, &h, name ); 80 re.DrawPic( viddef.width / 2 - w / 2, viddef.height / 2 - 110, name ); 81 } 82 83 void M_PushMenu ( void (*draw) (void), const char *(*key) (int k) ) 84 { 85 int i; 86 87 if (Cvar_VariableValue ("maxclients") == 1 88 && Com_ServerState ()) 89 Cvar_Set ("paused", "1"); 90 91 // if this menu is already present, drop back to that level 92 // to avoid stacking menus by hotkeys 93 for (i=0 ; i<m_menudepth ; i++) 94 if (m_layers[i].draw == draw && 95 m_layers[i].key == key) 96 { 97 m_menudepth = i; 98 } 99 100 if (i == m_menudepth) 101 { 102 if (m_menudepth >= MAX_MENU_DEPTH) 103 Com_Error (ERR_FATAL, "M_PushMenu: MAX_MENU_DEPTH"); 104 m_layers[m_menudepth].draw = m_drawfunc; 105 m_layers[m_menudepth].key = m_keyfunc; 106 m_menudepth++; 107 } 108 109 m_drawfunc = draw; 110 m_keyfunc = key; 111 112 m_entersound = true; 113 114 cls.key_dest = key_menu; 115 } 116 117 void M_ForceMenuOff (void) 118 { 119 m_drawfunc = 0; 120 m_keyfunc = 0; 121 cls.key_dest = key_game; 122 m_menudepth = 0; 123 Key_ClearStates (); 124 Cvar_Set ("paused", "0"); 125 } 126 127 void M_PopMenu (void) 128 { 129 S_StartLocalSound( menu_out_sound ); 130 if (m_menudepth < 1) 131 Com_Error (ERR_FATAL, "M_PopMenu: depth < 1"); 132 m_menudepth--; 133 134 m_drawfunc = m_layers[m_menudepth].draw; 135 m_keyfunc = m_layers[m_menudepth].key; 136 137 if (!m_menudepth) 138 M_ForceMenuOff (); 139 } 140 141 142 const char *Default_MenuKey( menuframework_s *m, int key ) 143 { 144 const char *sound = NULL; 145 menucommon_s *item; 146 147 if ( m ) 148 { 149 if ( ( item = Menu_ItemAtCursor( m ) ) != 0 ) 150 { 151 if ( item->type == MTYPE_FIELD ) 152 { 153 if ( Field_Key( ( menufield_s * ) item, key ) ) 154 return NULL; 155 } 156 } 157 } 158 159 switch ( key ) 160 { 161 case K_ESCAPE: 162 M_PopMenu(); 163 return menu_out_sound; 164 case K_KP_UPARROW: 165 case K_UPARROW: 166 if ( m ) 167 { 168 m->cursor--; 169 Menu_AdjustCursor( m, -1 ); 170 sound = menu_move_sound; 171 } 172 break; 173 case K_TAB: 174 if ( m ) 175 { 176 m->cursor++; 177 Menu_AdjustCursor( m, 1 ); 178 sound = menu_move_sound; 179 } 180 break; 181 case K_KP_DOWNARROW: 182 case K_DOWNARROW: 183 if ( m ) 184 { 185 m->cursor++; 186 Menu_AdjustCursor( m, 1 ); 187 sound = menu_move_sound; 188 } 189 break; 190 case K_KP_LEFTARROW: 191 case K_LEFTARROW: 192 if ( m ) 193 { 194 Menu_SlideItem( m, -1 ); 195 sound = menu_move_sound; 196 } 197 break; 198 case K_KP_RIGHTARROW: 199 case K_RIGHTARROW: 200 if ( m ) 201 { 202 Menu_SlideItem( m, 1 ); 203 sound = menu_move_sound; 204 } 205 break; 206 207 case K_MOUSE1: 208 case K_MOUSE2: 209 case K_MOUSE3: 210 case K_JOY1: 211 case K_JOY2: 212 case K_JOY3: 213 case K_JOY4: 214 case K_AUX1: 215 case K_AUX2: 216 case K_AUX3: 217 case K_AUX4: 218 case K_AUX5: 219 case K_AUX6: 220 case K_AUX7: 221 case K_AUX8: 222 case K_AUX9: 223 case K_AUX10: 224 case K_AUX11: 225 case K_AUX12: 226 case K_AUX13: 227 case K_AUX14: 228 case K_AUX15: 229 case K_AUX16: 230 case K_AUX17: 231 case K_AUX18: 232 case K_AUX19: 233 case K_AUX20: 234 case K_AUX21: 235 case K_AUX22: 236 case K_AUX23: 237 case K_AUX24: 238 case K_AUX25: 239 case K_AUX26: 240 case K_AUX27: 241 case K_AUX28: 242 case K_AUX29: 243 case K_AUX30: 244 case K_AUX31: 245 case K_AUX32: 246 247 case K_KP_ENTER: 248 case K_ENTER: 249 if ( m ) 250 Menu_SelectItem( m ); 251 sound = menu_move_sound; 252 break; 253 } 254 255 return sound; 256 } 257 258 //============================================================================= 259 260 /* 261 ================ 262 M_DrawCharacter 263 264 Draws one solid graphics character 265 cx and cy are in 320*240 coordinates, and will be centered on 266 higher res screens. 267 ================ 268 */ 269 void M_DrawCharacter (int cx, int cy, int num) 270 { 271 re.DrawChar ( cx + ((viddef.width - 320)>>1), cy + ((viddef.height - 240)>>1), num); 272 } 273 274 void M_Print (int cx, int cy, char *str) 275 { 276 while (*str) 277 { 278 M_DrawCharacter (cx, cy, (*str)+128); 279 str++; 280 cx += 8; 281 } 282 } 283 284 void M_PrintWhite (int cx, int cy, char *str) 285 { 286 while (*str) 287 { 288 M_DrawCharacter (cx, cy, *str); 289 str++; 290 cx += 8; 291 } 292 } 293 294 void M_DrawPic (int x, int y, char *pic) 295 { 296 re.DrawPic (x + ((viddef.width - 320)>>1), y + ((viddef.height - 240)>>1), pic); 297 } 298 299 300 /* 301 ============= 302 M_DrawCursor 303 304 Draws an animating cursor with the point at 305 x,y. The pic will extend to the left of x, 306 and both above and below y. 307 ============= 308 */ 309 void M_DrawCursor( int x, int y, int f ) 310 { 311 char cursorname[80]; 312 static qboolean cached; 313 314 if ( !cached ) 315 { 316 int i; 317 318 for ( i = 0; i < NUM_CURSOR_FRAMES; i++ ) 319 { 320 Com_sprintf( cursorname, sizeof( cursorname ), "m_cursor%d", i ); 321 322 re.RegisterPic( cursorname ); 323 } 324 cached = true; 325 } 326 327 Com_sprintf( cursorname, sizeof(cursorname), "m_cursor%d", f ); 328 re.DrawPic( x, y, cursorname ); 329 } 330 331 void M_DrawTextBox (int x, int y, int width, int lines) 332 { 333 int cx, cy; 334 int n; 335 336 // draw left side 337 cx = x; 338 cy = y; 339 M_DrawCharacter (cx, cy, 1); 340 for (n = 0; n < lines; n++) 341 { 342 cy += 8; 343 M_DrawCharacter (cx, cy, 4); 344 } 345 M_DrawCharacter (cx, cy+8, 7); 346 347 // draw middle 348 cx += 8; 349 while (width > 0) 350 { 351 cy = y; 352 M_DrawCharacter (cx, cy, 2); 353 for (n = 0; n < lines; n++) 354 { 355 cy += 8; 356 M_DrawCharacter (cx, cy, 5); 357 } 358 M_DrawCharacter (cx, cy+8, 8); 359 width -= 1; 360 cx += 8; 361 } 362 363 // draw right side 364 cy = y; 365 M_DrawCharacter (cx, cy, 3); 366 for (n = 0; n < lines; n++) 367 { 368 cy += 8; 369 M_DrawCharacter (cx, cy, 6); 370 } 371 M_DrawCharacter (cx, cy+8, 9); 372 } 373 374 375 /* 376 ======================================================================= 377 378 MAIN MENU 379 380 ======================================================================= 381 */ 382 #define MAIN_ITEMS 5 383 384 385 void M_Main_Draw (void) 386 { 387 int i; 388 int w, h; 389 int ystart; 390 int xoffset; 391 int widest = -1; 392 int totalheight = 0; 393 char litname[80]; 394 char *names[] = 395 { 396 "m_main_game", 397 "m_main_multiplayer", 398 "m_main_options", 399 "m_main_video", 400 "m_main_quit", 401 0 402 }; 403 404 for ( i = 0; names[i] != 0; i++ ) 405 { 406 re.DrawGetPicSize( &w, &h, names[i] ); 407 408 if ( w > widest ) 409 widest = w; 410 totalheight += ( h + 12 ); 411 } 412 413 ystart = ( viddef.height / 2 - 110 ); 414 xoffset = ( viddef.width - widest + 70 ) / 2; 415 416 for ( i = 0; names[i] != 0; i++ ) 417 { 418 if ( i != m_main_cursor ) 419 re.DrawPic( xoffset, ystart + i * 40 + 13, names[i] ); 420 } 421 strcpy( litname, names[m_main_cursor] ); 422 strcat( litname, "_sel" ); 423 re.DrawPic( xoffset, ystart + m_main_cursor * 40 + 13, litname ); 424 425 M_DrawCursor( xoffset - 25, ystart + m_main_cursor * 40 + 11, (int)(cls.realtime / 100)%NUM_CURSOR_FRAMES ); 426 427 re.DrawGetPicSize( &w, &h, "m_main_plaque" ); 428 re.DrawPic( xoffset - 30 - w, ystart, "m_main_plaque" ); 429 430 re.DrawPic( xoffset - 30 - w, ystart + h + 5, "m_main_logo" ); 431 } 432 433 434 const char *M_Main_Key (int key) 435 { 436 const char *sound = menu_move_sound; 437 438 switch (key) 439 { 440 case K_ESCAPE: 441 M_PopMenu (); 442 break; 443 444 case K_KP_DOWNARROW: 445 case K_DOWNARROW: 446 if (++m_main_cursor >= MAIN_ITEMS) 447 m_main_cursor = 0; 448 return sound; 449 450 case K_KP_UPARROW: 451 case K_UPARROW: 452 if (--m_main_cursor < 0) 453 m_main_cursor = MAIN_ITEMS - 1; 454 return sound; 455 456 case K_KP_ENTER: 457 case K_ENTER: 458 m_entersound = true; 459 460 switch (m_main_cursor) 461 { 462 case 0: 463 M_Menu_Game_f (); 464 break; 465 466 case 1: 467 M_Menu_Multiplayer_f(); 468 break; 469 470 case 2: 471 M_Menu_Options_f (); 472 break; 473 474 case 3: 475 M_Menu_Video_f (); 476 break; 477 478 case 4: 479 M_Menu_Quit_f (); 480 break; 481 } 482 } 483 484 return NULL; 485 } 486 487 488 void M_Menu_Main_f (void) 489 { 490 M_PushMenu (M_Main_Draw, M_Main_Key); 491 } 492 493 /* 494 ======================================================================= 495 496 MULTIPLAYER MENU 497 498 ======================================================================= 499 */ 500 static menuframework_s s_multiplayer_menu; 501 static menuaction_s s_join_network_server_action; 502 static menuaction_s s_start_network_server_action; 503 static menuaction_s s_player_setup_action; 504 505 static void Multiplayer_MenuDraw (void) 506 { 507 M_Banner( "m_banner_multiplayer" ); 508 509 Menu_AdjustCursor( &s_multiplayer_menu, 1 ); 510 Menu_Draw( &s_multiplayer_menu ); 511 } 512 513 static void PlayerSetupFunc( void *unused ) 514 { 515 M_Menu_PlayerConfig_f(); 516 } 517 518 static void JoinNetworkServerFunc( void *unused ) 519 { 520 M_Menu_JoinServer_f(); 521 } 522 523 static void StartNetworkServerFunc( void *unused ) 524 { 525 M_Menu_StartServer_f (); 526 } 527 528 void Multiplayer_MenuInit( void ) 529 { 530 s_multiplayer_menu.x = viddef.width * 0.50 - 64; 531 s_multiplayer_menu.nitems = 0; 532 533 s_join_network_server_action.generic.type = MTYPE_ACTION; 534 s_join_network_server_action.generic.flags = QMF_LEFT_JUSTIFY; 535 s_join_network_server_action.generic.x = 0; 536 s_join_network_server_action.generic.y = 0; 537 s_join_network_server_action.generic.name = " join network server"; 538 s_join_network_server_action.generic.callback = JoinNetworkServerFunc; 539 540 s_start_network_server_action.generic.type = MTYPE_ACTION; 541 s_start_network_server_action.generic.flags = QMF_LEFT_JUSTIFY; 542 s_start_network_server_action.generic.x = 0; 543 s_start_network_server_action.generic.y = 10; 544 s_start_network_server_action.generic.name = " start network server"; 545 s_start_network_server_action.generic.callback = StartNetworkServerFunc; 546 547 s_player_setup_action.generic.type = MTYPE_ACTION; 548 s_player_setup_action.generic.flags = QMF_LEFT_JUSTIFY; 549 s_player_setup_action.generic.x = 0; 550 s_player_setup_action.generic.y = 20; 551 s_player_setup_action.generic.name = " player setup"; 552 s_player_setup_action.generic.callback = PlayerSetupFunc; 553 554 Menu_AddItem( &s_multiplayer_menu, ( void * ) &s_join_network_server_action ); 555 Menu_AddItem( &s_multiplayer_menu, ( void * ) &s_start_network_server_action ); 556 Menu_AddItem( &s_multiplayer_menu, ( void * ) &s_player_setup_action ); 557 558 Menu_SetStatusBar( &s_multiplayer_menu, NULL ); 559 560 Menu_Center( &s_multiplayer_menu ); 561 } 562 563 const char *Multiplayer_MenuKey( int key ) 564 { 565 return Default_MenuKey( &s_multiplayer_menu, key ); 566 } 567 568 void M_Menu_Multiplayer_f( void ) 569 { 570 Multiplayer_MenuInit(); 571 M_PushMenu( Multiplayer_MenuDraw, Multiplayer_MenuKey ); 572 } 573 574 /* 575 ======================================================================= 576 577 KEYS MENU 578 579 ======================================================================= 580 */ 581 char *bindnames[][2] = 582 { 583 {"+attack", "attack"}, 584 {"weapnext", "next weapon"}, 585 {"+forward", "walk forward"}, 586 {"+back", "backpedal"}, 587 {"+left", "turn left"}, 588 {"+right", "turn right"}, 589 {"+speed", "run"}, 590 {"+moveleft", "step left"}, 591 {"+moveright", "step right"}, 592 {"+strafe", "sidestep"}, 593 {"+lookup", "look up"}, 594 {"+lookdown", "look down"}, 595 {"centerview", "center view"}, 596 {"+mlook", "mouse look"}, 597 {"+klook", "keyboard look"}, 598 {"+moveup", "up / jump"}, 599 {"+movedown", "down / crouch"}, 600 601 {"inven", "inventory"}, 602 {"invuse", "use item"}, 603 {"invdrop", "drop item"}, 604 {"invprev", "prev item"}, 605 {"invnext", "next item"}, 606 607 {"cmd help", "help computer" }, 608 { 0, 0 } 609 }; 610 611 int keys_cursor; 612 static int bind_grab; 613 614 static menuframework_s s_keys_menu; 615 static menuaction_s s_keys_attack_action; 616 static menuaction_s s_keys_change_weapon_action; 617 static menuaction_s s_keys_walk_forward_action; 618 static menuaction_s s_keys_backpedal_action; 619 static menuaction_s s_keys_turn_left_action; 620 static menuaction_s s_keys_turn_right_action; 621 static menuaction_s s_keys_run_action; 622 static menuaction_s s_keys_step_left_action; 623 static menuaction_s s_keys_step_right_action; 624 static menuaction_s s_keys_sidestep_action; 625 static menuaction_s s_keys_look_up_action; 626 static menuaction_s s_keys_look_down_action; 627 static menuaction_s s_keys_center_view_action; 628 static menuaction_s s_keys_mouse_look_action; 629 static menuaction_s s_keys_keyboard_look_action; 630 static menuaction_s s_keys_move_up_action; 631 static menuaction_s s_keys_move_down_action; 632 static menuaction_s s_keys_inventory_action; 633 static menuaction_s s_keys_inv_use_action; 634 static menuaction_s s_keys_inv_drop_action; 635 static menuaction_s s_keys_inv_prev_action; 636 static menuaction_s s_keys_inv_next_action; 637 638 static menuaction_s s_keys_help_computer_action; 639 640 static void M_UnbindCommand (char *command) 641 { 642 int j; 643 int l; 644 char *b; 645 646 l = strlen(command); 647 648 for (j=0 ; j<256 ; j++) 649 { 650 b = keybindings[j]; 651 if (!b) 652 continue; 653 if (!strncmp (b, command, l) ) 654 Key_SetBinding (j, ""); 655 } 656 } 657 658 static void M_FindKeysForCommand (char *command, int *twokeys) 659 { 660 int count; 661 int j; 662 int l; 663 char *b; 664 665 twokeys[0] = twokeys[1] = -1; 666 l = strlen(command); 667 count = 0; 668 669 for (j=0 ; j<256 ; j++) 670 { 671 b = keybindings[j]; 672 if (!b) 673 continue; 674 if (!strncmp (b, command, l) ) 675 { 676 twokeys[count] = j; 677 count++; 678 if (count == 2) 679 break; 680 } 681 } 682 } 683 684 static void KeyCursorDrawFunc( menuframework_s *menu ) 685 { 686 if ( bind_grab ) 687 re.DrawChar( menu->x, menu->y + menu->cursor * 9, '=' ); 688 else 689 re.DrawChar( menu->x, menu->y + menu->cursor * 9, 12 + ( ( int ) ( Sys_Milliseconds() / 250 ) & 1 ) ); 690 } 691 692 static void DrawKeyBindingFunc( void *self ) 693 { 694 int keys[2]; 695 menuaction_s *a = ( menuaction_s * ) self; 696 697 M_FindKeysForCommand( bindnames[a->generic.localdata[0]][0], keys); 698 699 if (keys[0] == -1) 700 { 701 Menu_DrawString( a->generic.x + a->generic.parent->x + 16, a->generic.y + a->generic.parent->y, "???" ); 702 } 703 else 704 { 705 int x; 706 const char *name; 707 708 name = Key_KeynumToString (keys[0]); 709 710 Menu_DrawString( a->generic.x + a->generic.parent->x + 16, a->generic.y + a->generic.parent->y, name ); 711 712 x = strlen(name) * 8; 713 714 if (keys[1] != -1) 715 { 716 Menu_DrawString( a->generic.x + a->generic.parent->x + 24 + x, a->generic.y + a->generic.parent->y, "or" ); 717 Menu_DrawString( a->generic.x + a->generic.parent->x + 48 + x, a->generic.y + a->generic.parent->y, Key_KeynumToString (keys[1]) ); 718 } 719 } 720 } 721 722 static void KeyBindingFunc( void *self ) 723 { 724 menuaction_s *a = ( menuaction_s * ) self; 725 int keys[2]; 726 727 M_FindKeysForCommand( bindnames[a->generic.localdata[0]][0], keys ); 728 729 if (keys[1] != -1) 730 M_UnbindCommand( bindnames[a->generic.localdata[0]][0]); 731 732 bind_grab = true; 733 734 Menu_SetStatusBar( &s_keys_menu, "press a key or button for this action" ); 735 } 736 737 static void Keys_MenuInit( void ) 738 { 739 int y = 0; 740 int i = 0; 741 742 s_keys_menu.x = viddef.width * 0.50; 743 s_keys_menu.nitems = 0; 744 s_keys_menu.cursordraw = KeyCursorDrawFunc; 745 746 s_keys_attack_action.generic.type = MTYPE_ACTION; 747 s_keys_attack_action.generic.flags = QMF_GRAYED; 748 s_keys_attack_action.generic.x = 0; 749 s_keys_attack_action.generic.y = y; 750 s_keys_attack_action.generic.ownerdraw = DrawKeyBindingFunc; 751 s_keys_attack_action.generic.localdata[0] = i; 752 s_keys_attack_action.generic.name = bindnames[s_keys_attack_action.generic.localdata[0]][1]; 753 754 s_keys_change_weapon_action.generic.type = MTYPE_ACTION; 755 s_keys_change_weapon_action.generic.flags = QMF_GRAYED; 756 s_keys_change_weapon_action.generic.x = 0; 757 s_keys_change_weapon_action.generic.y = y += 9; 758 s_keys_change_weapon_action.generic.ownerdraw = DrawKeyBindingFunc; 759 s_keys_change_weapon_action.generic.localdata[0] = ++i; 760 s_keys_change_weapon_action.generic.name = bindnames[s_keys_change_weapon_action.generic.localdata[0]][1]; 761 762 s_keys_walk_forward_action.generic.type = MTYPE_ACTION; 763 s_keys_walk_forward_action.generic.flags = QMF_GRAYED; 764 s_keys_walk_forward_action.generic.x = 0; 765 s_keys_walk_forward_action.generic.y = y += 9; 766 s_keys_walk_forward_action.generic.ownerdraw = DrawKeyBindingFunc; 767 s_keys_walk_forward_action.generic.localdata[0] = ++i; 768 s_keys_walk_forward_action.generic.name = bindnames[s_keys_walk_forward_action.generic.localdata[0]][1]; 769 770 s_keys_backpedal_action.generic.type = MTYPE_ACTION; 771 s_keys_backpedal_action.generic.flags = QMF_GRAYED; 772 s_keys_backpedal_action.generic.x = 0; 773 s_keys_backpedal_action.generic.y = y += 9; 774 s_keys_backpedal_action.generic.ownerdraw = DrawKeyBindingFunc; 775 s_keys_backpedal_action.generic.localdata[0] = ++i; 776 s_keys_backpedal_action.generic.name = bindnames[s_keys_backpedal_action.generic.localdata[0]][1]; 777 778 s_keys_turn_left_action.generic.type = MTYPE_ACTION; 779 s_keys_turn_left_action.generic.flags = QMF_GRAYED; 780 s_keys_turn_left_action.generic.x = 0; 781 s_keys_turn_left_action.generic.y = y += 9; 782 s_keys_turn_left_action.generic.ownerdraw = DrawKeyBindingFunc; 783 s_keys_turn_left_action.generic.localdata[0] = ++i; 784 s_keys_turn_left_action.generic.name = bindnames[s_keys_turn_left_action.generic.localdata[0]][1]; 785 786 s_keys_turn_right_action.generic.type = MTYPE_ACTION; 787 s_keys_turn_right_action.generic.flags = QMF_GRAYED; 788 s_keys_turn_right_action.generic.x = 0; 789 s_keys_turn_right_action.generic.y = y += 9; 790 s_keys_turn_right_action.generic.ownerdraw = DrawKeyBindingFunc; 791 s_keys_turn_right_action.generic.localdata[0] = ++i; 792 s_keys_turn_right_action.generic.name = bindnames[s_keys_turn_right_action.generic.localdata[0]][1]; 793 794 s_keys_run_action.generic.type = MTYPE_ACTION; 795 s_keys_run_action.generic.flags = QMF_GRAYED; 796 s_keys_run_action.generic.x = 0; 797 s_keys_run_action.generic.y = y += 9; 798 s_keys_run_action.generic.ownerdraw = DrawKeyBindingFunc; 799 s_keys_run_action.generic.localdata[0] = ++i; 800 s_keys_run_action.generic.name = bindnames[s_keys_run_action.generic.localdata[0]][1]; 801 802 s_keys_step_left_action.generic.type = MTYPE_ACTION; 803 s_keys_step_left_action.generic.flags = QMF_GRAYED; 804 s_keys_step_left_action.generic.x = 0; 805 s_keys_step_left_action.generic.y = y += 9; 806 s_keys_step_left_action.generic.ownerdraw = DrawKeyBindingFunc; 807 s_keys_step_left_action.generic.localdata[0] = ++i; 808 s_keys_step_left_action.generic.name = bindnames[s_keys_step_left_action.generic.localdata[0]][1]; 809 810 s_keys_step_right_action.generic.type = MTYPE_ACTION; 811 s_keys_step_right_action.generic.flags = QMF_GRAYED; 812 s_keys_step_right_action.generic.x = 0; 813 s_keys_step_right_action.generic.y = y += 9; 814 s_keys_step_right_action.generic.ownerdraw = DrawKeyBindingFunc; 815 s_keys_step_right_action.generic.localdata[0] = ++i; 816 s_keys_step_right_action.generic.name = bindnames[s_keys_step_right_action.generic.localdata[0]][1]; 817 818 s_keys_sidestep_action.generic.type = MTYPE_ACTION; 819 s_keys_sidestep_action.generic.flags = QMF_GRAYED; 820 s_keys_sidestep_action.generic.x = 0; 821 s_keys_sidestep_action.generic.y = y += 9; 822 s_keys_sidestep_action.generic.ownerdraw = DrawKeyBindingFunc; 823 s_keys_sidestep_action.generic.localdata[0] = ++i; 824 s_keys_sidestep_action.generic.name = bindnames[s_keys_sidestep_action.generic.localdata[0]][1]; 825 826 s_keys_look_up_action.generic.type = MTYPE_ACTION; 827 s_keys_look_up_action.generic.flags = QMF_GRAYED; 828 s_keys_look_up_action.generic.x = 0; 829 s_keys_look_up_action.generic.y = y += 9; 830 s_keys_look_up_action.generic.ownerdraw = DrawKeyBindingFunc; 831 s_keys_look_up_action.generic.localdata[0] = ++i; 832 s_keys_look_up_action.generic.name = bindnames[s_keys_look_up_action.generic.localdata[0]][1]; 833 834 s_keys_look_down_action.generic.type = MTYPE_ACTION; 835 s_keys_look_down_action.generic.flags = QMF_GRAYED; 836 s_keys_look_down_action.generic.x = 0; 837 s_keys_look_down_action.generic.y = y += 9; 838 s_keys_look_down_action.generic.ownerdraw = DrawKeyBindingFunc; 839 s_keys_look_down_action.generic.localdata[0] = ++i; 840 s_keys_look_down_action.generic.name = bindnames[s_keys_look_down_action.generic.localdata[0]][1]; 841 842 s_keys_center_view_action.generic.type = MTYPE_ACTION; 843 s_keys_center_view_action.generic.flags = QMF_GRAYED; 844 s_keys_center_view_action.generic.x = 0; 845 s_keys_center_view_action.generic.y = y += 9; 846 s_keys_center_view_action.generic.ownerdraw = DrawKeyBindingFunc; 847 s_keys_center_view_action.generic.localdata[0] = ++i; 848 s_keys_center_view_action.generic.name = bindnames[s_keys_center_view_action.generic.localdata[0]][1]; 849 850 s_keys_mouse_look_action.generic.type = MTYPE_ACTION; 851 s_keys_mouse_look_action.generic.flags = QMF_GRAYED; 852 s_keys_mouse_look_action.generic.x = 0; 853 s_keys_mouse_look_action.generic.y = y += 9; 854 s_keys_mouse_look_action.generic.ownerdraw = DrawKeyBindingFunc; 855 s_keys_mouse_look_action.generic.localdata[0] = ++i; 856 s_keys_mouse_look_action.generic.name = bindnames[s_keys_mouse_look_action.generic.localdata[0]][1]; 857 858 s_keys_keyboard_look_action.generic.type = MTYPE_ACTION; 859 s_keys_keyboard_look_action.generic.flags = QMF_GRAYED; 860 s_keys_keyboard_look_action.generic.x = 0; 861 s_keys_keyboard_look_action.generic.y = y += 9; 862 s_keys_keyboard_look_action.generic.ownerdraw = DrawKeyBindingFunc; 863 s_keys_keyboard_look_action.generic.localdata[0] = ++i; 864 s_keys_keyboard_look_action.generic.name = bindnames[s_keys_keyboard_look_action.generic.localdata[0]][1]; 865 866 s_keys_move_up_action.generic.type = MTYPE_ACTION; 867 s_keys_move_up_action.generic.flags = QMF_GRAYED; 868 s_keys_move_up_action.generic.x = 0; 869 s_keys_move_up_action.generic.y = y += 9; 870 s_keys_move_up_action.generic.ownerdraw = DrawKeyBindingFunc; 871 s_keys_move_up_action.generic.localdata[0] = ++i; 872 s_keys_move_up_action.generic.name = bindnames[s_keys_move_up_action.generic.localdata[0]][1]; 873 874 s_keys_move_down_action.generic.type = MTYPE_ACTION; 875 s_keys_move_down_action.generic.flags = QMF_GRAYED; 876 s_keys_move_down_action.generic.x = 0; 877 s_keys_move_down_action.generic.y = y += 9; 878 s_keys_move_down_action.generic.ownerdraw = DrawKeyBindingFunc; 879 s_keys_move_down_action.generic.localdata[0] = ++i; 880 s_keys_move_down_action.generic.name = bindnames[s_keys_move_down_action.generic.localdata[0]][1]; 881 882 s_keys_inventory_action.generic.type = MTYPE_ACTION; 883 s_keys_inventory_action.generic.flags = QMF_GRAYED; 884 s_keys_inventory_action.generic.x = 0; 885 s_keys_inventory_action.generic.y = y += 9; 886 s_keys_inventory_action.generic.ownerdraw = DrawKeyBindingFunc; 887 s_keys_inventory_action.generic.localdata[0] = ++i; 888 s_keys_inventory_action.generic.name = bindnames[s_keys_inventory_action.generic.localdata[0]][1]; 889 890 s_keys_inv_use_action.generic.type = MTYPE_ACTION; 891 s_keys_inv_use_action.generic.flags = QMF_GRAYED; 892 s_keys_inv_use_action.generic.x = 0; 893 s_keys_inv_use_action.generic.y = y += 9; 894 s_keys_inv_use_action.generic.ownerdraw = DrawKeyBindingFunc; 895 s_keys_inv_use_action.generic.localdata[0] = ++i; 896 s_keys_inv_use_action.generic.name = bindnames[s_keys_inv_use_action.generic.localdata[0]][1]; 897 898 s_keys_inv_drop_action.generic.type = MTYPE_ACTION; 899 s_keys_inv_drop_action.generic.flags = QMF_GRAYED; 900 s_keys_inv_drop_action.generic.x = 0; 901 s_keys_inv_drop_action.generic.y = y += 9; 902 s_keys_inv_drop_action.generic.ownerdraw = DrawKeyBindingFunc; 903 s_keys_inv_drop_action.generic.localdata[0] = ++i; 904 s_keys_inv_drop_action.generic.name = bindnames[s_keys_inv_drop_action.generic.localdata[0]][1]; 905 906 s_keys_inv_prev_action.generic.type = MTYPE_ACTION; 907 s_keys_inv_prev_action.generic.flags = QMF_GRAYED; 908 s_keys_inv_prev_action.generic.x = 0; 909 s_keys_inv_prev_action.generic.y = y += 9; 910 s_keys_inv_prev_action.generic.ownerdraw = DrawKeyBindingFunc; 911 s_keys_inv_prev_action.generic.localdata[0] = ++i; 912 s_keys_inv_prev_action.generic.name = bindnames[s_keys_inv_prev_action.generic.localdata[0]][1]; 913 914 s_keys_inv_next_action.generic.type = MTYPE_ACTION; 915 s_keys_inv_next_action.generic.flags = QMF_GRAYED; 916 s_keys_inv_next_action.generic.x = 0; 917 s_keys_inv_next_action.generic.y = y += 9; 918 s_keys_inv_next_action.generic.ownerdraw = DrawKeyBindingFunc; 919 s_keys_inv_next_action.generic.localdata[0] = ++i; 920 s_keys_inv_next_action.generic.name = bindnames[s_keys_inv_next_action.generic.localdata[0]][1]; 921 922 s_keys_help_computer_action.generic.type = MTYPE_ACTION; 923 s_keys_help_computer_action.generic.flags = QMF_GRAYED; 924 s_keys_help_computer_action.generic.x = 0; 925 s_keys_help_computer_action.generic.y = y += 9; 926 s_keys_help_computer_action.generic.ownerdraw = DrawKeyBindingFunc; 927 s_keys_help_computer_action.generic.localdata[0] = ++i; 928 s_keys_help_computer_action.generic.name = bindnames[s_keys_help_computer_action.generic.localdata[0]][1]; 929 930 Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_attack_action ); 931 Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_change_weapon_action ); 932 Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_walk_forward_action ); 933 Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_backpedal_action ); 934 Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_turn_left_action ); 935 Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_turn_right_action ); 936 Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_run_action ); 937 Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_step_left_action ); 938 Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_step_right_action ); 939 Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_sidestep_action ); 940 Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_look_up_action ); 941 Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_look_down_action ); 942 Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_center_view_action ); 943 Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_mouse_look_action ); 944 Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_keyboard_look_action ); 945 Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_move_up_action ); 946 Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_move_down_action ); 947 948 Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inventory_action ); 949 Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_use_action ); 950 Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_drop_action ); 951 Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_prev_action ); 952 Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_next_action ); 953 954 Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_help_computer_action ); 955 956 Menu_SetStatusBar( &s_keys_menu, "enter to change, backspace to clear" ); 957 Menu_Center( &s_keys_menu ); 958 } 959 960 static void Keys_MenuDraw (void) 961 { 962 Menu_AdjustCursor( &s_keys_menu, 1 ); 963 Menu_Draw( &s_keys_menu ); 964 } 965 966 static const char *Keys_MenuKey( int key ) 967 { 968 menuaction_s *item = ( menuaction_s * ) Menu_ItemAtCursor( &s_keys_menu ); 969 970 if ( bind_grab ) 971 { 972 if ( key != K_ESCAPE && key != '`' ) 973 { 974 char cmd[1024]; 975 976 Com_sprintf (cmd, sizeof(cmd), "bind \"%s\" \"%s\"\n", Key_KeynumToString(key), bindnames[item->generic.localdata[0]][0]); 977 Cbuf_InsertText (cmd); 978 } 979 980 Menu_SetStatusBar( &s_keys_menu, "enter to change, backspace to clear" ); 981 bind_grab = false; 982 return menu_out_sound; 983 } 984 985 switch ( key ) 986 { 987 case K_KP_ENTER: 988 case K_ENTER: 989 KeyBindingFunc( item ); 990 return menu_in_sound; 991 case K_BACKSPACE: // delete bindings 992 case K_DEL: // delete bindings 993 case K_KP_DEL: 994 M_UnbindCommand( bindnames[item->generic.localdata[0]][0] ); 995 return menu_out_sound; 996 default: 997 return Default_MenuKey( &s_keys_menu, key ); 998 } 999 } 1000 1001 void M_Menu_Keys_f (void) 1002 { 1003 Keys_MenuInit(); 1004 M_PushMenu( Keys_MenuDraw, Keys_MenuKey ); 1005 } 1006 1007 1008 /* 1009 ======================================================================= 1010 1011 CONTROLS MENU 1012 1013 ======================================================================= 1014 */ 1015 static cvar_t *win_noalttab; 1016 extern cvar_t *in_joystick; 1017 1018 static menuframework_s s_options_menu; 1019 static menuaction_s s_options_defaults_action; 1020 static menuaction_s s_options_customize_options_action; 1021 static menuslider_s s_options_sensitivity_slider; 1022 static menulist_s s_options_freelook_box; 1023 static menulist_s s_options_noalttab_box; 1024 static menulist_s s_options_alwaysrun_box; 1025 static menulist_s s_options_invertmouse_box; 1026 static menulist_s s_options_lookspring_box; 1027 static menulist_s s_options_lookstrafe_box; 1028 static menulist_s s_options_crosshair_box; 1029 static menuslider_s s_options_sfxvolume_slider; 1030 static menulist_s s_options_joystick_box; 1031 static menulist_s s_options_cdvolume_box; 1032 static menulist_s s_options_quality_list; 1033 static menulist_s s_options_compatibility_list; 1034 static menulist_s s_options_console_action; 1035 1036 static void CrosshairFunc( void *unused ) 1037 { 1038 Cvar_SetValue( "crosshair", s_options_crosshair_box.curvalue ); 1039 } 1040 1041 static void JoystickFunc( void *unused ) 1042 { 1043 Cvar_SetValue( "in_joystick", s_options_joystick_box.curvalue ); 1044 } 1045 1046 static void CustomizeControlsFunc( void *unused ) 1047 { 1048 M_Menu_Keys_f(); 1049 } 1050 1051 static void AlwaysRunFunc( void *unused ) 1052 { 1053 Cvar_SetValue( "cl_run", s_options_alwaysrun_box.curvalue ); 1054 } 1055 1056 static void FreeLookFunc( void *unused ) 1057 { 1058 Cvar_SetValue( "freelook", s_options_freelook_box.curvalue ); 1059 } 1060 1061 static void MouseSpeedFunc( void *unused ) 1062 { 1063 Cvar_SetValue( "sensitivity", s_options_sensitivity_slider.curvalue / 2.0F ); 1064 } 1065 1066 static void NoAltTabFunc( void *unused ) 1067 { 1068 Cvar_SetValue( "win_noalttab", s_options_noalttab_box.curvalue ); 1069 } 1070 1071 static float ClampCvar( float min, float max, float value ) 1072 { 1073 if ( value < min ) return min; 1074 if ( value > max ) return max; 1075 return value; 1076 } 1077 1078 static void ControlsSetMenuItemValues( void ) 1079 { 1080 s_options_sfxvolume_slider.curvalue = Cvar_VariableValue( "s_volume" ) * 10; 1081 s_options_cdvolume_box.curvalue = !Cvar_VariableValue("cd_nocd"); 1082 s_options_quality_list.curvalue = !Cvar_VariableValue( "s_loadas8bit" ); 1083 s_options_sensitivity_slider.curvalue = ( sensitivity->value ) * 2; 1084 1085 Cvar_SetValue( "cl_run", ClampCvar( 0, 1, cl_run->value ) ); 1086 s_options_alwaysrun_box.curvalue = cl_run->value; 1087 1088 s_options_invertmouse_box.curvalue = m_pitch->value < 0; 1089 1090 Cvar_SetValue( "lookspring", ClampCvar( 0, 1, lookspring->value ) ); 1091 s_options_lookspring_box.curvalue = lookspring->value; 1092 1093 Cvar_SetValue( "lookstrafe", ClampCvar( 0, 1, lookstrafe->value ) ); 1094 s_options_lookstrafe_box.curvalue = lookstrafe->value; 1095 1096 Cvar_SetValue( "freelook", ClampCvar( 0, 1, freelook->value ) ); 1097 s_options_freelook_box.curvalue = freelook->value; 1098 1099 Cvar_SetValue( "crosshair", ClampCvar( 0, 3, crosshair->value ) ); 1100 s_options_crosshair_box.curvalue = crosshair->value; 1101 1102 Cvar_SetValue( "in_joystick", ClampCvar( 0, 1, in_joystick->value ) ); 1103 s_options_joystick_box.curvalue = in_joystick->value; 1104 1105 s_options_noalttab_box.curvalue = win_noalttab->value; 1106 } 1107 1108 static void ControlsResetDefaultsFunc( void *unused ) 1109 { 1110 Cbuf_AddText ("exec default.cfg\n"); 1111 Cbuf_Execute(); 1112 1113 ControlsSetMenuItemValues(); 1114 } 1115 1116 static void InvertMouseFunc( void *unused ) 1117 { 1118 if ( s_options_invertmouse_box.curvalue == 0 ) 1119 { 1120 Cvar_SetValue( "m_pitch", fabs( m_pitch->value ) ); 1121 } 1122 else 1123 { 1124 Cvar_SetValue( "m_pitch", -fabs( m_pitch->value ) ); 1125 } 1126 } 1127 1128 static void LookspringFunc( void *unused ) 1129 { 1130 Cvar_SetValue( "lookspring", s_options_lookspring_box.curvalue ); 1131 } 1132 1133 static void LookstrafeFunc( void *unused ) 1134 { 1135 Cvar_SetValue( "lookstrafe", s_options_lookstrafe_box.curvalue ); 1136 } 1137 1138 static void UpdateVolumeFunc( void *unused ) 1139 { 1140 Cvar_SetValue( "s_volume", s_options_sfxvolume_slider.curvalue / 10 ); 1141 } 1142 1143 static void UpdateCDVolumeFunc( void *unused ) 1144 { 1145 Cvar_SetValue( "cd_nocd", !s_options_cdvolume_box.curvalue ); 1146 } 1147 1148 static void ConsoleFunc( void *unused ) 1149 { 1150 /* 1151 ** the proper way to do this is probably to have ToggleConsole_f accept a parameter 1152 */ 1153 extern void Key_ClearTyping( void ); 1154 1155 if ( cl.attractloop ) 1156 { 1157 Cbuf_AddText ("killserver\n"); 1158 return; 1159 } 1160 1161 Key_ClearTyping (); 1162 Con_ClearNotify (); 1163 1164 M_ForceMenuOff (); 1165 cls.key_dest = key_console; 1166 } 1167 1168 static void UpdateSoundQualityFunc( void *unused ) 1169 { 1170 if ( s_options_quality_list.curvalue ) 1171 { 1172 Cvar_SetValue( "s_khz", 22 ); 1173 Cvar_SetValue( "s_loadas8bit", false ); 1174 } 1175 else 1176 { 1177 Cvar_SetValue( "s_khz", 11 ); 1178 Cvar_SetValue( "s_loadas8bit", true ); 1179 } 1180 1181 Cvar_SetValue( "s_primary", s_options_compatibility_list.curvalue ); 1182 1183 M_DrawTextBox( 8, 120 - 48, 36, 3 ); 1184 M_Print( 16 + 16, 120 - 48 + 8, "Restarting the sound system. This" ); 1185 M_Print( 16 + 16, 120 - 48 + 16, "could take up to a minute, so" ); 1186 M_Print( 16 + 16, 120 - 48 + 24, "please be patient." ); 1187 1188 // the text box won't show up unless we do a buffer swap 1189 re.EndFrame(); 1190 1191 CL_Snd_Restart_f(); 1192 } 1193 1194 void Options_MenuInit( void ) 1195 { 1196 static const char *cd_music_items[] = 1197 { 1198 "disabled", 1199 "enabled", 1200 0 1201 }; 1202 static const char *quality_items[] = 1203 { 1204 "low", "high", 0 1205 }; 1206 1207 static const char *compatibility_items[] = 1208 { 1209 "max compatibility", "max performance", 0 1210 }; 1211 1212 static const char *yesno_names[] = 1213 { 1214 "no", 1215 "yes", 1216 0 1217 }; 1218 1219 static const char *crosshair_names[] = 1220 { 1221 "none", 1222 "cross", 1223 "dot", 1224 "angle", 1225 0 1226 }; 1227 1228 win_noalttab = Cvar_Get( "win_noalttab", "0", CVAR_ARCHIVE ); 1229 1230 /* 1231 ** configure controls menu and menu items 1232 */ 1233 s_options_menu.x = viddef.width / 2; 1234 s_options_menu.y = viddef.height / 2 - 58; 1235 s_options_menu.nitems = 0; 1236 1237 s_options_sfxvolume_slider.generic.type = MTYPE_SLIDER; 1238 s_options_sfxvolume_slider.generic.x = 0; 1239 s_options_sfxvolume_slider.generic.y = 0; 1240 s_options_sfxvolume_slider.generic.name = "effects volume"; 1241 s_options_sfxvolume_slider.generic.callback = UpdateVolumeFunc; 1242 s_options_sfxvolume_slider.minvalue = 0; 1243 s_options_sfxvolume_slider.maxvalue = 10; 1244 s_options_sfxvolume_slider.curvalue = Cvar_VariableValue( "s_volume" ) * 10; 1245 1246 s_options_cdvolume_box.generic.type = MTYPE_SPINCONTROL; 1247 s_options_cdvolume_box.generic.x = 0; 1248 s_options_cdvolume_box.generic.y = 10; 1249 s_options_cdvolume_box.generic.name = "CD music"; 1250 s_options_cdvolume_box.generic.callback = UpdateCDVolumeFunc; 1251 s_options_cdvolume_box.itemnames = cd_music_items; 1252 s_options_cdvolume_box.curvalue = !Cvar_VariableValue("cd_nocd"); 1253 1254 s_options_quality_list.generic.type = MTYPE_SPINCONTROL; 1255 s_options_quality_list.generic.x = 0; 1256 s_options_quality_list.generic.y = 20;; 1257 s_options_quality_list.generic.name = "sound quality"; 1258 s_options_quality_list.generic.callback = UpdateSoundQualityFunc; 1259 s_options_quality_list.itemnames = quality_items; 1260 s_options_quality_list.curvalue = !Cvar_VariableValue( "s_loadas8bit" ); 1261 1262 s_options_compatibility_list.generic.type = MTYPE_SPINCONTROL; 1263 s_options_compatibility_list.generic.x = 0; 1264 s_options_compatibility_list.generic.y = 30; 1265 s_options_compatibility_list.generic.name = "sound compatibility"; 1266 s_options_compatibility_list.generic.callback = UpdateSoundQualityFunc; 1267 s_options_compatibility_list.itemnames = compatibility_items; 1268 s_options_compatibility_list.curvalue = Cvar_VariableValue( "s_primary" ); 1269 1270 s_options_sensitivity_slider.generic.type = MTYPE_SLIDER; 1271 s_options_sensitivity_slider.generic.x = 0; 1272 s_options_sensitivity_slider.generic.y = 50; 1273 s_options_sensitivity_slider.generic.name = "mouse speed"; 1274 s_options_sensitivity_slider.generic.callback = MouseSpeedFunc; 1275 s_options_sensitivity_slider.minvalue = 2; 1276 s_options_sensitivity_slider.maxvalue = 22; 1277 1278 s_options_alwaysrun_box.generic.type = MTYPE_SPINCONTROL; 1279 s_options_alwaysrun_box.generic.x = 0; 1280 s_options_alwaysrun_box.generic.y = 60; 1281 s_options_alwaysrun_box.generic.name = "always run"; 1282 s_options_alwaysrun_box.generic.callback = AlwaysRunFunc; 1283 s_options_alwaysrun_box.itemnames = yesno_names; 1284 1285 s_options_invertmouse_box.generic.type = MTYPE_SPINCONTROL; 1286 s_options_invertmouse_box.generic.x = 0; 1287 s_options_invertmouse_box.generic.y = 70; 1288 s_options_invertmouse_box.generic.name = "invert mouse"; 1289 s_options_invertmouse_box.generic.callback = InvertMouseFunc; 1290 s_options_invertmouse_box.itemnames = yesno_names; 1291 1292 s_options_lookspring_box.generic.type = MTYPE_SPINCONTROL; 1293 s_options_lookspring_box.generic.x = 0; 1294 s_options_lookspring_box.generic.y = 80; 1295 s_options_lookspring_box.generic.name = "lookspring"; 1296 s_options_lookspring_box.generic.callback = LookspringFunc; 1297 s_options_lookspring_box.itemnames = yesno_names; 1298 1299 s_options_lookstrafe_box.generic.type = MTYPE_SPINCONTROL; 1300 s_options_lookstrafe_box.generic.x = 0; 1301 s_options_lookstrafe_box.generic.y = 90; 1302 s_options_lookstrafe_box.generic.name = "lookstrafe"; 1303 s_options_lookstrafe_box.generic.callback = LookstrafeFunc; 1304 s_options_lookstrafe_box.itemnames = yesno_names; 1305 1306 s_options_freelook_box.generic.type = MTYPE_SPINCONTROL; 1307 s_options_freelook_box.generic.x = 0; 1308 s_options_freelook_box.generic.y = 100; 1309 s_options_freelook_box.generic.name = "free look"; 1310 s_options_freelook_box.generic.callback = FreeLookFunc; 1311 s_options_freelook_box.itemnames = yesno_names; 1312 1313 s_options_crosshair_box.generic.type = MTYPE_SPINCONTROL; 1314 s_options_crosshair_box.generic.x = 0; 1315 s_options_crosshair_box.generic.y = 110; 1316 s_options_crosshair_box.generic.name = "crosshair"; 1317 s_options_crosshair_box.generic.callback = CrosshairFunc; 1318 s_options_crosshair_box.itemnames = crosshair_names; 1319 /* 1320 s_options_noalttab_box.generic.type = MTYPE_SPINCONTROL; 1321 s_options_noalttab_box.generic.x = 0; 1322 s_options_noalttab_box.generic.y = 110; 1323 s_options_noalttab_box.generic.name = "disable alt-tab"; 1324 s_options_noalttab_box.generic.callback = NoAltTabFunc; 1325 s_options_noalttab_box.itemnames = yesno_names; 1326 */ 1327 s_options_joystick_box.generic.type = MTYPE_SPINCONTROL; 1328 s_options_joystick_box.generic.x = 0; 1329 s_options_joystick_box.generic.y = 120; 1330 s_options_joystick_box.generic.name = "use joystick"; 1331 s_options_joystick_box.generic.callback = JoystickFunc; 1332 s_options_joystick_box.itemnames = yesno_names; 1333 1334 s_options_customize_options_action.generic.type = MTYPE_ACTION; 1335 s_options_customize_options_action.generic.x = 0; 1336 s_options_customize_options_action.generic.y = 140; 1337 s_options_customize_options_action.generic.name = "customize controls"; 1338 s_options_customize_options_action.generic.callback = CustomizeControlsFunc; 1339 1340 s_options_defaults_action.generic.type = MTYPE_ACTION; 1341 s_options_defaults_action.generic.x = 0; 1342 s_options_defaults_action.generic.y = 150; 1343 s_options_defaults_action.generic.name = "reset defaults"; 1344 s_options_defaults_action.generic.callback = ControlsResetDefaultsFunc; 1345 1346 s_options_console_action.generic.type = MTYPE_ACTION; 1347 s_options_console_action.generic.x = 0; 1348 s_options_console_action.generic.y = 160; 1349 s_options_console_action.generic.name = "go to console"; 1350 s_options_console_action.generic.callback = ConsoleFunc; 1351 1352 ControlsSetMenuItemValues(); 1353 1354 Menu_AddItem( &s_options_menu, ( void * ) &s_options_sfxvolume_slider ); 1355 Menu_AddItem( &s_options_menu, ( void * ) &s_options_cdvolume_box ); 1356 Menu_AddItem( &s_options_menu, ( void * ) &s_options_quality_list ); 1357 Menu_AddItem( &s_options_menu, ( void * ) &s_options_compatibility_list ); 1358 Menu_AddItem( &s_options_menu, ( void * ) &s_options_sensitivity_slider ); 1359 Menu_AddItem( &s_options_menu, ( void * ) &s_options_alwaysrun_box ); 1360 Menu_AddItem( &s_options_menu, ( void * ) &s_options_invertmouse_box ); 1361 Menu_AddItem( &s_options_menu, ( void * ) &s_options_lookspring_box ); 1362 Menu_AddItem( &s_options_menu, ( void * ) &s_options_lookstrafe_box ); 1363 Menu_AddItem( &s_options_menu, ( void * ) &s_options_freelook_box ); 1364 Menu_AddItem( &s_options_menu, ( void * ) &s_options_crosshair_box ); 1365 Menu_AddItem( &s_options_menu, ( void * ) &s_options_joystick_box ); 1366 Menu_AddItem( &s_options_menu, ( void * ) &s_options_customize_options_action ); 1367 Menu_AddItem( &s_options_menu, ( void * ) &s_options_defaults_action ); 1368 Menu_AddItem( &s_options_menu, ( void * ) &s_options_console_action ); 1369 } 1370 1371 void Options_MenuDraw (void) 1372 { 1373 M_Banner( "m_banner_options" ); 1374 Menu_AdjustCursor( &s_options_menu, 1 ); 1375 Menu_Draw( &s_options_menu ); 1376 } 1377 1378 const char *Options_MenuKey( int key ) 1379 { 1380 return Default_MenuKey( &s_options_menu, key ); 1381 } 1382 1383 void M_Menu_Options_f (void) 1384 { 1385 Options_MenuInit(); 1386 M_PushMenu ( Options_MenuDraw, Options_MenuKey ); 1387 } 1388 1389 /* 1390 ======================================================================= 1391 1392 VIDEO MENU 1393 1394 ======================================================================= 1395 */ 1396 1397 void M_Menu_Video_f (void) 1398 { 1399 VID_MenuInit(); 1400 M_PushMenu( VID_MenuDraw, VID_MenuKey ); 1401 } 1402 1403 /* 1404 ============================================================================= 1405 1406 END GAME MENU 1407 1408 ============================================================================= 1409 */ 1410 static int credits_start_time; 1411 static const char **credits; 1412 static char *creditsIndex[256]; 1413 static char *creditsBuffer; 1414 static const char *idcredits[] = 1415 { 1416 "+QUAKE II BY ID SOFTWARE", 1417 "", 1418 "+PROGRAMMING", 1419 "John Carmack", 1420 "John Cash", 1421 "Brian Hook", 1422 "", 1423 "+ART", 1424 "Adrian Carmack", 1425 "Kevin Cloud", 1426 "Paul Steed", 1427 "", 1428 "+LEVEL DESIGN", 1429 "Tim Willits", 1430 "American McGee", 1431 "Christian Antkow", 1432 "Paul Jaquays", 1433 "Brandon James", 1434 "", 1435 "+BIZ", 1436 "Todd Hollenshead", 1437 "Barrett (Bear) Alexander", 1438 "Donna Jackson", 1439 "", 1440 "", 1441 "+SPECIAL THANKS", 1442 "Ben Donges for beta testing", 1443 "", 1444 "", 1445 "", 1446 "", 1447 "", 1448 "", 1449 "+ADDITIONAL SUPPORT", 1450 "", 1451 "+LINUX PORT AND CTF", 1452 "Dave \"Zoid\" Kirsch", 1453 "", 1454 "+CINEMATIC SEQUENCES", 1455 "Ending Cinematic by Blur Studio - ", 1456 "Venice, CA", 1457 "", 1458 "Environment models for Introduction", 1459 "Cinematic by Karl Dolgener", 1460 "", 1461 "Assistance with environment design", 1462 "by Cliff Iwai", 1463 "", 1464 "+SOUND EFFECTS AND MUSIC", 1465 "Sound Design by Soundelux Media Labs.", 1466 "Music Composed and Produced by", 1467 "Soundelux Media Labs. Special thanks", 1468 "to Bill Brown, Tom Ozanich, Brian", 1469 "Celano, Jeff Eisner, and The Soundelux", 1470 "Players.", 1471 "", 1472 "\"Level Music\" by Sonic Mayhem", 1473 "www.sonicmayhem.com", 1474 "", 1475 "\"Quake II Theme Song\"", 1476 "(C) 1997 Rob Zombie. All Rights", 1477 "Reserved.", 1478 "", 1479 "Track 10 (\"Climb\") by Jer Sypult", 1480 "", 1481 "Voice of computers by", 1482 "Carly Staehlin-Taylor", 1483 "", 1484 "+THANKS TO ACTIVISION", 1485 "+IN PARTICULAR:", 1486 "", 1487 "John Tam", 1488 "Steve Rosenthal", 1489 "Marty Stratton", 1490 "Henk Hartong", 1491 "", 1492 "Quake II(tm) (C)1997 Id Software, Inc.", 1493 "All Rights Reserved. Distributed by", 1494 "Activision, Inc. under license.", 1495 "Quake II(tm), the Id Software name,", 1496 "the \"Q II\"(tm) logo and id(tm)", 1497 "logo are trademarks of Id Software,", 1498 "Inc. Activision(R) is a registered", 1499 "trademark of Activision, Inc. All", 1500 "other trademarks and trade names are", 1501 "properties of their respective owners.", 1502 0 1503 }; 1504 1505 static const char *xatcredits[] = 1506 { 1507 "+QUAKE II MISSION PACK: THE RECKONING", 1508 "+BY", 1509 "+XATRIX ENTERTAINMENT, INC.", 1510 "", 1511 "+DESIGN AND DIRECTION", 1512 "Drew Markham", 1513 "", 1514 "+PRODUCED BY", 1515 "Greg Goodrich", 1516 "", 1517 "+PROGRAMMING", 1518 "Rafael Paiz", 1519 "", 1520 "+LEVEL DESIGN / ADDITIONAL GAME DESIGN", 1521 "Alex Mayberry", 1522 "", 1523 "+LEVEL DESIGN", 1524 "Mal Blackwell", 1525 "Dan Koppel", 1526 "", 1527 "+ART DIRECTION", 1528 "Michael \"Maxx\" Kaufman", 1529 "", 1530 "+COMPUTER GRAPHICS SUPERVISOR AND", 1531 "+CHARACTER ANIMATION DIRECTION", 1532 "Barry Dempsey", 1533 "", 1534 "+SENIOR ANIMATOR AND MODELER", 1535 "Jason Hoover", 1536 "", 1537 "+CHARACTER ANIMATION AND", 1538 "+MOTION CAPTURE SPECIALIST", 1539 "Amit Doron", 1540 "", 1541 "+ART", 1542 "Claire Praderie-Markham", 1543 "Viktor Antonov", 1544 "Corky Lehmkuhl", 1545 "", 1546 "+INTRODUCTION ANIMATION", 1547 "Dominique Drozdz", 1548 "", 1549 "+ADDITIONAL LEVEL DESIGN", 1550 "Aaron Barber", 1551 "Rhett Baldwin", 1552 "", 1553 "+3D CHARACTER ANIMATION TOOLS", 1554 "Gerry Tyra, SA Technology", 1555 "", 1556 "+ADDITIONAL EDITOR TOOL PROGRAMMING", 1557 "Robert Duffy", 1558 "", 1559 "+ADDITIONAL PROGRAMMING", 1560 "Ryan Feltrin", 1561 "", 1562 "+PRODUCTION COORDINATOR", 1563 "Victoria Sylvester", 1564 "", 1565 "+SOUND DESIGN", 1566 "Gary Bradfield", 1567 "", 1568 "+MUSIC BY", 1569 "Sonic Mayhem", 1570 "", 1571 "", 1572 "", 1573 "+SPECIAL THANKS", 1574 "+TO", 1575 "+OUR FRIENDS AT ID SOFTWARE", 1576 "", 1577 "John Carmack", 1578 "John Cash", 1579 "Brian Hook", 1580 "Adrian Carmack", 1581 "Kevin Cloud", 1582 "Paul Steed", 1583 "Tim Willits", 1584 "Christian Antkow", 1585 "Paul Jaquays", 1586 "Brandon James", 1587 "Todd Hollenshead", 1588 "Barrett (Bear) Alexander", 1589 "Dave \"Zoid\" Kirsch", 1590 "Donna Jackson", 1591 "", 1592 "", 1593 "", 1594 "+THANKS TO ACTIVISION", 1595 "+IN PARTICULAR:", 1596 "", 1597 "Marty Stratton", 1598 "Henk \"The Original Ripper\" Hartong", 1599 "Kevin Kraff", 1600 "Jamey Gottlieb", 1601 "Chris Hepburn", 1602 "", 1603 "+AND THE GAME TESTERS", 1604 "", 1605 "Tim Vanlaw", 1606 "Doug Jacobs", 1607 "Steven Rosenthal", 1608 "David Baker", 1609 "Chris Campbell", 1610 "Aaron Casillas", 1611 "Steve Elwell", 1612 "Derek Johnstone", 1613 "Igor Krinitskiy", 1614 "Samantha Lee", 1615 "Michael Spann", 1616 "Chris Toft", 1617 "Juan Valdes", 1618 "", 1619 "+THANKS TO INTERGRAPH COMPUTER SYTEMS", 1620 "+IN PARTICULAR:", 1621 "", 1622 "Michael T. Nicolaou", 1623 "", 1624 "", 1625 "Quake II Mission Pack: The Reckoning", 1626 "(tm) (C)1998 Id Software, Inc. All", 1627 "Rights Reserved. Developed by Xatrix", 1628 "Entertainment, Inc. for Id Software,", 1629 "Inc. Distributed by Activision Inc.", 1630 "under license. Quake(R) is a", 1631 "registered trademark of Id Software,", 1632 "Inc. Quake II Mission Pack: The", 1633 "Reckoning(tm), Quake II(tm), the Id", 1634 "Software name, the \"Q II\"(tm) logo", 1635 "and id(tm) logo are trademarks of Id", 1636 "Software, Inc. Activision(R) is a", 1637 "registered trademark of Activision,", 1638 "Inc. Xatrix(R) is a registered", 1639 "trademark of Xatrix Entertainment,", 1640 "Inc. All other trademarks and trade", 1641 "names are properties of their", 1642 "respective owners.", 1643 0 1644 }; 1645 1646 static const char *roguecredits[] = 1647 { 1648 "+QUAKE II MISSION PACK 2: GROUND ZERO", 1649 "+BY", 1650 "+ROGUE ENTERTAINMENT, INC.", 1651 "", 1652 "+PRODUCED BY", 1653 "Jim Molinets", 1654 "", 1655 "+PROGRAMMING", 1656 "Peter Mack", 1657 "Patrick Magruder", 1658 "", 1659 "+LEVEL DESIGN", 1660 "Jim Molinets", 1661 "Cameron Lamprecht", 1662 "Berenger Fish", 1663 "Robert Selitto", 1664 "Steve Tietze", 1665 "Steve Thoms", 1666 "", 1667 "+ART DIRECTION", 1668 "Rich Fleider", 1669 "", 1670 "+ART", 1671 "Rich Fleider", 1672 "Steve Maines", 1673 "Won Choi", 1674 "", 1675 "+ANIMATION SEQUENCES", 1676 "Creat Studios", 1677 "Steve Maines", 1678 "", 1679 "+ADDITIONAL LEVEL DESIGN", 1680 "Rich Fleider", 1681 "Steve Maines", 1682 "Peter Mack", 1683 "", 1684 "+SOUND", 1685 "James Grunke", 1686 "", 1687 "+GROUND ZERO THEME", 1688 "+AND", 1689 "+MUSIC BY", 1690 "Sonic Mayhem", 1691 "", 1692 "+VWEP MODELS", 1693 "Brent \"Hentai\" Dill", 1694 "", 1695 "", 1696 "", 1697 "+SPECIAL THANKS", 1698 "+TO", 1699 "+OUR FRIENDS AT ID SOFTWARE", 1700 "", 1701 "John Carmack", 1702 "John Cash", 1703 "Brian Hook", 1704 "Adrian Carmack", 1705 "Kevin Cloud", 1706 "Paul Steed", 1707 "Tim Willits", 1708 "Christian Antkow", 1709 "Paul Jaquays", 1710 "Brandon James", 1711 "Todd Hollenshead", 1712 "Barrett (Bear) Alexander", 1713 "Katherine Anna Kang", 1714 "Donna Jackson", 1715 "Dave \"Zoid\" Kirsch", 1716 "", 1717 "", 1718 "", 1719 "+THANKS TO ACTIVISION", 1720 "+IN PARTICULAR:", 1721 "", 1722 "Marty Stratton", 1723 "Henk Hartong", 1724 "Mitch Lasky", 1725 "Steve Rosenthal", 1726 "Steve Elwell", 1727 "", 1728 "+AND THE GAME TESTERS", 1729 "", 1730 "The Ranger Clan", 1731 "Dave \"Zoid\" Kirsch", 1732 "Nihilistic Software", 1733 "Robert Duffy", 1734 "", 1735 "And Countless Others", 1736 "", 1737 "", 1738 "", 1739 "Quake II Mission Pack 2: Ground Zero", 1740 "(tm) (C)1998 Id Software, Inc. All", 1741 "Rights Reserved. Developed by Rogue", 1742 "Entertainment, Inc. for Id Software,", 1743 "Inc. Distributed by Activision Inc.", 1744 "under license. Quake(R) is a", 1745 "registered trademark of Id Software,", 1746 "Inc. Quake II Mission Pack 2: Ground", 1747 "Zero(tm), Quake II(tm), the Id", 1748 "Software name, the \"Q II\"(tm) logo", 1749 "and id(tm) logo are trademarks of Id", 1750 "Software, Inc. Activision(R) is a", 1751 "registered trademark of Activision,", 1752 "Inc. Rogue(R) is a registered", 1753 "trademark of Rogue Entertainment,", 1754 "Inc. All other trademarks and trade", 1755 "names are properties of their", 1756 "respective owners.", 1757 0 1758 }; 1759 1760 1761 void M_Credits_MenuDraw( void ) 1762 { 1763 int i, y; 1764 1765 /* 1766 ** draw the credits 1767 */ 1768 for ( i = 0, y = viddef.height - ( ( cls.realtime - credits_start_time ) / 40.0F ); credits[i] && y < viddef.height; y += 10, i++ ) 1769 { 1770 int j, stringoffset = 0; 1771 int bold = false; 1772 1773 if ( y <= -8 ) 1774 continue; 1775 1776 if ( credits[i][0] == '+' ) 1777 { 1778 bold = true; 1779 stringoffset = 1; 1780 } 1781 else 1782 { 1783 bold = false; 1784 stringoffset = 0; 1785 } 1786 1787 for ( j = 0; credits[i][j+stringoffset]; j++ ) 1788 { 1789 int x; 1790 1791 x = ( viddef.width - strlen( credits[i] ) * 8 - stringoffset * 8 ) / 2 + ( j + stringoffset ) * 8; 1792 1793 if ( bold ) 1794 re.DrawChar( x, y, credits[i][j+stringoffset] + 128 ); 1795 else 1796 re.DrawChar( x, y, credits[i][j+stringoffset] ); 1797 } 1798 } 1799 1800 if ( y < 0 ) 1801 credits_start_time = cls.realtime; 1802 } 1803 1804 const char *M_Credits_Key( int key ) 1805 { 1806 switch (key) 1807 { 1808 case K_ESCAPE: 1809 if (creditsBuffer) 1810 FS_FreeFile (creditsBuffer); 1811 M_PopMenu (); 1812 break; 1813 } 1814 1815 return menu_out_sound; 1816 1817 } 1818 1819 extern int Developer_searchpath (int who); 1820 1821 void M_Menu_Credits_f( void ) 1822 { 1823 int n; 1824 int count; 1825 char *p; 1826 int isdeveloper = 0; 1827 1828 creditsBuffer = NULL; 1829 count = FS_LoadFile ("credits", &creditsBuffer); 1830 if (count != -1) 1831 { 1832 p = creditsBuffer; 1833 for (n = 0; n < 255; n++) 1834 { 1835 creditsIndex[n] = p; 1836 while (*p != '\r' && *p != '\n') 1837 { 1838 p++; 1839 if (--count == 0) 1840 break; 1841 } 1842 if (*p == '\r') 1843 { 1844 *p++ = 0; 1845 if (--count == 0) 1846 break; 1847 } 1848 *p++ = 0; 1849 if (--count == 0) 1850 break; 1851 } 1852 creditsIndex[++n] = 0; 1853 credits = creditsIndex; 1854 } 1855 else 1856 { 1857 isdeveloper = Developer_searchpath (1); 1858 1859 if (isdeveloper == 1) // xatrix 1860 credits = xatcredits; 1861 else if (isdeveloper == 2) // ROGUE 1862 credits = roguecredits; 1863 else 1864 { 1865 credits = idcredits; 1866 } 1867 1868 } 1869 1870 credits_start_time = cls.realtime; 1871 M_PushMenu( M_Credits_MenuDraw, M_Credits_Key); 1872 } 1873 1874 /* 1875 ============================================================================= 1876 1877 GAME MENU 1878 1879 ============================================================================= 1880 */ 1881 1882 static int m_game_cursor; 1883 1884 static menuframework_s s_game_menu; 1885 static menuaction_s s_easy_game_action; 1886 static menuaction_s s_medium_game_action; 1887 static menuaction_s s_hard_game_action; 1888 static menuaction_s s_load_game_action; 1889 static menuaction_s s_save_game_action; 1890 static menuaction_s s_credits_action; 1891 static menuseparator_s s_blankline; 1892 1893 static void StartGame( void ) 1894 { 1895 // disable updates and start the cinematic going 1896 cl.servercount = -1; 1897 M_ForceMenuOff (); 1898 Cvar_SetValue( "deathmatch", 0 ); 1899 Cvar_SetValue( "coop", 0 ); 1900 1901 Cvar_SetValue( "gamerules", 0 ); //PGM 1902 1903 Cbuf_AddText ("loading ; killserver ; wait ; newgame\n"); 1904 cls.key_dest = key_game; 1905 } 1906 1907 static void EasyGameFunc( void *data ) 1908 { 1909 Cvar_ForceSet( "skill", "0" ); 1910 StartGame(); 1911 } 1912 1913 static void MediumGameFunc( void *data ) 1914 { 1915 Cvar_ForceSet( "skill", "1" ); 1916 StartGame(); 1917 } 1918 1919 static void HardGameFunc( void *data ) 1920 { 1921 Cvar_ForceSet( "skill", "2" ); 1922 StartGame(); 1923 } 1924 1925 static void LoadGameFunc( void *unused ) 1926 { 1927 M_Menu_LoadGame_f (); 1928 } 1929 1930 static void SaveGameFunc( void *unused ) 1931 { 1932 M_Menu_SaveGame_f(); 1933 } 1934 1935 static void CreditsFunc( void *unused ) 1936 { 1937 M_Menu_Credits_f(); 1938 } 1939 1940 void Game_MenuInit( void ) 1941 { 1942 static const char *difficulty_names[] = 1943 { 1944 "easy", 1945 "medium", 1946 "hard", 1947 0 1948 }; 1949 1950 s_game_menu.x = viddef.width * 0.50; 1951 s_game_menu.nitems = 0; 1952 1953 s_easy_game_action.generic.type = MTYPE_ACTION; 1954 s_easy_game_action.generic.flags = QMF_LEFT_JUSTIFY; 1955 s_easy_game_action.generic.x = 0; 1956 s_easy_game_action.generic.y = 0; 1957 s_easy_game_action.generic.name = "easy"; 1958 s_easy_game_action.generic.callback = EasyGameFunc; 1959 1960 s_medium_game_action.generic.type = MTYPE_ACTION; 1961 s_medium_game_action.generic.flags = QMF_LEFT_JUSTIFY; 1962 s_medium_game_action.generic.x = 0; 1963 s_medium_game_action.generic.y = 10; 1964 s_medium_game_action.generic.name = "medium"; 1965 s_medium_game_action.generic.callback = MediumGameFunc; 1966 1967 s_hard_game_action.generic.type = MTYPE_ACTION; 1968 s_hard_game_action.generic.flags = QMF_LEFT_JUSTIFY; 1969 s_hard_game_action.generic.x = 0; 1970 s_hard_game_action.generic.y = 20; 1971 s_hard_game_action.generic.name = "hard"; 1972 s_hard_game_action.generic.callback = HardGameFunc; 1973 1974 s_blankline.generic.type = MTYPE_SEPARATOR; 1975 1976 s_load_game_action.generic.type = MTYPE_ACTION; 1977 s_load_game_action.generic.flags = QMF_LEFT_JUSTIFY; 1978 s_load_game_action.generic.x = 0; 1979 s_load_game_action.generic.y = 40; 1980 s_load_game_action.generic.name = "load game"; 1981 s_load_game_action.generic.callback = LoadGameFunc; 1982 1983 s_save_game_action.generic.type = MTYPE_ACTION; 1984 s_save_game_action.generic.flags = QMF_LEFT_JUSTIFY; 1985 s_save_game_action.generic.x = 0; 1986 s_save_game_action.generic.y = 50; 1987 s_save_game_action.generic.name = "save game"; 1988 s_save_game_action.generic.callback = SaveGameFunc; 1989 1990 s_credits_action.generic.type = MTYPE_ACTION; 1991 s_credits_action.generic.flags = QMF_LEFT_JUSTIFY; 1992 s_credits_action.generic.x = 0; 1993 s_credits_action.generic.y = 60; 1994 s_credits_action.generic.name = "credits"; 1995 s_credits_action.generic.callback = CreditsFunc; 1996 1997 Menu_AddItem( &s_game_menu, ( void * ) &s_easy_game_action ); 1998 Menu_AddItem( &s_game_menu, ( void * ) &s_medium_game_action ); 1999 Menu_AddItem( &s_game_menu, ( void * ) &s_hard_game_action ); 2000 Menu_AddItem( &s_game_menu, ( void * ) &s_blankline ); 2001 Menu_AddItem( &s_game_menu, ( void * ) &s_load_game_action ); 2002 Menu_AddItem( &s_game_menu, ( void * ) &s_save_game_action ); 2003 Menu_AddItem( &s_game_menu, ( void * ) &s_blankline ); 2004 Menu_AddItem( &s_game_menu, ( void * ) &s_credits_action ); 2005 2006 Menu_Center( &s_game_menu ); 2007 } 2008 2009 void Game_MenuDraw( void ) 2010 { 2011 M_Banner( "m_banner_game" ); 2012 Menu_AdjustCursor( &s_game_menu, 1 ); 2013 Menu_Draw( &s_game_menu ); 2014 } 2015 2016 const char *Game_MenuKey( int key ) 2017 { 2018 return Default_MenuKey( &s_game_menu, key ); 2019 } 2020 2021 void M_Menu_Game_f (void) 2022 { 2023 Game_MenuInit(); 2024 M_PushMenu( Game_MenuDraw, Game_MenuKey ); 2025 m_game_cursor = 1; 2026 } 2027 2028 /* 2029 ============================================================================= 2030 2031 LOADGAME MENU 2032 2033 ============================================================================= 2034 */ 2035 2036 #define MAX_SAVEGAMES 15 2037 2038 static menuframework_s s_savegame_menu; 2039 2040 static menuframework_s s_loadgame_menu; 2041 static menuaction_s s_loadgame_actions[MAX_SAVEGAMES]; 2042 2043 char m_savestrings[MAX_SAVEGAMES][32]; 2044 qboolean m_savevalid[MAX_SAVEGAMES]; 2045 2046 void Create_Savestrings (void) 2047 { 2048 int i; 2049 FILE *f; 2050 char name[MAX_OSPATH]; 2051 2052 for (i=0 ; i<MAX_SAVEGAMES ; i++) 2053 { 2054 Com_sprintf (name, sizeof(name), "%s/save/save%i/server.ssv", FS_Gamedir(), i); 2055 f = fopen (name, "rb"); 2056 if (!f) 2057 { 2058 strcpy (m_savestrings[i], "<EMPTY>"); 2059 m_savevalid[i] = false; 2060 } 2061 else 2062 { 2063 FS_Read (m_savestrings[i], sizeof(m_savestrings[i]), f); 2064 fclose (f); 2065 m_savevalid[i] = true; 2066 } 2067 } 2068 } 2069 2070 void LoadGameCallback( void *self ) 2071 { 2072 menuaction_s *a = ( menuaction_s * ) self; 2073 2074 if ( m_savevalid[ a->generic.localdata[0] ] ) 2075 Cbuf_AddText (va("load save%i\n", a->generic.localdata[0] ) ); 2076 M_ForceMenuOff (); 2077 } 2078 2079 void LoadGame_MenuInit( void ) 2080 { 2081 int i; 2082 2083 s_loadgame_menu.x = viddef.width / 2 - 120; 2084 s_loadgame_menu.y = viddef.height / 2 - 58; 2085 s_loadgame_menu.nitems = 0; 2086 2087 Create_Savestrings(); 2088 2089 for ( i = 0; i < MAX_SAVEGAMES; i++ ) 2090 { 2091 s_loadgame_actions[i].generic.name = m_savestrings[i]; 2092 s_loadgame_actions[i].generic.flags = QMF_LEFT_JUSTIFY; 2093 s_loadgame_actions[i].generic.localdata[0] = i; 2094 s_loadgame_actions[i].generic.callback = LoadGameCallback; 2095 2096 s_loadgame_actions[i].generic.x = 0; 2097 s_loadgame_actions[i].generic.y = ( i ) * 10; 2098 if (i>0) // separate from autosave 2099 s_loadgame_actions[i].generic.y += 10; 2100 2101 s_loadgame_actions[i].generic.type = MTYPE_ACTION; 2102 2103 Menu_AddItem( &s_loadgame_menu, &s_loadgame_actions[i] ); 2104 } 2105 } 2106 2107 void LoadGame_MenuDraw( void ) 2108 { 2109 M_Banner( "m_banner_load_game" ); 2110 // Menu_AdjustCursor( &s_loadgame_menu, 1 ); 2111 Menu_Draw( &s_loadgame_menu ); 2112 } 2113 2114 const char *LoadGame_MenuKey( int key ) 2115 { 2116 if ( key == K_ESCAPE || key == K_ENTER ) 2117 { 2118 s_savegame_menu.cursor = s_loadgame_menu.cursor - 1; 2119 if ( s_savegame_menu.cursor < 0 ) 2120 s_savegame_menu.cursor = 0; 2121 } 2122 return Default_MenuKey( &s_loadgame_menu, key ); 2123 } 2124 2125 void M_Menu_LoadGame_f (void) 2126 { 2127 LoadGame_MenuInit(); 2128 M_PushMenu( LoadGame_MenuDraw, LoadGame_MenuKey ); 2129 } 2130 2131 2132 /* 2133 ============================================================================= 2134 2135 SAVEGAME MENU 2136 2137 ============================================================================= 2138 */ 2139 static menuframework_s s_savegame_menu; 2140 static menuaction_s s_savegame_actions[MAX_SAVEGAMES]; 2141 2142 void SaveGameCallback( void *self ) 2143 { 2144 menuaction_s *a = ( menuaction_s * ) self; 2145 2146 Cbuf_AddText (va("save save%i\n", a->generic.localdata[0] )); 2147 M_ForceMenuOff (); 2148 } 2149 2150 void SaveGame_MenuDraw( void ) 2151 { 2152 M_Banner( "m_banner_save_game" ); 2153 Menu_AdjustCursor( &s_savegame_menu, 1 ); 2154 Menu_Draw( &s_savegame_menu ); 2155 } 2156 2157 void SaveGame_MenuInit( void ) 2158 { 2159 int i; 2160 2161 s_savegame_menu.x = viddef.width / 2 - 120; 2162 s_savegame_menu.y = viddef.height / 2 - 58; 2163 s_savegame_menu.nitems = 0; 2164 2165 Create_Savestrings(); 2166 2167 // don't include the autosave slot 2168 for ( i = 0; i < MAX_SAVEGAMES-1; i++ ) 2169 { 2170 s_savegame_actions[i].generic.name = m_savestrings[i+1]; 2171 s_savegame_actions[i].generic.localdata[0] = i+1; 2172 s_savegame_actions[i].generic.flags = QMF_LEFT_JUSTIFY; 2173 s_savegame_actions[i].generic.callback = SaveGameCallback; 2174 2175 s_savegame_actions[i].generic.x = 0; 2176 s_savegame_actions[i].generic.y = ( i ) * 10; 2177 2178 s_savegame_actions[i].generic.type = MTYPE_ACTION; 2179 2180 Menu_AddItem( &s_savegame_menu, &s_savegame_actions[i] ); 2181 } 2182 } 2183 2184 const char *SaveGame_MenuKey( int key ) 2185 { 2186 if ( key == K_ENTER || key == K_ESCAPE ) 2187 { 2188 s_loadgame_menu.cursor = s_savegame_menu.cursor - 1; 2189 if ( s_loadgame_menu.cursor < 0 ) 2190 s_loadgame_menu.cursor = 0; 2191 } 2192 return Default_MenuKey( &s_savegame_menu, key ); 2193 } 2194 2195 void M_Menu_SaveGame_f (void) 2196 { 2197 if (!Com_ServerState()) 2198 return; // not playing a game 2199 2200 SaveGame_MenuInit(); 2201 M_PushMenu( SaveGame_MenuDraw, SaveGame_MenuKey ); 2202 Create_Savestrings (); 2203 } 2204 2205 2206 /* 2207 ============================================================================= 2208 2209 JOIN SERVER MENU 2210 2211 ============================================================================= 2212 */ 2213 #define MAX_LOCAL_SERVERS 8 2214 2215 static menuframework_s s_joinserver_menu; 2216 static menuseparator_s s_joinserver_server_title; 2217 static menuaction_s s_joinserver_search_action; 2218 static menuaction_s s_joinserver_address_book_action; 2219 static menuaction_s s_joinserver_server_actions[MAX_LOCAL_SERVERS]; 2220 2221 int m_num_servers; 2222 #define NO_SERVER_STRING "<no server>" 2223 2224 // user readable information 2225 static char local_server_names[MAX_LOCAL_SERVERS][80]; 2226 2227 // network address 2228 static netadr_t local_server_netadr[MAX_LOCAL_SERVERS]; 2229 2230 void M_AddToServerList (netadr_t adr, char *info) 2231 { 2232 int i; 2233 2234 if (m_num_servers == MAX_LOCAL_SERVERS) 2235 return; 2236 while ( *info == ' ' ) 2237 info++; 2238 2239 // ignore if duplicated 2240 for (i=0 ; i<m_num_servers ; i++) 2241 if (!strcmp(info, local_server_names[i])) 2242 return; 2243 2244 local_server_netadr[m_num_servers] = adr; 2245 strncpy (local_server_names[m_num_servers], info, sizeof(local_server_names[0])-1); 2246 m_num_servers++; 2247 } 2248 2249 2250 void JoinServerFunc( void *self ) 2251 { 2252 char buffer[128]; 2253 int index; 2254 2255 index = ( menuaction_s * ) self - s_joinserver_server_actions; 2256 2257 if ( Q_stricmp( local_server_names[index], NO_SERVER_STRING ) == 0 ) 2258 return; 2259 2260 if (index >= m_num_servers) 2261 return; 2262 2263 Com_sprintf (buffer, sizeof(buffer), "connect %s\n", NET_AdrToString (local_server_netadr[index])); 2264 Cbuf_AddText (buffer); 2265 M_ForceMenuOff (); 2266 } 2267 2268 void AddressBookFunc( void *self ) 2269 { 2270 M_Menu_AddressBook_f(); 2271 } 2272 2273 void NullCursorDraw( void *self ) 2274 { 2275 } 2276 2277 void SearchLocalGames( void ) 2278 { 2279 int i; 2280 2281 m_num_servers = 0; 2282 for (i=0 ; i<MAX_LOCAL_SERVERS ; i++) 2283 strcpy (local_server_names[i], NO_SERVER_STRING); 2284 2285 M_DrawTextBox( 8, 120 - 48, 36, 3 ); 2286 M_Print( 16 + 16, 120 - 48 + 8, "Searching for local servers, this" ); 2287 M_Print( 16 + 16, 120 - 48 + 16, "could take up to a minute, so" ); 2288 M_Print( 16 + 16, 120 - 48 + 24, "please be patient." ); 2289 2290 // the text box won't show up unless we do a buffer swap 2291 re.EndFrame(); 2292 2293 // send out info packets 2294 CL_PingServers_f(); 2295 } 2296 2297 void SearchLocalGamesFunc( void *self ) 2298 { 2299 SearchLocalGames(); 2300 } 2301 2302 void JoinServer_MenuInit( void ) 2303 { 2304 int i; 2305 2306 s_joinserver_menu.x = viddef.width * 0.50 - 120; 2307 s_joinserver_menu.nitems = 0; 2308 2309 s_joinserver_address_book_action.generic.type = MTYPE_ACTION; 2310 s_joinserver_address_book_action.generic.name = "address book"; 2311 s_joinserver_address_book_action.generic.flags = QMF_LEFT_JUSTIFY; 2312 s_joinserver_address_book_action.generic.x = 0; 2313 s_joinserver_address_book_action.generic.y = 0; 2314 s_joinserver_address_book_action.generic.callback = AddressBookFunc; 2315 2316 s_joinserver_search_action.generic.type = MTYPE_ACTION; 2317 s_joinserver_search_action.generic.name = "refresh server list"; 2318 s_joinserver_search_action.generic.flags = QMF_LEFT_JUSTIFY; 2319 s_joinserver_search_action.generic.x = 0; 2320 s_joinserver_search_action.generic.y = 10; 2321 s_joinserver_search_action.generic.callback = SearchLocalGamesFunc; 2322 s_joinserver_search_action.generic.statusbar = "search for servers"; 2323 2324 s_joinserver_server_title.generic.type = MTYPE_SEPARATOR; 2325 s_joinserver_server_title.generic.name = "connect to..."; 2326 s_joinserver_server_title.generic.x = 80; 2327 s_joinserver_server_title.generic.y = 30; 2328 2329 for ( i = 0; i < MAX_LOCAL_SERVERS; i++ ) 2330 { 2331 s_joinserver_server_actions[i].generic.type = MTYPE_ACTION; 2332 strcpy (local_server_names[i], NO_SERVER_STRING); 2333 s_joinserver_server_actions[i].generic.name = local_server_names[i]; 2334 s_joinserver_server_actions[i].generic.flags = QMF_LEFT_JUSTIFY; 2335 s_joinserver_server_actions[i].generic.x = 0; 2336 s_joinserver_server_actions[i].generic.y = 40 + i*10; 2337 s_joinserver_server_actions[i].generic.callback = JoinServerFunc; 2338 s_joinserver_server_actions[i].generic.statusbar = "press ENTER to connect"; 2339 } 2340 2341 Menu_AddItem( &s_joinserver_menu, &s_joinserver_address_book_action ); 2342 Menu_AddItem( &s_joinserver_menu, &s_joinserver_server_title ); 2343 Menu_AddItem( &s_joinserver_menu, &s_joinserver_search_action ); 2344 2345 for ( i = 0; i < 8; i++ ) 2346 Menu_AddItem( &s_joinserver_menu, &s_joinserver_server_actions[i] ); 2347 2348 Menu_Center( &s_joinserver_menu ); 2349 2350 SearchLocalGames(); 2351 } 2352 2353 void JoinServer_MenuDraw(void) 2354 { 2355 M_Banner( "m_banner_join_server" ); 2356 Menu_Draw( &s_joinserver_menu ); 2357 } 2358 2359 2360 const char *JoinServer_MenuKey( int key ) 2361 { 2362 return Default_MenuKey( &s_joinserver_menu, key ); 2363 } 2364 2365 void M_Menu_JoinServer_f (void) 2366 { 2367 JoinServer_MenuInit(); 2368 M_PushMenu( JoinServer_MenuDraw, JoinServer_MenuKey ); 2369 } 2370 2371 2372 /* 2373 ============================================================================= 2374 2375 START SERVER MENU 2376 2377 ============================================================================= 2378 */ 2379 static menuframework_s s_startserver_menu; 2380 static char **mapnames; 2381 static int nummaps; 2382 2383 static menuaction_s s_startserver_start_action; 2384 static menuaction_s s_startserver_dmoptions_action; 2385 static menufield_s s_timelimit_field; 2386 static menufield_s s_fraglimit_field; 2387 static menufield_s s_maxclients_field; 2388 static menufield_s s_hostname_field; 2389 static menulist_s s_startmap_list; 2390 static menulist_s s_rules_box; 2391 2392 void DMOptionsFunc( void *self ) 2393 { 2394 if (s_rules_box.curvalue == 1) 2395 return; 2396 M_Menu_DMOptions_f(); 2397 } 2398 2399 void RulesChangeFunc ( void *self ) 2400 { 2401 // DM 2402 if (s_rules_box.curvalue == 0) 2403 { 2404 s_maxclients_field.generic.statusbar = NULL; 2405 s_startserver_dmoptions_action.generic.statusbar = NULL; 2406 } 2407 else if(s_rules_box.curvalue == 1) // coop // PGM 2408 { 2409 s_maxclients_field.generic.statusbar = "4 maximum for cooperative"; 2410 if (atoi(s_maxclients_field.buffer) > 4) 2411 strcpy( s_maxclients_field.buffer, "4" ); 2412 s_startserver_dmoptions_action.generic.statusbar = "N/A for cooperative"; 2413 } 2414 //===== 2415 //PGM 2416 // ROGUE GAMES 2417 else if(Developer_searchpath(2) == 2) 2418 { 2419 if (s_rules_box.curvalue == 2) // tag 2420 { 2421 s_maxclients_field.generic.statusbar = NULL; 2422 s_startserver_dmoptions_action.generic.statusbar = NULL; 2423 } 2424 /* 2425 else if(s_rules_box.curvalue == 3) // deathball 2426 { 2427 s_maxclients_field.generic.statusbar = NULL; 2428 s_startserver_dmoptions_action.generic.statusbar = NULL; 2429 } 2430 */ 2431 } 2432 //PGM 2433 //===== 2434 } 2435 2436 void StartServerActionFunc( void *self ) 2437 { 2438 char startmap[1024]; 2439 int timelimit; 2440 int fraglimit; 2441 int maxclients; 2442 char *spot; 2443 2444 strcpy( startmap, strchr( mapnames[s_startmap_list.curvalue], '\n' ) + 1 ); 2445 2446 maxclients = atoi( s_maxclients_field.buffer ); 2447 timelimit = atoi( s_timelimit_field.buffer ); 2448 fraglimit = atoi( s_fraglimit_field.buffer ); 2449 2450 Cvar_SetValue( "maxclients", ClampCvar( 0, maxclients, maxclients ) ); 2451 Cvar_SetValue ("timelimit", ClampCvar( 0, timelimit, timelimit ) ); 2452 Cvar_SetValue ("fraglimit", ClampCvar( 0, fraglimit, fraglimit ) ); 2453 Cvar_Set("hostname", s_hostname_field.buffer ); 2454 // Cvar_SetValue ("deathmatch", !s_rules_box.curvalue ); 2455 // Cvar_SetValue ("coop", s_rules_box.curvalue ); 2456 2457 //PGM 2458 if((s_rules_box.curvalue < 2) || (Developer_searchpath(2) != 2)) 2459 { 2460 Cvar_SetValue ("deathmatch", !s_rules_box.curvalue ); 2461 Cvar_SetValue ("coop", s_rules_box.curvalue ); 2462 Cvar_SetValue ("gamerules", 0 ); 2463 } 2464 else 2465 { 2466 Cvar_SetValue ("deathmatch", 1 ); // deathmatch is always true for rogue games, right? 2467 Cvar_SetValue ("coop", 0 ); // FIXME - this might need to depend on which game we're running 2468 Cvar_SetValue ("gamerules", s_rules_box.curvalue ); 2469 } 2470 //PGM 2471 2472 spot = NULL; 2473 if (s_rules_box.curvalue == 1) // PGM 2474 { 2475 if(Q_stricmp(startmap, "bunk1") == 0) 2476 spot = "start"; 2477 else if(Q_stricmp(startmap, "mintro") == 0) 2478 spot = "start"; 2479 else if(Q_stricmp(startmap, "fact1") == 0) 2480 spot = "start"; 2481 else if(Q_stricmp(startmap, "power1") == 0) 2482 spot = "pstart"; 2483 else if(Q_stricmp(startmap, "biggun") == 0) 2484 spot = "bstart"; 2485 else if(Q_stricmp(startmap, "hangar1") == 0) 2486 spot = "unitstart"; 2487 else if(Q_stricmp(startmap, "city1") == 0) 2488 spot = "unitstart"; 2489 else if(Q_stricmp(startmap, "boss1") == 0) 2490 spot = "bosstart"; 2491 } 2492 2493 if (spot) 2494 { 2495 if (Com_ServerState()) 2496 Cbuf_AddText ("disconnect\n"); 2497 Cbuf_AddText (va("gamemap \"*%s$%s\"\n", startmap, spot)); 2498 } 2499 else 2500 { 2501 Cbuf_AddText (va("map %s\n", startmap)); 2502 } 2503 2504 M_ForceMenuOff (); 2505 } 2506 2507 void StartServer_MenuInit( void ) 2508 { 2509 static const char *dm_coop_names[] = 2510 { 2511 "deathmatch", 2512 "cooperative", 2513 0 2514 }; 2515 //======= 2516 //PGM 2517 static const char *dm_coop_names_rogue[] = 2518 { 2519 "deathmatch", 2520 "cooperative", 2521 "tag", 2522 // "deathball", 2523 0 2524 }; 2525 //PGM 2526 //======= 2527 char *buffer; 2528 char mapsname[1024]; 2529 char *s; 2530 int length; 2531 int i; 2532 FILE *fp; 2533 2534 /* 2535 ** load the list of map names 2536 */ 2537 Com_sprintf( mapsname, sizeof( mapsname ), "%s/maps.lst", FS_Gamedir() ); 2538 if ( ( fp = fopen( mapsname, "rb" ) ) == 0 ) 2539 { 2540 if ( ( length = FS_LoadFile( "maps.lst", ( void ** ) &buffer ) ) == -1 ) 2541 Com_Error( ERR_DROP, "couldn't find maps.lst\n" ); 2542 } 2543 else 2544 { 2545 #ifdef _WIN32 2546 length = filelength( fileno( fp ) ); 2547 #else 2548 fseek(fp, 0, SEEK_END); 2549 length = ftell(fp); 2550 fseek(fp, 0, SEEK_SET); 2551 #endif 2552 buffer = malloc( length ); 2553 fread( buffer, length, 1, fp ); 2554 } 2555 2556 s = buffer; 2557 2558 i = 0; 2559 while ( i < length ) 2560 { 2561 if ( s[i] == '\r' ) 2562 nummaps++; 2563 i++; 2564 } 2565 2566 if ( nummaps == 0 ) 2567 Com_Error( ERR_DROP, "no maps in maps.lst\n" ); 2568 2569 mapnames = malloc( sizeof( char * ) * ( nummaps + 1 ) ); 2570 memset( mapnames, 0, sizeof( char * ) * ( nummaps + 1 ) ); 2571 2572 s = buffer; 2573 2574 for ( i = 0; i < nummaps; i++ ) 2575 { 2576 char shortname[MAX_TOKEN_CHARS]; 2577 char longname[MAX_TOKEN_CHARS]; 2578 char scratch[200]; 2579 int j, l; 2580 2581 strcpy( shortname, COM_Parse( &s ) ); 2582 l = strlen(shortname); 2583 for (j=0 ; j<l ; j++) 2584 shortname[j] = toupper(shortname[j]); 2585 strcpy( longname, COM_Parse( &s ) ); 2586 Com_sprintf( scratch, sizeof( scratch ), "%s\n%s", longname, shortname ); 2587 2588 mapnames[i] = malloc( strlen( scratch ) + 1 ); 2589 strcpy( mapnames[i], scratch ); 2590 } 2591 mapnames[nummaps] = 0; 2592 2593 if ( fp != 0 ) 2594 { 2595 fp = 0; 2596 free( buffer ); 2597 } 2598 else 2599 { 2600 FS_FreeFile( buffer ); 2601 } 2602 2603 /* 2604 ** initialize the menu stuff 2605 */ 2606 s_startserver_menu.x = viddef.width * 0.50; 2607 s_startserver_menu.nitems = 0; 2608 2609 s_startmap_list.generic.type = MTYPE_SPINCONTROL; 2610 s_startmap_list.generic.x = 0; 2611 s_startmap_list.generic.y = 0; 2612 s_startmap_list.generic.name = "initial map"; 2613 s_startmap_list.itemnames = mapnames; 2614 2615 s_rules_box.generic.type = MTYPE_SPINCONTROL; 2616 s_rules_box.generic.x = 0; 2617 s_rules_box.generic.y = 20; 2618 s_rules_box.generic.name = "rules"; 2619 2620 //PGM - rogue games only available with rogue DLL. 2621 if(Developer_searchpath(2) == 2) 2622 s_rules_box.itemnames = dm_coop_names_rogue; 2623 else 2624 s_rules_box.itemnames = dm_coop_names; 2625 //PGM 2626 2627 if (Cvar_VariableValue("coop")) 2628 s_rules_box.curvalue = 1; 2629 else 2630 s_rules_box.curvalue = 0; 2631 s_rules_box.generic.callback = RulesChangeFunc; 2632 2633 s_timelimit_field.generic.type = MTYPE_FIELD; 2634 s_timelimit_field.generic.name = "time limit"; 2635 s_timelimit_field.generic.flags = QMF_NUMBERSONLY; 2636 s_timelimit_field.generic.x = 0; 2637 s_timelimit_field.generic.y = 36; 2638 s_timelimit_field.generic.statusbar = "0 = no limit"; 2639 s_timelimit_field.length = 3; 2640 s_timelimit_field.visible_length = 3; 2641 strcpy( s_timelimit_field.buffer, Cvar_VariableString("timelimit") ); 2642 2643 s_fraglimit_field.generic.type = MTYPE_FIELD; 2644 s_fraglimit_field.generic.name = "frag limit"; 2645 s_fraglimit_field.generic.flags = QMF_NUMBERSONLY; 2646 s_fraglimit_field.generic.x = 0; 2647 s_fraglimit_field.generic.y = 54; 2648 s_fraglimit_field.generic.statusbar = "0 = no limit"; 2649 s_fraglimit_field.length = 3; 2650 s_fraglimit_field.visible_length = 3; 2651 strcpy( s_fraglimit_field.buffer, Cvar_VariableString("fraglimit") ); 2652 2653 /* 2654 ** maxclients determines the maximum number of players that can join 2655 ** the game. If maxclients is only "1" then we should default the menu 2656 ** option to 8 players, otherwise use whatever its current value is. 2657 ** Clamping will be done when the server is actually started. 2658 */ 2659 s_maxclients_field.generic.type = MTYPE_FIELD; 2660 s_maxclients_field.generic.name = "max players"; 2661 s_maxclients_field.generic.flags = QMF_NUMBERSONLY; 2662 s_maxclients_field.generic.x = 0; 2663 s_maxclients_field.generic.y = 72; 2664 s_maxclients_field.generic.statusbar = NULL; 2665 s_maxclients_field.length = 3; 2666 s_maxclients_field.visible_length = 3; 2667 if ( Cvar_VariableValue( "maxclients" ) == 1 ) 2668 strcpy( s_maxclients_field.buffer, "8" ); 2669 else 2670 strcpy( s_maxclients_field.buffer, Cvar_VariableString("maxclients") ); 2671 2672 s_hostname_field.generic.type = MTYPE_FIELD; 2673 s_hostname_field.generic.name = "hostname"; 2674 s_hostname_field.generic.flags = 0; 2675 s_hostname_field.generic.x = 0; 2676 s_hostname_field.generic.y = 90; 2677 s_hostname_field.generic.statusbar = NULL; 2678 s_hostname_field.length = 12; 2679 s_hostname_field.visible_length = 12; 2680 strcpy( s_hostname_field.buffer, Cvar_VariableString("hostname") ); 2681 2682 s_startserver_dmoptions_action.generic.type = MTYPE_ACTION; 2683 s_startserver_dmoptions_action.generic.name = " deathmatch flags"; 2684 s_startserver_dmoptions_action.generic.flags= QMF_LEFT_JUSTIFY; 2685 s_startserver_dmoptions_action.generic.x = 24; 2686 s_startserver_dmoptions_action.generic.y = 108; 2687 s_startserver_dmoptions_action.generic.statusbar = NULL; 2688 s_startserver_dmoptions_action.generic.callback = DMOptionsFunc; 2689 2690 s_startserver_start_action.generic.type = MTYPE_ACTION; 2691 s_startserver_start_action.generic.name = " begin"; 2692 s_startserver_start_action.generic.flags= QMF_LEFT_JUSTIFY; 2693 s_startserver_start_action.generic.x = 24; 2694 s_startserver_start_action.generic.y = 128; 2695 s_startserver_start_action.generic.callback = StartServerActionFunc; 2696 2697 Menu_AddItem( &s_startserver_menu, &s_startmap_list ); 2698 Menu_AddItem( &s_startserver_menu, &s_rules_box ); 2699 Menu_AddItem( &s_startserver_menu, &s_timelimit_field ); 2700 Menu_AddItem( &s_startserver_menu, &s_fraglimit_field ); 2701 Menu_AddItem( &s_startserver_menu, &s_maxclients_field ); 2702 Menu_AddItem( &s_startserver_menu, &s_hostname_field ); 2703 Menu_AddItem( &s_startserver_menu, &s_startserver_dmoptions_action ); 2704 Menu_AddItem( &s_startserver_menu, &s_startserver_start_action ); 2705 2706 Menu_Center( &s_startserver_menu ); 2707 2708 // call this now to set proper inital state 2709 RulesChangeFunc ( NULL ); 2710 } 2711 2712 void StartServer_MenuDraw(void) 2713 { 2714 Menu_Draw( &s_startserver_menu ); 2715 } 2716 2717 const char *StartServer_MenuKey( int key ) 2718 { 2719 if ( key == K_ESCAPE ) 2720 { 2721 if ( mapnames ) 2722 { 2723 int i; 2724 2725 for ( i = 0; i < nummaps; i++ ) 2726 free( mapnames[i] ); 2727 free( mapnames ); 2728 } 2729 mapnames = 0; 2730 nummaps = 0; 2731 } 2732 2733 return Default_MenuKey( &s_startserver_menu, key ); 2734 } 2735 2736 void M_Menu_StartServer_f (void) 2737 { 2738 StartServer_MenuInit(); 2739 M_PushMenu( StartServer_MenuDraw, StartServer_MenuKey ); 2740 } 2741 2742 /* 2743 ============================================================================= 2744 2745 DMOPTIONS BOOK MENU 2746 2747 ============================================================================= 2748 */ 2749 static char dmoptions_statusbar[128]; 2750 2751 static menuframework_s s_dmoptions_menu; 2752 2753 static menulist_s s_friendlyfire_box; 2754 static menulist_s s_falls_box; 2755 static menulist_s s_weapons_stay_box; 2756 static menulist_s s_instant_powerups_box; 2757 static menulist_s s_powerups_box; 2758 static menulist_s s_health_box; 2759 static menulist_s s_spawn_farthest_box; 2760 static menulist_s s_teamplay_box; 2761 static menulist_s s_samelevel_box; 2762 static menulist_s s_force_respawn_box; 2763 static menulist_s s_armor_box; 2764 static menulist_s s_allow_exit_box; 2765 static menulist_s s_infinite_ammo_box; 2766 static menulist_s s_fixed_fov_box; 2767 static menulist_s s_quad_drop_box; 2768 2769 //ROGUE 2770 static menulist_s s_no_mines_box; 2771 static menulist_s s_no_nukes_box; 2772 static menulist_s s_stack_double_box; 2773 static menulist_s s_no_spheres_box; 2774 //ROGUE 2775 2776 static void DMFlagCallback( void *self ) 2777 { 2778 menulist_s *f = ( menulist_s * ) self; 2779 int flags; 2780 int bit = 0; 2781 2782 flags = Cvar_VariableValue( "dmflags" ); 2783 2784 if ( f == &s_friendlyfire_box ) 2785 { 2786 if ( f->curvalue ) 2787 flags &= ~DF_NO_FRIENDLY_FIRE; 2788 else 2789 flags |= DF_NO_FRIENDLY_FIRE; 2790 goto setvalue; 2791 } 2792 else if ( f == &s_falls_box ) 2793 { 2794 if ( f->curvalue ) 2795 flags &= ~DF_NO_FALLING; 2796 else 2797 flags |= DF_NO_FALLING; 2798 goto setvalue; 2799 } 2800 else if ( f == &s_weapons_stay_box ) 2801 { 2802 bit = DF_WEAPONS_STAY; 2803 } 2804 else if ( f == &s_instant_powerups_box ) 2805 { 2806 bit = DF_INSTANT_ITEMS; 2807 } 2808 else if ( f == &s_allow_exit_box ) 2809 { 2810 bit = DF_ALLOW_EXIT; 2811 } 2812 else if ( f == &s_powerups_box ) 2813 { 2814 if ( f->curvalue ) 2815 flags &= ~DF_NO_ITEMS; 2816 else 2817 flags |= DF_NO_ITEMS; 2818 goto setvalue; 2819 } 2820 else if ( f == &s_health_box ) 2821 { 2822 if ( f->curvalue ) 2823 flags &= ~DF_NO_HEALTH; 2824 else 2825 flags |= DF_NO_HEALTH; 2826 goto setvalue; 2827 } 2828 else if ( f == &s_spawn_farthest_box ) 2829 { 2830 bit = DF_SPAWN_FARTHEST; 2831 } 2832 else if ( f == &s_teamplay_box ) 2833 { 2834 if ( f->curvalue == 1 ) 2835 { 2836 flags |= DF_SKINTEAMS; 2837 flags &= ~DF_MODELTEAMS; 2838 } 2839 else if ( f->curvalue == 2 ) 2840 { 2841 flags |= DF_MODELTEAMS; 2842 flags &= ~DF_SKINTEAMS; 2843 } 2844 else 2845 { 2846 flags &= ~( DF_MODELTEAMS | DF_SKINTEAMS ); 2847 } 2848 2849 goto setvalue; 2850 } 2851 else if ( f == &s_samelevel_box ) 2852 { 2853 bit = DF_SAME_LEVEL; 2854 } 2855 else if ( f == &s_force_respawn_box ) 2856 { 2857 bit = DF_FORCE_RESPAWN; 2858 } 2859 else if ( f == &s_armor_box ) 2860 { 2861 if ( f->curvalue ) 2862 flags &= ~DF_NO_ARMOR; 2863 else 2864 flags |= DF_NO_ARMOR; 2865 goto setvalue; 2866 } 2867 else if ( f == &s_infinite_ammo_box ) 2868 { 2869 bit = DF_INFINITE_AMMO; 2870 } 2871 else if ( f == &s_fixed_fov_box ) 2872 { 2873 bit = DF_FIXED_FOV; 2874 } 2875 else if ( f == &s_quad_drop_box ) 2876 { 2877 bit = DF_QUAD_DROP; 2878 } 2879 2880 //======= 2881 //ROGUE 2882 else if (Developer_searchpath(2) == 2) 2883 { 2884 if ( f == &s_no_mines_box) 2885 { 2886 bit = DF_NO_MINES; 2887 } 2888 else if ( f == &s_no_nukes_box) 2889 { 2890 bit = DF_NO_NUKES; 2891 } 2892 else if ( f == &s_stack_double_box) 2893 { 2894 bit = DF_NO_STACK_DOUBLE; 2895 } 2896 else if ( f == &s_no_spheres_box) 2897 { 2898 bit = DF_NO_SPHERES; 2899 } 2900 } 2901 //ROGUE 2902 //======= 2903 2904 if ( f ) 2905 { 2906 if ( f->curvalue == 0 ) 2907 flags &= ~bit; 2908 else 2909 flags |= bit; 2910 } 2911 2912 setvalue: 2913 Cvar_SetValue ("dmflags", flags); 2914 2915 Com_sprintf( dmoptions_statusbar, sizeof( dmoptions_statusbar ), "dmflags = %d", flags ); 2916 2917 } 2918 2919 void DMOptions_MenuInit( void ) 2920 { 2921 static const char *yes_no_names[] = 2922 { 2923 "no", "yes", 0 2924 }; 2925 static const char *teamplay_names[] = 2926 { 2927 "disabled", "by skin", "by model", 0 2928 }; 2929 int dmflags = Cvar_VariableValue( "dmflags" ); 2930 int y = 0; 2931 2932 s_dmoptions_menu.x = viddef.width * 0.50; 2933 s_dmoptions_menu.nitems = 0; 2934 2935 s_falls_box.generic.type = MTYPE_SPINCONTROL; 2936 s_falls_box.generic.x = 0; 2937 s_falls_box.generic.y = y; 2938 s_falls_box.generic.name = "falling damage"; 2939 s_falls_box.generic.callback = DMFlagCallback; 2940 s_falls_box.itemnames = yes_no_names; 2941 s_falls_box.curvalue = ( dmflags & DF_NO_FALLING ) == 0; 2942 2943 s_weapons_stay_box.generic.type = MTYPE_SPINCONTROL; 2944 s_weapons_stay_box.generic.x = 0; 2945 s_weapons_stay_box.generic.y = y += 10; 2946 s_weapons_stay_box.generic.name = "weapons stay"; 2947 s_weapons_stay_box.generic.callback = DMFlagCallback; 2948 s_weapons_stay_box.itemnames = yes_no_names; 2949 s_weapons_stay_box.curvalue = ( dmflags & DF_WEAPONS_STAY ) != 0; 2950 2951 s_instant_powerups_box.generic.type = MTYPE_SPINCONTROL; 2952 s_instant_powerups_box.generic.x = 0; 2953 s_instant_powerups_box.generic.y = y += 10; 2954 s_instant_powerups_box.generic.name = "instant powerups"; 2955 s_instant_powerups_box.generic.callback = DMFlagCallback; 2956 s_instant_powerups_box.itemnames = yes_no_names; 2957 s_instant_powerups_box.curvalue = ( dmflags & DF_INSTANT_ITEMS ) != 0; 2958 2959 s_powerups_box.generic.type = MTYPE_SPINCONTROL; 2960 s_powerups_box.generic.x = 0; 2961 s_powerups_box.generic.y = y += 10; 2962 s_powerups_box.generic.name = "allow powerups"; 2963 s_powerups_box.generic.callback = DMFlagCallback; 2964 s_powerups_box.itemnames = yes_no_names; 2965 s_powerups_box.curvalue = ( dmflags & DF_NO_ITEMS ) == 0; 2966 2967 s_health_box.generic.type = MTYPE_SPINCONTROL; 2968 s_health_box.generic.x = 0; 2969 s_health_box.generic.y = y += 10; 2970 s_health_box.generic.callback = DMFlagCallback; 2971 s_health_box.generic.name = "allow health"; 2972 s_health_box.itemnames = yes_no_names; 2973 s_health_box.curvalue = ( dmflags & DF_NO_HEALTH ) == 0; 2974 2975 s_armor_box.generic.type = MTYPE_SPINCONTROL; 2976 s_armor_box.generic.x = 0; 2977 s_armor_box.generic.y = y += 10; 2978 s_armor_box.generic.name = "allow armor"; 2979 s_armor_box.generic.callback = DMFlagCallback; 2980 s_armor_box.itemnames = yes_no_names; 2981 s_armor_box.curvalue = ( dmflags & DF_NO_ARMOR ) == 0; 2982 2983 s_spawn_farthest_box.generic.type = MTYPE_SPINCONTROL; 2984 s_spawn_farthest_box.generic.x = 0; 2985 s_spawn_farthest_box.generic.y = y += 10; 2986 s_spawn_farthest_box.generic.name = "spawn farthest"; 2987 s_spawn_farthest_box.generic.callback = DMFlagCallback; 2988 s_spawn_farthest_box.itemnames = yes_no_names; 2989 s_spawn_farthest_box.curvalue = ( dmflags & DF_SPAWN_FARTHEST ) != 0; 2990 2991 s_samelevel_box.generic.type = MTYPE_SPINCONTROL; 2992 s_samelevel_box.generic.x = 0; 2993 s_samelevel_box.generic.y = y += 10; 2994 s_samelevel_box.generic.name = "same map"; 2995 s_samelevel_box.generic.callback = DMFlagCallback; 2996 s_samelevel_box.itemnames = yes_no_names; 2997 s_samelevel_box.curvalue = ( dmflags & DF_SAME_LEVEL ) != 0; 2998 2999 s_force_respawn_box.generic.type = MTYPE_SPINCONTROL; 3000 s_force_respawn_box.generic.x = 0; 3001 s_force_respawn_box.generic.y = y += 10; 3002 s_force_respawn_box.generic.name = "force respawn"; 3003 s_force_respawn_box.generic.callback = DMFlagCallback; 3004 s_force_respawn_box.itemnames = yes_no_names; 3005 s_force_respawn_box.curvalue = ( dmflags & DF_FORCE_RESPAWN ) != 0; 3006 3007 s_teamplay_box.generic.type = MTYPE_SPINCONTROL; 3008 s_teamplay_box.generic.x = 0; 3009 s_teamplay_box.generic.y = y += 10; 3010 s_teamplay_box.generic.name = "teamplay"; 3011 s_teamplay_box.generic.callback = DMFlagCallback; 3012 s_teamplay_box.itemnames = teamplay_names; 3013 3014 s_allow_exit_box.generic.type = MTYPE_SPINCONTROL; 3015 s_allow_exit_box.generic.x = 0; 3016 s_allow_exit_box.generic.y = y += 10; 3017 s_allow_exit_box.generic.name = "allow exit"; 3018 s_allow_exit_box.generic.callback = DMFlagCallback; 3019 s_allow_exit_box.itemnames = yes_no_names; 3020 s_allow_exit_box.curvalue = ( dmflags & DF_ALLOW_EXIT ) != 0; 3021 3022 s_infinite_ammo_box.generic.type = MTYPE_SPINCONTROL; 3023 s_infinite_ammo_box.generic.x = 0; 3024 s_infinite_ammo_box.generic.y = y += 10; 3025 s_infinite_ammo_box.generic.name = "infinite ammo"; 3026 s_infinite_ammo_box.generic.callback = DMFlagCallback; 3027 s_infinite_ammo_box.itemnames = yes_no_names; 3028 s_infinite_ammo_box.curvalue = ( dmflags & DF_INFINITE_AMMO ) != 0; 3029 3030 s_fixed_fov_box.generic.type = MTYPE_SPINCONTROL; 3031 s_fixed_fov_box.generic.x = 0; 3032 s_fixed_fov_box.generic.y = y += 10; 3033 s_fixed_fov_box.generic.name = "fixed FOV"; 3034 s_fixed_fov_box.generic.callback = DMFlagCallback; 3035 s_fixed_fov_box.itemnames = yes_no_names; 3036 s_fixed_fov_box.curvalue = ( dmflags & DF_FIXED_FOV ) != 0; 3037 3038 s_quad_drop_box.generic.type = MTYPE_SPINCONTROL; 3039 s_quad_drop_box.generic.x = 0; 3040 s_quad_drop_box.generic.y = y += 10; 3041 s_quad_drop_box.generic.name = "quad drop"; 3042 s_quad_drop_box.generic.callback = DMFlagCallback; 3043 s_quad_drop_box.itemnames = yes_no_names; 3044 s_quad_drop_box.curvalue = ( dmflags & DF_QUAD_DROP ) != 0; 3045 3046 s_friendlyfire_box.generic.type = MTYPE_SPINCONTROL; 3047 s_friendlyfire_box.generic.x = 0; 3048 s_friendlyfire_box.generic.y = y += 10; 3049 s_friendlyfire_box.generic.name = "friendly fire"; 3050 s_friendlyfire_box.generic.callback = DMFlagCallback; 3051 s_friendlyfire_box.itemnames = yes_no_names; 3052 s_friendlyfire_box.curvalue = ( dmflags & DF_NO_FRIENDLY_FIRE ) == 0; 3053 3054 //============ 3055 //ROGUE 3056 if(Developer_searchpath(2) == 2) 3057 { 3058 s_no_mines_box.generic.type = MTYPE_SPINCONTROL; 3059 s_no_mines_box.generic.x = 0; 3060 s_no_mines_box.generic.y = y += 10; 3061 s_no_mines_box.generic.name = "remove mines"; 3062 s_no_mines_box.generic.callback = DMFlagCallback; 3063 s_no_mines_box.itemnames = yes_no_names; 3064 s_no_mines_box.curvalue = ( dmflags & DF_NO_MINES ) != 0; 3065 3066 s_no_nukes_box.generic.type = MTYPE_SPINCONTROL; 3067 s_no_nukes_box.generic.x = 0; 3068 s_no_nukes_box.generic.y = y += 10; 3069 s_no_nukes_box.generic.name = "remove nukes"; 3070 s_no_nukes_box.generic.callback = DMFlagCallback; 3071 s_no_nukes_box.itemnames = yes_no_names; 3072 s_no_nukes_box.curvalue = ( dmflags & DF_NO_NUKES ) != 0; 3073 3074 s_stack_double_box.generic.type = MTYPE_SPINCONTROL; 3075 s_stack_double_box.generic.x = 0; 3076 s_stack_double_box.generic.y = y += 10; 3077 s_stack_double_box.generic.name = "2x/4x stacking off"; 3078 s_stack_double_box.generic.callback = DMFlagCallback; 3079 s_stack_double_box.itemnames = yes_no_names; 3080 s_stack_double_box.curvalue = ( dmflags & DF_NO_STACK_DOUBLE ) != 0; 3081 3082 s_no_spheres_box.generic.type = MTYPE_SPINCONTROL; 3083 s_no_spheres_box.generic.x = 0; 3084 s_no_spheres_box.generic.y = y += 10; 3085 s_no_spheres_box.generic.name = "remove spheres"; 3086 s_no_spheres_box.generic.callback = DMFlagCallback; 3087 s_no_spheres_box.itemnames = yes_no_names; 3088 s_no_spheres_box.curvalue = ( dmflags & DF_NO_SPHERES ) != 0; 3089 3090 } 3091 //ROGUE 3092 //============ 3093 3094 Menu_AddItem( &s_dmoptions_menu, &s_falls_box ); 3095 Menu_AddItem( &s_dmoptions_menu, &s_weapons_stay_box ); 3096 Menu_AddItem( &s_dmoptions_menu, &s_instant_powerups_box ); 3097 Menu_AddItem( &s_dmoptions_menu, &s_powerups_box ); 3098 Menu_AddItem( &s_dmoptions_menu, &s_health_box ); 3099 Menu_AddItem( &s_dmoptions_menu, &s_armor_box ); 3100 Menu_AddItem( &s_dmoptions_menu, &s_spawn_farthest_box ); 3101 Menu_AddItem( &s_dmoptions_menu, &s_samelevel_box ); 3102 Menu_AddItem( &s_dmoptions_menu, &s_force_respawn_box ); 3103 Menu_AddItem( &s_dmoptions_menu, &s_teamplay_box ); 3104 Menu_AddItem( &s_dmoptions_menu, &s_allow_exit_box ); 3105 Menu_AddItem( &s_dmoptions_menu, &s_infinite_ammo_box ); 3106 Menu_AddItem( &s_dmoptions_menu, &s_fixed_fov_box ); 3107 Menu_AddItem( &s_dmoptions_menu, &s_quad_drop_box ); 3108 Menu_AddItem( &s_dmoptions_menu, &s_friendlyfire_box ); 3109 3110 //======= 3111 //ROGUE 3112 if(Developer_searchpath(2) == 2) 3113 { 3114 Menu_AddItem( &s_dmoptions_menu, &s_no_mines_box ); 3115 Menu_AddItem( &s_dmoptions_menu, &s_no_nukes_box ); 3116 Menu_AddItem( &s_dmoptions_menu, &s_stack_double_box ); 3117 Menu_AddItem( &s_dmoptions_menu, &s_no_spheres_box ); 3118 } 3119 //ROGUE 3120 //======= 3121 3122 Menu_Center( &s_dmoptions_menu ); 3123 3124 // set the original dmflags statusbar 3125 DMFlagCallback( 0 ); 3126 Menu_SetStatusBar( &s_dmoptions_menu, dmoptions_statusbar ); 3127 } 3128 3129 void DMOptions_MenuDraw(void) 3130 { 3131 Menu_Draw( &s_dmoptions_menu ); 3132 } 3133 3134 const char *DMOptions_MenuKey( int key ) 3135 { 3136 return Default_MenuKey( &s_dmoptions_menu, key ); 3137 } 3138 3139 void M_Menu_DMOptions_f (void) 3140 { 3141 DMOptions_MenuInit(); 3142 M_PushMenu( DMOptions_MenuDraw, DMOptions_MenuKey ); 3143 } 3144 3145 /* 3146 ============================================================================= 3147 3148 DOWNLOADOPTIONS BOOK MENU 3149 3150 ============================================================================= 3151 */ 3152 static menuframework_s s_downloadoptions_menu; 3153 3154 static menuseparator_s s_download_title; 3155 static menulist_s s_allow_download_box; 3156 static menulist_s s_allow_download_maps_box; 3157 static menulist_s s_allow_download_models_box; 3158 static menulist_s s_allow_download_players_box; 3159 static menulist_s s_allow_download_sounds_box; 3160 3161 static void DownloadCallback( void *self ) 3162 { 3163 menulist_s *f = ( menulist_s * ) self; 3164 3165 if (f == &s_allow_download_box) 3166 { 3167 Cvar_SetValue("allow_download", f->curvalue); 3168 } 3169 3170 else if (f == &s_allow_download_maps_box) 3171 { 3172 Cvar_SetValue("allow_download_maps", f->curvalue); 3173 } 3174 3175 else if (f == &s_allow_download_models_box) 3176 { 3177 Cvar_SetValue("allow_download_models", f->curvalue); 3178 } 3179 3180 else if (f == &s_allow_download_players_box) 3181 { 3182 Cvar_SetValue("allow_download_players", f->curvalue); 3183 } 3184 3185 else if (f == &s_allow_download_sounds_box) 3186 { 3187 Cvar_SetValue("allow_download_sounds", f->curvalue); 3188 } 3189 } 3190 3191 void DownloadOptions_MenuInit( void ) 3192 { 3193 static const char *yes_no_names[] = 3194 { 3195 "no", "yes", 0 3196 }; 3197 int y = 0; 3198 3199 s_downloadoptions_menu.x = viddef.width * 0.50; 3200 s_downloadoptions_menu.nitems = 0; 3201 3202 s_download_title.generic.type = MTYPE_SEPARATOR; 3203 s_download_title.generic.name = "Download Options"; 3204 s_download_title.generic.x = 48; 3205 s_download_title.generic.y = y; 3206 3207 s_allow_download_box.generic.type = MTYPE_SPINCONTROL; 3208 s_allow_download_box.generic.x = 0; 3209 s_allow_download_box.generic.y = y += 20; 3210 s_allow_download_box.generic.name = "allow downloading"; 3211 s_allow_download_box.generic.callback = DownloadCallback; 3212 s_allow_download_box.itemnames = yes_no_names; 3213 s_allow_download_box.curvalue = (Cvar_VariableValue("allow_download") != 0); 3214 3215 s_allow_download_maps_box.generic.type = MTYPE_SPINCONTROL; 3216 s_allow_download_maps_box.generic.x = 0; 3217 s_allow_download_maps_box.generic.y = y += 20; 3218 s_allow_download_maps_box.generic.name = "maps"; 3219 s_allow_download_maps_box.generic.callback = DownloadCallback; 3220 s_allow_download_maps_box.itemnames = yes_no_names; 3221 s_allow_download_maps_box.curvalue = (Cvar_VariableValue("allow_download_maps") != 0); 3222 3223 s_allow_download_players_box.generic.type = MTYPE_SPINCONTROL; 3224 s_allow_download_players_box.generic.x = 0; 3225 s_allow_download_players_box.generic.y = y += 10; 3226 s_allow_download_players_box.generic.name = "player models/skins"; 3227 s_allow_download_players_box.generic.callback = DownloadCallback; 3228 s_allow_download_players_box.itemnames = yes_no_names; 3229 s_allow_download_players_box.curvalue = (Cvar_VariableValue("allow_download_players") != 0); 3230 3231 s_allow_download_models_box.generic.type = MTYPE_SPINCONTROL; 3232 s_allow_download_models_box.generic.x = 0; 3233 s_allow_download_models_box.generic.y = y += 10; 3234 s_allow_download_models_box.generic.name = "models"; 3235 s_allow_download_models_box.generic.callback = DownloadCallback; 3236 s_allow_download_models_box.itemnames = yes_no_names; 3237 s_allow_download_models_box.curvalue = (Cvar_VariableValue("allow_download_models") != 0); 3238 3239 s_allow_download_sounds_box.generic.type = MTYPE_SPINCONTROL; 3240 s_allow_download_sounds_box.generic.x = 0; 3241 s_allow_download_sounds_box.generic.y = y += 10; 3242 s_allow_download_sounds_box.generic.name = "sounds"; 3243 s_allow_download_sounds_box.generic.callback = DownloadCallback; 3244 s_allow_download_sounds_box.itemnames = yes_no_names; 3245 s_allow_download_sounds_box.curvalue = (Cvar_VariableValue("allow_download_sounds") != 0); 3246 3247 Menu_AddItem( &s_downloadoptions_menu, &s_download_title ); 3248 Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_box ); 3249 Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_maps_box ); 3250 Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_players_box ); 3251 Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_models_box ); 3252 Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_sounds_box ); 3253 3254 Menu_Center( &s_downloadoptions_menu ); 3255 3256 // skip over title 3257 if (s_downloadoptions_menu.cursor == 0) 3258 s_downloadoptions_menu.cursor = 1; 3259 } 3260 3261 void DownloadOptions_MenuDraw(void) 3262 { 3263 Menu_Draw( &s_downloadoptions_menu ); 3264 } 3265 3266 const char *DownloadOptions_MenuKey( int key ) 3267 { 3268 return Default_MenuKey( &s_downloadoptions_menu, key ); 3269 } 3270 3271 void M_Menu_DownloadOptions_f (void) 3272 { 3273 DownloadOptions_MenuInit(); 3274 M_PushMenu( DownloadOptions_MenuDraw, DownloadOptions_MenuKey ); 3275 } 3276 /* 3277 ============================================================================= 3278 3279 ADDRESS BOOK MENU 3280 3281 ============================================================================= 3282 */ 3283 #define NUM_ADDRESSBOOK_ENTRIES 9 3284 3285 static menuframework_s s_addressbook_menu; 3286 static menufield_s s_addressbook_fields[NUM_ADDRESSBOOK_ENTRIES]; 3287 3288 void AddressBook_MenuInit( void ) 3289 { 3290 int i; 3291 3292 s_addressbook_menu.x = viddef.width / 2 - 142; 3293 s_addressbook_menu.y = viddef.height / 2 - 58; 3294 s_addressbook_menu.nitems = 0; 3295 3296 for ( i = 0; i < NUM_ADDRESSBOOK_ENTRIES; i++ ) 3297 { 3298 cvar_t *adr; 3299 char buffer[20]; 3300 3301 Com_sprintf( buffer, sizeof( buffer ), "adr%d", i ); 3302 3303 adr = Cvar_Get( buffer, "", CVAR_ARCHIVE ); 3304 3305 s_addressbook_fields[i].generic.type = MTYPE_FIELD; 3306 s_addressbook_fields[i].generic.name = 0; 3307 s_addressbook_fields[i].generic.callback = 0; 3308 s_addressbook_fields[i].generic.x = 0; 3309 s_addressbook_fields[i].generic.y = i * 18 + 0; 3310 s_addressbook_fields[i].generic.localdata[0] = i; 3311 s_addressbook_fields[i].cursor = 0; 3312 s_addressbook_fields[i].length = 60; 3313 s_addressbook_fields[i].visible_length = 30; 3314 3315 strcpy( s_addressbook_fields[i].buffer, adr->string ); 3316 3317 Menu_AddItem( &s_addressbook_menu, &s_addressbook_fields[i] ); 3318 } 3319 } 3320 3321 const char *AddressBook_MenuKey( int key ) 3322 { 3323 if ( key == K_ESCAPE ) 3324 { 3325 int index; 3326 char buffer[20]; 3327 3328 for ( index = 0; index < NUM_ADDRESSBOOK_ENTRIES; index++ ) 3329 { 3330 Com_sprintf( buffer, sizeof( buffer ), "adr%d", index ); 3331 Cvar_Set( buffer, s_addressbook_fields[index].buffer ); 3332 } 3333 } 3334 return Default_MenuKey( &s_addressbook_menu, key ); 3335 } 3336 3337 void AddressBook_MenuDraw(void) 3338 { 3339 M_Banner( "m_banner_addressbook" ); 3340 Menu_Draw( &s_addressbook_menu ); 3341 } 3342 3343 void M_Menu_AddressBook_f(void) 3344 { 3345 AddressBook_MenuInit(); 3346 M_PushMenu( AddressBook_MenuDraw, AddressBook_MenuKey ); 3347 } 3348 3349 /* 3350 ============================================================================= 3351 3352 PLAYER CONFIG MENU 3353 3354 ============================================================================= 3355 */ 3356 static menuframework_s s_player_config_menu; 3357 static menufield_s s_player_name_field; 3358 static menulist_s s_player_model_box; 3359 static menulist_s s_player_skin_box; 3360 static menulist_s s_player_handedness_box; 3361 static menulist_s s_player_rate_box; 3362 static menuseparator_s s_player_skin_title; 3363 static menuseparator_s s_player_model_title; 3364 static menuseparator_s s_player_hand_title; 3365 static menuseparator_s s_player_rate_title; 3366 static menuaction_s s_player_download_action; 3367 3368 #define MAX_DISPLAYNAME 16 3369 #define MAX_PLAYERMODELS 1024 3370 3371 typedef struct 3372 { 3373 int nskins; 3374 char **skindisplaynames; 3375 char displayname[MAX_DISPLAYNAME]; 3376 char directory[MAX_QPATH]; 3377 } playermodelinfo_s; 3378 3379 static playermodelinfo_s s_pmi[MAX_PLAYERMODELS]; 3380 static char *s_pmnames[MAX_PLAYERMODELS]; 3381 static int s_numplayermodels; 3382 3383 static int rate_tbl[] = { 2500, 3200, 5000, 10000, 25000, 0 }; 3384 static const char *rate_names[] = { "28.8 Modem", "33.6 Modem", "Single ISDN", 3385 "Dual ISDN/Cable", "T1/LAN", "User defined", 0 }; 3386 3387 void DownloadOptionsFunc( void *self ) 3388 { 3389 M_Menu_DownloadOptions_f(); 3390 } 3391 3392 static void HandednessCallback( void *unused ) 3393 { 3394 Cvar_SetValue( "hand", s_player_handedness_box.curvalue ); 3395 } 3396 3397 static void RateCallback( void *unused ) 3398 { 3399 if (s_player_rate_box.curvalue != sizeof(rate_tbl) / sizeof(*rate_tbl) - 1) 3400 Cvar_SetValue( "rate", rate_tbl[s_player_rate_box.curvalue] ); 3401 } 3402 3403 static void ModelCallback( void *unused ) 3404 { 3405 s_player_skin_box.itemnames = s_pmi[s_player_model_box.curvalue].skindisplaynames; 3406 s_player_skin_box.curvalue = 0; 3407 } 3408 3409 static void FreeFileList( char **list, int n ) 3410 { 3411 int i; 3412 3413 for ( i = 0; i < n; i++ ) 3414 { 3415 if ( list[i] ) 3416 { 3417 free( list[i] ); 3418 list[i] = 0; 3419 } 3420 } 3421 free( list ); 3422 } 3423 3424 static qboolean IconOfSkinExists( char *skin, char **pcxfiles, int npcxfiles ) 3425 { 3426 int i; 3427 char scratch[1024]; 3428 3429 strcpy( scratch, skin ); 3430 *strrchr( scratch, '.' ) = 0; 3431 strcat( scratch, "_i.pcx" ); 3432 3433 for ( i = 0; i < npcxfiles; i++ ) 3434 { 3435 if ( strcmp( pcxfiles[i], scratch ) == 0 ) 3436 return true; 3437 } 3438 3439 return false; 3440 } 3441 3442 static qboolean PlayerConfig_ScanDirectories( void ) 3443 { 3444 char findname[1024]; 3445 char scratch[1024]; 3446 int ndirs = 0, npms = 0; 3447 char **dirnames; 3448 char *path = NULL; 3449 int i; 3450 3451 extern char **FS_ListFiles( char *, int *, unsigned, unsigned ); 3452 3453 s_numplayermodels = 0; 3454 3455 /* 3456 ** get a list of directories 3457 */ 3458 do 3459 { 3460 path = FS_NextPath( path ); 3461 Com_sprintf( findname, sizeof(findname), "%s/players/*.*", path ); 3462 3463 if ( ( dirnames = FS_ListFiles( findname, &ndirs, SFF_SUBDIR, 0 ) ) != 0 ) 3464 break; 3465 } while ( path ); 3466 3467 if ( !dirnames ) 3468 return false; 3469 3470 /* 3471 ** go through the subdirectories 3472 */ 3473 npms = ndirs; 3474 if ( npms > MAX_PLAYERMODELS ) 3475 npms = MAX_PLAYERMODELS; 3476 3477 for ( i = 0; i < npms; i++ ) 3478 { 3479 int k, s; 3480 char *a, *b, *c; 3481 char **pcxnames; 3482 char **skinnames; 3483 int npcxfiles; 3484 int nskins = 0; 3485 3486 if ( dirnames[i] == 0 ) 3487 continue; 3488 3489 // verify the existence of tris.md2 3490 strcpy( scratch, dirnames[i] ); 3491 strcat( scratch, "/tris.md2" ); 3492 if ( !Sys_FindFirst( scratch, 0, SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM ) ) 3493 { 3494 free( dirnames[i] ); 3495 dirnames[i] = 0; 3496 Sys_FindClose(); 3497 continue; 3498 } 3499 Sys_FindClose(); 3500 3501 // verify the existence of at least one pcx skin 3502 strcpy( scratch, dirnames[i] ); 3503 strcat( scratch, "/*.pcx" ); 3504 pcxnames = FS_ListFiles( scratch, &npcxfiles, 0, SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM ); 3505 3506 if ( !pcxnames ) 3507 { 3508 free( dirnames[i] ); 3509 dirnames[i] = 0; 3510 continue; 3511 } 3512 3513 // count valid skins, which consist of a skin with a matching "_i" icon 3514 for ( k = 0; k < npcxfiles-1; k++ ) 3515 { 3516 if ( !strstr( pcxnames[k], "_i.pcx" ) ) 3517 { 3518 if ( IconOfSkinExists( pcxnames[k], pcxnames, npcxfiles - 1 ) ) 3519 { 3520 nskins++; 3521 } 3522 } 3523 } 3524 if ( !nskins ) 3525 continue; 3526 3527 skinnames = malloc( sizeof( char * ) * ( nskins + 1 ) ); 3528 memset( skinnames, 0, sizeof( char * ) * ( nskins + 1 ) ); 3529 3530 // copy the valid skins 3531 for ( s = 0, k = 0; k < npcxfiles-1; k++ ) 3532 { 3533 char *a, *b, *c; 3534 3535 if ( !strstr( pcxnames[k], "_i.pcx" ) ) 3536 { 3537 if ( IconOfSkinExists( pcxnames[k], pcxnames, npcxfiles - 1 ) ) 3538 { 3539 a = strrchr( pcxnames[k], '/' ); 3540 b = strrchr( pcxnames[k], '\\' ); 3541 3542 if ( a > b ) 3543 c = a; 3544 else 3545 c = b; 3546 3547 strcpy( scratch, c + 1 ); 3548 3549 if ( strrchr( scratch, '.' ) ) 3550 *strrchr( scratch, '.' ) = 0; 3551 3552 skinnames[s] = strdup( scratch ); 3553 s++; 3554 } 3555 } 3556 } 3557 3558 // at this point we have a valid player model 3559 s_pmi[s_numplayermodels].nskins = nskins; 3560 s_pmi[s_numplayermodels].skindisplaynames = skinnames; 3561 3562 // make short name for the model 3563 a = strrchr( dirnames[i], '/' ); 3564 b = strrchr( dirnames[i], '\\' ); 3565 3566 if ( a > b ) 3567 c = a; 3568 else 3569 c = b; 3570 3571 strncpy( s_pmi[s_numplayermodels].displayname, c + 1, MAX_DISPLAYNAME-1 ); 3572 strcpy( s_pmi[s_numplayermodels].directory, c + 1 ); 3573 3574 FreeFileList( pcxnames, npcxfiles ); 3575 3576 s_numplayermodels++; 3577 } 3578 if ( dirnames ) 3579 FreeFileList( dirnames, ndirs ); 3580 } 3581 3582 static int pmicmpfnc( const void *_a, const void *_b ) 3583 { 3584 const playermodelinfo_s *a = ( const playermodelinfo_s * ) _a; 3585 const playermodelinfo_s *b = ( const playermodelinfo_s * ) _b; 3586 3587 /* 3588 ** sort by male, female, then alphabetical 3589 */ 3590 if ( strcmp( a->directory, "male" ) == 0 ) 3591 return -1; 3592 else if ( strcmp( b->directory, "male" ) == 0 ) 3593 return 1; 3594 3595 if ( strcmp( a->directory, "female" ) == 0 ) 3596 return -1; 3597 else if ( strcmp( b->directory, "female" ) == 0 ) 3598 return 1; 3599 3600 return strcmp( a->directory, b->directory ); 3601 } 3602 3603 3604 qboolean PlayerConfig_MenuInit( void ) 3605 { 3606 extern cvar_t *name; 3607 extern cvar_t *team; 3608 extern cvar_t *skin; 3609 char currentdirectory[1024]; 3610 char currentskin[1024]; 3611 int i = 0; 3612 3613 int currentdirectoryindex = 0; 3614 int currentskinindex = 0; 3615 3616 cvar_t *hand = Cvar_Get( "hand", "0", CVAR_USERINFO | CVAR_ARCHIVE ); 3617 3618 static const char *handedness[] = { "right", "left", "center", 0 }; 3619 3620 PlayerConfig_ScanDirectories(); 3621 3622 if (s_numplayermodels == 0) 3623 return false; 3624 3625 if ( hand->value < 0 || hand->value > 2 ) 3626 Cvar_SetValue( "hand", 0 ); 3627 3628 strcpy( currentdirectory, skin->string ); 3629 3630 if ( strchr( currentdirectory, '/' ) ) 3631 { 3632 strcpy( currentskin, strchr( currentdirectory, '/' ) + 1 ); 3633 *strchr( currentdirectory, '/' ) = 0; 3634 } 3635 else if ( strchr( currentdirectory, '\\' ) ) 3636 { 3637 strcpy( currentskin, strchr( currentdirectory, '\\' ) + 1 ); 3638 *strchr( currentdirectory, '\\' ) = 0; 3639 } 3640 else 3641 { 3642 strcpy( currentdirectory, "male" ); 3643 strcpy( currentskin, "grunt" ); 3644 } 3645 3646 qsort( s_pmi, s_numplayermodels, sizeof( s_pmi[0] ), pmicmpfnc ); 3647 3648 memset( s_pmnames, 0, sizeof( s_pmnames ) ); 3649 for ( i = 0; i < s_numplayermodels; i++ ) 3650 { 3651 s_pmnames[i] = s_pmi[i].displayname; 3652 if ( Q_stricmp( s_pmi[i].directory, currentdirectory ) == 0 ) 3653 { 3654 int j; 3655 3656 currentdirectoryindex = i; 3657 3658 for ( j = 0; j < s_pmi[i].nskins; j++ ) 3659 { 3660 if ( Q_stricmp( s_pmi[i].skindisplaynames[j], currentskin ) == 0 ) 3661 { 3662 currentskinindex = j; 3663 break; 3664 } 3665 } 3666 } 3667 } 3668 3669 s_player_config_menu.x = viddef.width / 2 - 95; 3670 s_player_config_menu.y = viddef.height / 2 - 97; 3671 s_player_config_menu.nitems = 0; 3672 3673 s_player_name_field.generic.type = MTYPE_FIELD; 3674 s_player_name_field.generic.name = "name"; 3675 s_player_name_field.generic.callback = 0; 3676 s_player_name_field.generic.x = 0; 3677 s_player_name_field.generic.y = 0; 3678 s_player_name_field.length = 20; 3679 s_player_name_field.visible_length = 20; 3680 strcpy( s_player_name_field.buffer, name->string ); 3681 s_player_name_field.cursor = strlen( name->string ); 3682 3683 s_player_model_title.generic.type = MTYPE_SEPARATOR; 3684 s_player_model_title.generic.name = "model"; 3685 s_player_model_title.generic.x = -8; 3686 s_player_model_title.generic.y = 60; 3687 3688 s_player_model_box.generic.type = MTYPE_SPINCONTROL; 3689 s_player_model_box.generic.x = -56; 3690 s_player_model_box.generic.y = 70; 3691 s_player_model_box.generic.callback = ModelCallback; 3692 s_player_model_box.generic.cursor_offset = -48; 3693 s_player_model_box.curvalue = currentdirectoryindex; 3694 s_player_model_box.itemnames = s_pmnames; 3695 3696 s_player_skin_title.generic.type = MTYPE_SEPARATOR; 3697 s_player_skin_title.generic.name = "skin"; 3698 s_player_skin_title.generic.x = -16; 3699 s_player_skin_title.generic.y = 84; 3700 3701 s_player_skin_box.generic.type = MTYPE_SPINCONTROL; 3702 s_player_skin_box.generic.x = -56; 3703 s_player_skin_box.generic.y = 94; 3704 s_player_skin_box.generic.name = 0; 3705 s_player_skin_box.generic.callback = 0; 3706 s_player_skin_box.generic.cursor_offset = -48; 3707 s_player_skin_box.curvalue = currentskinindex; 3708 s_player_skin_box.itemnames = s_pmi[currentdirectoryindex].skindisplaynames; 3709 3710 s_player_hand_title.generic.type = MTYPE_SEPARATOR; 3711 s_player_hand_title.generic.name = "handedness"; 3712 s_player_hand_title.generic.x = 32; 3713 s_player_hand_title.generic.y = 108; 3714 3715 s_player_handedness_box.generic.type = MTYPE_SPINCONTROL; 3716 s_player_handedness_box.generic.x = -56; 3717 s_player_handedness_box.generic.y = 118; 3718 s_player_handedness_box.generic.name = 0; 3719 s_player_handedness_box.generic.cursor_offset = -48; 3720 s_player_handedness_box.generic.callback = HandednessCallback; 3721 s_player_handedness_box.curvalue = Cvar_VariableValue( "hand" ); 3722 s_player_handedness_box.itemnames = handedness; 3723 3724 for (i = 0; i < sizeof(rate_tbl) / sizeof(*rate_tbl) - 1; i++) 3725 if (Cvar_VariableValue("rate") == rate_tbl[i]) 3726 break; 3727 3728 s_player_rate_title.generic.type = MTYPE_SEPARATOR; 3729 s_player_rate_title.generic.name = "connect speed"; 3730 s_player_rate_title.generic.x = 56; 3731 s_player_rate_title.generic.y = 156; 3732 3733 s_player_rate_box.generic.type = MTYPE_SPINCONTROL; 3734 s_player_rate_box.generic.x = -56; 3735 s_player_rate_box.generic.y = 166; 3736 s_player_rate_box.generic.name = 0; 3737 s_player_rate_box.generic.cursor_offset = -48; 3738 s_player_rate_box.generic.callback = RateCallback; 3739 s_player_rate_box.curvalue = i; 3740 s_player_rate_box.itemnames = rate_names; 3741 3742 s_player_download_action.generic.type = MTYPE_ACTION; 3743 s_player_download_action.generic.name = "download options"; 3744 s_player_download_action.generic.flags= QMF_LEFT_JUSTIFY; 3745 s_player_download_action.generic.x = -24; 3746 s_player_download_action.generic.y = 186; 3747 s_player_download_action.generic.statusbar = NULL; 3748 s_player_download_action.generic.callback = DownloadOptionsFunc; 3749 3750 Menu_AddItem( &s_player_config_menu, &s_player_name_field ); 3751 Menu_AddItem( &s_player_config_menu, &s_player_model_title ); 3752 Menu_AddItem( &s_player_config_menu, &s_player_model_box ); 3753 if ( s_player_skin_box.itemnames ) 3754 { 3755 Menu_AddItem( &s_player_config_menu, &s_player_skin_title ); 3756 Menu_AddItem( &s_player_config_menu, &s_player_skin_box ); 3757 } 3758 Menu_AddItem( &s_player_config_menu, &s_player_hand_title ); 3759 Menu_AddItem( &s_player_config_menu, &s_player_handedness_box ); 3760 Menu_AddItem( &s_player_config_menu, &s_player_rate_title ); 3761 Menu_AddItem( &s_player_config_menu, &s_player_rate_box ); 3762 Menu_AddItem( &s_player_config_menu, &s_player_download_action ); 3763 3764 return true; 3765 } 3766 3767 void PlayerConfig_MenuDraw( void ) 3768 { 3769 extern float CalcFov( float fov_x, float w, float h ); 3770 refdef_t refdef; 3771 char scratch[MAX_QPATH]; 3772 3773 memset( &refdef, 0, sizeof( refdef ) ); 3774 3775 refdef.x = viddef.width / 2; 3776 refdef.y = viddef.height / 2 - 72; 3777 refdef.width = 144; 3778 refdef.height = 168; 3779 refdef.fov_x = 40; 3780 refdef.fov_y = CalcFov( refdef.fov_x, refdef.width, refdef.height ); 3781 refdef.time = cls.realtime*0.001; 3782 3783 if ( s_pmi[s_player_model_box.curvalue].skindisplaynames ) 3784 { 3785 static int yaw; 3786 int maxframe = 29; 3787 entity_t entity; 3788 3789 memset( &entity, 0, sizeof( entity ) ); 3790 3791 Com_sprintf( scratch, sizeof( scratch ), "players/%s/tris.md2", s_pmi[s_player_model_box.curvalue].directory ); 3792 entity.model = re.RegisterModel( scratch ); 3793 Com_sprintf( scratch, sizeof( scratch ), "players/%s/%s.pcx", s_pmi[s_player_model_box.curvalue].directory, s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] ); 3794 entity.skin = re.RegisterSkin( scratch ); 3795 entity.flags = RF_FULLBRIGHT; 3796 entity.origin[0] = 80; 3797 entity.origin[1] = 0; 3798 entity.origin[2] = 0; 3799 VectorCopy( entity.origin, entity.oldorigin ); 3800 entity.frame = 0; 3801 entity.oldframe = 0; 3802 entity.backlerp = 0.0; 3803 entity.angles[1] = yaw++; 3804 if ( ++yaw > 360 ) 3805 yaw -= 360; 3806 3807 refdef.areabits = 0; 3808 refdef.num_entities = 1; 3809 refdef.entities = &entity; 3810 refdef.lightstyles = 0; 3811 refdef.rdflags = RDF_NOWORLDMODEL; 3812 3813 Menu_Draw( &s_player_config_menu ); 3814 3815 M_DrawTextBox( ( refdef.x ) * ( 320.0F / viddef.width ) - 8, ( viddef.height / 2 ) * ( 240.0F / viddef.height) - 77, refdef.width / 8, refdef.height / 8 ); 3816 refdef.height += 4; 3817 3818 re.RenderFrame( &refdef ); 3819 3820 Com_sprintf( scratch, sizeof( scratch ), "/players/%s/%s_i.pcx", 3821 s_pmi[s_player_model_box.curvalue].directory, 3822 s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] ); 3823 re.DrawPic( s_player_config_menu.x - 40, refdef.y, scratch ); 3824 } 3825 } 3826 3827 const char *PlayerConfig_MenuKey (int key) 3828 { 3829 int i; 3830 3831 if ( key == K_ESCAPE ) 3832 { 3833 char scratch[1024]; 3834 3835 Cvar_Set( "name", s_player_name_field.buffer ); 3836 3837 Com_sprintf( scratch, sizeof( scratch ), "%s/%s", 3838 s_pmi[s_player_model_box.curvalue].directory, 3839 s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] ); 3840 3841 Cvar_Set( "skin", scratch ); 3842 3843 for ( i = 0; i < s_numplayermodels; i++ ) 3844 { 3845 int j; 3846 3847 for ( j = 0; j < s_pmi[i].nskins; j++ ) 3848 { 3849 if ( s_pmi[i].skindisplaynames[j] ) 3850 free( s_pmi[i].skindisplaynames[j] ); 3851 s_pmi[i].skindisplaynames[j] = 0; 3852 } 3853 free( s_pmi[i].skindisplaynames ); 3854 s_pmi[i].skindisplaynames = 0; 3855 s_pmi[i].nskins = 0; 3856 } 3857 } 3858 return Default_MenuKey( &s_player_config_menu, key ); 3859 } 3860 3861 3862 void M_Menu_PlayerConfig_f (void) 3863 { 3864 if (!PlayerConfig_MenuInit()) 3865 { 3866 Menu_SetStatusBar( &s_multiplayer_menu, "No valid player models found" ); 3867 return; 3868 } 3869 Menu_SetStatusBar( &s_multiplayer_menu, NULL ); 3870 M_PushMenu( PlayerConfig_MenuDraw, PlayerConfig_MenuKey ); 3871 } 3872 3873 3874 /* 3875 ======================================================================= 3876 3877 GALLERY MENU 3878 3879 ======================================================================= 3880 */ 3881 #if 0 3882 void M_Menu_Gallery_f( void ) 3883 { 3884 extern void Gallery_MenuDraw( void ); 3885 extern const char *Gallery_MenuKey( int key ); 3886 3887 M_PushMenu( Gallery_MenuDraw, Gallery_MenuKey ); 3888 } 3889 #endif 3890 3891 /* 3892 ======================================================================= 3893 3894 QUIT MENU 3895 3896 ======================================================================= 3897 */ 3898 3899 const char *M_Quit_Key (int key) 3900 { 3901 switch (key) 3902 { 3903 case K_ESCAPE: 3904 case 'n': 3905 case 'N': 3906 M_PopMenu (); 3907 break; 3908 3909 case 'Y': 3910 case 'y': 3911 cls.key_dest = key_console; 3912 CL_Quit_f (); 3913 break; 3914 3915 default: 3916 break; 3917 } 3918 3919 return NULL; 3920 3921 } 3922 3923 3924 void M_Quit_Draw (void) 3925 { 3926 int w, h; 3927 3928 re.DrawGetPicSize (&w, &h, "quit"); 3929 re.DrawPic ( (viddef.width-w)/2, (viddef.height-h)/2, "quit"); 3930 } 3931 3932 3933 void M_Menu_Quit_f (void) 3934 { 3935 M_PushMenu (M_Quit_Draw, M_Quit_Key); 3936 } 3937 3938 3939 3940 //============================================================================= 3941 /* Menu Subsystem */ 3942 3943 3944 /* 3945 ================= 3946 M_Init 3947 ================= 3948 */ 3949 void M_Init (void) 3950 { 3951 Cmd_AddCommand ("menu_main", M_Menu_Main_f); 3952 Cmd_AddCommand ("menu_game", M_Menu_Game_f); 3953 Cmd_AddCommand ("menu_loadgame", M_Menu_LoadGame_f); 3954 Cmd_AddCommand ("menu_savegame", M_Menu_SaveGame_f); 3955 Cmd_AddCommand ("menu_joinserver", M_Menu_JoinServer_f); 3956 Cmd_AddCommand ("menu_addressbook", M_Menu_AddressBook_f); 3957 Cmd_AddCommand ("menu_startserver", M_Menu_StartServer_f); 3958 Cmd_AddCommand ("menu_dmoptions", M_Menu_DMOptions_f); 3959 Cmd_AddCommand ("menu_playerconfig", M_Menu_PlayerConfig_f); 3960 Cmd_AddCommand ("menu_downloadoptions", M_Menu_DownloadOptions_f); 3961 Cmd_AddCommand ("menu_credits", M_Menu_Credits_f ); 3962 Cmd_AddCommand ("menu_multiplayer", M_Menu_Multiplayer_f ); 3963 Cmd_AddCommand ("menu_video", M_Menu_Video_f); 3964 Cmd_AddCommand ("menu_options", M_Menu_Options_f); 3965 Cmd_AddCommand ("menu_keys", M_Menu_Keys_f); 3966 Cmd_AddCommand ("menu_quit", M_Menu_Quit_f); 3967 } 3968 3969 3970 /* 3971 ================= 3972 M_Draw 3973 ================= 3974 */ 3975 void M_Draw (void) 3976 { 3977 if (cls.key_dest != key_menu) 3978 return; 3979 3980 // repaint everything next frame 3981 SCR_DirtyScreen (); 3982 3983 // dim everything behind it down 3984 if (cl.cinematictime > 0) 3985 re.DrawFill (0,0,viddef.width, viddef.height, 0); 3986 else 3987 re.DrawFadeScreen (); 3988 3989 m_drawfunc (); 3990 3991 // delay playing the enter sound until after the 3992 // menu has been drawn, to avoid delay while 3993 // caching images 3994 if (m_entersound) 3995 { 3996 S_StartLocalSound( menu_in_sound ); 3997 m_entersound = false; 3998 } 3999 } 4000 4001 4002 /* 4003 ================= 4004 M_Keydown 4005 ================= 4006 */ 4007 void M_Keydown (int key) 4008 { 4009 const char *s; 4010 4011 if (m_keyfunc) 4012 if ( ( s = m_keyfunc( key ) ) != 0 ) 4013 S_StartLocalSound( ( char * ) s ); 4014 } 4015 4016