q3rally/engine/code/q3_ui/ui_rally_servers.c

1981 lines
74 KiB
C
Raw Normal View History

2011-02-18 14:31:32 +00:00
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
2021-03-24 20:13:01 +00:00
Copyright (C) 2002-2021 Q3Rally Team (Per Thormann - q3rally@gmail.com)
2011-02-18 14:31:32 +00:00
This file is part of q3rally source code.
q3rally source code 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.
q3rally source code 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 q3rally; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
/*
=======================================================================
MULTIPLAYER MENU (SERVER BROWSER)
=======================================================================
*/
#include "ui_local.h"
#define MAX_GLOBALSERVERS 128
// #define MAX_PINGREQUESTS 16
#define MAX_ADDRESSLENGTH 64
// STONELANCE
//#define MAX_HOSTNAMELENGTH 22
//#define MAX_MAPNAMELENGTH 16
#define MAX_HOSTNAMELENGTH 42
#define MAX_MAPNAMELENGTH 12
// END
#define MAX_LISTBOXITEMS 128
#define MAX_LOCALSERVERS 128
#define MAX_STATUSLENGTH 64
#define MAX_LEAGUELENGTH 28
// STONELANCE
//#define MAX_LISTBOXWIDTH 61
#define MAX_LISTBOXWIDTH 90
/*
#define ART_BACK0 "menu/art/back_0"
#define ART_BACK1 "menu/art/back_1"
#define ART_CREATE0 "menu/art/create_0"
#define ART_CREATE1 "menu/art/create_1"
#define ART_SPECIFY0 "menu/art/specify_0"
#define ART_SPECIFY1 "menu/art/specify_1"
#define ART_REFRESH0 "menu/art/refresh_0"
#define ART_REFRESH1 "menu/art/refresh_1"
#define ART_CONNECT0 "menu/art/fight_0"
#define ART_CONNECT1 "menu/art/fight_1"
#define ART_ARROWS0 "menu/art/arrows_vert_0"
#define ART_ARROWS_UP "menu/art/arrows_vert_top"
#define ART_ARROWS_DOWN "menu/art/arrows_vert_bot"
*/
// END
#define ART_UNKNOWNMAP "menu/art/unknownmap"
#define ART_REMOVE0 "menu/art/delete_0"
#define ART_REMOVE1 "menu/art/delete_1"
#define ART_SAVE0 "menu/art/save_0"
#define ART_SAVE1 "menu/art/save_1"
#define GLOBALRANKINGS_LOGO "menu/art/gr/grlogo"
#define ID_MASTER 10
#define ID_GAMETYPE 11
#define ID_SORTKEY 12
#define ID_SHOW_FULL 13
#define ID_SHOW_EMPTY 14
#define ID_ONLY_HUMANS 15
#define ID_LIST 16
// STONELANCE
//#define ID_SCROLL_UP 16
//#define ID_SCROLL_DOWN 17
// END
#define ID_BACK 18
#define ID_REFRESH 19
#define ID_SPECIFY 20
#define ID_CREATE 21
#define ID_CONNECT 22
#define ID_REMOVE 23
#define ID_SAVE 24
#define GR_LOGO 30
#define GR_LETTERS 31
#define UIAS_LOCAL 0
#define UIAS_GLOBAL0 1
#define UIAS_GLOBAL1 2
#define UIAS_GLOBAL2 3
#define UIAS_GLOBAL3 4
#define UIAS_GLOBAL4 5
#define UIAS_GLOBAL5 6
#define UIAS_FAVORITES 7
#define UIAS_NUM_SOURCES 8
#define UI_MAX_MASTER_SERVERS 6
2011-02-18 14:31:32 +00:00
#define SORT_HOST 0
#define SORT_MAP 1
#define SORT_CLIENTS 2
#define SORT_GAME 3
#define SORT_PING 4
#define SORT_NUM_SORTS 5
2011-02-18 14:31:32 +00:00
#define GAMES_ALL 0
// STONELANCE
/*
#define GAMES_FFA 1
#define GAMES_TEAMPLAY 2
#define GAMES_TOURNEY 3
#define GAMES_CTF 4
*/
#define GAMES_RACING 1
#define GAMES_RACING_DM 2
#define GAMES_DERBY 3
#define GAMES_DEATHMATCH 4
#define GAMES_TEAM_RACING 5
#define GAMES_TEAM_RACING_DM 6
#define GAMES_TEAMPLAY 7
#define GAMES_CTF 8
#define GAMES_DOMINATION 9
#define GAMES_NUM_GAMES 10
2011-02-18 14:31:32 +00:00
// END
static const char *master_items[] = {
"Local",
"Internet",
"Master1",
"Master2",
"Master3",
"Master4",
"Master5",
"Favorites",
NULL
2011-02-18 14:31:32 +00:00
};
static const char *servertype_items[] = {
"All",
// STONELANCE
/*
"Free For All",
"Team Deathmatch",
"Tournament",
"Capture the Flag",
*/
"Racing",
"Racing Deathmatch",
"Demolition Derby",
"Deathmatch",
"Team Racing",
"Team Racing Deathmatch",
"Team Deathmatch",
"Capture the Flag",
"Domination",
2011-02-18 14:31:32 +00:00
// END
0
};
static const char *sortkey_items[] = {
"Server Name",
"Map Name",
"Open Player Spots",
"Game Type",
"Ping Time",
0
};
static char* gamenames[] = {
// STONELANCE
/*
"DM ", // deathmatch
"1v1", // tournament
"SP ", // single player
"Team DM", // team deathmatch
"CTF", // capture the flag
"One Flag CTF", // one flag ctf
"OverLoad", // Overload
"Harvester", // Harvester
"Rocket Arena 3", // Rocket Arena 3
"Q3F", // Q3F
"Urban Terror", // Urban Terror
"OSP", // Orange Smoothie Productions
*/
"Race",
"Race DM",
"SP ",
2011-02-18 14:31:32 +00:00
"Derby",
"DM ",
"TRace",
"TRace DM",
"Team DM", // team deathmatch
"CTF", // capture the flag
"Domination", // domination
2011-02-18 14:31:32 +00:00
// END
"???", // unknown
0
};
static char* netnames[] = {
"??? ",
"UDP ",
"UDP6",
2011-02-18 14:31:32 +00:00
NULL
};
// STONELANCE
//static char quake3worldMessage[] = "Visit www.quake3world.com - News, Community, Events, Files";
static char quake3worldMessage[] = "Visit www.q3rally.com - News, Forums, Files";
// END
static char globalRankingsMessage[] = "Visit www.globalrankings.com - you kick ass, we'll take names";
typedef struct {
char adrstr[MAX_ADDRESSLENGTH];
int start;
} pinglist_t;
typedef struct servernode_s {
char adrstr[MAX_ADDRESSLENGTH];
char hostname[MAX_HOSTNAMELENGTH];
char mapname[MAX_MAPNAMELENGTH];
int numclients;
int humanclients;
int maxclients;
int pingtime;
int gametype;
char gamename[12];
int nettype;
int minPing;
int maxPing;
} servernode_t;
typedef struct {
char buff[MAX_LISTBOXWIDTH];
servernode_t* servernode;
} table_t;
typedef struct {
menuframework_s menu;
menutext_s banner;
menulist_s master;
menulist_s gametype;
menulist_s sortkey;
menuradiobutton_s showfull;
menuradiobutton_s showempty;
menuradiobutton_s onlyhumans;
menulist_s list;
menutext_s save;
menubitmap_s mappic;
// STONELANCE
/*
menubitmap_s arrows;
menubitmap_s up;
menubitmap_s down;
*/
// END
menutext_s status;
menutext_s statusbar;
// STONELANCE
/*
menubitmap_s remove;
menubitmap_s back;
menubitmap_s refresh;
menubitmap_s specify;
menubitmap_s create;
menubitmap_s go;
*/
menutext_s remove;
menutext_s back;
menutext_s refresh;
menutext_s specify;
menutext_s create;
menutext_s go;
// END
pinglist_t pinglist[MAX_PINGREQUESTS];
table_t table[MAX_LISTBOXITEMS];
char* items[MAX_LISTBOXITEMS];
int numqueriedservers;
int *numservers;
servernode_t *serverlist;
int currentping;
qboolean refreshservers;
int nextpingtime;
int maxservers;
int refreshtime;
char favoriteaddresses[MAX_FAVORITESERVERS][MAX_ADDRESSLENGTH];
int numfavoriteaddresses;
menubitmap_s grlogo;
menubitmap_s grletters;
menutext_s league;
menutext_s practice;
} arenaservers_t;
static arenaservers_t g_arenaservers;
static servernode_t g_globalserverlist[UI_MAX_MASTER_SERVERS][MAX_GLOBALSERVERS];
static int g_numglobalservers[UI_MAX_MASTER_SERVERS];
2011-02-18 14:31:32 +00:00
static servernode_t g_localserverlist[MAX_LOCALSERVERS];
static int g_numlocalservers;
static servernode_t g_favoriteserverlist[MAX_FAVORITESERVERS];
static int g_numfavoriteservers;
static int g_servertype;
static int g_gametype;
static int g_sortkey;
static int g_onlyhumans;
static int g_emptyservers;
static int g_fullservers;
/*
=================
ArenaServers_AddToFavorites
=================
*/
static void ArenaServers_AddToFavorites(void)
{
servernode_t* servernodeptr;
int i;
// check favourite server list isn't full
if (g_numfavoriteservers == MAX_FAVORITESERVERS)
return;
// check we have a server list available
if (!g_arenaservers.list.numitems)
return;
// check the server isn't on the favourites list already
servernodeptr=g_arenaservers.table[g_arenaservers.list.curvalue].servernode;
for (i=0; i < g_numfavoriteservers; i++)
if (!Q_stricmp(g_arenaservers.favoriteaddresses[i],servernodeptr->adrstr))
return;
// we already have a responsive server, no further sanity checks required
strcpy(g_arenaservers.favoriteaddresses[g_numfavoriteservers],
servernodeptr->adrstr);
// copy over server details
memcpy( &g_favoriteserverlist[g_numfavoriteservers],
servernodeptr,sizeof(servernode_t));
g_numfavoriteservers++;
g_arenaservers.numfavoriteaddresses = g_numfavoriteservers;
}
/*
=================
ArenaServers_MaxPing
=================
*/
static int ArenaServers_MaxPing( void ) {
int maxPing;
maxPing = (int)trap_Cvar_VariableValue( "cl_maxPing" );
if( maxPing < 100 ) {
maxPing = 100;
}
return maxPing;
}
/*
=================
ArenaServers_Compare
=================
*/
static int QDECL ArenaServers_Compare( const void *arg1, const void *arg2 ) {
float f1;
float f2;
servernode_t* t1;
servernode_t* t2;
t1 = (servernode_t *)arg1;
t2 = (servernode_t *)arg2;
switch( g_sortkey ) {
case SORT_HOST:
return Q_stricmp( t1->hostname, t2->hostname );
case SORT_MAP:
return Q_stricmp( t1->mapname, t2->mapname );
case SORT_CLIENTS:
f1 = t1->maxclients - t1->numclients;
if( f1 < 0 ) {
f1 = 0;
}
f2 = t2->maxclients - t2->numclients;
if( f2 < 0 ) {
f2 = 0;
}
if( f1 < f2 ) {
return 1;
}
if( f1 == f2 ) {
return 0;
}
return -1;
case SORT_GAME:
if( t1->gametype < t2->gametype ) {
return -1;
}
if( t1->gametype == t2->gametype ) {
return 0;
}
return 1;
case SORT_PING:
if( t1->pingtime < t2->pingtime ) {
return -1;
}
if( t1->pingtime > t2->pingtime ) {
return 1;
}
return Q_stricmp( t1->hostname, t2->hostname );
}
return 0;
}
/*
=================
ArenaServers_SourceForLAN
Convert ui's g_servertype to AS_* used by trap calls.
=================
*/
int ArenaServers_SourceForLAN(void) {
switch( g_servertype ) {
default:
case UIAS_LOCAL:
return AS_LOCAL;
case UIAS_GLOBAL0:
case UIAS_GLOBAL1:
case UIAS_GLOBAL2:
case UIAS_GLOBAL3:
case UIAS_GLOBAL4:
case UIAS_GLOBAL5:
return AS_GLOBAL;
case UIAS_FAVORITES:
return AS_FAVORITES;
}
}
/*
=================
ArenaServers_GametypeForGames
=================
*/
int ArenaServers_GametypeForGames(int games) {
int gametype;
switch( games ) {
default:
case GAMES_ALL:
gametype = -1;
break;
// STONELANCE
/*
case GAMES_FFA:
gametype = GT_FFA;
break;
*/
case GAMES_RACING:
gametype = GT_RACING;
break;
case GAMES_RACING_DM:
gametype = GT_RACING_DM;
break;
case GAMES_DERBY:
gametype = GT_DERBY;
break;
case GAMES_TEAM_RACING:
gametype = GT_TEAM_RACING;
break;
case GAMES_TEAM_RACING_DM:
gametype = GT_TEAM_RACING_DM;
break;
case GAMES_DEATHMATCH:
gametype = GT_DEATHMATCH;
break;
// END
case GAMES_TEAMPLAY:
gametype = GT_TEAM;
break;
// STONELANCE - removed gametype
/*
case GAMES_TOURNEY:
gametype = GT_TOURNAMENT;
break;
*/
// END
case GAMES_CTF:
gametype = GT_CTF;
break;
case GAMES_DOMINATION:
gametype = GT_DOMINATION;
break;
}
return gametype;
}
2011-02-18 14:31:32 +00:00
/*
=================
ArenaServers_Go
=================
*/
static void ArenaServers_Go( void ) {
servernode_t* servernode;
servernode = g_arenaservers.table[g_arenaservers.list.curvalue].servernode;
if( servernode ) {
trap_Cmd_ExecuteText( EXEC_APPEND, va( "connect %s\n", servernode->adrstr ) );
}
}
/*
=================
ArenaServers_UpdatePicture
=================
*/
static void ArenaServers_UpdatePicture( void ) {
static char picname[64];
servernode_t* servernodeptr;
if( !g_arenaservers.list.numitems ) {
g_arenaservers.mappic.generic.name = NULL;
}
else {
servernodeptr = g_arenaservers.table[g_arenaservers.list.curvalue].servernode;
Com_sprintf( picname, sizeof(picname), "levelshots/%s", servernodeptr->mapname );
2011-02-18 14:31:32 +00:00
g_arenaservers.mappic.generic.name = picname;
}
// force shader update during draw
g_arenaservers.mappic.shader = 0;
}
/*
=================
ArenaServers_UpdateMenu
=================
*/
static void ArenaServers_UpdateMenu( void ) {
int i;
int j;
int count;
char* buff;
servernode_t* servernodeptr;
table_t* tableptr;
char *pingColor;
int gametype;
2011-02-18 14:31:32 +00:00
if( g_arenaservers.numqueriedservers > 0 ) {
// servers found
if( g_arenaservers.refreshservers && ( g_arenaservers.currentping <= g_arenaservers.numqueriedservers ) ) {
// show progress
Com_sprintf( g_arenaservers.status.string, MAX_STATUSLENGTH, "%d of %d Arena Servers.", g_arenaservers.currentping, g_arenaservers.numqueriedservers);
g_arenaservers.statusbar.string = "Press SPACE to stop";
qsort( g_arenaservers.serverlist, *g_arenaservers.numservers, sizeof( servernode_t ), ArenaServers_Compare);
}
else {
// all servers pinged - enable controls
g_arenaservers.save.generic.flags &= ~QMF_GRAYED;
g_arenaservers.master.generic.flags &= ~QMF_GRAYED;
g_arenaservers.gametype.generic.flags &= ~QMF_GRAYED;
g_arenaservers.sortkey.generic.flags &= ~QMF_GRAYED;
g_arenaservers.showempty.generic.flags &= ~QMF_GRAYED;
g_arenaservers.onlyhumans.generic.flags &= ~QMF_GRAYED;
g_arenaservers.showfull.generic.flags &= ~QMF_GRAYED;
// STONELANCE
// g_arenaservers.list.generic.flags &= ~QMF_GRAYED;
g_arenaservers.list.generic.flags &= ~QMF_SCROLL_ONLY;
// END
g_arenaservers.refresh.generic.flags &= ~QMF_GRAYED;
g_arenaservers.go.generic.flags &= ~QMF_GRAYED;
// update status bar
if( g_servertype >= UIAS_GLOBAL0 && g_servertype <= UIAS_GLOBAL5 ) {
2011-02-18 14:31:32 +00:00
g_arenaservers.statusbar.string = quake3worldMessage;
}
else {
g_arenaservers.statusbar.string = "";
}
if (!(g_arenaservers.grlogo.generic.flags & QMF_HIDDEN)) {
g_arenaservers.statusbar.string = globalRankingsMessage;
}
}
}
else {
// no servers found
if( g_arenaservers.refreshservers ) {
strcpy( g_arenaservers.status.string,"Scanning For Servers." );
g_arenaservers.statusbar.string = "Press SPACE to stop";
// disable controls during refresh
g_arenaservers.save.generic.flags |= QMF_GRAYED;
g_arenaservers.master.generic.flags |= QMF_GRAYED;
g_arenaservers.gametype.generic.flags |= QMF_GRAYED;
g_arenaservers.sortkey.generic.flags |= QMF_GRAYED;
g_arenaservers.showempty.generic.flags |= QMF_GRAYED;
g_arenaservers.onlyhumans.generic.flags |= QMF_GRAYED;
g_arenaservers.showfull.generic.flags |= QMF_GRAYED;
// STONELANCE
// g_arenaservers.list.generic.flags |= QMF_GRAYED;
g_arenaservers.list.generic.flags |= QMF_SCROLL_ONLY;
// END
g_arenaservers.refresh.generic.flags |= QMF_GRAYED;
g_arenaservers.go.generic.flags |= QMF_GRAYED;
}
else {
if( g_arenaservers.numqueriedservers < 0 ) {
strcpy(g_arenaservers.status.string,"No Response From Master Server." );
}
else {
strcpy(g_arenaservers.status.string,"No Servers Found." );
}
// update status bar
if( g_servertype >= UIAS_GLOBAL0 && g_servertype <= UIAS_GLOBAL5 ) {
2011-02-18 14:31:32 +00:00
g_arenaservers.statusbar.string = quake3worldMessage;
}
else {
g_arenaservers.statusbar.string = "";
}
// end of refresh - set control state
g_arenaservers.save.generic.flags |= QMF_GRAYED;
g_arenaservers.master.generic.flags &= ~QMF_GRAYED;
g_arenaservers.gametype.generic.flags &= ~QMF_GRAYED;
g_arenaservers.sortkey.generic.flags &= ~QMF_GRAYED;
g_arenaservers.showempty.generic.flags &= ~QMF_GRAYED;
g_arenaservers.onlyhumans.generic.flags &= ~QMF_GRAYED;
2011-02-18 14:31:32 +00:00
g_arenaservers.showfull.generic.flags &= ~QMF_GRAYED;
// STONELANCE
// g_arenaservers.list.generic.flags |= QMF_GRAYED;
g_arenaservers.list.generic.flags |= QMF_SCROLL_ONLY;
// END
g_arenaservers.refresh.generic.flags &= ~QMF_GRAYED;
g_arenaservers.go.generic.flags |= QMF_GRAYED;
}
// zero out list box
g_arenaservers.list.numitems = 0;
g_arenaservers.list.curvalue = 0;
// STONELANCE
// g_arenaservers.list.top = 0;
// END
// update picture
ArenaServers_UpdatePicture();
return;
}
// build list box strings - apply culling filters
servernodeptr = g_arenaservers.serverlist;
count = *g_arenaservers.numservers;
for( i = 0, j = 0; i < count; i++, servernodeptr++ ) {
tableptr = &g_arenaservers.table[j];
tableptr->servernode = servernodeptr;
buff = tableptr->buff;
// can only cull valid results
if( !g_emptyservers && !servernodeptr->numclients ) {
continue;
}
//If "Show only humans" and "Hide empty server" are enabled hide servers that only have bots
if( !g_emptyservers && g_onlyhumans && !servernodeptr->humanclients ) {
continue;
}
if( !g_fullservers && ( servernodeptr->numclients == servernodeptr->maxclients ) ) {
continue;
}
gametype = ArenaServers_GametypeForGames(g_gametype);
if( gametype != -1 && servernodeptr->gametype != gametype ) {
continue;
2011-02-18 14:31:32 +00:00
}
if( servernodeptr->pingtime < servernodeptr->minPing ) {
pingColor = S_COLOR_BLUE;
}
else if( servernodeptr->maxPing && servernodeptr->pingtime > servernodeptr->maxPing ) {
pingColor = S_COLOR_BLUE;
}
else if( servernodeptr->pingtime < 200 ) {
pingColor = S_COLOR_GREEN;
}
else if( servernodeptr->pingtime < 400 ) {
pingColor = S_COLOR_YELLOW;
}
else {
pingColor = S_COLOR_RED;
}
// STONELANCE
/*
Com_sprintf( buff, MAX_LISTBOXWIDTH, "%-20.20s %-12.12s %2d/%2d %-8.8s %4s%s%3d",
2011-02-18 14:31:32 +00:00
servernodeptr->hostname, servernodeptr->mapname, servernodeptr->numclients,
servernodeptr->maxclients, servernodeptr->gamename,
netnames[servernodeptr->nettype], pingColor, servernodeptr->pingtime );
*/
Com_sprintf( buff, MAX_LISTBOXWIDTH, "%-42.42s %-12.12s %2d/%2d %-10.10s %4s %s%5d",
2011-02-18 14:31:32 +00:00
servernodeptr->hostname, servernodeptr->mapname, servernodeptr->numclients,
servernodeptr->maxclients, servernodeptr->gamename,
netnames[servernodeptr->nettype], pingColor, servernodeptr->pingtime );
// END
j++;
}
// Com_sprintf( g_arenaservers.status.string, MAX_STATUSLENGTH, "%d of %d Arena Servers.", j, *g_arenaservers.numservers );
g_arenaservers.list.numitems = j;
g_arenaservers.list.curvalue = 0;
// STONELANCE
// g_arenaservers.list.top = 0;
// END
// update picture
ArenaServers_UpdatePicture();
}
/*
=================
ArenaServers_Remove
=================
*/
static void ArenaServers_Remove( void )
{
int i;
servernode_t* servernodeptr;
table_t* tableptr;
if (!g_arenaservers.list.numitems)
return;
// remove selected item from display list
// items are in scattered order due to sort and cull
// perform delete on list box contents, resync all lists
tableptr = &g_arenaservers.table[g_arenaservers.list.curvalue];
servernodeptr = tableptr->servernode;
// find address in master list
for (i=0; i<g_arenaservers.numfavoriteaddresses; i++)
if (!Q_stricmp(g_arenaservers.favoriteaddresses[i],servernodeptr->adrstr))
break;
// delete address from master list
if (i <= g_arenaservers.numfavoriteaddresses-1)
{
if (i < g_arenaservers.numfavoriteaddresses-1)
{
// shift items up
memcpy( &g_arenaservers.favoriteaddresses[i], &g_arenaservers.favoriteaddresses[i+1], (g_arenaservers.numfavoriteaddresses - i - 1)*MAX_ADDRESSLENGTH);
}
g_arenaservers.numfavoriteaddresses--;
}
// find address in server list
for (i=0; i<g_numfavoriteservers; i++)
if (&g_favoriteserverlist[i] == servernodeptr)
break;
// delete address from server list
if (i <= g_numfavoriteservers-1)
{
if (i < g_numfavoriteservers-1)
{
// shift items up
memcpy( &g_favoriteserverlist[i], &g_favoriteserverlist[i+1], (g_numfavoriteservers - i - 1)*sizeof(servernode_t));
}
g_numfavoriteservers--;
}
g_arenaservers.numqueriedservers = g_arenaservers.numfavoriteaddresses;
g_arenaservers.currentping = g_arenaservers.numfavoriteaddresses;
}
/*
=================
ArenaServers_Insert
=================
*/
static void ArenaServers_Insert( char* adrstr, char* info, int pingtime )
{
servernode_t* servernodeptr;
char* s;
int i;
if ((pingtime >= ArenaServers_MaxPing()) && (g_servertype != UIAS_FAVORITES))
2011-02-18 14:31:32 +00:00
{
// slow global or local servers do not get entered
return;
}
//remove
//trap_Cmd_ExecuteText( EXEC_NOW, va( "echo infostring: %s\n", info ) );
if (*g_arenaservers.numservers >= g_arenaservers.maxservers) {
// list full;
servernodeptr = g_arenaservers.serverlist+(*g_arenaservers.numservers)-1;
} else {
// next slot
servernodeptr = g_arenaservers.serverlist+(*g_arenaservers.numservers);
(*g_arenaservers.numservers)++;
}
Q_strncpyz( servernodeptr->adrstr, adrstr, MAX_ADDRESSLENGTH );
Q_strncpyz( servernodeptr->hostname, Info_ValueForKey( info, "hostname"), MAX_HOSTNAMELENGTH );
Q_CleanStr( servernodeptr->hostname );
Q_strupr( servernodeptr->hostname );
Q_strncpyz( servernodeptr->mapname, Info_ValueForKey( info, "mapname"), MAX_MAPNAMELENGTH );
Q_CleanStr( servernodeptr->mapname );
// ZTM: Fix using linux without pk3s
//Q_strupr( servernodeptr->mapname );
2011-02-18 14:31:32 +00:00
servernodeptr->numclients = atoi( Info_ValueForKey( info, "clients") );
servernodeptr->humanclients = atoi( Info_ValueForKey( info, "g_humanplayers") );
servernodeptr->maxclients = atoi( Info_ValueForKey( info, "sv_maxclients") );
servernodeptr->pingtime = pingtime;
servernodeptr->minPing = atoi( Info_ValueForKey( info, "minPing") );
servernodeptr->maxPing = atoi( Info_ValueForKey( info, "maxPing") );
/*
s = Info_ValueForKey( info, "nettype" );
for (i=0; ;i++)
{
if (!netnames[i])
{
servernodeptr->nettype = 0;
break;
}
else if (!Q_stricmp( netnames[i], s ))
{
servernodeptr->nettype = i;
break;
}
}
*/
servernodeptr->nettype = atoi(Info_ValueForKey(info, "nettype"));
if (servernodeptr->nettype < 0 || servernodeptr->nettype >= ARRAY_LEN(netnames) - 1) {
servernodeptr->nettype = 0;
}
2011-02-18 14:31:32 +00:00
s = Info_ValueForKey( info, "game");
i = atoi( Info_ValueForKey( info, "gametype") );
if( i < 0 ) {
i = 0;
}
// STONELANCE
else if( i >= GT_MAX_GAME_TYPE ) {
i = GT_MAX_GAME_TYPE;
2011-02-18 14:31:32 +00:00
}
/*
else if( i > 11 ) {
i = 12;
}
*/
// END
if ( *s ) {
servernodeptr->gametype = -1;
Q_strncpyz( servernodeptr->gamename, s, sizeof(servernodeptr->gamename) );
}
else {
servernodeptr->gametype = i;
Q_strncpyz( servernodeptr->gamename, gamenames[i], sizeof(servernodeptr->gamename) );
}
}
/*
=================
ArenaServers_InsertFavorites
Insert nonresponsive address book entries into display lists.
=================
*/
void ArenaServers_InsertFavorites( void )
{
int i;
int j;
char info[MAX_INFO_STRING];
// resync existing results with new or deleted cvars
info[0] = '\0';
Info_SetValueForKey( info, "hostname", "No Response" );
for (i=0; i<g_arenaservers.numfavoriteaddresses; i++)
{
// find favorite address in refresh list
for (j=0; j<g_numfavoriteservers; j++)
if (!Q_stricmp(g_arenaservers.favoriteaddresses[i],g_favoriteserverlist[j].adrstr))
break;
if ( j >= g_numfavoriteservers)
{
// not in list, add it
ArenaServers_Insert( g_arenaservers.favoriteaddresses[i], info, ArenaServers_MaxPing() );
}
}
}
/*
=================
ArenaServers_LoadFavorites
Load cvar address book entries into local lists.
=================
*/
void ArenaServers_LoadFavorites( void )
{
int i;
int j;
int numtempitems;
char adrstr[MAX_ADDRESSLENGTH];
servernode_t templist[MAX_FAVORITESERVERS];
qboolean found;
found = qfalse;
// copy the old
memcpy( templist, g_favoriteserverlist, sizeof(servernode_t)*MAX_FAVORITESERVERS );
numtempitems = g_numfavoriteservers;
// clear the current for sync
memset( g_favoriteserverlist, 0, sizeof(servernode_t)*MAX_FAVORITESERVERS );
g_numfavoriteservers = 0;
// resync existing results with new or deleted cvars
for (i=0; i<MAX_FAVORITESERVERS; i++)
{
trap_Cvar_VariableStringBuffer( va("server%d",i+1), adrstr, MAX_ADDRESSLENGTH );
if (!adrstr[0])
continue;
// quick sanity check to avoid slow domain name resolving
// first character must be numeric
if (adrstr[0] < '0' || adrstr[0] > '9')
continue;
// favorite server addresses must be maintained outside refresh list
// this mimics local and global netadr's stored in client
// these can be fetched to fill ping list
strcpy( g_arenaservers.favoriteaddresses[g_numfavoriteservers], adrstr );
// find this server in the old list
for (j=0; j<numtempitems; j++)
if (!Q_stricmp( templist[j].adrstr, adrstr ))
break;
if (j < numtempitems)
{
// found server - add exisiting results
memcpy( &g_favoriteserverlist[g_numfavoriteservers], &templist[j], sizeof(servernode_t) );
found = qtrue;
}
else
{
// add new server
Q_strncpyz( g_favoriteserverlist[g_numfavoriteservers].adrstr, adrstr, MAX_ADDRESSLENGTH );
g_favoriteserverlist[g_numfavoriteservers].pingtime = ArenaServers_MaxPing();
}
g_numfavoriteservers++;
}
g_arenaservers.numfavoriteaddresses = g_numfavoriteservers;
if (!found)
{
// no results were found, reset server list
// list will be automatically refreshed when selected
g_numfavoriteservers = 0;
}
}
/*
=================
ArenaServers_StopRefresh
=================
*/
static void ArenaServers_StopRefresh( void )
{
if (!g_arenaservers.refreshservers)
// not currently refreshing
return;
g_arenaservers.refreshservers = qfalse;
if (g_servertype == UIAS_FAVORITES)
2011-02-18 14:31:32 +00:00
{
// nonresponsive favorites must be shown
ArenaServers_InsertFavorites();
}
// final tally
if (g_arenaservers.numqueriedservers >= 0)
{
g_arenaservers.currentping = *g_arenaservers.numservers;
g_arenaservers.numqueriedservers = *g_arenaservers.numservers;
}
// sort
qsort( g_arenaservers.serverlist, *g_arenaservers.numservers, sizeof( servernode_t ), ArenaServers_Compare);
ArenaServers_UpdateMenu();
}
/*
=================
ArenaServers_DoRefresh
=================
*/
static void ArenaServers_DoRefresh( void )
{
int i;
int j;
int time;
int maxPing;
char adrstr[MAX_ADDRESSLENGTH];
char info[MAX_INFO_STRING];
if (uis.realtime < g_arenaservers.refreshtime)
{
if (g_servertype != UIAS_FAVORITES) {
if (g_servertype == UIAS_LOCAL) {
if (!trap_LAN_GetServerCount(AS_LOCAL)) {
2011-02-18 14:31:32 +00:00
return;
}
}
if (trap_LAN_GetServerCount(ArenaServers_SourceForLAN()) < 0) {
2011-02-18 14:31:32 +00:00
// still waiting for response
return;
}
}
}
if (uis.realtime < g_arenaservers.nextpingtime)
{
// wait for time trigger
return;
}
// trigger at 10Hz intervals
g_arenaservers.nextpingtime = uis.realtime + 50;
// process ping results
maxPing = ArenaServers_MaxPing();
for (i=0; i<MAX_PINGREQUESTS; i++)
{
trap_LAN_GetPing( i, adrstr, MAX_ADDRESSLENGTH, &time );
if (!adrstr[0])
{
// ignore empty or pending pings
continue;
}
// find ping result in our local list
for (j=0; j<MAX_PINGREQUESTS; j++)
if (!Q_stricmp( adrstr, g_arenaservers.pinglist[j].adrstr ))
break;
if (j < MAX_PINGREQUESTS)
{
// found it
if (!time)
{
time = uis.realtime - g_arenaservers.pinglist[j].start;
if (time < maxPing)
{
// still waiting
continue;
}
}
if (time > maxPing)
{
// stale it out
info[0] = '\0';
time = maxPing;
}
else
{
trap_LAN_GetPingInfo( i, info, MAX_INFO_STRING );
}
// insert ping results
ArenaServers_Insert( adrstr, info, time );
// clear this query from internal list
g_arenaservers.pinglist[j].adrstr[0] = '\0';
}
// clear this query from external list
trap_LAN_ClearPing( i );
}
// get results of servers query
// counts can increase as servers respond
if (g_servertype == UIAS_FAVORITES) {
2011-02-18 14:31:32 +00:00
g_arenaservers.numqueriedservers = g_arenaservers.numfavoriteaddresses;
} else {
g_arenaservers.numqueriedservers = trap_LAN_GetServerCount(ArenaServers_SourceForLAN());
2011-02-18 14:31:32 +00:00
}
// if (g_arenaservers.numqueriedservers > g_arenaservers.maxservers)
// g_arenaservers.numqueriedservers = g_arenaservers.maxservers;
// send ping requests in reasonable bursts
// iterate ping through all found servers
for (i=0; i<MAX_PINGREQUESTS && g_arenaservers.currentping < g_arenaservers.numqueriedservers; i++)
{
if (trap_LAN_GetPingQueueCount() >= MAX_PINGREQUESTS)
{
// ping queue is full
break;
}
// find empty slot
for (j=0; j<MAX_PINGREQUESTS; j++)
if (!g_arenaservers.pinglist[j].adrstr[0])
break;
if (j >= MAX_PINGREQUESTS)
// no empty slots available yet - wait for timeout
break;
// get an address to ping
if (g_servertype == UIAS_FAVORITES) {
2011-02-18 14:31:32 +00:00
strcpy( adrstr, g_arenaservers.favoriteaddresses[g_arenaservers.currentping] );
} else {
trap_LAN_GetServerAddressString(ArenaServers_SourceForLAN(), g_arenaservers.currentping, adrstr, MAX_ADDRESSLENGTH );
2011-02-18 14:31:32 +00:00
}
strcpy( g_arenaservers.pinglist[j].adrstr, adrstr );
g_arenaservers.pinglist[j].start = uis.realtime;
trap_Cmd_ExecuteText( EXEC_NOW, va( "ping %s\n", adrstr ) );
// advance to next server
g_arenaservers.currentping++;
}
if (!trap_LAN_GetPingQueueCount())
{
// all pings completed
ArenaServers_StopRefresh();
return;
}
// update the user interface with ping status
ArenaServers_UpdateMenu();
}
/*
=================
ArenaServers_StartRefresh
=================
*/
static void ArenaServers_StartRefresh( void )
{
int i, gametype;
2011-02-18 14:31:32 +00:00
char myargs[32], protocol[32];
memset( g_arenaservers.serverlist, 0, g_arenaservers.maxservers*sizeof(table_t) );
for (i=0; i<MAX_PINGREQUESTS; i++)
{
g_arenaservers.pinglist[i].adrstr[0] = '\0';
trap_LAN_ClearPing( i );
}
g_arenaservers.refreshservers = qtrue;
g_arenaservers.currentping = 0;
g_arenaservers.nextpingtime = 0;
*g_arenaservers.numservers = 0;
g_arenaservers.numqueriedservers = 0;
// allow max 5 seconds for responses
g_arenaservers.refreshtime = uis.realtime + 5000;
// place menu in zeroed state
ArenaServers_UpdateMenu();
if( g_servertype == UIAS_LOCAL ) {
2011-02-18 14:31:32 +00:00
trap_Cmd_ExecuteText( EXEC_APPEND, "localservers\n" );
return;
}
if( g_servertype >= UIAS_GLOBAL0 && g_servertype <= UIAS_GLOBAL5 ) {
gametype = ArenaServers_GametypeForGames(g_arenaservers.gametype.curvalue);
2011-02-18 14:31:32 +00:00
// Add requested gametype to args for dpmaster
if (gametype != -1) {
Com_sprintf( myargs, sizeof (myargs), " gametype=%i", gametype );
} else {
myargs[0] = '\0';
}
2011-02-18 14:31:32 +00:00
if (g_emptyservers) {
strcat(myargs, " empty");
}
if (g_fullservers) {
strcat(myargs, " full");
}
protocol[0] = '\0';
trap_Cvar_VariableStringBuffer( "debug_protocol", protocol, sizeof(protocol) );
if (strlen(protocol)) {
trap_Cmd_ExecuteText( EXEC_APPEND, va( "globalservers %d %s%s\n", g_servertype - UIAS_GLOBAL0, protocol, myargs ));
2011-02-18 14:31:32 +00:00
}
else {
trap_Cmd_ExecuteText( EXEC_APPEND, va( "globalservers %d %d%s\n", g_servertype - UIAS_GLOBAL0, (int)trap_Cvar_VariableValue( "protocol" ), myargs ) );
2011-02-18 14:31:32 +00:00
}
}
}
/*
=================
ArenaServers_SaveChanges
=================
*/
void ArenaServers_SaveChanges( void )
{
int i;
for (i=0; i<g_arenaservers.numfavoriteaddresses; i++)
trap_Cvar_Set( va("server%d",i+1), g_arenaservers.favoriteaddresses[i] );
for (; i<MAX_FAVORITESERVERS; i++)
trap_Cvar_Set( va("server%d",i+1), "" );
}
/*
=================
ArenaServers_Sort
=================
*/
void ArenaServers_Sort( int type ) {
if( g_sortkey == type ) {
return;
}
g_sortkey = type;
qsort( g_arenaservers.serverlist, *g_arenaservers.numservers, sizeof( servernode_t ), ArenaServers_Compare);
}
/*
=================
ArenaServers_SetType
=================
*/
int ArenaServers_SetType( int type )
2011-02-18 14:31:32 +00:00
{
if(type >= UIAS_GLOBAL1 && type <= UIAS_GLOBAL5)
{
char masterstr[2], cvarname[sizeof("sv_master1")];
ioquake3 resync to revision 3385 from 3347. Fix going to previous browser source in q3_ui Limit ui_smallFont/ui_bigFont/cg_noTaunt cvars to missionpack Fix team chat box for spectators Don't draw crosshair 0 in Team Arena setup menu Make client for Windows x86_64 use OpenAL64.dll by default Fix loading renderer DLLs on Windows x86 Add Windows application manifest Disable DPI scaling on Windows ignore window resize event on fullscreen Don't reload arenas.txt/*.arena files in Team Arena UI Fix crash when out of memory in Team Arena's String_Alloc Fix in_nograb not releasing the mouse cursor Update UI player animation handling to match CGame Fix specifying minimum mac os version in make-macosx.sh Fix listen server sending snapshots each client frame Statically link libgcc on Windows Fix hit accuracy stats for lightning gun and shotgun kills Don't link to libGL at compile time Add common OpenGL version parsing + OpenGL 3 fixes Support parsing OpenGL ES version strings Fix setting cflags/libs from sdl2-config Load OpenGL ES 1.1 function procs [qcommon] Use unsigned types where wrapping arithmetic is intended OpenGL2: Fix brightness when r_autoExposure is disabled OpenGL2: Fix MD3 surface with zero shaders dividing by zero [botlib/be_aas_def.h] Change array size from MAX_PATH to MAX_QPATH Don't redefine MAX_PATH in bot code Fix memory leak in (unused) AAS_FloodAreas() Fix compiling GLSL shaders under Windows. Only draw cm_patch/bot debug polygons in world scenes Fix reading crash log when log wraps around buffer Don't send team overlay info to bots Fix a race condition in the makedirs target Fix shader corruption on OpenBSD
2017-11-04 11:30:30 +00:00
int direction;
if (type == g_servertype || type == ((g_servertype+1) % UIAS_NUM_SOURCES)) {
ioquake3 resync to revision 3385 from 3347. Fix going to previous browser source in q3_ui Limit ui_smallFont/ui_bigFont/cg_noTaunt cvars to missionpack Fix team chat box for spectators Don't draw crosshair 0 in Team Arena setup menu Make client for Windows x86_64 use OpenAL64.dll by default Fix loading renderer DLLs on Windows x86 Add Windows application manifest Disable DPI scaling on Windows ignore window resize event on fullscreen Don't reload arenas.txt/*.arena files in Team Arena UI Fix crash when out of memory in Team Arena's String_Alloc Fix in_nograb not releasing the mouse cursor Update UI player animation handling to match CGame Fix specifying minimum mac os version in make-macosx.sh Fix listen server sending snapshots each client frame Statically link libgcc on Windows Fix hit accuracy stats for lightning gun and shotgun kills Don't link to libGL at compile time Add common OpenGL version parsing + OpenGL 3 fixes Support parsing OpenGL ES version strings Fix setting cflags/libs from sdl2-config Load OpenGL ES 1.1 function procs [qcommon] Use unsigned types where wrapping arithmetic is intended OpenGL2: Fix brightness when r_autoExposure is disabled OpenGL2: Fix MD3 surface with zero shaders dividing by zero [botlib/be_aas_def.h] Change array size from MAX_PATH to MAX_QPATH Don't redefine MAX_PATH in bot code Fix memory leak in (unused) AAS_FloodAreas() Fix compiling GLSL shaders under Windows. Only draw cm_patch/bot debug polygons in world scenes Fix reading crash log when log wraps around buffer Don't send team overlay info to bots Fix a race condition in the makedirs target Fix shader corruption on OpenBSD
2017-11-04 11:30:30 +00:00
direction = 1;
} else {
direction = -1;
}
while(type >= UIAS_GLOBAL1 && type <= UIAS_GLOBAL5)
{
Com_sprintf(cvarname, sizeof(cvarname), "sv_master%d", type - UIAS_GLOBAL0);
trap_Cvar_VariableStringBuffer(cvarname, masterstr, sizeof(masterstr));
if(*masterstr)
break;
ioquake3 resync to revision 3385 from 3347. Fix going to previous browser source in q3_ui Limit ui_smallFont/ui_bigFont/cg_noTaunt cvars to missionpack Fix team chat box for spectators Don't draw crosshair 0 in Team Arena setup menu Make client for Windows x86_64 use OpenAL64.dll by default Fix loading renderer DLLs on Windows x86 Add Windows application manifest Disable DPI scaling on Windows ignore window resize event on fullscreen Don't reload arenas.txt/*.arena files in Team Arena UI Fix crash when out of memory in Team Arena's String_Alloc Fix in_nograb not releasing the mouse cursor Update UI player animation handling to match CGame Fix specifying minimum mac os version in make-macosx.sh Fix listen server sending snapshots each client frame Statically link libgcc on Windows Fix hit accuracy stats for lightning gun and shotgun kills Don't link to libGL at compile time Add common OpenGL version parsing + OpenGL 3 fixes Support parsing OpenGL ES version strings Fix setting cflags/libs from sdl2-config Load OpenGL ES 1.1 function procs [qcommon] Use unsigned types where wrapping arithmetic is intended OpenGL2: Fix brightness when r_autoExposure is disabled OpenGL2: Fix MD3 surface with zero shaders dividing by zero [botlib/be_aas_def.h] Change array size from MAX_PATH to MAX_QPATH Don't redefine MAX_PATH in bot code Fix memory leak in (unused) AAS_FloodAreas() Fix compiling GLSL shaders under Windows. Only draw cm_patch/bot debug polygons in world scenes Fix reading crash log when log wraps around buffer Don't send team overlay info to bots Fix a race condition in the makedirs target Fix shader corruption on OpenBSD
2017-11-04 11:30:30 +00:00
type += direction;
}
}
g_servertype = type;
switch( type ) {
default:
case UIAS_LOCAL:
g_arenaservers.save.generic.flags &= ~(QMF_INACTIVE|QMF_HIDDEN);
g_arenaservers.remove.generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);
g_arenaservers.serverlist = g_localserverlist;
g_arenaservers.numservers = &g_numlocalservers;
g_arenaservers.maxservers = MAX_LOCALSERVERS;
break;
case UIAS_GLOBAL0:
case UIAS_GLOBAL1:
case UIAS_GLOBAL2:
case UIAS_GLOBAL3:
case UIAS_GLOBAL4:
case UIAS_GLOBAL5:
g_arenaservers.save.generic.flags &= ~(QMF_INACTIVE|QMF_HIDDEN);
g_arenaservers.remove.generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);
g_arenaservers.serverlist = g_globalserverlist[type-UIAS_GLOBAL0];
g_arenaservers.numservers = &g_numglobalservers[type-UIAS_GLOBAL0];
g_arenaservers.maxservers = MAX_GLOBALSERVERS;
break;
case UIAS_FAVORITES:
g_arenaservers.save.generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);
g_arenaservers.remove.generic.flags &= ~(QMF_INACTIVE|QMF_HIDDEN);
g_arenaservers.serverlist = g_favoriteserverlist;
g_arenaservers.numservers = &g_numfavoriteservers;
g_arenaservers.maxservers = MAX_FAVORITESERVERS;
break;
}
2011-02-18 14:31:32 +00:00
if( !*g_arenaservers.numservers ) {
ArenaServers_StartRefresh();
}
else {
// avoid slow operation, use existing results
g_arenaservers.currentping = *g_arenaservers.numservers;
g_arenaservers.numqueriedservers = *g_arenaservers.numservers;
ArenaServers_UpdateMenu();
strcpy(g_arenaservers.status.string,"hit refresh to update");
2011-02-18 14:31:32 +00:00
}
return type;
2011-02-18 14:31:32 +00:00
}
/*
=================
ArenaServers_Event
=================
*/
static void ArenaServers_Event( void* ptr, int event ) {
int id;
id = ((menucommon_s*)ptr)->id;
if( event != QM_ACTIVATED && id != ID_LIST ) {
return;
}
switch( id ) {
case ID_MASTER:
g_arenaservers.master.curvalue = ArenaServers_SetType( g_arenaservers.master.curvalue );
2011-02-18 14:31:32 +00:00
trap_Cvar_SetValue( "ui_browserMaster", g_arenaservers.master.curvalue );
break;
case ID_GAMETYPE:
trap_Cvar_SetValue( "ui_browserGameType", g_arenaservers.gametype.curvalue );
g_gametype = g_arenaservers.gametype.curvalue;
ArenaServers_UpdateMenu();
break;
case ID_SORTKEY:
trap_Cvar_SetValue( "ui_browserSortKey", g_arenaservers.sortkey.curvalue );
ArenaServers_Sort( g_arenaservers.sortkey.curvalue );
ArenaServers_UpdateMenu();
break;
case ID_SHOW_FULL:
trap_Cvar_SetValue( "ui_browserShowFull", g_arenaservers.showfull.curvalue );
g_fullservers = g_arenaservers.showfull.curvalue;
ArenaServers_UpdateMenu();
break;
case ID_SHOW_EMPTY:
trap_Cvar_SetValue( "ui_browserShowEmpty", g_arenaservers.showempty.curvalue );
g_emptyservers = g_arenaservers.showempty.curvalue;
ArenaServers_UpdateMenu();
break;
case ID_ONLY_HUMANS:
trap_Cvar_SetValue( "ui_browserOnlyHumans", g_arenaservers.onlyhumans.curvalue );
g_onlyhumans = g_arenaservers.onlyhumans.curvalue;
ArenaServers_UpdateMenu();
break;
case ID_LIST:
if( event == QM_GOTFOCUS ) {
ArenaServers_UpdatePicture();
}
break;
// STONELANCE - removed
/*
case ID_SCROLL_UP:
ScrollList_Key( &g_arenaservers.list, K_UPARROW );
break;
case ID_SCROLL_DOWN:
ScrollList_Key( &g_arenaservers.list, K_DOWNARROW );
break;
*/
// END
case ID_BACK:
ArenaServers_StopRefresh();
ArenaServers_SaveChanges();
UI_PopMenu();
break;
case ID_REFRESH:
ArenaServers_StartRefresh();
break;
case ID_SPECIFY:
UI_SpecifyServerMenu();
break;
case ID_CREATE:
UI_StartServerMenu( qtrue );
break;
case ID_CONNECT:
ArenaServers_Go();
break;
case ID_REMOVE:
ArenaServers_Remove();
ArenaServers_UpdateMenu();
break;
case ID_SAVE:
ArenaServers_AddToFavorites();
ArenaServers_SaveChanges();
break;
}
}
/*
=================
ArenaServers_MenuDraw
=================
*/
static void ArenaServers_MenuDraw( void )
{
if (g_arenaservers.refreshservers)
ArenaServers_DoRefresh();
Menu_Draw( &g_arenaservers.menu );
}
/*
=================
ArenaServers_MenuKey
=================
*/
static sfxHandle_t ArenaServers_MenuKey( int key ) {
if( key == K_SPACE && g_arenaservers.refreshservers ) {
ArenaServers_StopRefresh();
return menu_move_sound;
}
if( ( key == K_DEL || key == K_KP_DEL ) && ( g_servertype == UIAS_FAVORITES ) &&
2011-02-18 14:31:32 +00:00
( Menu_ItemAtCursor( &g_arenaservers.menu) == &g_arenaservers.list ) ) {
ArenaServers_Remove();
ArenaServers_UpdateMenu();
return menu_move_sound;
}
if( key == K_MOUSE2 || key == K_ESCAPE ) {
ArenaServers_StopRefresh();
ArenaServers_SaveChanges();
}
return Menu_DefaultKey( &g_arenaservers.menu, key );
}
/*
=================
ArenaServers_MenuInit
=================
*/
static void ArenaServers_MenuInit( void ) {
int i;
int y;
static char statusbuffer[MAX_STATUSLENGTH];
static char leaguebuffer[MAX_LEAGUELENGTH];
// zero set all our globals
memset( &g_arenaservers, 0 ,sizeof(arenaservers_t) );
ArenaServers_Cache();
g_arenaservers.menu.fullscreen = qtrue;
g_arenaservers.menu.wrapAround = qtrue;
g_arenaservers.menu.draw = ArenaServers_MenuDraw;
2011-02-18 14:31:32 +00:00
g_arenaservers.menu.key = ArenaServers_MenuKey;
g_arenaservers.banner.generic.type = MTYPE_BTEXT;
g_arenaservers.banner.generic.flags = QMF_CENTER_JUSTIFY;
g_arenaservers.banner.generic.x = 320;
g_arenaservers.banner.generic.y = 16;
g_arenaservers.banner.string = "ARENA SERVERS";
g_arenaservers.banner.style = UI_CENTER;
// STONELANCE
// g_arenaservers.banner.color = color_white;
g_arenaservers.banner.color = text_color_normal;
// END
g_arenaservers.grlogo.generic.type = MTYPE_BITMAP;
g_arenaservers.grlogo.generic.name = GLOBALRANKINGS_LOGO;
g_arenaservers.grlogo.generic.flags = QMF_INACTIVE|QMF_HIDDEN;
g_arenaservers.grlogo.generic.x = 530;
g_arenaservers.grlogo.generic.y = 40;
g_arenaservers.grlogo.width = 32;
g_arenaservers.grlogo.height = 64;
g_arenaservers.league.generic.type = MTYPE_TEXT;
g_arenaservers.league.generic.flags = QMF_HIDDEN;
g_arenaservers.league.generic.x = g_arenaservers.grlogo.generic.x +
(g_arenaservers.grlogo.width / 2);
g_arenaservers.league.generic.y = g_arenaservers.grlogo.generic.y +
g_arenaservers.grlogo.height + 2;
g_arenaservers.league.string = leaguebuffer;
g_arenaservers.league.style = UI_CENTER|UI_SMALLFONT;
g_arenaservers.league.color = menu_text_color;
g_arenaservers.practice.generic.type = MTYPE_TEXT;
g_arenaservers.practice.generic.flags = QMF_HIDDEN;
g_arenaservers.practice.generic.x = g_arenaservers.grlogo.generic.x +
(g_arenaservers.grlogo.width / 2);
g_arenaservers.practice.generic.y = g_arenaservers.grlogo.generic.y + 6;
g_arenaservers.practice.string = "practice";
g_arenaservers.practice.style = UI_CENTER|UI_SMALLFONT;
g_arenaservers.practice.color = menu_text_color;
y = 80;
g_arenaservers.master.generic.type = MTYPE_SPINCONTROL;
g_arenaservers.master.generic.name = "Servers:";
g_arenaservers.master.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
g_arenaservers.master.generic.callback = ArenaServers_Event;
g_arenaservers.master.generic.id = ID_MASTER;
// STONELANCE
// g_arenaservers.master.generic.x = 320;
g_arenaservers.master.generic.x = 330;
// END
g_arenaservers.master.generic.y = y;
g_arenaservers.master.itemnames = master_items;
y += SMALLCHAR_HEIGHT;
g_arenaservers.gametype.generic.type = MTYPE_SPINCONTROL;
g_arenaservers.gametype.generic.name = "Game Type:";
g_arenaservers.gametype.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
g_arenaservers.gametype.generic.callback = ArenaServers_Event;
g_arenaservers.gametype.generic.id = ID_GAMETYPE;
// STONELANCE
// g_arenaservers.gametype.generic.x = 320;
g_arenaservers.gametype.generic.x = 330;
// END
g_arenaservers.gametype.generic.y = y;
g_arenaservers.gametype.itemnames = servertype_items;
y += SMALLCHAR_HEIGHT;
g_arenaservers.sortkey.generic.type = MTYPE_SPINCONTROL;
g_arenaservers.sortkey.generic.name = "Sort By:";
g_arenaservers.sortkey.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
g_arenaservers.sortkey.generic.callback = ArenaServers_Event;
g_arenaservers.sortkey.generic.id = ID_SORTKEY;
// STONELANCE
// g_arenaservers.sortkey.generic.x = 320;
g_arenaservers.sortkey.generic.x = 330;
// END
g_arenaservers.sortkey.generic.y = y;
g_arenaservers.sortkey.itemnames = sortkey_items;
y += SMALLCHAR_HEIGHT;
g_arenaservers.showfull.generic.type = MTYPE_RADIOBUTTON;
g_arenaservers.showfull.generic.name = "Show Full:";
g_arenaservers.showfull.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
g_arenaservers.showfull.generic.callback = ArenaServers_Event;
g_arenaservers.showfull.generic.id = ID_SHOW_FULL;
// STONELANCE
// g_arenaservers.showfull.generic.x = 320;
g_arenaservers.showfull.generic.x = 330;
// END
g_arenaservers.showfull.generic.y = y;
y += SMALLCHAR_HEIGHT;
g_arenaservers.showempty.generic.type = MTYPE_RADIOBUTTON;
g_arenaservers.showempty.generic.name = "Show Empty:";
g_arenaservers.showempty.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
g_arenaservers.showempty.generic.callback = ArenaServers_Event;
g_arenaservers.showempty.generic.id = ID_SHOW_EMPTY;
// STONELANCE
// g_arenaservers.showempty.generic.x = 320;
g_arenaservers.showempty.generic.x = 330;
// END
g_arenaservers.showempty.generic.y = y;
y += SMALLCHAR_HEIGHT;
g_arenaservers.onlyhumans.generic.type = MTYPE_RADIOBUTTON;
g_arenaservers.onlyhumans.generic.name = "Only humans:";
g_arenaservers.onlyhumans.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
g_arenaservers.onlyhumans.generic.callback = ArenaServers_Event;
g_arenaservers.onlyhumans.generic.id = ID_ONLY_HUMANS;
g_arenaservers.onlyhumans.generic.x = 330;
2011-02-18 14:31:32 +00:00
g_arenaservers.onlyhumans.generic.y = y;
// STONELANCE
// y += 3 * SMALLCHAR_HEIGHT;
// g_arenaservers.list.generic.type = MTYPE_SCROLLLIST;
// g_arenaservers.list.generic.flags = QMF_HIGHLIGHT_IF_FOCUS;
y += 2 * SMALLCHAR_HEIGHT;
g_arenaservers.list.generic.type = MTYPE_LISTBOX;
g_arenaservers.list.scrollbarAlignment = SB_RIGHT;
g_arenaservers.list.generic.flags = QMF_CENTER_JUSTIFY|QMF_HIGHLIGHT_IF_FOCUS;
// END
g_arenaservers.list.generic.id = ID_LIST;
g_arenaservers.list.generic.callback = ArenaServers_Event;
// STONELANCE
// g_arenaservers.list.generic.x = 72;
g_arenaservers.list.generic.x = 320;
// END
g_arenaservers.list.generic.y = y;
g_arenaservers.list.width = MAX_LISTBOXWIDTH;
g_arenaservers.list.height = 11;
g_arenaservers.list.itemnames = (const char **)g_arenaservers.items;
for( i = 0; i < MAX_LISTBOXITEMS; i++ ) {
g_arenaservers.items[i] = g_arenaservers.table[i].buff;
}
g_arenaservers.mappic.generic.type = MTYPE_BITMAP;
g_arenaservers.mappic.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
g_arenaservers.mappic.generic.x = 72;
g_arenaservers.mappic.generic.y = 80;
g_arenaservers.mappic.width = 170;
2011-02-18 14:31:32 +00:00
g_arenaservers.mappic.height = 96;
g_arenaservers.mappic.errorpic = ART_UNKNOWNMAP;
// STONELANCE
/*
g_arenaservers.arrows.generic.type = MTYPE_BITMAP;
g_arenaservers.arrows.generic.name = ART_ARROWS0;
g_arenaservers.arrows.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
g_arenaservers.arrows.generic.callback = ArenaServers_Event;
g_arenaservers.arrows.generic.x = 512+48;
g_arenaservers.arrows.generic.y = 240-64+16;
g_arenaservers.arrows.width = 64;
g_arenaservers.arrows.height = 128;
g_arenaservers.up.generic.type = MTYPE_BITMAP;
g_arenaservers.up.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_MOUSEONLY;
g_arenaservers.up.generic.callback = ArenaServers_Event;
g_arenaservers.up.generic.id = ID_SCROLL_UP;
g_arenaservers.up.generic.x = 512+48;
g_arenaservers.up.generic.y = 240-64+16;
g_arenaservers.up.width = 64;
g_arenaservers.up.height = 64;
g_arenaservers.up.focuspic = ART_ARROWS_UP;
g_arenaservers.down.generic.type = MTYPE_BITMAP;
g_arenaservers.down.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_MOUSEONLY;
g_arenaservers.down.generic.callback = ArenaServers_Event;
g_arenaservers.down.generic.id = ID_SCROLL_DOWN;
g_arenaservers.down.generic.x = 512+48;
g_arenaservers.down.generic.y = 240+16;
g_arenaservers.down.width = 64;
g_arenaservers.down.height = 64;
g_arenaservers.down.focuspic = ART_ARROWS_DOWN;
*/
// END
y = 376;
g_arenaservers.status.generic.type = MTYPE_TEXT;
g_arenaservers.status.generic.x = 320;
g_arenaservers.status.generic.y = y;
g_arenaservers.status.string = statusbuffer;
g_arenaservers.status.style = UI_CENTER|UI_SMALLFONT;
g_arenaservers.status.color = menu_text_color;
y += SMALLCHAR_HEIGHT;
g_arenaservers.statusbar.generic.type = MTYPE_TEXT;
g_arenaservers.statusbar.generic.x = 320;
g_arenaservers.statusbar.generic.y = y;
g_arenaservers.statusbar.string = "";
g_arenaservers.statusbar.style = UI_CENTER|UI_SMALLFONT;
g_arenaservers.statusbar.color = text_color_normal;
// STONELANCE
/*
g_arenaservers.remove.generic.type = MTYPE_BITMAP;
g_arenaservers.remove.generic.name = ART_REMOVE0;
g_arenaservers.remove.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
g_arenaservers.remove.generic.callback = ArenaServers_Event;
g_arenaservers.remove.generic.id = ID_REMOVE;
g_arenaservers.remove.generic.x = 450;
g_arenaservers.remove.generic.y = 86;
g_arenaservers.remove.width = 96;
g_arenaservers.remove.height = 48;
g_arenaservers.remove.focuspic = ART_REMOVE1;
g_arenaservers.back.generic.type = MTYPE_BITMAP;
g_arenaservers.back.generic.name = ART_BACK0;
g_arenaservers.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
g_arenaservers.back.generic.callback = ArenaServers_Event;
g_arenaservers.back.generic.id = ID_BACK;
g_arenaservers.back.generic.x = 0;
g_arenaservers.back.generic.y = 480-64;
g_arenaservers.back.width = 128;
g_arenaservers.back.height = 64;
g_arenaservers.back.focuspic = ART_BACK1;
g_arenaservers.specify.generic.type = MTYPE_BITMAP;
g_arenaservers.specify.generic.name = ART_SPECIFY0;
g_arenaservers.specify.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
g_arenaservers.specify.generic.callback = ArenaServers_Event;
g_arenaservers.specify.generic.id = ID_SPECIFY;
g_arenaservers.specify.generic.x = 128;
g_arenaservers.specify.generic.y = 480-64;
g_arenaservers.specify.width = 128;
g_arenaservers.specify.height = 64;
g_arenaservers.specify.focuspic = ART_SPECIFY1;
g_arenaservers.refresh.generic.type = MTYPE_BITMAP;
g_arenaservers.refresh.generic.name = ART_REFRESH0;
g_arenaservers.refresh.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
g_arenaservers.refresh.generic.callback = ArenaServers_Event;
g_arenaservers.refresh.generic.id = ID_REFRESH;
g_arenaservers.refresh.generic.x = 256;
g_arenaservers.refresh.generic.y = 480-64;
g_arenaservers.refresh.width = 128;
g_arenaservers.refresh.height = 64;
g_arenaservers.refresh.focuspic = ART_REFRESH1;
g_arenaservers.create.generic.type = MTYPE_BITMAP;
g_arenaservers.create.generic.name = ART_CREATE0;
g_arenaservers.create.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
g_arenaservers.create.generic.callback = ArenaServers_Event;
g_arenaservers.create.generic.id = ID_CREATE;
g_arenaservers.create.generic.x = 384;
g_arenaservers.create.generic.y = 480-64;
g_arenaservers.create.width = 128;
g_arenaservers.create.height = 64;
g_arenaservers.create.focuspic = ART_CREATE1;
g_arenaservers.go.generic.type = MTYPE_BITMAP;
g_arenaservers.go.generic.name = ART_CONNECT0;
g_arenaservers.go.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
g_arenaservers.go.generic.callback = ArenaServers_Event;
g_arenaservers.go.generic.id = ID_CONNECT;
g_arenaservers.go.generic.x = 640;
g_arenaservers.go.generic.y = 480-64;
g_arenaservers.go.width = 128;
g_arenaservers.go.height = 64;
g_arenaservers.go.focuspic = ART_CONNECT1;
*/
g_arenaservers.remove.generic.type = MTYPE_PTEXT;
g_arenaservers.remove.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
g_arenaservers.remove.generic.callback = ArenaServers_Event;
g_arenaservers.remove.generic.id = ID_REMOVE;
g_arenaservers.remove.generic.x = 480;
g_arenaservers.remove.generic.y = 86;
g_arenaservers.remove.string = "<DELETE>";
g_arenaservers.remove.color = text_color_normal;
g_arenaservers.remove.style = UI_LEFT | UI_SMALLFONT;
g_arenaservers.save.generic.type = MTYPE_PTEXT;
g_arenaservers.save.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
g_arenaservers.save.generic.callback = ArenaServers_Event;
g_arenaservers.save.generic.id = ID_SAVE;
g_arenaservers.save.generic.x = 480;
g_arenaservers.save.generic.y = 87;
g_arenaservers.save.string = "<SAVE>";
g_arenaservers.save.color = text_color_normal;
g_arenaservers.save.style = UI_LEFT | UI_SMALLFONT;
g_arenaservers.back.generic.type = MTYPE_PTEXT;
g_arenaservers.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
g_arenaservers.back.generic.x = 20;
g_arenaservers.back.generic.y = 480 - 50;
g_arenaservers.back.generic.id = ID_BACK;
g_arenaservers.back.generic.callback = ArenaServers_Event;
g_arenaservers.back.string = "< BACK";
g_arenaservers.back.color = text_color_normal;
g_arenaservers.back.style = UI_LEFT | UI_SMALLFONT;
g_arenaservers.specify.generic.type = MTYPE_PTEXT;
g_arenaservers.specify.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
g_arenaservers.specify.generic.x = 160 - 32;
g_arenaservers.specify.generic.y = 480-50;
g_arenaservers.specify.generic.id = ID_SPECIFY;
g_arenaservers.specify.generic.callback = ArenaServers_Event;
g_arenaservers.specify.string = "<SPECIFY>";
g_arenaservers.specify.color = text_color_normal;
g_arenaservers.specify.style = UI_LEFT | UI_SMALLFONT;
g_arenaservers.refresh.generic.type = MTYPE_PTEXT;
g_arenaservers.refresh.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
g_arenaservers.refresh.generic.x = 320 - 52;
g_arenaservers.refresh.generic.y = 480 - 50;
g_arenaservers.refresh.generic.id = ID_REFRESH;
g_arenaservers.refresh.generic.callback = ArenaServers_Event;
g_arenaservers.refresh.string = "<REFRESH>";
g_arenaservers.refresh.color = text_color_normal;
g_arenaservers.refresh.style = UI_LEFT | UI_SMALLFONT;
g_arenaservers.create.generic.type = MTYPE_PTEXT;
g_arenaservers.create.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
g_arenaservers.create.generic.x = 460 - 56;
g_arenaservers.create.generic.y = 480 - 50;
g_arenaservers.create.generic.id = ID_CREATE;
g_arenaservers.create.generic.callback = ArenaServers_Event;
g_arenaservers.create.string = "<CREATE>";
g_arenaservers.create.color = text_color_normal;
g_arenaservers.create.style = UI_LEFT | UI_SMALLFONT;
g_arenaservers.go.generic.type = MTYPE_PTEXT;
g_arenaservers.go.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
g_arenaservers.go.generic.x = 640 - 20;
g_arenaservers.go.generic.y = 480 - 50;
g_arenaservers.go.generic.id = ID_CONNECT;
g_arenaservers.go.generic.callback = ArenaServers_Event;
g_arenaservers.go.string = "CONNECT >";
g_arenaservers.go.color = text_color_normal;
g_arenaservers.go.style = UI_RIGHT | UI_SMALLFONT;
// END
Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.banner );
Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.grlogo );
Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.league );
Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.practice );
Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.master );
Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.gametype );
Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.sortkey );
Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.showfull);
Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.showempty );
Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.onlyhumans );
Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.mappic );
Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.list );
Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.status );
Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.statusbar );
// STONELANCE
/*
Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.arrows );
Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.up );
Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.down );
*/
// END
Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.remove );
Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.save );
Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.back );
Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.specify );
Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.refresh );
Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.create );
Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.go );
ArenaServers_LoadFavorites();
g_arenaservers.master.curvalue = g_servertype = Com_Clamp( 0, UIAS_NUM_SOURCES-1, ui_browserMaster.integer );
2011-02-18 14:31:32 +00:00
g_gametype = Com_Clamp( 0, GAMES_NUM_GAMES-1, ui_browserGameType.integer );
2011-02-18 14:31:32 +00:00
g_arenaservers.gametype.curvalue = g_gametype;
g_sortkey = Com_Clamp( 0, SORT_NUM_SORTS-1, ui_browserSortKey.integer );
2011-02-18 14:31:32 +00:00
g_arenaservers.sortkey.curvalue = g_sortkey;
g_fullservers = Com_Clamp( 0, 1, ui_browserShowFull.integer );
g_arenaservers.showfull.curvalue = g_fullservers;
g_emptyservers = Com_Clamp( 0, 1, ui_browserShowEmpty.integer );
g_arenaservers.showempty.curvalue = g_emptyservers;
g_arenaservers.onlyhumans.curvalue = Com_Clamp( 0, 1, ui_browserOnlyHumans.integer );
g_onlyhumans = ui_browserOnlyHumans.integer;
// force to initial state and refresh
g_arenaservers.master.curvalue = g_servertype = ArenaServers_SetType(g_servertype);
2011-02-18 14:31:32 +00:00
trap_Cvar_Register(NULL, "debug_protocol", "", 0 );
}
/*
=================
ArenaServers_Cache
=================
*/
void ArenaServers_Cache( void ) {
// STOENLANCE
/*
trap_R_RegisterShaderNoMip( ART_BACK0 );
trap_R_RegisterShaderNoMip( ART_BACK1 );
trap_R_RegisterShaderNoMip( ART_CREATE0 );
trap_R_RegisterShaderNoMip( ART_CREATE1 );
trap_R_RegisterShaderNoMip( ART_SPECIFY0 );
trap_R_RegisterShaderNoMip( ART_SPECIFY1 );
trap_R_RegisterShaderNoMip( ART_REFRESH0 );
trap_R_RegisterShaderNoMip( ART_REFRESH1 );
trap_R_RegisterShaderNoMip( ART_CONNECT0 );
trap_R_RegisterShaderNoMip( ART_CONNECT1 );
trap_R_RegisterShaderNoMip( ART_ARROWS0 );
trap_R_RegisterShaderNoMip( ART_ARROWS_UP );
trap_R_RegisterShaderNoMip( ART_ARROWS_DOWN );
*/
// END
trap_R_RegisterShaderNoMip( ART_UNKNOWNMAP );
trap_R_RegisterShaderNoMip( GLOBALRANKINGS_LOGO );
}
/*
=================
UI_ArenaServersMenu
=================
*/
void UI_ArenaServersMenu( void ) {
ArenaServers_MenuInit();
UI_PushMenu( &g_arenaservers.menu );
}