ui_startserver.c (59010B)
1 /* 2 =========================================================================== 3 Copyright (C) 1999-2005 Id Software, Inc. 4 5 This file is part of Quake III Arena source code. 6 7 Quake III Arena source code is free software; you can redistribute it 8 and/or modify it under the terms of the GNU General Public License as 9 published by the Free Software Foundation; either version 2 of the License, 10 or (at your option) any later version. 11 12 Quake III Arena source code is distributed in the hope that it will be 13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with Foobar; if not, write to the Free Software 19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 =========================================================================== 21 */ 22 // 23 /* 24 ============================================================================= 25 26 START SERVER MENU ***** 27 28 ============================================================================= 29 */ 30 31 32 #include "ui_local.h" 33 34 35 #define GAMESERVER_BACK0 "menu/art/back_0" 36 #define GAMESERVER_BACK1 "menu/art/back_1" 37 #define GAMESERVER_NEXT0 "menu/art/next_0" 38 #define GAMESERVER_NEXT1 "menu/art/next_1" 39 #define GAMESERVER_FRAMEL "menu/art/frame2_l" 40 #define GAMESERVER_FRAMER "menu/art/frame1_r" 41 #define GAMESERVER_SELECT "menu/art/maps_select" 42 #define GAMESERVER_SELECTED "menu/art/maps_selected" 43 #define GAMESERVER_FIGHT0 "menu/art/fight_0" 44 #define GAMESERVER_FIGHT1 "menu/art/fight_1" 45 #define GAMESERVER_UNKNOWNMAP "menu/art/unknownmap" 46 #define GAMESERVER_ARROWS "menu/art/gs_arrows_0" 47 #define GAMESERVER_ARROWSL "menu/art/gs_arrows_l" 48 #define GAMESERVER_ARROWSR "menu/art/gs_arrows_r" 49 50 #define MAX_MAPROWS 2 51 #define MAX_MAPCOLS 2 52 #define MAX_MAPSPERPAGE 4 53 54 #define MAX_SERVERSTEXT 8192 55 56 #define MAX_SERVERMAPS 64 57 #define MAX_NAMELENGTH 16 58 59 #define ID_GAMETYPE 10 60 #define ID_PICTURES 11 // 12, 13, 14 61 #define ID_PREVPAGE 15 62 #define ID_NEXTPAGE 16 63 #define ID_STARTSERVERBACK 17 64 #define ID_STARTSERVERNEXT 18 65 66 typedef struct { 67 menuframework_s menu; 68 69 menutext_s banner; 70 menubitmap_s framel; 71 menubitmap_s framer; 72 73 menulist_s gametype; 74 menubitmap_s mappics[MAX_MAPSPERPAGE]; 75 menubitmap_s mapbuttons[MAX_MAPSPERPAGE]; 76 menubitmap_s arrows; 77 menubitmap_s prevpage; 78 menubitmap_s nextpage; 79 menubitmap_s back; 80 menubitmap_s next; 81 82 menutext_s mapname; 83 menubitmap_s item_null; 84 85 qboolean multiplayer; 86 int currentmap; 87 int nummaps; 88 int page; 89 int maxpages; 90 char maplist[MAX_SERVERMAPS][MAX_NAMELENGTH]; 91 int mapGamebits[MAX_SERVERMAPS]; 92 } startserver_t; 93 94 static startserver_t s_startserver; 95 96 static const char *gametype_items[] = { 97 "Free For All", 98 "Team Deathmatch", 99 "Tournament", 100 "Capture the Flag", 101 0 102 }; 103 104 static int gametype_remap[] = {GT_FFA, GT_TEAM, GT_TOURNAMENT, GT_CTF}; 105 static int gametype_remap2[] = {0, 2, 0, 1, 3}; 106 107 // use ui_servers2.c definition 108 extern const char* punkbuster_items[]; 109 110 static void UI_ServerOptionsMenu( qboolean multiplayer ); 111 112 113 /* 114 ================= 115 GametypeBits 116 ================= 117 */ 118 static int GametypeBits( char *string ) { 119 int bits; 120 char *p; 121 char *token; 122 123 bits = 0; 124 p = string; 125 while( 1 ) { 126 token = COM_ParseExt( &p, qfalse ); 127 if( token[0] == 0 ) { 128 break; 129 } 130 131 if( Q_stricmp( token, "ffa" ) == 0 ) { 132 bits |= 1 << GT_FFA; 133 continue; 134 } 135 136 if( Q_stricmp( token, "tourney" ) == 0 ) { 137 bits |= 1 << GT_TOURNAMENT; 138 continue; 139 } 140 141 if( Q_stricmp( token, "single" ) == 0 ) { 142 bits |= 1 << GT_SINGLE_PLAYER; 143 continue; 144 } 145 146 if( Q_stricmp( token, "team" ) == 0 ) { 147 bits |= 1 << GT_TEAM; 148 continue; 149 } 150 151 if( Q_stricmp( token, "ctf" ) == 0 ) { 152 bits |= 1 << GT_CTF; 153 continue; 154 } 155 } 156 157 return bits; 158 } 159 160 161 /* 162 ================= 163 StartServer_Update 164 ================= 165 */ 166 static void StartServer_Update( void ) { 167 int i; 168 int top; 169 static char picname[MAX_MAPSPERPAGE][64]; 170 171 top = s_startserver.page*MAX_MAPSPERPAGE; 172 173 for (i=0; i<MAX_MAPSPERPAGE; i++) 174 { 175 if (top+i >= s_startserver.nummaps) 176 break; 177 178 Com_sprintf( picname[i], sizeof(picname[i]), "levelshots/%s", s_startserver.maplist[top+i] ); 179 180 s_startserver.mappics[i].generic.flags &= ~QMF_HIGHLIGHT; 181 s_startserver.mappics[i].generic.name = picname[i]; 182 s_startserver.mappics[i].shader = 0; 183 184 // reset 185 s_startserver.mapbuttons[i].generic.flags |= QMF_PULSEIFFOCUS; 186 s_startserver.mapbuttons[i].generic.flags &= ~QMF_INACTIVE; 187 } 188 189 for (; i<MAX_MAPSPERPAGE; i++) 190 { 191 s_startserver.mappics[i].generic.flags &= ~QMF_HIGHLIGHT; 192 s_startserver.mappics[i].generic.name = NULL; 193 s_startserver.mappics[i].shader = 0; 194 195 // disable 196 s_startserver.mapbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS; 197 s_startserver.mapbuttons[i].generic.flags |= QMF_INACTIVE; 198 } 199 200 201 // no servers to start 202 if( !s_startserver.nummaps ) { 203 s_startserver.next.generic.flags |= QMF_INACTIVE; 204 205 // set the map name 206 strcpy( s_startserver.mapname.string, "NO MAPS FOUND" ); 207 } 208 else { 209 // set the highlight 210 s_startserver.next.generic.flags &= ~QMF_INACTIVE; 211 i = s_startserver.currentmap - top; 212 if ( i >=0 && i < MAX_MAPSPERPAGE ) 213 { 214 s_startserver.mappics[i].generic.flags |= QMF_HIGHLIGHT; 215 s_startserver.mapbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS; 216 } 217 218 // set the map name 219 strcpy( s_startserver.mapname.string, s_startserver.maplist[s_startserver.currentmap] ); 220 } 221 222 Q_strupr( s_startserver.mapname.string ); 223 } 224 225 226 /* 227 ================= 228 StartServer_MapEvent 229 ================= 230 */ 231 static void StartServer_MapEvent( void* ptr, int event ) { 232 if( event != QM_ACTIVATED) { 233 return; 234 } 235 236 s_startserver.currentmap = (s_startserver.page*MAX_MAPSPERPAGE) + (((menucommon_s*)ptr)->id - ID_PICTURES); 237 StartServer_Update(); 238 } 239 240 241 /* 242 ================= 243 StartServer_GametypeEvent 244 ================= 245 */ 246 static void StartServer_GametypeEvent( void* ptr, int event ) { 247 int i; 248 int count; 249 int gamebits; 250 int matchbits; 251 const char *info; 252 253 if( event != QM_ACTIVATED) { 254 return; 255 } 256 257 count = UI_GetNumArenas(); 258 s_startserver.nummaps = 0; 259 matchbits = 1 << gametype_remap[s_startserver.gametype.curvalue]; 260 if( gametype_remap[s_startserver.gametype.curvalue] == GT_FFA ) { 261 matchbits |= ( 1 << GT_SINGLE_PLAYER ); 262 } 263 for( i = 0; i < count; i++ ) { 264 info = UI_GetArenaInfoByNumber( i ); 265 266 gamebits = GametypeBits( Info_ValueForKey( info, "type") ); 267 if( !( gamebits & matchbits ) ) { 268 continue; 269 } 270 271 Q_strncpyz( s_startserver.maplist[s_startserver.nummaps], Info_ValueForKey( info, "map"), MAX_NAMELENGTH ); 272 Q_strupr( s_startserver.maplist[s_startserver.nummaps] ); 273 s_startserver.mapGamebits[s_startserver.nummaps] = gamebits; 274 s_startserver.nummaps++; 275 } 276 s_startserver.maxpages = (s_startserver.nummaps + MAX_MAPSPERPAGE-1)/MAX_MAPSPERPAGE; 277 s_startserver.page = 0; 278 s_startserver.currentmap = 0; 279 280 StartServer_Update(); 281 } 282 283 284 /* 285 ================= 286 StartServer_MenuEvent 287 ================= 288 */ 289 static void StartServer_MenuEvent( void* ptr, int event ) { 290 if( event != QM_ACTIVATED ) { 291 return; 292 } 293 294 switch( ((menucommon_s*)ptr)->id ) { 295 case ID_PREVPAGE: 296 if( s_startserver.page > 0 ) { 297 s_startserver.page--; 298 StartServer_Update(); 299 } 300 break; 301 302 case ID_NEXTPAGE: 303 if( s_startserver.page < s_startserver.maxpages - 1 ) { 304 s_startserver.page++; 305 StartServer_Update(); 306 } 307 break; 308 309 case ID_STARTSERVERNEXT: 310 trap_Cvar_SetValue( "g_gameType", gametype_remap[s_startserver.gametype.curvalue] ); 311 UI_ServerOptionsMenu( s_startserver.multiplayer ); 312 break; 313 314 case ID_STARTSERVERBACK: 315 UI_PopMenu(); 316 break; 317 } 318 } 319 320 321 /* 322 =============== 323 StartServer_LevelshotDraw 324 =============== 325 */ 326 static void StartServer_LevelshotDraw( void *self ) { 327 menubitmap_s *b; 328 int x; 329 int y; 330 int w; 331 int h; 332 int n; 333 334 b = (menubitmap_s *)self; 335 336 if( !b->generic.name ) { 337 return; 338 } 339 340 if( b->generic.name && !b->shader ) { 341 b->shader = trap_R_RegisterShaderNoMip( b->generic.name ); 342 if( !b->shader && b->errorpic ) { 343 b->shader = trap_R_RegisterShaderNoMip( b->errorpic ); 344 } 345 } 346 347 if( b->focuspic && !b->focusshader ) { 348 b->focusshader = trap_R_RegisterShaderNoMip( b->focuspic ); 349 } 350 351 x = b->generic.x; 352 y = b->generic.y; 353 w = b->width; 354 h = b->height; 355 if( b->shader ) { 356 UI_DrawHandlePic( x, y, w, h, b->shader ); 357 } 358 359 x = b->generic.x; 360 y = b->generic.y + b->height; 361 UI_FillRect( x, y, b->width, 28, colorBlack ); 362 363 x += b->width / 2; 364 y += 4; 365 n = s_startserver.page * MAX_MAPSPERPAGE + b->generic.id - ID_PICTURES; 366 UI_DrawString( x, y, s_startserver.maplist[n], UI_CENTER|UI_SMALLFONT, color_orange ); 367 368 x = b->generic.x; 369 y = b->generic.y; 370 w = b->width; 371 h = b->height + 28; 372 if( b->generic.flags & QMF_HIGHLIGHT ) { 373 UI_DrawHandlePic( x, y, w, h, b->focusshader ); 374 } 375 } 376 377 378 /* 379 ================= 380 StartServer_MenuInit 381 ================= 382 */ 383 static void StartServer_MenuInit( void ) { 384 int i; 385 int x; 386 int y; 387 static char mapnamebuffer[64]; 388 389 // zero set all our globals 390 memset( &s_startserver, 0 ,sizeof(startserver_t) ); 391 392 StartServer_Cache(); 393 394 s_startserver.menu.wrapAround = qtrue; 395 s_startserver.menu.fullscreen = qtrue; 396 397 s_startserver.banner.generic.type = MTYPE_BTEXT; 398 s_startserver.banner.generic.x = 320; 399 s_startserver.banner.generic.y = 16; 400 s_startserver.banner.string = "GAME SERVER"; 401 s_startserver.banner.color = color_white; 402 s_startserver.banner.style = UI_CENTER; 403 404 s_startserver.framel.generic.type = MTYPE_BITMAP; 405 s_startserver.framel.generic.name = GAMESERVER_FRAMEL; 406 s_startserver.framel.generic.flags = QMF_INACTIVE; 407 s_startserver.framel.generic.x = 0; 408 s_startserver.framel.generic.y = 78; 409 s_startserver.framel.width = 256; 410 s_startserver.framel.height = 329; 411 412 s_startserver.framer.generic.type = MTYPE_BITMAP; 413 s_startserver.framer.generic.name = GAMESERVER_FRAMER; 414 s_startserver.framer.generic.flags = QMF_INACTIVE; 415 s_startserver.framer.generic.x = 376; 416 s_startserver.framer.generic.y = 76; 417 s_startserver.framer.width = 256; 418 s_startserver.framer.height = 334; 419 420 s_startserver.gametype.generic.type = MTYPE_SPINCONTROL; 421 s_startserver.gametype.generic.name = "Game Type:"; 422 s_startserver.gametype.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; 423 s_startserver.gametype.generic.callback = StartServer_GametypeEvent; 424 s_startserver.gametype.generic.id = ID_GAMETYPE; 425 s_startserver.gametype.generic.x = 320 - 24; 426 s_startserver.gametype.generic.y = 368; 427 s_startserver.gametype.itemnames = gametype_items; 428 429 for (i=0; i<MAX_MAPSPERPAGE; i++) 430 { 431 x = (i % MAX_MAPCOLS) * (128+8) + 188; 432 y = (i / MAX_MAPROWS) * (128+8) + 96; 433 434 s_startserver.mappics[i].generic.type = MTYPE_BITMAP; 435 s_startserver.mappics[i].generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE; 436 s_startserver.mappics[i].generic.x = x; 437 s_startserver.mappics[i].generic.y = y; 438 s_startserver.mappics[i].generic.id = ID_PICTURES+i; 439 s_startserver.mappics[i].width = 128; 440 s_startserver.mappics[i].height = 96; 441 s_startserver.mappics[i].focuspic = GAMESERVER_SELECTED; 442 s_startserver.mappics[i].errorpic = GAMESERVER_UNKNOWNMAP; 443 s_startserver.mappics[i].generic.ownerdraw = StartServer_LevelshotDraw; 444 445 s_startserver.mapbuttons[i].generic.type = MTYPE_BITMAP; 446 s_startserver.mapbuttons[i].generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_NODEFAULTINIT; 447 s_startserver.mapbuttons[i].generic.id = ID_PICTURES+i; 448 s_startserver.mapbuttons[i].generic.callback = StartServer_MapEvent; 449 s_startserver.mapbuttons[i].generic.x = x - 30; 450 s_startserver.mapbuttons[i].generic.y = y - 32; 451 s_startserver.mapbuttons[i].width = 256; 452 s_startserver.mapbuttons[i].height = 248; 453 s_startserver.mapbuttons[i].generic.left = x; 454 s_startserver.mapbuttons[i].generic.top = y; 455 s_startserver.mapbuttons[i].generic.right = x + 128; 456 s_startserver.mapbuttons[i].generic.bottom = y + 128; 457 s_startserver.mapbuttons[i].focuspic = GAMESERVER_SELECT; 458 } 459 460 s_startserver.arrows.generic.type = MTYPE_BITMAP; 461 s_startserver.arrows.generic.name = GAMESERVER_ARROWS; 462 s_startserver.arrows.generic.flags = QMF_INACTIVE; 463 s_startserver.arrows.generic.x = 260; 464 s_startserver.arrows.generic.y = 400; 465 s_startserver.arrows.width = 128; 466 s_startserver.arrows.height = 32; 467 468 s_startserver.prevpage.generic.type = MTYPE_BITMAP; 469 s_startserver.prevpage.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; 470 s_startserver.prevpage.generic.callback = StartServer_MenuEvent; 471 s_startserver.prevpage.generic.id = ID_PREVPAGE; 472 s_startserver.prevpage.generic.x = 260; 473 s_startserver.prevpage.generic.y = 400; 474 s_startserver.prevpage.width = 64; 475 s_startserver.prevpage.height = 32; 476 s_startserver.prevpage.focuspic = GAMESERVER_ARROWSL; 477 478 s_startserver.nextpage.generic.type = MTYPE_BITMAP; 479 s_startserver.nextpage.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; 480 s_startserver.nextpage.generic.callback = StartServer_MenuEvent; 481 s_startserver.nextpage.generic.id = ID_NEXTPAGE; 482 s_startserver.nextpage.generic.x = 321; 483 s_startserver.nextpage.generic.y = 400; 484 s_startserver.nextpage.width = 64; 485 s_startserver.nextpage.height = 32; 486 s_startserver.nextpage.focuspic = GAMESERVER_ARROWSR; 487 488 s_startserver.mapname.generic.type = MTYPE_PTEXT; 489 s_startserver.mapname.generic.flags = QMF_CENTER_JUSTIFY|QMF_INACTIVE; 490 s_startserver.mapname.generic.x = 320; 491 s_startserver.mapname.generic.y = 440; 492 s_startserver.mapname.string = mapnamebuffer; 493 s_startserver.mapname.style = UI_CENTER|UI_BIGFONT; 494 s_startserver.mapname.color = text_color_normal; 495 496 s_startserver.back.generic.type = MTYPE_BITMAP; 497 s_startserver.back.generic.name = GAMESERVER_BACK0; 498 s_startserver.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; 499 s_startserver.back.generic.callback = StartServer_MenuEvent; 500 s_startserver.back.generic.id = ID_STARTSERVERBACK; 501 s_startserver.back.generic.x = 0; 502 s_startserver.back.generic.y = 480-64; 503 s_startserver.back.width = 128; 504 s_startserver.back.height = 64; 505 s_startserver.back.focuspic = GAMESERVER_BACK1; 506 507 s_startserver.next.generic.type = MTYPE_BITMAP; 508 s_startserver.next.generic.name = GAMESERVER_NEXT0; 509 s_startserver.next.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; 510 s_startserver.next.generic.callback = StartServer_MenuEvent; 511 s_startserver.next.generic.id = ID_STARTSERVERNEXT; 512 s_startserver.next.generic.x = 640; 513 s_startserver.next.generic.y = 480-64; 514 s_startserver.next.width = 128; 515 s_startserver.next.height = 64; 516 s_startserver.next.focuspic = GAMESERVER_NEXT1; 517 518 s_startserver.item_null.generic.type = MTYPE_BITMAP; 519 s_startserver.item_null.generic.flags = QMF_LEFT_JUSTIFY|QMF_MOUSEONLY|QMF_SILENT; 520 s_startserver.item_null.generic.x = 0; 521 s_startserver.item_null.generic.y = 0; 522 s_startserver.item_null.width = 640; 523 s_startserver.item_null.height = 480; 524 525 Menu_AddItem( &s_startserver.menu, &s_startserver.banner ); 526 Menu_AddItem( &s_startserver.menu, &s_startserver.framel ); 527 Menu_AddItem( &s_startserver.menu, &s_startserver.framer ); 528 529 Menu_AddItem( &s_startserver.menu, &s_startserver.gametype ); 530 for (i=0; i<MAX_MAPSPERPAGE; i++) 531 { 532 Menu_AddItem( &s_startserver.menu, &s_startserver.mappics[i] ); 533 Menu_AddItem( &s_startserver.menu, &s_startserver.mapbuttons[i] ); 534 } 535 536 Menu_AddItem( &s_startserver.menu, &s_startserver.arrows ); 537 Menu_AddItem( &s_startserver.menu, &s_startserver.prevpage ); 538 Menu_AddItem( &s_startserver.menu, &s_startserver.nextpage ); 539 Menu_AddItem( &s_startserver.menu, &s_startserver.back ); 540 Menu_AddItem( &s_startserver.menu, &s_startserver.next ); 541 Menu_AddItem( &s_startserver.menu, &s_startserver.mapname ); 542 Menu_AddItem( &s_startserver.menu, &s_startserver.item_null ); 543 544 StartServer_GametypeEvent( NULL, QM_ACTIVATED ); 545 } 546 547 548 /* 549 ================= 550 StartServer_Cache 551 ================= 552 */ 553 void StartServer_Cache( void ) 554 { 555 int i; 556 const char *info; 557 qboolean precache; 558 char picname[64]; 559 560 trap_R_RegisterShaderNoMip( GAMESERVER_BACK0 ); 561 trap_R_RegisterShaderNoMip( GAMESERVER_BACK1 ); 562 trap_R_RegisterShaderNoMip( GAMESERVER_NEXT0 ); 563 trap_R_RegisterShaderNoMip( GAMESERVER_NEXT1 ); 564 trap_R_RegisterShaderNoMip( GAMESERVER_FRAMEL ); 565 trap_R_RegisterShaderNoMip( GAMESERVER_FRAMER ); 566 trap_R_RegisterShaderNoMip( GAMESERVER_SELECT ); 567 trap_R_RegisterShaderNoMip( GAMESERVER_SELECTED ); 568 trap_R_RegisterShaderNoMip( GAMESERVER_UNKNOWNMAP ); 569 trap_R_RegisterShaderNoMip( GAMESERVER_ARROWS ); 570 trap_R_RegisterShaderNoMip( GAMESERVER_ARROWSL ); 571 trap_R_RegisterShaderNoMip( GAMESERVER_ARROWSR ); 572 573 precache = trap_Cvar_VariableValue("com_buildscript"); 574 575 s_startserver.nummaps = UI_GetNumArenas(); 576 577 for( i = 0; i < s_startserver.nummaps; i++ ) { 578 info = UI_GetArenaInfoByNumber( i ); 579 580 Q_strncpyz( s_startserver.maplist[i], Info_ValueForKey( info, "map"), MAX_NAMELENGTH ); 581 Q_strupr( s_startserver.maplist[i] ); 582 s_startserver.mapGamebits[i] = GametypeBits( Info_ValueForKey( info, "type") ); 583 584 if( precache ) { 585 Com_sprintf( picname, sizeof(picname), "levelshots/%s", s_startserver.maplist[i] ); 586 trap_R_RegisterShaderNoMip(picname); 587 } 588 } 589 590 s_startserver.maxpages = (s_startserver.nummaps + MAX_MAPSPERPAGE-1)/MAX_MAPSPERPAGE; 591 } 592 593 594 /* 595 ================= 596 UI_StartServerMenu 597 ================= 598 */ 599 void UI_StartServerMenu( qboolean multiplayer ) { 600 StartServer_MenuInit(); 601 s_startserver.multiplayer = multiplayer; 602 UI_PushMenu( &s_startserver.menu ); 603 } 604 605 606 607 /* 608 ============================================================================= 609 610 SERVER OPTIONS MENU ***** 611 612 ============================================================================= 613 */ 614 615 #define ID_PLAYER_TYPE 20 616 #define ID_MAXCLIENTS 21 617 #define ID_DEDICATED 22 618 #define ID_GO 23 619 #define ID_BACK 24 620 621 #define PLAYER_SLOTS 12 622 623 624 typedef struct { 625 menuframework_s menu; 626 627 menutext_s banner; 628 629 menubitmap_s mappic; 630 menubitmap_s picframe; 631 632 menulist_s dedicated; 633 menufield_s timelimit; 634 menufield_s fraglimit; 635 menufield_s flaglimit; 636 menuradiobutton_s friendlyfire; 637 menufield_s hostname; 638 menuradiobutton_s pure; 639 menulist_s botSkill; 640 641 menutext_s player0; 642 menulist_s playerType[PLAYER_SLOTS]; 643 menutext_s playerName[PLAYER_SLOTS]; 644 menulist_s playerTeam[PLAYER_SLOTS]; 645 646 menubitmap_s go; 647 menubitmap_s next; 648 menubitmap_s back; 649 650 qboolean multiplayer; 651 int gametype; 652 char mapnamebuffer[32]; 653 char playerNameBuffers[PLAYER_SLOTS][16]; 654 655 qboolean newBot; 656 int newBotIndex; 657 char newBotName[16]; 658 659 menulist_s punkbuster; 660 } serveroptions_t; 661 662 static serveroptions_t s_serveroptions; 663 664 static const char *dedicated_list[] = { 665 "No", 666 "LAN", 667 "Internet", 668 0 669 }; 670 671 static const char *playerType_list[] = { 672 "Open", 673 "Bot", 674 "----", 675 0 676 }; 677 678 static const char *playerTeam_list[] = { 679 "Blue", 680 "Red", 681 0 682 }; 683 684 static const char *botSkill_list[] = { 685 "I Can Win", 686 "Bring It On", 687 "Hurt Me Plenty", 688 "Hardcore", 689 "Nightmare!", 690 0 691 }; 692 693 694 /* 695 ================= 696 BotAlreadySelected 697 ================= 698 */ 699 static qboolean BotAlreadySelected( const char *checkName ) { 700 int n; 701 702 for( n = 1; n < PLAYER_SLOTS; n++ ) { 703 if( s_serveroptions.playerType[n].curvalue != 1 ) { 704 continue; 705 } 706 if( (s_serveroptions.gametype >= GT_TEAM) && 707 (s_serveroptions.playerTeam[n].curvalue != s_serveroptions.playerTeam[s_serveroptions.newBotIndex].curvalue ) ) { 708 continue; 709 } 710 if( Q_stricmp( checkName, s_serveroptions.playerNameBuffers[n] ) == 0 ) { 711 return qtrue; 712 } 713 } 714 715 return qfalse; 716 } 717 718 719 /* 720 ================= 721 ServerOptions_Start 722 ================= 723 */ 724 static void ServerOptions_Start( void ) { 725 int timelimit; 726 int fraglimit; 727 int maxclients; 728 int dedicated; 729 int friendlyfire; 730 int flaglimit; 731 int pure; 732 int skill; 733 int n; 734 char buf[64]; 735 736 737 timelimit = atoi( s_serveroptions.timelimit.field.buffer ); 738 fraglimit = atoi( s_serveroptions.fraglimit.field.buffer ); 739 flaglimit = atoi( s_serveroptions.flaglimit.field.buffer ); 740 dedicated = s_serveroptions.dedicated.curvalue; 741 friendlyfire = s_serveroptions.friendlyfire.curvalue; 742 pure = s_serveroptions.pure.curvalue; 743 skill = s_serveroptions.botSkill.curvalue + 1; 744 745 //set maxclients 746 for( n = 0, maxclients = 0; n < PLAYER_SLOTS; n++ ) { 747 if( s_serveroptions.playerType[n].curvalue == 2 ) { 748 continue; 749 } 750 if( (s_serveroptions.playerType[n].curvalue == 1) && (s_serveroptions.playerNameBuffers[n][0] == 0) ) { 751 continue; 752 } 753 maxclients++; 754 } 755 756 switch( s_serveroptions.gametype ) { 757 case GT_FFA: 758 default: 759 trap_Cvar_SetValue( "ui_ffa_fraglimit", fraglimit ); 760 trap_Cvar_SetValue( "ui_ffa_timelimit", timelimit ); 761 break; 762 763 case GT_TOURNAMENT: 764 trap_Cvar_SetValue( "ui_tourney_fraglimit", fraglimit ); 765 trap_Cvar_SetValue( "ui_tourney_timelimit", timelimit ); 766 break; 767 768 case GT_TEAM: 769 trap_Cvar_SetValue( "ui_team_fraglimit", fraglimit ); 770 trap_Cvar_SetValue( "ui_team_timelimit", timelimit ); 771 trap_Cvar_SetValue( "ui_team_friendlt", friendlyfire ); 772 break; 773 774 case GT_CTF: 775 trap_Cvar_SetValue( "ui_ctf_fraglimit", fraglimit ); 776 trap_Cvar_SetValue( "ui_ctf_timelimit", timelimit ); 777 trap_Cvar_SetValue( "ui_ctf_friendlt", friendlyfire ); 778 break; 779 } 780 781 trap_Cvar_SetValue( "sv_maxclients", Com_Clamp( 0, 12, maxclients ) ); 782 trap_Cvar_SetValue( "dedicated", Com_Clamp( 0, 2, dedicated ) ); 783 trap_Cvar_SetValue ("timelimit", Com_Clamp( 0, timelimit, timelimit ) ); 784 trap_Cvar_SetValue ("fraglimit", Com_Clamp( 0, fraglimit, fraglimit ) ); 785 trap_Cvar_SetValue ("capturelimit", Com_Clamp( 0, flaglimit, flaglimit ) ); 786 trap_Cvar_SetValue( "g_friendlyfire", friendlyfire ); 787 trap_Cvar_SetValue( "sv_pure", pure ); 788 trap_Cvar_Set("sv_hostname", s_serveroptions.hostname.field.buffer ); 789 790 trap_Cvar_SetValue( "sv_punkbuster", s_serveroptions.punkbuster.curvalue ); 791 792 // the wait commands will allow the dedicated to take effect 793 trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", s_startserver.maplist[s_startserver.currentmap] ) ); 794 795 // add bots 796 trap_Cmd_ExecuteText( EXEC_APPEND, "wait 3\n" ); 797 for( n = 1; n < PLAYER_SLOTS; n++ ) { 798 if( s_serveroptions.playerType[n].curvalue != 1 ) { 799 continue; 800 } 801 if( s_serveroptions.playerNameBuffers[n][0] == 0 ) { 802 continue; 803 } 804 if( s_serveroptions.playerNameBuffers[n][0] == '-' ) { 805 continue; 806 } 807 if( s_serveroptions.gametype >= GT_TEAM ) { 808 Com_sprintf( buf, sizeof(buf), "addbot %s %i %s\n", s_serveroptions.playerNameBuffers[n], skill, 809 playerTeam_list[s_serveroptions.playerTeam[n].curvalue] ); 810 } 811 else { 812 Com_sprintf( buf, sizeof(buf), "addbot %s %i\n", s_serveroptions.playerNameBuffers[n], skill ); 813 } 814 trap_Cmd_ExecuteText( EXEC_APPEND, buf ); 815 } 816 817 // set player's team 818 if( dedicated == 0 && s_serveroptions.gametype >= GT_TEAM ) { 819 trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait 5; team %s\n", playerTeam_list[s_serveroptions.playerTeam[0].curvalue] ) ); 820 } 821 } 822 823 824 /* 825 ================= 826 ServerOptions_InitPlayerItems 827 ================= 828 */ 829 static void ServerOptions_InitPlayerItems( void ) { 830 int n; 831 int v; 832 833 // init types 834 if( s_serveroptions.multiplayer ) { 835 v = 0; // open 836 } 837 else { 838 v = 1; // bot 839 } 840 841 for( n = 0; n < PLAYER_SLOTS; n++ ) { 842 s_serveroptions.playerType[n].curvalue = v; 843 } 844 845 if( s_serveroptions.multiplayer && (s_serveroptions.gametype < GT_TEAM) ) { 846 for( n = 8; n < PLAYER_SLOTS; n++ ) { 847 s_serveroptions.playerType[n].curvalue = 2; 848 } 849 } 850 851 // if not a dedicated server, first slot is reserved for the human on the server 852 if( s_serveroptions.dedicated.curvalue == 0 ) { 853 // human 854 s_serveroptions.playerType[0].generic.flags |= QMF_INACTIVE; 855 s_serveroptions.playerType[0].curvalue = 0; 856 trap_Cvar_VariableStringBuffer( "name", s_serveroptions.playerNameBuffers[0], sizeof(s_serveroptions.playerNameBuffers[0]) ); 857 Q_CleanStr( s_serveroptions.playerNameBuffers[0] ); 858 } 859 860 // init teams 861 if( s_serveroptions.gametype >= GT_TEAM ) { 862 for( n = 0; n < (PLAYER_SLOTS / 2); n++ ) { 863 s_serveroptions.playerTeam[n].curvalue = 0; 864 } 865 for( ; n < PLAYER_SLOTS; n++ ) { 866 s_serveroptions.playerTeam[n].curvalue = 1; 867 } 868 } 869 else { 870 for( n = 0; n < PLAYER_SLOTS; n++ ) { 871 s_serveroptions.playerTeam[n].generic.flags |= (QMF_INACTIVE|QMF_HIDDEN); 872 } 873 } 874 } 875 876 877 /* 878 ================= 879 ServerOptions_SetPlayerItems 880 ================= 881 */ 882 static void ServerOptions_SetPlayerItems( void ) { 883 int start; 884 int n; 885 886 // types 887 // for( n = 0; n < PLAYER_SLOTS; n++ ) { 888 // if( (!s_serveroptions.multiplayer) && (n > 0) && (s_serveroptions.playerType[n].curvalue == 0) ) { 889 // s_serveroptions.playerType[n].curvalue = 1; 890 // } 891 // } 892 893 // names 894 if( s_serveroptions.dedicated.curvalue == 0 ) { 895 s_serveroptions.player0.string = "Human"; 896 s_serveroptions.playerName[0].generic.flags &= ~QMF_HIDDEN; 897 898 start = 1; 899 } 900 else { 901 s_serveroptions.player0.string = "Open"; 902 start = 0; 903 } 904 for( n = start; n < PLAYER_SLOTS; n++ ) { 905 if( s_serveroptions.playerType[n].curvalue == 1 ) { 906 s_serveroptions.playerName[n].generic.flags &= ~(QMF_INACTIVE|QMF_HIDDEN); 907 } 908 else { 909 s_serveroptions.playerName[n].generic.flags |= (QMF_INACTIVE|QMF_HIDDEN); 910 } 911 } 912 913 // teams 914 if( s_serveroptions.gametype < GT_TEAM ) { 915 return; 916 } 917 for( n = start; n < PLAYER_SLOTS; n++ ) { 918 if( s_serveroptions.playerType[n].curvalue == 2 ) { 919 s_serveroptions.playerTeam[n].generic.flags |= (QMF_INACTIVE|QMF_HIDDEN); 920 } 921 else { 922 s_serveroptions.playerTeam[n].generic.flags &= ~(QMF_INACTIVE|QMF_HIDDEN); 923 } 924 } 925 } 926 927 928 /* 929 ================= 930 ServerOptions_Event 931 ================= 932 */ 933 static void ServerOptions_Event( void* ptr, int event ) { 934 switch( ((menucommon_s*)ptr)->id ) { 935 936 //if( event != QM_ACTIVATED && event != QM_LOSTFOCUS) { 937 // return; 938 //} 939 case ID_PLAYER_TYPE: 940 if( event != QM_ACTIVATED ) { 941 break; 942 } 943 ServerOptions_SetPlayerItems(); 944 break; 945 946 case ID_MAXCLIENTS: 947 case ID_DEDICATED: 948 ServerOptions_SetPlayerItems(); 949 break; 950 case ID_GO: 951 if( event != QM_ACTIVATED ) { 952 break; 953 } 954 ServerOptions_Start(); 955 break; 956 957 case ID_STARTSERVERNEXT: 958 if( event != QM_ACTIVATED ) { 959 break; 960 } 961 break; 962 case ID_BACK: 963 if( event != QM_ACTIVATED ) { 964 break; 965 } 966 UI_PopMenu(); 967 break; 968 } 969 } 970 971 972 static void ServerOptions_PlayerNameEvent( void* ptr, int event ) { 973 int n; 974 975 if( event != QM_ACTIVATED ) { 976 return; 977 } 978 n = ((menutext_s*)ptr)->generic.id; 979 s_serveroptions.newBotIndex = n; 980 UI_BotSelectMenu( s_serveroptions.playerNameBuffers[n] ); 981 } 982 983 984 /* 985 ================= 986 ServerOptions_StatusBar 987 ================= 988 */ 989 static void ServerOptions_StatusBar( void* ptr ) { 990 switch( ((menucommon_s*)ptr)->id ) { 991 default: 992 UI_DrawString( 320, 440, "0 = NO LIMIT", UI_CENTER|UI_SMALLFONT, colorWhite ); 993 break; 994 } 995 } 996 997 998 /* 999 =============== 1000 ServerOptions_LevelshotDraw 1001 =============== 1002 */ 1003 static void ServerOptions_LevelshotDraw( void *self ) { 1004 menubitmap_s *b; 1005 int x; 1006 int y; 1007 1008 // strange place for this, but it works 1009 if( s_serveroptions.newBot ) { 1010 Q_strncpyz( s_serveroptions.playerNameBuffers[s_serveroptions.newBotIndex], s_serveroptions.newBotName, 16 ); 1011 s_serveroptions.newBot = qfalse; 1012 } 1013 1014 b = (menubitmap_s *)self; 1015 1016 Bitmap_Draw( b ); 1017 1018 x = b->generic.x; 1019 y = b->generic.y + b->height; 1020 UI_FillRect( x, y, b->width, 40, colorBlack ); 1021 1022 x += b->width / 2; 1023 y += 4; 1024 UI_DrawString( x, y, s_serveroptions.mapnamebuffer, UI_CENTER|UI_SMALLFONT, color_orange ); 1025 1026 y += SMALLCHAR_HEIGHT; 1027 UI_DrawString( x, y, gametype_items[gametype_remap2[s_serveroptions.gametype]], UI_CENTER|UI_SMALLFONT, color_orange ); 1028 } 1029 1030 1031 static void ServerOptions_InitBotNames( void ) { 1032 int count; 1033 int n; 1034 const char *arenaInfo; 1035 const char *botInfo; 1036 char *p; 1037 char *bot; 1038 char bots[MAX_INFO_STRING]; 1039 1040 if( s_serveroptions.gametype >= GT_TEAM ) { 1041 Q_strncpyz( s_serveroptions.playerNameBuffers[1], "grunt", 16 ); 1042 Q_strncpyz( s_serveroptions.playerNameBuffers[2], "major", 16 ); 1043 if( s_serveroptions.gametype == GT_TEAM ) { 1044 Q_strncpyz( s_serveroptions.playerNameBuffers[3], "visor", 16 ); 1045 } 1046 else { 1047 s_serveroptions.playerType[3].curvalue = 2; 1048 } 1049 s_serveroptions.playerType[4].curvalue = 2; 1050 s_serveroptions.playerType[5].curvalue = 2; 1051 1052 Q_strncpyz( s_serveroptions.playerNameBuffers[6], "sarge", 16 ); 1053 Q_strncpyz( s_serveroptions.playerNameBuffers[7], "grunt", 16 ); 1054 Q_strncpyz( s_serveroptions.playerNameBuffers[8], "major", 16 ); 1055 if( s_serveroptions.gametype == GT_TEAM ) { 1056 Q_strncpyz( s_serveroptions.playerNameBuffers[9], "visor", 16 ); 1057 } 1058 else { 1059 s_serveroptions.playerType[9].curvalue = 2; 1060 } 1061 s_serveroptions.playerType[10].curvalue = 2; 1062 s_serveroptions.playerType[11].curvalue = 2; 1063 1064 return; 1065 } 1066 1067 count = 1; // skip the first slot, reserved for a human 1068 1069 // get info for this map 1070 arenaInfo = UI_GetArenaInfoByMap( s_serveroptions.mapnamebuffer ); 1071 1072 // get the bot info - we'll seed with them if any are listed 1073 Q_strncpyz( bots, Info_ValueForKey( arenaInfo, "bots" ), sizeof(bots) ); 1074 p = &bots[0]; 1075 while( *p && count < PLAYER_SLOTS ) { 1076 //skip spaces 1077 while( *p && *p == ' ' ) { 1078 p++; 1079 } 1080 if( !p ) { 1081 break; 1082 } 1083 1084 // mark start of bot name 1085 bot = p; 1086 1087 // skip until space of null 1088 while( *p && *p != ' ' ) { 1089 p++; 1090 } 1091 if( *p ) { 1092 *p++ = 0; 1093 } 1094 1095 botInfo = UI_GetBotInfoByName( bot ); 1096 bot = Info_ValueForKey( botInfo, "name" ); 1097 1098 Q_strncpyz( s_serveroptions.playerNameBuffers[count], bot, sizeof(s_serveroptions.playerNameBuffers[count]) ); 1099 count++; 1100 } 1101 1102 // set the rest of the bot slots to "---" 1103 for( n = count; n < PLAYER_SLOTS; n++ ) { 1104 strcpy( s_serveroptions.playerNameBuffers[n], "--------" ); 1105 } 1106 1107 // pad up to #8 as open slots 1108 for( ;count < 8; count++ ) { 1109 s_serveroptions.playerType[count].curvalue = 0; 1110 } 1111 1112 // close off the rest by default 1113 for( ;count < PLAYER_SLOTS; count++ ) { 1114 if( s_serveroptions.playerType[count].curvalue == 1 ) { 1115 s_serveroptions.playerType[count].curvalue = 2; 1116 } 1117 } 1118 } 1119 1120 1121 /* 1122 ================= 1123 ServerOptions_SetMenuItems 1124 ================= 1125 */ 1126 static void ServerOptions_SetMenuItems( void ) { 1127 static char picname[64]; 1128 1129 switch( s_serveroptions.gametype ) { 1130 case GT_FFA: 1131 default: 1132 Com_sprintf( s_serveroptions.fraglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_ffa_fraglimit" ) ) ); 1133 Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_ffa_timelimit" ) ) ); 1134 break; 1135 1136 case GT_TOURNAMENT: 1137 Com_sprintf( s_serveroptions.fraglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_tourney_fraglimit" ) ) ); 1138 Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_tourney_timelimit" ) ) ); 1139 break; 1140 1141 case GT_TEAM: 1142 Com_sprintf( s_serveroptions.fraglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_team_fraglimit" ) ) ); 1143 Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_team_timelimit" ) ) ); 1144 s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_team_friendly" ) ); 1145 break; 1146 1147 case GT_CTF: 1148 Com_sprintf( s_serveroptions.flaglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 100, trap_Cvar_VariableValue( "ui_ctf_capturelimit" ) ) ); 1149 Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_ctf_timelimit" ) ) ); 1150 s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_ctf_friendly" ) ); 1151 break; 1152 } 1153 1154 Q_strncpyz( s_serveroptions.hostname.field.buffer, UI_Cvar_VariableString( "sv_hostname" ), sizeof( s_serveroptions.hostname.field.buffer ) ); 1155 s_serveroptions.pure.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "sv_pure" ) ); 1156 1157 // set the map pic 1158 Com_sprintf( picname, 64, "levelshots/%s", s_startserver.maplist[s_startserver.currentmap] ); 1159 s_serveroptions.mappic.generic.name = picname; 1160 1161 // set the map name 1162 strcpy( s_serveroptions.mapnamebuffer, s_startserver.mapname.string ); 1163 Q_strupr( s_serveroptions.mapnamebuffer ); 1164 1165 // get the player selections initialized 1166 ServerOptions_InitPlayerItems(); 1167 ServerOptions_SetPlayerItems(); 1168 1169 // seed bot names 1170 ServerOptions_InitBotNames(); 1171 ServerOptions_SetPlayerItems(); 1172 } 1173 1174 /* 1175 ================= 1176 PlayerName_Draw 1177 ================= 1178 */ 1179 static void PlayerName_Draw( void *item ) { 1180 menutext_s *s; 1181 float *color; 1182 int x, y; 1183 int style; 1184 qboolean focus; 1185 1186 s = (menutext_s *)item; 1187 1188 x = s->generic.x; 1189 y = s->generic.y; 1190 1191 style = UI_SMALLFONT; 1192 focus = (s->generic.parent->cursor == s->generic.menuPosition); 1193 1194 if ( s->generic.flags & QMF_GRAYED ) 1195 color = text_color_disabled; 1196 else if ( focus ) 1197 { 1198 color = text_color_highlight; 1199 style |= UI_PULSE; 1200 } 1201 else if ( s->generic.flags & QMF_BLINK ) 1202 { 1203 color = text_color_highlight; 1204 style |= UI_BLINK; 1205 } 1206 else 1207 color = text_color_normal; 1208 1209 if ( focus ) 1210 { 1211 // draw cursor 1212 UI_FillRect( s->generic.left, s->generic.top, s->generic.right-s->generic.left+1, s->generic.bottom-s->generic.top+1, listbar_color ); 1213 UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, color); 1214 } 1215 1216 UI_DrawString( x - SMALLCHAR_WIDTH, y, s->generic.name, style|UI_RIGHT, color ); 1217 UI_DrawString( x + SMALLCHAR_WIDTH, y, s->string, style|UI_LEFT, color ); 1218 } 1219 1220 1221 /* 1222 ================= 1223 ServerOptions_MenuInit 1224 ================= 1225 */ 1226 #define OPTIONS_X 456 1227 1228 static void ServerOptions_MenuInit( qboolean multiplayer ) { 1229 int y; 1230 int n; 1231 1232 memset( &s_serveroptions, 0 ,sizeof(serveroptions_t) ); 1233 s_serveroptions.multiplayer = multiplayer; 1234 s_serveroptions.gametype = (int)Com_Clamp( 0, 5, trap_Cvar_VariableValue( "g_gameType" ) ); 1235 s_serveroptions.punkbuster.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "sv_punkbuster" ) ); 1236 1237 ServerOptions_Cache(); 1238 1239 s_serveroptions.menu.wrapAround = qtrue; 1240 s_serveroptions.menu.fullscreen = qtrue; 1241 1242 s_serveroptions.banner.generic.type = MTYPE_BTEXT; 1243 s_serveroptions.banner.generic.x = 320; 1244 s_serveroptions.banner.generic.y = 16; 1245 s_serveroptions.banner.string = "GAME SERVER"; 1246 s_serveroptions.banner.color = color_white; 1247 s_serveroptions.banner.style = UI_CENTER; 1248 1249 s_serveroptions.mappic.generic.type = MTYPE_BITMAP; 1250 s_serveroptions.mappic.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE; 1251 s_serveroptions.mappic.generic.x = 352; 1252 s_serveroptions.mappic.generic.y = 80; 1253 s_serveroptions.mappic.width = 160; 1254 s_serveroptions.mappic.height = 120; 1255 s_serveroptions.mappic.errorpic = GAMESERVER_UNKNOWNMAP; 1256 s_serveroptions.mappic.generic.ownerdraw = ServerOptions_LevelshotDraw; 1257 1258 s_serveroptions.picframe.generic.type = MTYPE_BITMAP; 1259 s_serveroptions.picframe.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE|QMF_HIGHLIGHT; 1260 s_serveroptions.picframe.generic.x = 352 - 38; 1261 s_serveroptions.picframe.generic.y = 80 - 40; 1262 s_serveroptions.picframe.width = 320; 1263 s_serveroptions.picframe.height = 320; 1264 s_serveroptions.picframe.focuspic = GAMESERVER_SELECT; 1265 1266 y = 272; 1267 if( s_serveroptions.gametype != GT_CTF ) { 1268 s_serveroptions.fraglimit.generic.type = MTYPE_FIELD; 1269 s_serveroptions.fraglimit.generic.name = "Frag Limit:"; 1270 s_serveroptions.fraglimit.generic.flags = QMF_NUMBERSONLY|QMF_PULSEIFFOCUS|QMF_SMALLFONT; 1271 s_serveroptions.fraglimit.generic.x = OPTIONS_X; 1272 s_serveroptions.fraglimit.generic.y = y; 1273 s_serveroptions.fraglimit.generic.statusbar = ServerOptions_StatusBar; 1274 s_serveroptions.fraglimit.field.widthInChars = 3; 1275 s_serveroptions.fraglimit.field.maxchars = 3; 1276 } 1277 else { 1278 s_serveroptions.flaglimit.generic.type = MTYPE_FIELD; 1279 s_serveroptions.flaglimit.generic.name = "Capture Limit:"; 1280 s_serveroptions.flaglimit.generic.flags = QMF_NUMBERSONLY|QMF_PULSEIFFOCUS|QMF_SMALLFONT; 1281 s_serveroptions.flaglimit.generic.x = OPTIONS_X; 1282 s_serveroptions.flaglimit.generic.y = y; 1283 s_serveroptions.flaglimit.generic.statusbar = ServerOptions_StatusBar; 1284 s_serveroptions.flaglimit.field.widthInChars = 3; 1285 s_serveroptions.flaglimit.field.maxchars = 3; 1286 } 1287 1288 y += BIGCHAR_HEIGHT+2; 1289 s_serveroptions.timelimit.generic.type = MTYPE_FIELD; 1290 s_serveroptions.timelimit.generic.name = "Time Limit:"; 1291 s_serveroptions.timelimit.generic.flags = QMF_NUMBERSONLY|QMF_PULSEIFFOCUS|QMF_SMALLFONT; 1292 s_serveroptions.timelimit.generic.x = OPTIONS_X; 1293 s_serveroptions.timelimit.generic.y = y; 1294 s_serveroptions.timelimit.generic.statusbar = ServerOptions_StatusBar; 1295 s_serveroptions.timelimit.field.widthInChars = 3; 1296 s_serveroptions.timelimit.field.maxchars = 3; 1297 1298 if( s_serveroptions.gametype >= GT_TEAM ) { 1299 y += BIGCHAR_HEIGHT+2; 1300 s_serveroptions.friendlyfire.generic.type = MTYPE_RADIOBUTTON; 1301 s_serveroptions.friendlyfire.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; 1302 s_serveroptions.friendlyfire.generic.x = OPTIONS_X; 1303 s_serveroptions.friendlyfire.generic.y = y; 1304 s_serveroptions.friendlyfire.generic.name = "Friendly Fire:"; 1305 } 1306 1307 y += BIGCHAR_HEIGHT+2; 1308 s_serveroptions.pure.generic.type = MTYPE_RADIOBUTTON; 1309 s_serveroptions.pure.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; 1310 s_serveroptions.pure.generic.x = OPTIONS_X; 1311 s_serveroptions.pure.generic.y = y; 1312 s_serveroptions.pure.generic.name = "Pure Server:"; 1313 1314 if( s_serveroptions.multiplayer ) { 1315 y += BIGCHAR_HEIGHT+2; 1316 s_serveroptions.dedicated.generic.type = MTYPE_SPINCONTROL; 1317 s_serveroptions.dedicated.generic.id = ID_DEDICATED; 1318 s_serveroptions.dedicated.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; 1319 s_serveroptions.dedicated.generic.callback = ServerOptions_Event; 1320 s_serveroptions.dedicated.generic.x = OPTIONS_X; 1321 s_serveroptions.dedicated.generic.y = y; 1322 s_serveroptions.dedicated.generic.name = "Dedicated:"; 1323 s_serveroptions.dedicated.itemnames = dedicated_list; 1324 } 1325 1326 if( s_serveroptions.multiplayer ) { 1327 y += BIGCHAR_HEIGHT+2; 1328 s_serveroptions.hostname.generic.type = MTYPE_FIELD; 1329 s_serveroptions.hostname.generic.name = "Hostname:"; 1330 s_serveroptions.hostname.generic.flags = QMF_SMALLFONT; 1331 s_serveroptions.hostname.generic.x = OPTIONS_X; 1332 s_serveroptions.hostname.generic.y = y; 1333 s_serveroptions.hostname.field.widthInChars = 18; 1334 s_serveroptions.hostname.field.maxchars = 64; 1335 } 1336 1337 y += BIGCHAR_HEIGHT+2; 1338 s_serveroptions.punkbuster.generic.type = MTYPE_SPINCONTROL; 1339 s_serveroptions.punkbuster.generic.name = "Punkbuster:"; 1340 s_serveroptions.punkbuster.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; 1341 s_serveroptions.punkbuster.generic.id = 0; 1342 s_serveroptions.punkbuster.generic.x = OPTIONS_X; 1343 s_serveroptions.punkbuster.generic.y = y; 1344 s_serveroptions.punkbuster.itemnames = punkbuster_items; 1345 1346 y = 80; 1347 s_serveroptions.botSkill.generic.type = MTYPE_SPINCONTROL; 1348 s_serveroptions.botSkill.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; 1349 s_serveroptions.botSkill.generic.name = "Bot Skill: "; 1350 s_serveroptions.botSkill.generic.x = 32 + (strlen(s_serveroptions.botSkill.generic.name) + 2 ) * SMALLCHAR_WIDTH; 1351 s_serveroptions.botSkill.generic.y = y; 1352 s_serveroptions.botSkill.itemnames = botSkill_list; 1353 s_serveroptions.botSkill.curvalue = 1; 1354 1355 y += ( 2 * SMALLCHAR_HEIGHT ); 1356 s_serveroptions.player0.generic.type = MTYPE_TEXT; 1357 s_serveroptions.player0.generic.flags = QMF_SMALLFONT; 1358 s_serveroptions.player0.generic.x = 32 + SMALLCHAR_WIDTH; 1359 s_serveroptions.player0.generic.y = y; 1360 s_serveroptions.player0.color = color_orange; 1361 s_serveroptions.player0.style = UI_LEFT|UI_SMALLFONT; 1362 1363 for( n = 0; n < PLAYER_SLOTS; n++ ) { 1364 s_serveroptions.playerType[n].generic.type = MTYPE_SPINCONTROL; 1365 s_serveroptions.playerType[n].generic.flags = QMF_SMALLFONT; 1366 s_serveroptions.playerType[n].generic.id = ID_PLAYER_TYPE; 1367 s_serveroptions.playerType[n].generic.callback = ServerOptions_Event; 1368 s_serveroptions.playerType[n].generic.x = 32; 1369 s_serveroptions.playerType[n].generic.y = y; 1370 s_serveroptions.playerType[n].itemnames = playerType_list; 1371 1372 s_serveroptions.playerName[n].generic.type = MTYPE_TEXT; 1373 s_serveroptions.playerName[n].generic.flags = QMF_SMALLFONT; 1374 s_serveroptions.playerName[n].generic.x = 96; 1375 s_serveroptions.playerName[n].generic.y = y; 1376 s_serveroptions.playerName[n].generic.callback = ServerOptions_PlayerNameEvent; 1377 s_serveroptions.playerName[n].generic.id = n; 1378 s_serveroptions.playerName[n].generic.ownerdraw = PlayerName_Draw; 1379 s_serveroptions.playerName[n].color = color_orange; 1380 s_serveroptions.playerName[n].style = UI_SMALLFONT; 1381 s_serveroptions.playerName[n].string = s_serveroptions.playerNameBuffers[n]; 1382 s_serveroptions.playerName[n].generic.top = s_serveroptions.playerName[n].generic.y; 1383 s_serveroptions.playerName[n].generic.bottom = s_serveroptions.playerName[n].generic.y + SMALLCHAR_HEIGHT; 1384 s_serveroptions.playerName[n].generic.left = s_serveroptions.playerName[n].generic.x - SMALLCHAR_HEIGHT/ 2; 1385 s_serveroptions.playerName[n].generic.right = s_serveroptions.playerName[n].generic.x + 16 * SMALLCHAR_WIDTH; 1386 1387 s_serveroptions.playerTeam[n].generic.type = MTYPE_SPINCONTROL; 1388 s_serveroptions.playerTeam[n].generic.flags = QMF_SMALLFONT; 1389 s_serveroptions.playerTeam[n].generic.x = 240; 1390 s_serveroptions.playerTeam[n].generic.y = y; 1391 s_serveroptions.playerTeam[n].itemnames = playerTeam_list; 1392 1393 y += ( SMALLCHAR_HEIGHT + 4 ); 1394 } 1395 1396 s_serveroptions.back.generic.type = MTYPE_BITMAP; 1397 s_serveroptions.back.generic.name = GAMESERVER_BACK0; 1398 s_serveroptions.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; 1399 s_serveroptions.back.generic.callback = ServerOptions_Event; 1400 s_serveroptions.back.generic.id = ID_BACK; 1401 s_serveroptions.back.generic.x = 0; 1402 s_serveroptions.back.generic.y = 480-64; 1403 s_serveroptions.back.width = 128; 1404 s_serveroptions.back.height = 64; 1405 s_serveroptions.back.focuspic = GAMESERVER_BACK1; 1406 1407 s_serveroptions.next.generic.type = MTYPE_BITMAP; 1408 s_serveroptions.next.generic.name = GAMESERVER_NEXT0; 1409 s_serveroptions.next.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_INACTIVE|QMF_GRAYED|QMF_HIDDEN; 1410 s_serveroptions.next.generic.callback = ServerOptions_Event; 1411 s_serveroptions.next.generic.id = ID_STARTSERVERNEXT; 1412 s_serveroptions.next.generic.x = 640; 1413 s_serveroptions.next.generic.y = 480-64-72; 1414 s_serveroptions.next.generic.statusbar = ServerOptions_StatusBar; 1415 s_serveroptions.next.width = 128; 1416 s_serveroptions.next.height = 64; 1417 s_serveroptions.next.focuspic = GAMESERVER_NEXT1; 1418 1419 s_serveroptions.go.generic.type = MTYPE_BITMAP; 1420 s_serveroptions.go.generic.name = GAMESERVER_FIGHT0; 1421 s_serveroptions.go.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; 1422 s_serveroptions.go.generic.callback = ServerOptions_Event; 1423 s_serveroptions.go.generic.id = ID_GO; 1424 s_serveroptions.go.generic.x = 640; 1425 s_serveroptions.go.generic.y = 480-64; 1426 s_serveroptions.go.width = 128; 1427 s_serveroptions.go.height = 64; 1428 s_serveroptions.go.focuspic = GAMESERVER_FIGHT1; 1429 1430 Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.banner ); 1431 1432 Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.mappic ); 1433 Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.picframe ); 1434 1435 Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.botSkill ); 1436 Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.player0 ); 1437 for( n = 0; n < PLAYER_SLOTS; n++ ) { 1438 if( n != 0 ) { 1439 Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.playerType[n] ); 1440 } 1441 Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.playerName[n] ); 1442 if( s_serveroptions.gametype >= GT_TEAM ) { 1443 Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.playerTeam[n] ); 1444 } 1445 } 1446 1447 if( s_serveroptions.gametype != GT_CTF ) { 1448 Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.fraglimit ); 1449 } 1450 else { 1451 Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.flaglimit ); 1452 } 1453 Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.timelimit ); 1454 if( s_serveroptions.gametype >= GT_TEAM ) { 1455 Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.friendlyfire ); 1456 } 1457 Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.pure ); 1458 if( s_serveroptions.multiplayer ) { 1459 Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.dedicated ); 1460 } 1461 if( s_serveroptions.multiplayer ) { 1462 Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.hostname ); 1463 } 1464 1465 Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.back ); 1466 Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.next ); 1467 Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.go ); 1468 1469 Menu_AddItem( &s_serveroptions.menu, (void*) &s_serveroptions.punkbuster ); 1470 1471 ServerOptions_SetMenuItems(); 1472 } 1473 1474 /* 1475 ================= 1476 ServerOptions_Cache 1477 ================= 1478 */ 1479 void ServerOptions_Cache( void ) { 1480 trap_R_RegisterShaderNoMip( GAMESERVER_BACK0 ); 1481 trap_R_RegisterShaderNoMip( GAMESERVER_BACK1 ); 1482 trap_R_RegisterShaderNoMip( GAMESERVER_FIGHT0 ); 1483 trap_R_RegisterShaderNoMip( GAMESERVER_FIGHT1 ); 1484 trap_R_RegisterShaderNoMip( GAMESERVER_SELECT ); 1485 trap_R_RegisterShaderNoMip( GAMESERVER_UNKNOWNMAP ); 1486 } 1487 1488 1489 /* 1490 ================= 1491 UI_ServerOptionsMenu 1492 ================= 1493 */ 1494 static void UI_ServerOptionsMenu( qboolean multiplayer ) { 1495 ServerOptions_MenuInit( multiplayer ); 1496 UI_PushMenu( &s_serveroptions.menu ); 1497 } 1498 1499 1500 1501 /* 1502 ============================================================================= 1503 1504 BOT SELECT MENU ***** 1505 1506 ============================================================================= 1507 */ 1508 1509 1510 #define BOTSELECT_BACK0 "menu/art/back_0" 1511 #define BOTSELECT_BACK1 "menu/art/back_1" 1512 #define BOTSELECT_ACCEPT0 "menu/art/accept_0" 1513 #define BOTSELECT_ACCEPT1 "menu/art/accept_1" 1514 #define BOTSELECT_SELECT "menu/art/opponents_select" 1515 #define BOTSELECT_SELECTED "menu/art/opponents_selected" 1516 #define BOTSELECT_ARROWS "menu/art/gs_arrows_0" 1517 #define BOTSELECT_ARROWSL "menu/art/gs_arrows_l" 1518 #define BOTSELECT_ARROWSR "menu/art/gs_arrows_r" 1519 1520 #define PLAYERGRID_COLS 4 1521 #define PLAYERGRID_ROWS 4 1522 #define MAX_MODELSPERPAGE (PLAYERGRID_ROWS * PLAYERGRID_COLS) 1523 1524 1525 typedef struct { 1526 menuframework_s menu; 1527 1528 menutext_s banner; 1529 1530 menubitmap_s pics[MAX_MODELSPERPAGE]; 1531 menubitmap_s picbuttons[MAX_MODELSPERPAGE]; 1532 menutext_s picnames[MAX_MODELSPERPAGE]; 1533 1534 menubitmap_s arrows; 1535 menubitmap_s left; 1536 menubitmap_s right; 1537 1538 menubitmap_s go; 1539 menubitmap_s back; 1540 1541 int numBots; 1542 int modelpage; 1543 int numpages; 1544 int selectedmodel; 1545 int sortedBotNums[MAX_BOTS]; 1546 char boticons[MAX_MODELSPERPAGE][MAX_QPATH]; 1547 char botnames[MAX_MODELSPERPAGE][16]; 1548 } botSelectInfo_t; 1549 1550 static botSelectInfo_t botSelectInfo; 1551 1552 1553 /* 1554 ================= 1555 UI_BotSelectMenu_SortCompare 1556 ================= 1557 */ 1558 static int QDECL UI_BotSelectMenu_SortCompare( const void *arg1, const void *arg2 ) { 1559 int num1, num2; 1560 const char *info1, *info2; 1561 const char *name1, *name2; 1562 1563 num1 = *(int *)arg1; 1564 num2 = *(int *)arg2; 1565 1566 info1 = UI_GetBotInfoByNumber( num1 ); 1567 info2 = UI_GetBotInfoByNumber( num2 ); 1568 1569 name1 = Info_ValueForKey( info1, "name" ); 1570 name2 = Info_ValueForKey( info2, "name" ); 1571 1572 return Q_stricmp( name1, name2 ); 1573 } 1574 1575 1576 /* 1577 ================= 1578 UI_BotSelectMenu_BuildList 1579 ================= 1580 */ 1581 static void UI_BotSelectMenu_BuildList( void ) { 1582 int n; 1583 1584 botSelectInfo.modelpage = 0; 1585 botSelectInfo.numBots = UI_GetNumBots(); 1586 botSelectInfo.numpages = botSelectInfo.numBots / MAX_MODELSPERPAGE; 1587 if( botSelectInfo.numBots % MAX_MODELSPERPAGE ) { 1588 botSelectInfo.numpages++; 1589 } 1590 1591 // initialize the array 1592 for( n = 0; n < botSelectInfo.numBots; n++ ) { 1593 botSelectInfo.sortedBotNums[n] = n; 1594 } 1595 1596 // now sort it 1597 qsort( botSelectInfo.sortedBotNums, botSelectInfo.numBots, sizeof(botSelectInfo.sortedBotNums[0]), UI_BotSelectMenu_SortCompare ); 1598 } 1599 1600 1601 /* 1602 ================= 1603 ServerPlayerIcon 1604 ================= 1605 */ 1606 static void ServerPlayerIcon( const char *modelAndSkin, char *iconName, int iconNameMaxSize ) { 1607 char *skin; 1608 char model[MAX_QPATH]; 1609 1610 Q_strncpyz( model, modelAndSkin, sizeof(model)); 1611 skin = Q_strrchr( model, '/' ); 1612 if ( skin ) { 1613 *skin++ = '\0'; 1614 } 1615 else { 1616 skin = "default"; 1617 } 1618 1619 Com_sprintf(iconName, iconNameMaxSize, "models/players/%s/icon_%s.tga", model, skin ); 1620 1621 if( !trap_R_RegisterShaderNoMip( iconName ) && Q_stricmp( skin, "default" ) != 0 ) { 1622 Com_sprintf(iconName, iconNameMaxSize, "models/players/%s/icon_default.tga", model ); 1623 } 1624 } 1625 1626 1627 /* 1628 ================= 1629 UI_BotSelectMenu_UpdateGrid 1630 ================= 1631 */ 1632 static void UI_BotSelectMenu_UpdateGrid( void ) { 1633 const char *info; 1634 int i; 1635 int j; 1636 1637 j = botSelectInfo.modelpage * MAX_MODELSPERPAGE; 1638 for( i = 0; i < (PLAYERGRID_ROWS * PLAYERGRID_COLS); i++, j++) { 1639 if( j < botSelectInfo.numBots ) { 1640 info = UI_GetBotInfoByNumber( botSelectInfo.sortedBotNums[j] ); 1641 ServerPlayerIcon( Info_ValueForKey( info, "model" ), botSelectInfo.boticons[i], MAX_QPATH ); 1642 Q_strncpyz( botSelectInfo.botnames[i], Info_ValueForKey( info, "name" ), 16 ); 1643 Q_CleanStr( botSelectInfo.botnames[i] ); 1644 botSelectInfo.pics[i].generic.name = botSelectInfo.boticons[i]; 1645 if( BotAlreadySelected( botSelectInfo.botnames[i] ) ) { 1646 botSelectInfo.picnames[i].color = color_red; 1647 } 1648 else { 1649 botSelectInfo.picnames[i].color = color_orange; 1650 } 1651 botSelectInfo.picbuttons[i].generic.flags &= ~QMF_INACTIVE; 1652 } 1653 else { 1654 // dead slot 1655 botSelectInfo.pics[i].generic.name = NULL; 1656 botSelectInfo.picbuttons[i].generic.flags |= QMF_INACTIVE; 1657 botSelectInfo.botnames[i][0] = 0; 1658 } 1659 1660 botSelectInfo.pics[i].generic.flags &= ~QMF_HIGHLIGHT; 1661 botSelectInfo.pics[i].shader = 0; 1662 botSelectInfo.picbuttons[i].generic.flags |= QMF_PULSEIFFOCUS; 1663 } 1664 1665 // set selected model 1666 i = botSelectInfo.selectedmodel % MAX_MODELSPERPAGE; 1667 botSelectInfo.pics[i].generic.flags |= QMF_HIGHLIGHT; 1668 botSelectInfo.picbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS; 1669 1670 if( botSelectInfo.numpages > 1 ) { 1671 if( botSelectInfo.modelpage > 0 ) { 1672 botSelectInfo.left.generic.flags &= ~QMF_INACTIVE; 1673 } 1674 else { 1675 botSelectInfo.left.generic.flags |= QMF_INACTIVE; 1676 } 1677 1678 if( botSelectInfo.modelpage < (botSelectInfo.numpages - 1) ) { 1679 botSelectInfo.right.generic.flags &= ~QMF_INACTIVE; 1680 } 1681 else { 1682 botSelectInfo.right.generic.flags |= QMF_INACTIVE; 1683 } 1684 } 1685 else { 1686 // hide left/right markers 1687 botSelectInfo.left.generic.flags |= QMF_INACTIVE; 1688 botSelectInfo.right.generic.flags |= QMF_INACTIVE; 1689 } 1690 } 1691 1692 1693 /* 1694 ================= 1695 UI_BotSelectMenu_Default 1696 ================= 1697 */ 1698 static void UI_BotSelectMenu_Default( char *bot ) { 1699 const char *botInfo; 1700 const char *test; 1701 int n; 1702 int i; 1703 1704 for( n = 0; n < botSelectInfo.numBots; n++ ) { 1705 botInfo = UI_GetBotInfoByNumber( n ); 1706 test = Info_ValueForKey( botInfo, "name" ); 1707 if( Q_stricmp( bot, test ) == 0 ) { 1708 break; 1709 } 1710 } 1711 if( n == botSelectInfo.numBots ) { 1712 botSelectInfo.selectedmodel = 0; 1713 return; 1714 } 1715 1716 for( i = 0; i < botSelectInfo.numBots; i++ ) { 1717 if( botSelectInfo.sortedBotNums[i] == n ) { 1718 break; 1719 } 1720 } 1721 if( i == botSelectInfo.numBots ) { 1722 botSelectInfo.selectedmodel = 0; 1723 return; 1724 } 1725 1726 botSelectInfo.selectedmodel = i; 1727 } 1728 1729 1730 /* 1731 ================= 1732 UI_BotSelectMenu_LeftEvent 1733 ================= 1734 */ 1735 static void UI_BotSelectMenu_LeftEvent( void* ptr, int event ) { 1736 if( event != QM_ACTIVATED ) { 1737 return; 1738 } 1739 if( botSelectInfo.modelpage > 0 ) { 1740 botSelectInfo.modelpage--; 1741 botSelectInfo.selectedmodel = botSelectInfo.modelpage * MAX_MODELSPERPAGE; 1742 UI_BotSelectMenu_UpdateGrid(); 1743 } 1744 } 1745 1746 1747 /* 1748 ================= 1749 UI_BotSelectMenu_RightEvent 1750 ================= 1751 */ 1752 static void UI_BotSelectMenu_RightEvent( void* ptr, int event ) { 1753 if( event != QM_ACTIVATED ) { 1754 return; 1755 } 1756 if( botSelectInfo.modelpage < botSelectInfo.numpages - 1 ) { 1757 botSelectInfo.modelpage++; 1758 botSelectInfo.selectedmodel = botSelectInfo.modelpage * MAX_MODELSPERPAGE; 1759 UI_BotSelectMenu_UpdateGrid(); 1760 } 1761 } 1762 1763 1764 /* 1765 ================= 1766 UI_BotSelectMenu_BotEvent 1767 ================= 1768 */ 1769 static void UI_BotSelectMenu_BotEvent( void* ptr, int event ) { 1770 int i; 1771 1772 if( event != QM_ACTIVATED ) { 1773 return; 1774 } 1775 1776 for( i = 0; i < (PLAYERGRID_ROWS * PLAYERGRID_COLS); i++ ) { 1777 botSelectInfo.pics[i].generic.flags &= ~QMF_HIGHLIGHT; 1778 botSelectInfo.picbuttons[i].generic.flags |= QMF_PULSEIFFOCUS; 1779 } 1780 1781 // set selected 1782 i = ((menucommon_s*)ptr)->id; 1783 botSelectInfo.pics[i].generic.flags |= QMF_HIGHLIGHT; 1784 botSelectInfo.picbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS; 1785 botSelectInfo.selectedmodel = botSelectInfo.modelpage * MAX_MODELSPERPAGE + i; 1786 } 1787 1788 1789 /* 1790 ================= 1791 UI_BotSelectMenu_BackEvent 1792 ================= 1793 */ 1794 static void UI_BotSelectMenu_BackEvent( void* ptr, int event ) { 1795 if( event != QM_ACTIVATED ) { 1796 return; 1797 } 1798 UI_PopMenu(); 1799 } 1800 1801 1802 /* 1803 ================= 1804 UI_BotSelectMenu_SelectEvent 1805 ================= 1806 */ 1807 static void UI_BotSelectMenu_SelectEvent( void* ptr, int event ) { 1808 if( event != QM_ACTIVATED ) { 1809 return; 1810 } 1811 UI_PopMenu(); 1812 1813 s_serveroptions.newBot = qtrue; 1814 Q_strncpyz( s_serveroptions.newBotName, botSelectInfo.botnames[botSelectInfo.selectedmodel % MAX_MODELSPERPAGE], 16 ); 1815 } 1816 1817 1818 /* 1819 ================= 1820 UI_BotSelectMenu_Cache 1821 ================= 1822 */ 1823 void UI_BotSelectMenu_Cache( void ) { 1824 trap_R_RegisterShaderNoMip( BOTSELECT_BACK0 ); 1825 trap_R_RegisterShaderNoMip( BOTSELECT_BACK1 ); 1826 trap_R_RegisterShaderNoMip( BOTSELECT_ACCEPT0 ); 1827 trap_R_RegisterShaderNoMip( BOTSELECT_ACCEPT1 ); 1828 trap_R_RegisterShaderNoMip( BOTSELECT_SELECT ); 1829 trap_R_RegisterShaderNoMip( BOTSELECT_SELECTED ); 1830 trap_R_RegisterShaderNoMip( BOTSELECT_ARROWS ); 1831 trap_R_RegisterShaderNoMip( BOTSELECT_ARROWSL ); 1832 trap_R_RegisterShaderNoMip( BOTSELECT_ARROWSR ); 1833 } 1834 1835 1836 static void UI_BotSelectMenu_Init( char *bot ) { 1837 int i, j, k; 1838 int x, y; 1839 1840 memset( &botSelectInfo, 0 ,sizeof(botSelectInfo) ); 1841 botSelectInfo.menu.wrapAround = qtrue; 1842 botSelectInfo.menu.fullscreen = qtrue; 1843 1844 UI_BotSelectMenu_Cache(); 1845 1846 botSelectInfo.banner.generic.type = MTYPE_BTEXT; 1847 botSelectInfo.banner.generic.x = 320; 1848 botSelectInfo.banner.generic.y = 16; 1849 botSelectInfo.banner.string = "SELECT BOT"; 1850 botSelectInfo.banner.color = color_white; 1851 botSelectInfo.banner.style = UI_CENTER; 1852 1853 y = 80; 1854 for( i = 0, k = 0; i < PLAYERGRID_ROWS; i++) { 1855 x = 180; 1856 for( j = 0; j < PLAYERGRID_COLS; j++, k++ ) { 1857 botSelectInfo.pics[k].generic.type = MTYPE_BITMAP; 1858 botSelectInfo.pics[k].generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE; 1859 botSelectInfo.pics[k].generic.x = x; 1860 botSelectInfo.pics[k].generic.y = y; 1861 botSelectInfo.pics[k].generic.name = botSelectInfo.boticons[k]; 1862 botSelectInfo.pics[k].width = 64; 1863 botSelectInfo.pics[k].height = 64; 1864 botSelectInfo.pics[k].focuspic = BOTSELECT_SELECTED; 1865 botSelectInfo.pics[k].focuscolor = colorRed; 1866 1867 botSelectInfo.picbuttons[k].generic.type = MTYPE_BITMAP; 1868 botSelectInfo.picbuttons[k].generic.flags = QMF_LEFT_JUSTIFY|QMF_NODEFAULTINIT|QMF_PULSEIFFOCUS; 1869 botSelectInfo.picbuttons[k].generic.callback = UI_BotSelectMenu_BotEvent; 1870 botSelectInfo.picbuttons[k].generic.id = k; 1871 botSelectInfo.picbuttons[k].generic.x = x - 16; 1872 botSelectInfo.picbuttons[k].generic.y = y - 16; 1873 botSelectInfo.picbuttons[k].generic.left = x; 1874 botSelectInfo.picbuttons[k].generic.top = y; 1875 botSelectInfo.picbuttons[k].generic.right = x + 64; 1876 botSelectInfo.picbuttons[k].generic.bottom = y + 64; 1877 botSelectInfo.picbuttons[k].width = 128; 1878 botSelectInfo.picbuttons[k].height = 128; 1879 botSelectInfo.picbuttons[k].focuspic = BOTSELECT_SELECT; 1880 botSelectInfo.picbuttons[k].focuscolor = colorRed; 1881 1882 botSelectInfo.picnames[k].generic.type = MTYPE_TEXT; 1883 botSelectInfo.picnames[k].generic.flags = QMF_SMALLFONT; 1884 botSelectInfo.picnames[k].generic.x = x + 32; 1885 botSelectInfo.picnames[k].generic.y = y + 64; 1886 botSelectInfo.picnames[k].string = botSelectInfo.botnames[k]; 1887 botSelectInfo.picnames[k].color = color_orange; 1888 botSelectInfo.picnames[k].style = UI_CENTER|UI_SMALLFONT; 1889 1890 x += (64 + 6); 1891 } 1892 y += (64 + SMALLCHAR_HEIGHT + 6); 1893 } 1894 1895 botSelectInfo.arrows.generic.type = MTYPE_BITMAP; 1896 botSelectInfo.arrows.generic.name = BOTSELECT_ARROWS; 1897 botSelectInfo.arrows.generic.flags = QMF_INACTIVE; 1898 botSelectInfo.arrows.generic.x = 260; 1899 botSelectInfo.arrows.generic.y = 440; 1900 botSelectInfo.arrows.width = 128; 1901 botSelectInfo.arrows.height = 32; 1902 1903 botSelectInfo.left.generic.type = MTYPE_BITMAP; 1904 botSelectInfo.left.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; 1905 botSelectInfo.left.generic.callback = UI_BotSelectMenu_LeftEvent; 1906 botSelectInfo.left.generic.x = 260; 1907 botSelectInfo.left.generic.y = 440; 1908 botSelectInfo.left.width = 64; 1909 botSelectInfo.left.height = 32; 1910 botSelectInfo.left.focuspic = BOTSELECT_ARROWSL; 1911 1912 botSelectInfo.right.generic.type = MTYPE_BITMAP; 1913 botSelectInfo.right.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; 1914 botSelectInfo.right.generic.callback = UI_BotSelectMenu_RightEvent; 1915 botSelectInfo.right.generic.x = 321; 1916 botSelectInfo.right.generic.y = 440; 1917 botSelectInfo.right.width = 64; 1918 botSelectInfo.right.height = 32; 1919 botSelectInfo.right.focuspic = BOTSELECT_ARROWSR; 1920 1921 botSelectInfo.back.generic.type = MTYPE_BITMAP; 1922 botSelectInfo.back.generic.name = BOTSELECT_BACK0; 1923 botSelectInfo.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; 1924 botSelectInfo.back.generic.callback = UI_BotSelectMenu_BackEvent; 1925 botSelectInfo.back.generic.x = 0; 1926 botSelectInfo.back.generic.y = 480-64; 1927 botSelectInfo.back.width = 128; 1928 botSelectInfo.back.height = 64; 1929 botSelectInfo.back.focuspic = BOTSELECT_BACK1; 1930 1931 botSelectInfo.go.generic.type = MTYPE_BITMAP; 1932 botSelectInfo.go.generic.name = BOTSELECT_ACCEPT0; 1933 botSelectInfo.go.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; 1934 botSelectInfo.go.generic.callback = UI_BotSelectMenu_SelectEvent; 1935 botSelectInfo.go.generic.x = 640; 1936 botSelectInfo.go.generic.y = 480-64; 1937 botSelectInfo.go.width = 128; 1938 botSelectInfo.go.height = 64; 1939 botSelectInfo.go.focuspic = BOTSELECT_ACCEPT1; 1940 1941 Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.banner ); 1942 for( i = 0; i < MAX_MODELSPERPAGE; i++ ) { 1943 Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.pics[i] ); 1944 Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.picbuttons[i] ); 1945 Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.picnames[i] ); 1946 } 1947 Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.arrows ); 1948 Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.left ); 1949 Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.right ); 1950 Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.back ); 1951 Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.go ); 1952 1953 UI_BotSelectMenu_BuildList(); 1954 UI_BotSelectMenu_Default( bot ); 1955 botSelectInfo.modelpage = botSelectInfo.selectedmodel / MAX_MODELSPERPAGE; 1956 UI_BotSelectMenu_UpdateGrid(); 1957 } 1958 1959 1960 /* 1961 ================= 1962 UI_BotSelectMenu 1963 ================= 1964 */ 1965 void UI_BotSelectMenu( char *bot ) { 1966 UI_BotSelectMenu_Init( bot ); 1967 UI_PushMenu( &botSelectInfo.menu ); 1968 }