q3rally/engine/code/q3_ui/ui_rally_servers.c
2021-03-24 20:13:01 +00:00

1980 lines
74 KiB
C

/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2002-2021 Q3Rally Team (Per Thormann - q3rally@gmail.com)
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
#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
#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
// END
static const char *master_items[] = {
"Local",
"Internet",
"Master1",
"Master2",
"Master3",
"Master4",
"Master5",
"Favorites",
NULL
};
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",
// 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 ",
"Derby",
"DM ",
"TRace",
"TRace DM",
"Team DM", // team deathmatch
"CTF", // capture the flag
"Domination", // domination
// END
"???", // unknown
0
};
static char* netnames[] = {
"??? ",
"UDP ",
"UDP6",
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];
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;
}
/*
=================
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 );
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;
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 ) {
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 ) {
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;
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;
}
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",
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",
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))
{
// 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 );
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;
}
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;
}
/*
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)
{
// 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)) {
return;
}
}
if (trap_LAN_GetServerCount(ArenaServers_SourceForLAN()) < 0) {
// 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) {
g_arenaservers.numqueriedservers = g_arenaservers.numfavoriteaddresses;
} else {
g_arenaservers.numqueriedservers = trap_LAN_GetServerCount(ArenaServers_SourceForLAN());
}
// 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) {
strcpy( adrstr, g_arenaservers.favoriteaddresses[g_arenaservers.currentping] );
} else {
trap_LAN_GetServerAddressString(ArenaServers_SourceForLAN(), g_arenaservers.currentping, adrstr, MAX_ADDRESSLENGTH );
}
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;
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 ) {
trap_Cmd_ExecuteText( EXEC_APPEND, "localservers\n" );
return;
}
if( g_servertype >= UIAS_GLOBAL0 && g_servertype <= UIAS_GLOBAL5 ) {
gametype = ArenaServers_GametypeForGames(g_arenaservers.gametype.curvalue);
// Add requested gametype to args for dpmaster
if (gametype != -1) {
Com_sprintf( myargs, sizeof (myargs), " gametype=%i", gametype );
} else {
myargs[0] = '\0';
}
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 ));
}
else {
trap_Cmd_ExecuteText( EXEC_APPEND, va( "globalservers %d %d%s\n", g_servertype - UIAS_GLOBAL0, (int)trap_Cvar_VariableValue( "protocol" ), myargs ) );
}
}
}
/*
=================
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 )
{
if(type >= UIAS_GLOBAL1 && type <= UIAS_GLOBAL5)
{
char masterstr[2], cvarname[sizeof("sv_master1")];
int direction;
if (type == g_servertype || type == ((g_servertype+1) % UIAS_NUM_SOURCES)) {
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;
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;
}
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");
}
return type;
}
/*
=================
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 );
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 ) &&
( 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;
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;
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;
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 );
g_gametype = Com_Clamp( 0, GAMES_NUM_GAMES-1, ui_browserGameType.integer );
g_arenaservers.gametype.curvalue = g_gametype;
g_sortkey = Com_Clamp( 0, SORT_NUM_SORTS-1, ui_browserSortKey.integer );
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);
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 );
}