/* Copyright (C) 1997-2001 Id Software, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "ui_local.h" void M_RefreshScrollWindowList( void ); //pinging #define PING_ONCE static unsigned int nextServerTime = 0; static unsigned int nextPingTime = 0; /* ============================================================================= JOIN SERVER MENU ============================================================================= */ static menuframework_s s_joinserver_menu; static menucommon_t *menuitem_fullfilter; static menucommon_t *menuitem_emptyfilter; static menucommon_t *menuitem_skillfilter; static menucommon_t *menuitem_passwordfilter; static menucommon_t *menuitem_gametypefilter; static menucommon_t *menuitem_maxpingfilter; #ifdef BATTLEYE static menucommon_t *menuitem_battleyefilter; #endif typedef struct server_s { char hostname[80]; char map[80]; int curuser; int maxuser; int bots; char gametype[80]; int skilllevel; int id; qboolean password; unsigned int ping; unsigned int ping_retries; qboolean displayed; #ifdef BATTLEYE int battleye; #endif char address[80]; struct server_s *pnext; } server_t; server_t *servers; int numServers; char ui_responseToken[MAX_TOKEN_CHARS]; //================== //UI_GetResponseToken //================== char *UI_GetResponseToken( char **data_p ) { int c; int len; unsigned backlen; char *data; data = *data_p; len = 0; ui_responseToken[0] = 0; if( !data ) { *data_p = NULL; return ""; } backlen = strlen( data ); if( backlen < strlen("\\EOT") ) { *data_p = NULL; return ""; } skipbackslash: c = *data; if( c == '\\' ) { if( data[1] == '\\' ) { data += 2; goto skipbackslash; } } if( !c ) { *data_p = NULL; return ""; } do { if( len < MAX_TOKEN_CHARS ) { ui_responseToken[len] = c; len++; } data++; c = *data; }while( c && c != '\\' ); if( len == MAX_TOKEN_CHARS ) { len = 0; } ui_responseToken[len] = 0; *data_p = data; return ui_responseToken; } //================== //FreeServerlist //================== void M_FreeServerlist( void ) { server_t *ptr; while( servers ) { ptr = servers; servers = ptr->pnext; UI_Free(ptr); } servers = NULL; numServers = 0; M_RefreshScrollWindowList(); } //================== //M_RegisterServerItem //================== server_t *M_RegisterServerItem( char *adr, char *info ) { server_t *newserv, *checkserv; //check for the address being already in the list checkserv = servers; while( checkserv ) { if( !Q_stricmp( adr, checkserv->address ) ) return checkserv; checkserv = checkserv->pnext; } newserv = (server_t*)UI_Malloc(sizeof(server_t)); Q_strncpyz( newserv->address, adr, sizeof(newserv->address) ); // fill in fields with empty msgs, in case any of them isn't received Q_snprintfz( newserv->hostname, sizeof(newserv->hostname), "Unnamed Server" ); Q_snprintfz( newserv->map, sizeof(newserv->map), "Unknown" ); Q_snprintfz( newserv->gametype, sizeof(newserv->gametype), "Unknown" ); newserv->curuser = -1; newserv->maxuser = -1; newserv->skilllevel = 1; newserv->password = qfalse; newserv->bots = 0; newserv->ping = 9999; newserv->ping_retries = 0; #ifdef BATTLEYE newserv->battleye = 0; #endif // set up the actual new item newserv->pnext = servers; servers = newserv; newserv->id = numServers; numServers++; return newserv; } //================== //M_AddToServerList // The client sent us a new server adress for our list //================== void M_AddToServerList( char *adr, char *info ) { server_t *newserv; int l; char *pntr; char *tok; qboolean need_refresh = qfalse; newserv = M_RegisterServerItem( adr, info ); // parse the info string pntr = info; if( strstr(pntr, "\\") == NULL ) // temp: check for old formatting { pntr = info; l = strlen(pntr) - 15; Q_snprintfz( newserv->hostname, l, "%s", pntr ); newserv->hostname[l] = '\0'; pntr += l; l = strlen(pntr) - 6; Q_snprintfz( newserv->map, l, "%s", pntr ); newserv->map[l] = '\0'; pntr += l; sscanf( pntr, "%d/%d", &newserv->curuser, &newserv->maxuser ); } else { // new formatting pntr = info; while( &pntr ) { tok = UI_GetResponseToken( &pntr ); if( !tok || !strlen(tok) || !Q_stricmp(tok, "EOT")) break; // got cmd if( !Q_stricmp(tok, "n") ) { tok = UI_GetResponseToken( &pntr ); if( !tok || !strlen(tok) || !Q_stricmp(tok, "EOT")) break; if( Q_stricmp( newserv->hostname, tok ) ) { need_refresh = qtrue; Q_snprintfz( newserv->hostname, sizeof(newserv->hostname), tok ); } continue; } // got cmd if( !Q_stricmp(tok, "m") ) { tok = UI_GetResponseToken( &pntr ); if( !tok || !strlen(tok) || !Q_stricmp(tok, "EOT")) break; while( *tok == ' ' )tok++; // remove spaces in front of the gametype name if( Q_stricmp( newserv->map, tok ) ) { need_refresh = qtrue; Q_snprintfz( newserv->map, sizeof(newserv->map), tok ); } continue; } // got cmd if( !Q_stricmp(tok, "u") ) { int curuser, maxuser; tok = UI_GetResponseToken( &pntr ); if( !tok || !strlen(tok) || !Q_stricmp(tok, "EOT")) break; sscanf( tok, "%d/%d", &curuser, &maxuser ); if( curuser != newserv->curuser || maxuser != newserv->maxuser ) { need_refresh = qtrue; newserv->curuser = curuser; newserv->maxuser = maxuser; } continue; } // got cmd if( !Q_stricmp(tok, "b") ) { int bots; tok = UI_GetResponseToken( &pntr ); if( !tok || !strlen(tok) || !Q_stricmp(tok, "EOT")) break; bots = atoi(tok); if( bots != newserv->bots ) { need_refresh = qtrue; newserv->bots = bots; } continue; } // got cmd if( !Q_stricmp(tok, "g") ) { tok = UI_GetResponseToken( &pntr ); if( !tok || !strlen(tok) || !Q_stricmp(tok, "EOT")) break; while( *tok == ' ' )tok++; // remove spaces in front of the gametype name if( Q_stricmp( newserv->gametype, tok ) ) { need_refresh = qtrue; Q_snprintfz( newserv->gametype, sizeof(newserv->gametype), tok ); } continue; } // got cmd if( !Q_stricmp(tok, "s") ) { int skilllevel; tok = UI_GetResponseToken( &pntr ); if( !tok || !strlen(tok) || !Q_stricmp(tok, "EOT")) break; skilllevel = atoi(tok); if( skilllevel != newserv->skilllevel ) { need_refresh = qtrue; newserv->skilllevel = skilllevel; } continue; } // got cmd if( !Q_stricmp(tok, "p") ) { int password; tok = UI_GetResponseToken( &pntr ); if( !tok || !strlen(tok) || !Q_stricmp(tok, "EOT")) break; password = (atoi(tok)); if( password != newserv->password ) { need_refresh = qtrue; newserv->password = password; } continue; } #ifdef BATTLEYE // got cmd if( !Q_stricmp(tok, "be") ) { int battleye; tok = UI_GetResponseToken( &pntr ); if( !tok || !strlen(tok) || !Q_stricmp(tok, "EOT")) break; battleye = (atoi(tok)); if( battleye != newserv->battleye ) { need_refresh = qtrue; newserv->battleye = battleye; } continue; } #endif // got cmd if( !Q_stricmp(tok, "ping") ) { int ping; tok = UI_GetResponseToken( &pntr ); if( !tok || !strlen(tok) || !Q_stricmp(tok, "EOT")) break; ping = (atoi(tok)); if( ping != newserv->ping || newserv->ping_retries == 0 ) { need_refresh = qtrue; #ifdef PING_ONCE newserv->ping = ping; nextServerTime = uis.time; #else if( newserv->ping < 999 && ping < 999 ) { newserv->ping = (newserv->ping + ping) * 0.5; } else { newserv->ping = ping; } #endif if( newserv->ping > 999 ) newserv->ping = 999; } continue; } Com_Printf( "UI:M_AddToServerList(%s): Unknown token:\"%s\"\n", adr, tok ); } } if( need_refresh ) M_RefreshScrollWindowList(); } #define SERVER_PINGING_MINRETRY 50 #define SERVER_PINGING_MAXRETRYTIMEOUTS 1 //================== //GetNextServerToPing - Get a non yet pinged server //================== server_t *GetNextServerToPing( void ) { server_t *server; server = servers; while( server ) { if( server->ping > 999 && server->ping_retries < SERVER_PINGING_MAXRETRYTIMEOUTS ) return server; server = server->pnext; } return NULL; } //================== //PingServers //================== void PingServers( void ) { static server_t *pingingServer = NULL; server_t *server; if( nextServerTime > uis.time ) { // it's not time to move into the next server yet, keep trying current if( pingingServer ) { if( nextPingTime > uis.time ) return; nextPingTime = uis.time + SERVER_PINGING_MINRETRY; trap_Cmd_ExecuteText( EXEC_APPEND, va( "pingserver %s", pingingServer->address ) ); } return; } if( nextServerTime <= uis.time && pingingServer && pingingServer->ping > SERVER_PINGING_TIMEOUT ) UI_Printf( "Server %s timed out\n", pingingServer?pingingServer->address:""); nextServerTime = uis.time + SERVER_PINGING_MINRETRY; server = GetNextServerToPing(); if( !server ) { pingingServer = NULL; return; } server->ping_retries++; pingingServer = server; #ifdef PING_ONCE trap_Cmd_ExecuteText( EXEC_APPEND, va( "pingserver %s", pingingServer->address ) ); nextPingTime = nextServerTime; #else nextPingTime = uis.time + (SERVER_PINGING_MINRETRY/2); #endif } //================== //ResetAllPings //================== void ResetAllPings( void ) { server_t *server; server = servers; while( server ) { server->ping = 9999; server->ping_retries = 0; server = server->pnext; } nextServerTime = uis.time; } //================== //SearchGames //================== void SearchGames( char *s ) { char *mlist, *master; int ignore_empty = 0; int ignore_full = 0; #ifdef PING_ONCE // clear all ping values so they are retried ResetAllPings(); #endif //"show all", "is", "is not", 0 if( menuitem_emptyfilter ) ignore_empty = (menuitem_emptyfilter->curvalue == 2); if( menuitem_fullfilter ) ignore_full = (menuitem_fullfilter->curvalue == 2); mlist = trap_Cvar_VariableString("masterservers"); if( !mlist || !(*mlist) ) { Menu_SetStatusBar( &s_joinserver_menu, "No master server defined" ); return; } if( !Q_stricmp( s, "local" ) ) { // send out request trap_Cmd_ExecuteText( EXEC_APPEND, va("requestservers %s %s %s\n", s, ignore_full ? "" : "full", ignore_empty ? "" : "empty" ) ); return; } // request to each ip on the list while( mlist ) { master = COM_Parse( &mlist ); if ( !master || !(*master) ) break; // send out request trap_Cmd_ExecuteText( EXEC_APPEND, va("requestservers %s %s %s %s %s\n", s, master, GAMENAME, ignore_full ? "" : "full", ignore_empty ? "" : "empty" ) ); } } //============================================================================= // scroll list //============================================================================= m_itemslisthead_t serversScrollList; //================== //GetBestNextPingServer //================== server_t *GetBestNextPingServer( server_t *server ) { server_t *ptr = servers, *best = NULL; unsigned int minping = 0, bestping = 1000; // > 1000 = not pinged, < 1000 = pinged if( server ) minping = server->ping; while( ptr ) { if( ptr->displayed == qfalse && ptr->ping >= minping ) { if( ptr->ping < bestping ) { best = ptr; bestping = ptr->ping; } } ptr = ptr->pnext; } if( best != NULL ) best->displayed = qtrue; return best; } //================== //M_RefreshScrollWindowList //================== void M_RefreshScrollWindowList( void ) { server_t *ptr = NULL; qboolean add; int addedItems = 0; UI_FreeScrollItemList( &serversScrollList ); // mark all servers as not added ptr = servers; while( ptr ) { ptr->displayed = qfalse; ptr = ptr->pnext; } while( (ptr = GetBestNextPingServer( ptr )) != NULL ) { add = qtrue; // ignore if full (local) if( menuitem_fullfilter && menuitem_fullfilter->curvalue ) { int full = ( ptr->curuser && (ptr->curuser == ptr->maxuser) ); if( menuitem_fullfilter->curvalue - 1 == full ) { add = qfalse; } } // ignore if empty (local) if( menuitem_emptyfilter && menuitem_emptyfilter->curvalue ) { int empty = ( ptr->curuser != 0 ); if( menuitem_emptyfilter->curvalue - 1 != empty ) { add = qfalse; } } // ignore if it has password and we are filtering those if( menuitem_passwordfilter && menuitem_passwordfilter->curvalue ) { if( menuitem_passwordfilter->curvalue - 1 == ptr->password ) { add = qfalse; } } #ifdef BATTLEYE // ignore if it has battleye and we are filtering those if( menuitem_battleyefilter && menuitem_battleyefilter->curvalue ) { if( menuitem_battleyefilter->curvalue - 1 != ptr->battleye ) { add = qfalse; } } #endif // ignore if it's of filtered ping if( menuitem_maxpingfilter && (int)trap_Cvar_VariableValue("ui_filter_ping") ) { if( ptr->ping > trap_Cvar_VariableValue("ui_filter_ping") ) { add = qfalse; } } // ignore if it's of filtered gametype if( menuitem_gametypefilter && menuitem_gametypefilter->curvalue ) { if( Q_stricmp(menuitem_gametypefilter->itemnames[menuitem_gametypefilter->curvalue], ptr->gametype) ) { add = qfalse; } } // ignore if it's of filtered skill if( menuitem_skillfilter && menuitem_skillfilter->curvalue ) { if( menuitem_skillfilter->curvalue - 1 != ptr->skilllevel ) { add = qfalse; } } if( add )UI_AddItemToScrollList( &serversScrollList, va("%i", addedItems++), (void *)ptr ); } } //============================================================================= // Servers window //============================================================================= static int MAX_MENU_SERVERS = 12; static int scrollbar_curvalue = 0; #define NO_SERVER_STRING "" #define NO_MAP_STRING "..." #define NO_USERS_STRING "..." #define NO_GAMETYPE_STRING "..." //================== //M_Connect_UpdateFiltersSettings //================== void M_Connect_UpdateFiltersSettings( menucommon_t *menuitem ) { // remember filter options by using cvars if( menuitem_fullfilter )trap_Cvar_SetValue( "ui_filter_full", menuitem_fullfilter->curvalue ); if( menuitem_emptyfilter )trap_Cvar_SetValue( "ui_filter_empty", menuitem_emptyfilter->curvalue ); if( menuitem_passwordfilter )trap_Cvar_SetValue( "ui_filter_password", menuitem_passwordfilter->curvalue ); if( menuitem_skillfilter )trap_Cvar_SetValue( "ui_filter_skill", menuitem_skillfilter->curvalue ); if( menuitem_gametypefilter )trap_Cvar_SetValue( "ui_filter_gametype", menuitem_gametypefilter->curvalue ); if( menuitem_maxpingfilter )trap_Cvar_Set( "ui_filter_ping", UI_GetMenuitemFieldBuffer(menuitem_maxpingfilter) ); #ifdef BATTLEYE if( menuitem_battleyefilter )trap_Cvar_SetValue( "ui_filter_battleye", menuitem_battleyefilter->curvalue ); #endif M_RefreshScrollWindowList(); } //================== //M_Connect_UpdateScrollbar //================== void M_Connect_UpdateScrollbar( menucommon_t *menuitem ) { scrollbar_curvalue = menuitem->curvalue; menuitem->maxvalue = max( 0, serversScrollList.numItems - MAX_MENU_SERVERS ); } //================== //GetInforServerFunc //================== void GetInforServerFunc( menucommon_t *menuitem ) { char buffer[128]; server_t *server = NULL; m_listitem_t *listitem; menuitem->localdata[1] = menuitem->localdata[0] + scrollbar_curvalue; listitem = UI_FindItemInScrollListWithId( &serversScrollList, menuitem->localdata[1] ); if( listitem && listitem->data ) server = (server_t *)listitem->data; if( server ) { Q_snprintfz( buffer, sizeof(buffer), "getinfo %s\n", server->address ); trap_Cmd_ExecuteText( EXEC_APPEND, buffer ); } } //================== //M_Connect_Joinserver //================== void M_Connect_Joinserver( menucommon_t *menuitem ) { char buffer[128]; server_t *server = NULL; m_listitem_t *listitem; menuitem->localdata[1] = menuitem->localdata[0] + scrollbar_curvalue; listitem = UI_FindItemInScrollListWithId( &serversScrollList, menuitem->localdata[1] ); if( listitem && listitem->data ) server = (server_t *)listitem->data; if( server ) { Q_snprintfz( buffer, sizeof(buffer), "connect %s\n", server->address ); trap_Cmd_ExecuteText( EXEC_APPEND, buffer ); } } //================== //M_UpdateSeverButton //================== void M_UpdateSeverButton( menucommon_t *menuitem ) { server_t *server = NULL; m_listitem_t *listitem; menuitem->localdata[1] = menuitem->localdata[0] + scrollbar_curvalue; listitem = UI_FindItemInScrollListWithId( &serversScrollList, menuitem->localdata[1] ); if( listitem && listitem->data ) server = (server_t *)listitem->data; if( server ) { Q_snprintfz( menuitem->title , MAX_STRING_CHARS, "%s%-3.3s %-5.5s %s%-6.6s %s%-12.12s %s%-32.32s%s", S_COLOR_WHITE, va( "%i", server->ping ), va( "%i/%i", server->curuser, server->maxuser ), S_COLOR_YELLOW, server->gametype, S_COLOR_ORANGE, server->map, S_COLOR_WHITE, server->hostname, S_COLOR_WHITE ); } else Q_snprintfz(menuitem->title, MAX_STRING_CHARS, NO_SERVER_STRING); } static int lastSearchType = 0; static void SearchGamesFunc( menucommon_t *menuitem ) { menucommon_t *typemenuitem = UI_MenuItemByName( "m_connect_search_type" ); if( !typemenuitem ) return; clamp( typemenuitem->curvalue, 0, 1 ); if( lastSearchType != typemenuitem->curvalue ) { lastSearchType = typemenuitem->curvalue; M_FreeServerlist(); } SearchGames( typemenuitem->itemnames[typemenuitem->curvalue] ); } #ifdef BATTLEYE #ifdef WIN32 void ToggleCLBattleyeFunc( menucommon_t *menuitem ) { trap_Cvar_SetValue( "cl_battleye", (menuitem->curvalue != 0) ); } #endif #endif //================== //JoinServer_MenuInit //================== void JoinServer_MenuInit( void ) { menucommon_t *menuitem; menucommon_t *menuitem_filters_background; int i; int y = 0; int yoffset; static char sbar[64]; int scrollwindow_width, scrollwindow_height; static char *filter_names[] = { "show all", "show only", "don't show", 0 }; static char *search_names[] = { "global", "local", 0 }; static char *gametype_filternames[] = { "show all", "dm", "duel", "tdm", "ctf", "race", "midair", 0 }; static char *skill_filternames[] = { "show all", "beginner", "expert", "hardcore", 0 }; static char *battleye_filternames[] = { "show all", "disabled", "optional", "required", 0 }; // we have to open the cvars like this so they are created as CVAR_ARCHIVE trap_Cvar_Get( "ui_filter_full", "0", CVAR_ARCHIVE ); trap_Cvar_Get( "ui_filter_empty", "0", CVAR_ARCHIVE ); trap_Cvar_Get( "ui_filter_password", "0", CVAR_ARCHIVE ); trap_Cvar_Get( "ui_filter_skill", "1", CVAR_ARCHIVE ); trap_Cvar_Get( "ui_filter_gametype", "0", CVAR_ARCHIVE ); trap_Cvar_Get( "ui_filter_ping", "0", CVAR_ARCHIVE ); #ifdef BATTLEYE trap_Cvar_Get( "ui_filter_battleye", "0", CVAR_ARCHIVE ); #endif if( uis.vidWidth < 800 ) scrollwindow_width = uis.vidWidth * 0.85; else if( uis.vidWidth < 1024 ) scrollwindow_width = uis.vidWidth * 0.75; else scrollwindow_width = uis.vidWidth * 0.65; s_joinserver_menu.x = uis.vidWidth * 0.5; //fixme s_joinserver_menu.nitems = 0; yoffset = UI_SCALED_HEIGHT(72); // left space for the logo menuitem_filters_background = UI_InitMenuItem( "m_connect_filters", va("%sfilters",S_COLOR_WHITE) , -(scrollwindow_width/2), y+yoffset, MTYPE_SEPARATOR, ALIGN_LEFT_TOP, uis.fontSystemSmall, NULL ); Menu_AddItem( &s_joinserver_menu, menuitem_filters_background ); // create an associated picture to the items to act as window background menuitem = menuitem_filters_background; menuitem->pict.shader = uis.whiteShader; menuitem->pict.shaderHigh = NULL; Vector4Copy( colorMdGrey, menuitem->pict.color ); menuitem->pict.color[3] = 0.65f; menuitem->pict.yoffset = 0; menuitem->pict.xoffset = 0; menuitem->pict.width = scrollwindow_width; menuitem->pict.height = yoffset + menuitem->pict.yoffset; // will be set later yoffset += 0.5 * trap_SCR_strHeight( menuitem_filters_background->font ); menuitem_fullfilter = UI_InitMenuItem( "m_connect_filterfull", "full", UI_SCALED_WIDTH(-80), y+yoffset, MTYPE_SPINCONTROL, ALIGN_RIGHT_TOP, uis.fontSystemSmall, M_Connect_UpdateFiltersSettings ); Menu_AddItem( &s_joinserver_menu, menuitem_fullfilter ); UI_SetupSpinControl( menuitem_fullfilter, filter_names, trap_Cvar_VariableValue("ui_filter_full") ); //yoffset += trap_SCR_strHeight( menuitem_fullfilter->font ); menuitem_gametypefilter = UI_InitMenuItem( "m_connect_filtergametype", "gametype", UI_SCALED_WIDTH(120), y+yoffset, MTYPE_SPINCONTROL, ALIGN_RIGHT_TOP, uis.fontSystemSmall, M_Connect_UpdateFiltersSettings ); Menu_AddItem( &s_joinserver_menu, menuitem_gametypefilter ); UI_SetupSpinControl( menuitem_gametypefilter, gametype_filternames, trap_Cvar_VariableValue("ui_filter_gametype") ); yoffset += trap_SCR_strHeight( menuitem_gametypefilter->font ); menuitem_emptyfilter = UI_InitMenuItem( "m_connect_filterempty", "empty", UI_SCALED_WIDTH(-80), y+yoffset, MTYPE_SPINCONTROL, ALIGN_RIGHT_TOP, uis.fontSystemSmall, M_Connect_UpdateFiltersSettings ); Menu_AddItem( &s_joinserver_menu, menuitem_emptyfilter ); UI_SetupSpinControl( menuitem_emptyfilter, filter_names, trap_Cvar_VariableValue("ui_filter_empty") ); //yoffset += trap_SCR_strHeight( menuitem_emptyfilter->font ); menuitem_skillfilter = UI_InitMenuItem( "m_connect_filterskill", "skill", UI_SCALED_WIDTH(120), y+yoffset, MTYPE_SPINCONTROL, ALIGN_RIGHT_TOP, uis.fontSystemSmall, M_Connect_UpdateFiltersSettings ); Menu_AddItem( &s_joinserver_menu, menuitem_skillfilter ); UI_SetupSpinControl( menuitem_skillfilter, skill_filternames, trap_Cvar_VariableValue("ui_filter_skill") ); yoffset += trap_SCR_strHeight( menuitem_skillfilter->font ); menuitem_passwordfilter = UI_InitMenuItem( "m_connect_filterpassword", "password", UI_SCALED_WIDTH(-80), y+yoffset, MTYPE_SPINCONTROL, ALIGN_RIGHT_TOP, uis.fontSystemSmall, M_Connect_UpdateFiltersSettings ); Menu_AddItem( &s_joinserver_menu, menuitem_passwordfilter ); UI_SetupSpinControl( menuitem_passwordfilter, filter_names, trap_Cvar_VariableValue("ui_filter_password") ); //yoffset += trap_SCR_strHeight( menuitem_passwordfilter->font ); menuitem_maxpingfilter = UI_InitMenuItem( "m_connect_filterping", "maxping", UI_SCALED_WIDTH(120), y+yoffset, MTYPE_FIELD, ALIGN_RIGHT_TOP, uis.fontSystemSmall, M_Connect_UpdateFiltersSettings ); Menu_AddItem( &s_joinserver_menu, menuitem_maxpingfilter ); UI_SetupField( menuitem_maxpingfilter, trap_Cvar_VariableString("ui_filter_ping"), 4, -1 ); yoffset += trap_SCR_strHeight( menuitem_maxpingfilter->font ); #ifdef BATTLEYE menuitem_battleyefilter = UI_InitMenuItem( "m_connect_filterbattleye", "BattlEye", UI_SCALED_WIDTH(-80), y+yoffset, MTYPE_SPINCONTROL, ALIGN_RIGHT_TOP, uis.fontSystemSmall, M_Connect_UpdateFiltersSettings ); Menu_AddItem( &s_joinserver_menu, menuitem_battleyefilter ); UI_SetupSpinControl( menuitem_battleyefilter, battleye_filternames, trap_Cvar_VariableValue("ui_filter_battleye") ); yoffset += trap_SCR_strHeight( menuitem_battleyefilter->font ); #endif // here ends the filters background, set it's image height now menuitem_filters_background->pict.height = yoffset - menuitem_filters_background->pict.height + ( 0.5 * trap_SCR_strHeight( menuitem_skillfilter->font ) ); yoffset += trap_SCR_strHeight( menuitem_skillfilter->font ); #ifdef BATTLEYE #ifdef WIN32 menuitem = UI_InitMenuItem( "m_connect_toggle_battleye", "BattlEye Client", UI_SCALED_WIDTH(-80), y+yoffset, MTYPE_SPINCONTROL, MTYPE_SPINCONTROL, uis.fontSystemSmall, ToggleCLBattleyeFunc ); Menu_AddItem( &s_joinserver_menu, menuitem ); UI_SetupSpinControl( menuitem, offon_names, trap_Cvar_VariableValue("cl_battleye") ); //yoffset += trap_SCR_strHeight( menuitem->font ); #endif #endif menuitem = UI_InitMenuItem( "m_connect_search_type", "search", UI_SCALED_WIDTH(120), y+yoffset, MTYPE_SPINCONTROL, MTYPE_SPINCONTROL, uis.fontSystemSmall, NULL ); Menu_AddItem( &s_joinserver_menu, menuitem ); UI_SetupSpinControl( menuitem, search_names, 0 ); yoffset += trap_SCR_strHeight( menuitem->font ); yoffset += trap_SCR_strHeight( menuitem->font ); // scrollbar scrollwindow_height = uis.vidHeight - ( yoffset + ( 4 * trap_SCR_strHeight( uis.fontSystemBig ) ) ); MAX_MENU_SERVERS = ( scrollwindow_height / trap_SCR_strHeight( uis.fontSystemSmall ) ); if( MAX_MENU_SERVERS < 5 ) MAX_MENU_SERVERS = 5; menuitem = UI_InitMenuItem( "m_connect_scrollbar", NULL, (scrollwindow_width*0.5)+8, y+yoffset, MTYPE_SCROLLBAR, ALIGN_LEFT_TOP, uis.fontSystemSmall, M_Connect_UpdateScrollbar ); UI_SetupScrollbar( menuitem, MAX_MENU_SERVERS-1, 0, 0, 0 ); Menu_AddItem( &s_joinserver_menu, menuitem ); for( i = 0; i < MAX_MENU_SERVERS; i++ ) { menuitem = UI_InitMenuItem( va("m_connect_button_%i", i), NO_SERVER_STRING, -(scrollwindow_width*0.5), y+yoffset, MTYPE_ACTION, ALIGN_LEFT_TOP, uis.fontSystemSmall, M_Connect_Joinserver ); menuitem->statusbar = "press ENTER to connect"; menuitem->ownerdraw = M_UpdateSeverButton; menuitem->localdata[0] = i; // line in the window menuitem->localdata[1] = i; // line in list menuitem->width = scrollwindow_width; // adjust strings to this width Menu_AddItem( &s_joinserver_menu, menuitem ); // create an associated picture to the items to act as window background menuitem->pict.shader = uis.whiteShader; menuitem->pict.shaderHigh = uis.whiteShader; Vector4Copy( colorWhite, menuitem->pict.colorHigh ); Vector4Copy( ( i & 1 )?colorDkGrey:colorMdGrey, menuitem->pict.color ); menuitem->pict.color[3] = menuitem->pict.colorHigh[3] = 0.65f; menuitem->pict.yoffset = 0; menuitem->pict.xoffset = 0; menuitem->pict.width = scrollwindow_width; menuitem->pict.height = trap_SCR_strHeight( menuitem->font ); yoffset += trap_SCR_strHeight( menuitem->font ); } yoffset += trap_SCR_strHeight( menuitem->font ); menuitem = UI_InitMenuItem( "m_connect_search", "search!", 16, y+yoffset, MTYPE_ACTION, ALIGN_LEFT_TOP, uis.fontSystemBig, SearchGamesFunc ); Menu_AddItem( &s_joinserver_menu, menuitem ); Q_snprintfz ( sbar, sizeof(sbar), "Master server at %s", trap_Cvar_VariableString("masterservers") ); menuitem->statusbar = sbar; // back menuitem = UI_InitMenuItem( "m_connect_back", "back", -16, y+yoffset, MTYPE_ACTION, ALIGN_RIGHT_TOP, uis.fontSystemBig, M_genericBackFunc ); Menu_AddItem( &s_joinserver_menu, menuitem ); yoffset += trap_SCR_strHeight( menuitem->font ); //Menu_Center( &s_joinserver_menu ); Menu_Init( &s_joinserver_menu ); } void JoinServer_MenuDraw( void ) { PingServers(); Menu_Draw( &s_joinserver_menu ); } const char *JoinServer_MenuKey( int key ) { menucommon_t *item; item = Menu_ItemAtCursor( &s_joinserver_menu ); if ( key == K_ESCAPE || ( (key == K_MOUSE2) && (item->type != MTYPE_SPINCONTROL) && (item->type != MTYPE_SLIDER)) ) { } return Default_MenuKey( &s_joinserver_menu, key ); } const char *JoinServer_MenuCharEvent( int key ) { return Default_MenuCharEvent( &s_joinserver_menu, key ); } void M_Menu_JoinServer_f( void ) { JoinServer_MenuInit(); M_PushMenu( &s_joinserver_menu, JoinServer_MenuDraw, JoinServer_MenuKey, JoinServer_MenuCharEvent ); }