mirror of
https://github.com/UberGames/lilium-voyager.git
synced 2025-01-07 09:20:46 +00:00
9f239d647b
This commit fixes the vanilla Q3 UI VMs not displaying a server list when id Software's master server is down. Originally master 0 for the globalservers command was Internet and master 1 was MPlayer (defunct). In 2008 ioquake3 changed it so that master 0 to 4 were five separate master servers with no affect on original Quake3/Team Arena UI VMs; they continued to get the server list from master.quake3arena.com. id Software's master server (master.quake3arena.com) goes down occasionally. Using ioq3's UI VM additional master servers can be accessed but players using the original UI VMs are unable to get a server list. In order to fix the original UI VMs in Quake3/Team Arena's pk3s this commit makes 'globalservers 0' fetch all master servers. So players get a combined list of id Software's and ioquake3's master list. Or just ioquake3's list if id Software's master is down. Getting lists from individual master servers using globalservers has changed from 0 through 4 to 1 through 5 to accommodate using 0 for other purposes. This commit modifies ioq3's UI code to support the new values for globalservers command. A side affect of these changes is that UI VMs based on ioq3 since 2008 will have Internet1 fetch all master servers and Internet2 request sv_master1 instead of sv_master2 and so on. It may be worth noting that getting server list from masters 3-5 could not be done using ioq3's UI before 2011.
1636 lines
44 KiB
C
1636 lines
44 KiB
C
/*
|
|
===========================================================================
|
|
Copyright (C) 1999-2005 Id Software, Inc.
|
|
|
|
This file is part of Quake III Arena source code.
|
|
|
|
Quake III Arena 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.
|
|
|
|
Quake III Arena 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 Quake III Arena source code; 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 32
|
|
#define MAX_ADDRESSLENGTH 64
|
|
#define MAX_HOSTNAMELENGTH 22
|
|
#define MAX_MAPNAMELENGTH 16
|
|
#define MAX_LISTBOXITEMS 128
|
|
#define MAX_LOCALSERVERS 128
|
|
#define MAX_STATUSLENGTH 64
|
|
#define MAX_LEAGUELENGTH 28
|
|
#define MAX_LISTBOXWIDTH 68
|
|
|
|
#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"
|
|
#define ART_UNKNOWNMAP "menu/art/unknownmap"
|
|
#define ART_REMOVE0 "menu/art/delete_0"
|
|
#define ART_REMOVE1 "menu/art/delete_1"
|
|
#define ART_PUNKBUSTER "menu/art/pblogo"
|
|
|
|
#define ID_MASTER 10
|
|
#define ID_GAMETYPE 11
|
|
#define ID_SORTKEY 12
|
|
#define ID_SHOW_FULL 13
|
|
#define ID_SHOW_EMPTY 14
|
|
#define ID_LIST 15
|
|
#define ID_SCROLL_UP 16
|
|
#define ID_SCROLL_DOWN 17
|
|
#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_PUNKBUSTER 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 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 GAMES_ALL 0
|
|
#define GAMES_FFA 1
|
|
#define GAMES_TEAMPLAY 2
|
|
#define GAMES_TOURNEY 3
|
|
#define GAMES_CTF 4
|
|
|
|
static const char *master_items[] = {
|
|
"Local",
|
|
"Internet",
|
|
"Master1",
|
|
"Master2",
|
|
"Master3",
|
|
"Master4",
|
|
"Master5",
|
|
"Favorites",
|
|
NULL
|
|
};
|
|
|
|
static const char *servertype_items[] = {
|
|
"All",
|
|
"Free For All",
|
|
"Team Deathmatch",
|
|
"Tournament",
|
|
"Capture the Flag",
|
|
NULL
|
|
};
|
|
|
|
static const char *sortkey_items[] = {
|
|
"Server Name",
|
|
"Map Name",
|
|
"Open Player Spots",
|
|
"Game Type",
|
|
"Ping Time",
|
|
NULL
|
|
};
|
|
|
|
static char* gamenames[] = {
|
|
"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
|
|
"???", // unknown
|
|
NULL
|
|
};
|
|
|
|
static char* netnames[] = {
|
|
"??? ",
|
|
"UDP ",
|
|
"UDP6",
|
|
NULL
|
|
};
|
|
|
|
static char quake3worldMessage[] = "Visit www.quake3world.com - News, Community, Events, Files";
|
|
|
|
const char* punkbuster_items[] = {
|
|
"Disabled",
|
|
"Enabled",
|
|
NULL
|
|
};
|
|
|
|
const char* punkbuster_msg[] = {
|
|
"PunkBuster will be",
|
|
"disabled the next time",
|
|
"Quake III Arena",
|
|
"is started.",
|
|
NULL
|
|
};
|
|
|
|
typedef struct {
|
|
char adrstr[MAX_ADDRESSLENGTH];
|
|
int start;
|
|
} pinglist_t;
|
|
|
|
typedef struct servernode_s {
|
|
char adrstr[MAX_ADDRESSLENGTH];
|
|
char hostname[MAX_HOSTNAMELENGTH+3];
|
|
char mapname[MAX_MAPNAMELENGTH];
|
|
int numclients;
|
|
int maxclients;
|
|
int pingtime;
|
|
int gametype;
|
|
char gamename[12];
|
|
int nettype;
|
|
int minPing;
|
|
int maxPing;
|
|
qboolean bPB;
|
|
|
|
} 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;
|
|
|
|
menulist_s list;
|
|
menubitmap_s mappic;
|
|
menubitmap_s arrows;
|
|
menubitmap_s up;
|
|
menubitmap_s down;
|
|
menutext_s status;
|
|
menutext_s statusbar;
|
|
|
|
menubitmap_s remove;
|
|
menubitmap_s back;
|
|
menubitmap_s refresh;
|
|
menubitmap_s specify;
|
|
menubitmap_s create;
|
|
menubitmap_s go;
|
|
|
|
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;
|
|
|
|
menulist_s punkbuster;
|
|
menubitmap_s pblogo;
|
|
} 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_emptyservers;
|
|
static int g_fullservers;
|
|
|
|
|
|
/*
|
|
=================
|
|
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_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.tga", 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;
|
|
|
|
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.gametype.generic.flags &= ~QMF_GRAYED;
|
|
g_arenaservers.sortkey.generic.flags &= ~QMF_GRAYED;
|
|
g_arenaservers.showempty.generic.flags &= ~QMF_GRAYED;
|
|
g_arenaservers.showfull.generic.flags &= ~QMF_GRAYED;
|
|
g_arenaservers.list.generic.flags &= ~QMF_GRAYED;
|
|
g_arenaservers.refresh.generic.flags &= ~QMF_GRAYED;
|
|
g_arenaservers.go.generic.flags &= ~QMF_GRAYED;
|
|
g_arenaservers.punkbuster.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 = "";
|
|
}
|
|
|
|
}
|
|
}
|
|
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.gametype.generic.flags |= QMF_GRAYED;
|
|
g_arenaservers.sortkey.generic.flags |= QMF_GRAYED;
|
|
g_arenaservers.showempty.generic.flags |= QMF_GRAYED;
|
|
g_arenaservers.showfull.generic.flags |= QMF_GRAYED;
|
|
g_arenaservers.list.generic.flags |= QMF_GRAYED;
|
|
g_arenaservers.refresh.generic.flags |= QMF_GRAYED;
|
|
g_arenaservers.go.generic.flags |= QMF_GRAYED;
|
|
g_arenaservers.punkbuster.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.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.showfull.generic.flags &= ~QMF_GRAYED;
|
|
g_arenaservers.list.generic.flags |= QMF_GRAYED;
|
|
g_arenaservers.refresh.generic.flags &= ~QMF_GRAYED;
|
|
g_arenaservers.go.generic.flags |= QMF_GRAYED;
|
|
g_arenaservers.punkbuster.generic.flags &= ~QMF_GRAYED;
|
|
}
|
|
|
|
// zero out list box
|
|
g_arenaservers.list.numitems = 0;
|
|
g_arenaservers.list.curvalue = 0;
|
|
g_arenaservers.list.top = 0;
|
|
|
|
// 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( !g_fullservers && ( servernodeptr->numclients == servernodeptr->maxclients ) ) {
|
|
continue;
|
|
}
|
|
|
|
switch( g_gametype ) {
|
|
case GAMES_ALL:
|
|
break;
|
|
|
|
case GAMES_FFA:
|
|
if( servernodeptr->gametype != GT_FFA ) {
|
|
continue;
|
|
}
|
|
break;
|
|
|
|
case GAMES_TEAMPLAY:
|
|
if( servernodeptr->gametype != GT_TEAM ) {
|
|
continue;
|
|
}
|
|
break;
|
|
|
|
case GAMES_TOURNEY:
|
|
if( servernodeptr->gametype != GT_TOURNAMENT ) {
|
|
continue;
|
|
}
|
|
break;
|
|
|
|
case GAMES_CTF:
|
|
if( servernodeptr->gametype != GT_CTF ) {
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
Com_sprintf( buff, MAX_LISTBOXWIDTH, "%-20.20s %-12.12s %2d/%2d %-8.8s %4s%s%3d " S_COLOR_YELLOW "%s",
|
|
servernodeptr->hostname, servernodeptr->mapname, servernodeptr->numclients,
|
|
servernodeptr->maxclients, servernodeptr->gamename,
|
|
netnames[servernodeptr->nettype], pingColor, servernodeptr->pingtime, servernodeptr->bPB ? "Yes" : "No" );
|
|
j++;
|
|
}
|
|
|
|
g_arenaservers.list.numitems = j;
|
|
g_arenaservers.list.curvalue = 0;
|
|
g_arenaservers.list.top = 0;
|
|
|
|
// 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))
|
|
{
|
|
// delete address from master list
|
|
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--;
|
|
memset( &g_arenaservers.favoriteaddresses[g_arenaservers.numfavoriteaddresses], 0, MAX_ADDRESSLENGTH );
|
|
break;
|
|
}
|
|
}
|
|
|
|
// find address in server list
|
|
for (i=0; i<g_numfavoriteservers; i++)
|
|
{
|
|
if (&g_favoriteserverlist[i] == servernodeptr)
|
|
{
|
|
|
|
// delete address from server list
|
|
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--;
|
|
memset( &g_favoriteserverlist[ g_numfavoriteservers ], 0, sizeof(servernode_t));
|
|
break;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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 );
|
|
Q_strupr( servernodeptr->mapname );
|
|
|
|
servernodeptr->numclients = atoi( Info_ValueForKey( info, "clients") );
|
|
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") );
|
|
servernodeptr->bPB = atoi( Info_ValueForKey( info, "punkbuster") );
|
|
|
|
/*
|
|
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;
|
|
}
|
|
else if( i > 11 ) {
|
|
i = 12;
|
|
}
|
|
if( *s ) {
|
|
servernodeptr->gametype = i;//-1;
|
|
Q_strncpyz( servernodeptr->gamename, s, sizeof(servernodeptr->gamename) );
|
|
}
|
|
else {
|
|
servernodeptr->gametype = i;
|
|
Q_strncpyz( servernodeptr->gamename, gamenames[i], sizeof(servernodeptr->gamename) );
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
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;
|
|
|
|
// 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;
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
} else if (g_servertype == UIAS_LOCAL) {
|
|
if (!trap_LAN_GetServerCount(AS_LOCAL)) {
|
|
// no local servers found, check again
|
|
trap_Cmd_ExecuteText( EXEC_APPEND, "localservers\n" );
|
|
g_arenaservers.refreshtime = uis.realtime + 5000;
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (uis.realtime < g_arenaservers.nextpingtime)
|
|
{
|
|
// wait for time trigger
|
|
return;
|
|
}
|
|
|
|
// trigger at 10Hz intervals
|
|
g_arenaservers.nextpingtime = uis.realtime + 10;
|
|
|
|
// 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;
|
|
|
|
// set hostname for nonresponsive favorite server
|
|
if (g_servertype == UIAS_FAVORITES) {
|
|
Info_SetValueForKey( info, "hostname", adrstr );
|
|
Info_SetValueForKey( info, "game", "???" );
|
|
}
|
|
}
|
|
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;
|
|
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 ) {
|
|
switch( g_arenaservers.gametype.curvalue ) {
|
|
default:
|
|
case GAMES_ALL:
|
|
myargs[0] = 0;
|
|
break;
|
|
|
|
case GAMES_FFA:
|
|
strcpy( myargs, " ffa" );
|
|
break;
|
|
|
|
case GAMES_TEAMPLAY:
|
|
strcpy( myargs, " team" );
|
|
break;
|
|
|
|
case GAMES_TOURNEY:
|
|
strcpy( myargs, " tourney" );
|
|
break;
|
|
|
|
case GAMES_CTF:
|
|
strcpy( myargs, " ctf" );
|
|
break;
|
|
}
|
|
|
|
|
|
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 )
|
|
{
|
|
ArenaServers_StopRefresh();
|
|
|
|
if(type >= UIAS_GLOBAL1 && type <= UIAS_GLOBAL5)
|
|
{
|
|
char masterstr[2], cvarname[sizeof("sv_master1")];
|
|
|
|
while(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++;
|
|
}
|
|
}
|
|
|
|
g_servertype = type;
|
|
|
|
switch( type ) {
|
|
default:
|
|
case UIAS_LOCAL:
|
|
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.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.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;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
PunkBuster_Confirm
|
|
=================
|
|
*/
|
|
static void Punkbuster_ConfirmEnable( qboolean result ) {
|
|
if (result)
|
|
{
|
|
trap_SetPbClStatus(1);
|
|
}
|
|
g_arenaservers.punkbuster.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "cl_punkbuster" ) );
|
|
}
|
|
|
|
static void Punkbuster_ConfirmDisable( qboolean result ) {
|
|
if (result)
|
|
{
|
|
trap_SetPbClStatus(0);
|
|
UI_Message( punkbuster_msg );
|
|
}
|
|
g_arenaservers.punkbuster.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "cl_punkbuster" ) );
|
|
}
|
|
|
|
/*
|
|
=================
|
|
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_LIST:
|
|
if( event == QM_GOTFOCUS ) {
|
|
ArenaServers_UpdatePicture();
|
|
}
|
|
break;
|
|
|
|
case ID_SCROLL_UP:
|
|
ScrollList_Key( &g_arenaservers.list, K_UPARROW );
|
|
break;
|
|
|
|
case ID_SCROLL_DOWN:
|
|
ScrollList_Key( &g_arenaservers.list, K_DOWNARROW );
|
|
break;
|
|
|
|
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_PUNKBUSTER:
|
|
if (g_arenaservers.punkbuster.curvalue)
|
|
{
|
|
UI_ConfirmMenu_Style( "Enable Punkbuster?", UI_CENTER|UI_INVERSE|UI_SMALLFONT, 0, Punkbuster_ConfirmEnable );
|
|
}
|
|
else
|
|
{
|
|
UI_ConfirmMenu_Style( "Disable Punkbuster?", UI_CENTER|UI_INVERSE|UI_SMALLFONT, 0, Punkbuster_ConfirmDisable );
|
|
}
|
|
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];
|
|
|
|
// 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;
|
|
g_arenaservers.banner.color = color_white;
|
|
|
|
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;
|
|
g_arenaservers.master.generic.x = 320;
|
|
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;
|
|
g_arenaservers.gametype.generic.x = 320;
|
|
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;
|
|
g_arenaservers.sortkey.generic.x = 320;
|
|
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;
|
|
g_arenaservers.showfull.generic.x = 320;
|
|
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;
|
|
g_arenaservers.showempty.generic.x = 320;
|
|
g_arenaservers.showempty.generic.y = y;
|
|
|
|
y += 3 * SMALLCHAR_HEIGHT;
|
|
g_arenaservers.list.generic.type = MTYPE_SCROLLLIST;
|
|
g_arenaservers.list.generic.flags = QMF_HIGHLIGHT_IF_FOCUS;
|
|
g_arenaservers.list.generic.id = ID_LIST;
|
|
g_arenaservers.list.generic.callback = ArenaServers_Event;
|
|
g_arenaservers.list.generic.x = 72;
|
|
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 = 128;
|
|
g_arenaservers.mappic.height = 96;
|
|
g_arenaservers.mappic.errorpic = ART_UNKNOWNMAP;
|
|
|
|
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;
|
|
|
|
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;
|
|
|
|
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.punkbuster.generic.type = MTYPE_SPINCONTROL;
|
|
g_arenaservers.punkbuster.generic.name = "Punkbuster:";
|
|
g_arenaservers.punkbuster.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
|
|
g_arenaservers.punkbuster.generic.callback = ArenaServers_Event;
|
|
g_arenaservers.punkbuster.generic.id = ID_PUNKBUSTER;
|
|
g_arenaservers.punkbuster.generic.x = 480+32;
|
|
g_arenaservers.punkbuster.generic.y = 144;
|
|
g_arenaservers.punkbuster.itemnames = punkbuster_items;
|
|
|
|
g_arenaservers.pblogo.generic.type = MTYPE_BITMAP;
|
|
g_arenaservers.pblogo.generic.name = ART_PUNKBUSTER;
|
|
g_arenaservers.pblogo.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
|
|
g_arenaservers.pblogo.generic.x = 526;
|
|
g_arenaservers.pblogo.generic.y = 176;
|
|
g_arenaservers.pblogo.width = 32;
|
|
g_arenaservers.pblogo.height = 16;
|
|
g_arenaservers.pblogo.errorpic = ART_UNKNOWNMAP;
|
|
|
|
Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.banner );
|
|
|
|
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.mappic );
|
|
Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.status );
|
|
Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.statusbar );
|
|
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 );
|
|
Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.list );
|
|
|
|
Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.remove );
|
|
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 );
|
|
|
|
Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.punkbuster );
|
|
Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.pblogo );
|
|
|
|
ArenaServers_LoadFavorites();
|
|
|
|
g_arenaservers.master.curvalue = g_servertype = Com_Clamp( 0, 6, ui_browserMaster.integer );
|
|
|
|
g_gametype = Com_Clamp( 0, 4, ui_browserGameType.integer );
|
|
g_arenaservers.gametype.curvalue = g_gametype;
|
|
|
|
g_sortkey = Com_Clamp( 0, 4, 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.punkbuster.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "cl_punkbuster" ) );
|
|
|
|
// 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 ) {
|
|
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 );
|
|
trap_R_RegisterShaderNoMip( ART_UNKNOWNMAP );
|
|
trap_R_RegisterShaderNoMip( ART_PUNKBUSTER );
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
UI_ArenaServersMenu
|
|
=================
|
|
*/
|
|
void UI_ArenaServersMenu( void ) {
|
|
ArenaServers_MenuInit();
|
|
UI_PushMenu( &g_arenaservers.menu );
|
|
}
|