Oct 8th 2000: xqf-0.9.4f - Alex Burger <alex@fragit.net>

-UnrealTournament master support using Gamespy style master via QStat 2.4a
-Add Epic UT Master server to default master list
-Remove Gamespy master server entry from default master list
-Fixed master list bug

Oct 4th 2000: xqf-0.9.4e - Alex Burger <alex@fragit.net>
-Soldier of Fortune support
-Gamespy master server support when used with QStat 2.4a
-Format of 'lists' file changed to record game type in master entry
-Ability to add the same master to multiple games such as Gamespy's master

xqf-0.9.4d - Bill Adams <webmaster@evil.inetarena.com>
-When browsing Q3A games the mods (e.g. arena, osp, beryllium, etc.) show
 up in the "Game" column along with the game type (FFA, etc.).
-The mod appears in its own column for Q3A games
-You can filter by mod
-You can filter by the version string


git-svn-id: http://svn.code.sf.net/p/xqf/code/trunk@8 d2ac09be-c843-0410-8b1f-f8a84130e0ec
This commit is contained in:
Alex Burger 2000-11-05 20:55:58 +00:00 committed by alex_b
parent 9ca134e3c3
commit 85e3cf4db0
17 changed files with 426 additions and 47 deletions

View File

@ -0,0 +1,20 @@
Oct 8th 2000: xqf-0.9.4f - Alex Burger <alex@fragit.net>
-UnrealTournament master support using Gamespy style master via QStat 2.4a
-Add Epic UT Master server to default master list
-Remove Gamespy master server entry from default master list
-Fixed master list bug
Oct 4th 2000: xqf-0.9.4e - Alex Burger <alex@fragit.net>
-Soldier of Fortune support
-Gamespy master server support when used with QStat 2.4a
-Format of 'lists' file changed to record game type in master entry
-Ability to add the same master to multiple games such as Gamespy's master
xqf-0.9.4d - Bill Adams <webmaster@evil.inetarena.com>
-When browsing Q3A games the mods (e.g. arena, osp, beryllium, etc.) show
up in the "Game" column along with the game type (FFA, etc.).
-The mod appears in its own column for Q3A games
-You can filter by mod
-You can filter by the version string

View File

@ -1,6 +1,6 @@
XQF 0.9.4
(March 18 2000)
XQF 0.9.4f
(October 4th 2000)
DESCRIPTION
-----------
@ -13,8 +13,10 @@ Development platform: Debian/Linux (glibc2.1), XFree86 3.3.6, GTK+ 1.2.7.
Features:
- Supports Quake, QuakeWorld, Quake2, Quake3: Arena, Hexen2, HexenWorld,
Sin, Half-Life, Kingpin, Heretic2, Unreal Tournament
Sin, Half-Life, Kingpin, Heretic2, Unreal Tournament,
Soldier of Fortune
- Uses QStat to communicate with masters/servers
- Support (unauthenticated) Gamespy style master servers using QStat 2.4a
- Displays server rules and player info
- Players and servers sorting
- Favorite servers list
@ -35,7 +37,7 @@ REQUIREMENTS
- A UNIX computer and C compiler (gcc)
- X11 (X Window System)
- GTK+ 1.2.5+ http://www.gtk.org
- QStat 2.3g http://www.activesw.com/people/steve/qstat.html
- QStat 2.4 http://www.activesw.com/people/steve/qstat.html
- [Optionally] wget ftp://ftp.gnu.org/gnu/wget/ to retrieve server
listings from the Web
- [Optionally] gzip http://www.gnu.org/software/gzip/gzip.html
@ -56,9 +58,23 @@ To install the binary become root if necessary and run "make install".
USAGE
-----
QStat 2.2b or 2.3[cdefg] is required. QStat 2.3g is *HIGHLY* recommended.
QStat 2.2b or 2.3[cdefg] is required. QStat 2.4 is *HIGHLY* recommended.
It must be in your $PATH.
Gamespy style master and Soldier of Fortune support is only available with
QStat 2.4a.
Note: Gamespy's master servers use an authentication sequence that is not
supported by QStat 2.4a. This means that you can not query a Gamespy master
using QStat and XQF. The Unreal Tournament master server at Epic also
uses a Gamespy style master server but does not require authentication.
This means that you can query Epic's UT master server using:
gmaster://unreal.epicgames.com:28900
Please see the QStat documentation for more information on the types of
master servers.
QStat home page is http://www.activesw.com/people/steve/qstat.html
Server list navigation:
@ -69,6 +85,14 @@ Server list navigation:
XQF can be customized via GTK's rc files. XQF parses files
/etc/gtkrc, $HOME/.gtkrc, $HOME/.qf/gtkrc.
When adding a master server, the following prefixes are support:
master:// (regular master server)
gmaster:// (Gamespy style master server)
http:// (html page containing list)
Not specifying a prefix will default to master://
Please send bug reports or suggestions to roma@botik.ru

View File

@ -65,6 +65,8 @@ int filter_not_full;
int filter_not_empty;
int filter_no_cheats;
int filter_no_password;
char *mod_contains;
char *version_contains;
unsigned filter_current_time = 1;
@ -75,6 +77,8 @@ static GtkWidget *filter_not_full_check_button;
static GtkWidget *filter_not_empty_check_button;
static GtkWidget *filter_no_cheats_check_button;
static GtkWidget *filter_no_password_check_button;
static GtkWidget *mod_contains_entry;
static GtkWidget *version_contains_entry;
void apply_filters (unsigned mask, struct server *s) {
@ -124,11 +128,31 @@ GSList *build_filtered_list (unsigned mask, GSList *servers) {
static int server_filter (struct server *s) {
char **info_ptr;
if (s->ping == -1) /* no information */
return TRUE;
if( mod_contains && strlen( mod_contains ) && ! s->mod )
return FALSE;
if( version_contains && strlen (version_contains)) {
/* Filter for the version */
for (info_ptr = s->info; info_ptr && *info_ptr; info_ptr += 2) {
if (strcmp (*info_ptr, "version") == 0) {
if( !strstr( info_ptr[1], version_contains )){
return FALSE;
}
}
}
}/*end version check */
if (s->retries < filter_retries &&
s->ping < filter_ping &&
s->ping < filter_ping &&
( !mod_contains || !strlen( mod_contains ) ||
( s->mod && strstr( s->mod, mod_contains ))) &&
(!filter_not_full || s->curplayers != s->maxplayers) &&
(!filter_not_empty || s->curplayers != 0) &&
(!filter_no_cheats || (s->flags & SERVER_CHEATS) == 0) &&
@ -148,13 +172,17 @@ static void server_filter_init (void) {
filter_not_empty = config_get_bool ("not empty=false");
filter_no_cheats = config_get_bool ("no cheats=false");
filter_no_password = config_get_bool ("no password=false");
mod_contains = config_get_string_with_default ("mod_contains",NULL);
version_contains = config_get_string_with_default ("version_contains",NULL);
config_pop_prefix ();
}
static void server_filter_new_defaults (void) {
int i;
char *cptr;
gchar *gcptr;
int text_changed;
config_push_prefix ("/" CONFIG_FILE "/Server Filter");
@ -171,6 +199,72 @@ static void server_filter_new_defaults (void) {
filters[FILTER_SERVER].changed = FILTER_CHANGED;
}
/* MOD string values -- baa */
gcptr = gtk_editable_get_chars (GTK_EDITABLE (mod_contains_entry), 0, -1 );
text_changed = 0;
if( strlen( gcptr )){
/*
First case, the user entered something. See if the value
is different
*/
if (mod_contains){
if( strcmp( gcptr, mod_contains )) text_changed = 1;
g_free( mod_contains );
} else {
text_changed = 1;
}
mod_contains = g_malloc( sizeof( char ) * ( strlen( gcptr ) + 1 ));
sprintf( mod_contains, "%s\0", gcptr );
if (text_changed) {
config_set_string ("mod_contains", mod_contains );
filters[FILTER_SERVER].changed = FILTER_CHANGED;
}
} else {
if (mod_contains){
text_changed = 1; /* From something to nothing */
g_free( mod_contains );
config_set_string ("mod_contains", "" );
filters[FILTER_SERVER].changed = FILTER_CHANGED;
}
mod_contains = NULL;
}
g_free( gcptr );
/* Version string values -- baa */
gcptr = gtk_editable_get_chars (GTK_EDITABLE (version_contains_entry), 0, -1 );
text_changed = 0;
if( strlen( gcptr )){
/*
First case, the user entered something. See if the value
is different
*/
if (version_contains){
if( strcmp( gcptr, version_contains )) text_changed = 1;
g_free( version_contains );
} else {
text_changed = 1;
}
version_contains = g_malloc( sizeof( char ) * ( strlen( gcptr ) + 1 ));
sprintf( version_contains, "%s\0", gcptr );
if (text_changed) {
config_set_string ("version_contains", version_contains );
filters[FILTER_SERVER].changed = FILTER_CHANGED;
}
} else {
if (version_contains){
text_changed = 1; /* From something to nothing */
g_free( version_contains );
config_set_string ("version_contains", "" );
filters[FILTER_SERVER].changed = FILTER_CHANGED;
}
version_contains = NULL;
}
g_free( gcptr );
i = GTK_TOGGLE_BUTTON (filter_not_full_check_button)->active;
if (filter_not_full != i) {
config_set_bool ("not full", filter_not_full = i);
@ -225,7 +319,7 @@ static void server_filter_page (GtkWidget *notebook) {
alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
gtk_container_add (GTK_CONTAINER (frame), alignment);
table = gtk_table_new (6, 2, FALSE);
table = gtk_table_new (6, 5, FALSE);
gtk_table_set_row_spacings (GTK_TABLE (table), 2);
gtk_table_set_col_spacings (GTK_TABLE (table), 4);
gtk_container_set_border_width (GTK_CONTAINER (table), 6);
@ -264,6 +358,43 @@ static void server_filter_page (GtkWidget *notebook) {
1, 2, 1, 2);
gtk_widget_show (filter_retries_spinner);
/* MOD Filter -- baa */
/* http://developer.gnome.org/doc/API/gtk/gtktable.html */
label = gtk_label_new ("the mod contains the string");
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (table), label, 3, 4, 0, 1, GTK_FILL, GTK_FILL,
0, 0);
gtk_widget_show (label);
mod_contains_entry = gtk_entry_new_with_max_length (32);
gtk_widget_set_usize (mod_contains_entry, 64, -1);
gtk_entry_set_editable (GTK_ENTRY (mod_contains_entry), TRUE);
gtk_entry_set_text (GTK_ENTRY (mod_contains_entry),
(mod_contains)? mod_contains : "");
gtk_table_attach_defaults (GTK_TABLE (table), mod_contains_entry, 4, 5, 0, 1);
gtk_widget_show (mod_contains_entry);
/* Version Filter -- baa */
label = gtk_label_new ("the version contains the string");
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (table), label, 3, 4, 1, 2, GTK_FILL, GTK_FILL,
0, 0);
gtk_widget_show (label);
version_contains_entry = gtk_entry_new_with_max_length (32);
gtk_widget_set_usize (version_contains_entry, 64, -1);
gtk_entry_set_editable (GTK_ENTRY (version_contains_entry), TRUE);
gtk_entry_set_text (GTK_ENTRY (version_contains_entry),
(version_contains)? version_contains : "");
gtk_table_attach_defaults (GTK_TABLE (table), version_contains_entry, 4, 5, 1, 2);
gtk_widget_show (version_contains_entry);
/* not full */
filter_not_full_check_button =

View File

@ -307,6 +307,27 @@ struct game games[] = {
NULL,
quake_save_info
},
{
SFS_SERVER,
GAME_CONNECT | GAME_RCON,
"Soldier of Fortune",
SFS_DEFAULT_PORT,
0,
"SFS",
"SFS",
"-sfs",
"-q2s", // assume a standard Quake2 style master. May be wrong.
&sfs_pix,
q2_parse_player,
quake_parse_server,
q2_analyze_serverinfo,
config_is_valid_generic,
NULL,
q2_exec_generic,
NULL,
quake_save_info
},
{
HR_SERVER,
GAME_CONNECT | GAME_RCON,
@ -339,7 +360,7 @@ struct game games[] = {
"UNS",
"UNS",
"-uns",
NULL,
"uns",
&un_pix,
un_parse_player,
@ -735,12 +756,13 @@ static void q2_analyze_serverinfo (struct server *s) {
#ifdef QSTAT23
static char *q3a_gametypes[5] = {
static char *q3a_gametypes[6] = {
"<FFA>", /* Free for All */
"<1v1>", /* Tournament */
NULL, /* Single Player */
"<TDM>", /* Team Deathmatch */
"<CTF>"
"<CTF>",
" mod ", /* 5 is usually a client-side mod */
};
@ -753,17 +775,36 @@ static void q3_analyze_serverinfo (struct server *s) {
s->flags |= SERVER_SPECTATE;
for (info_ptr = s->info; info_ptr && *info_ptr; info_ptr += 2) {
/*
fs_game sets the active directory and is how one chooses
a mod on the command line. This should not show up in
the server string but some times it does. We will
take either fs_game or gamename as the "mod" string.
--baa
*/
if (strcmp (*info_ptr, "fs_game") == 0) {
s->game = info_ptr[1];
if (strcmp (info_ptr[1], "baseq3")) {
s->mod = info_ptr[1];
}
}
else if (strcmp (*info_ptr, "gamename") == 0) {
if (strcmp (info_ptr[1], "baseq3")) {
/* We only set the mod if the name is NOT baseq3. */
s->mod = info_ptr[1];
}
}
else if (!s->game && strcmp (*info_ptr, "g_gametype") == 0) {
/* A value of 5 is usually a mod */
n = strtol (info_ptr[1], &endptr, 10);
if (endptr == info_ptr[1]) {
s->game = info_ptr[1];
}
else {
if (n < 5)
if (n < 6)
s->game = q3a_gametypes[n];
}
}

View File

@ -45,6 +45,7 @@
#include "xpm/sn.xpm"
#include "xpm/hl.xpm"
#include "xpm/kp.xpm"
#include "xpm/sfs.xpm"
#include "xpm/hr2.xpm"
#include "xpm/un.xpm"
@ -92,6 +93,7 @@ struct pixmap hw_pix;
struct pixmap sn_pix;
struct pixmap hl_pix;
struct pixmap kp_pix;
struct pixmap sfs_pix;
struct pixmap hr_pix;
struct pixmap un_pix;
@ -186,6 +188,7 @@ void free_pixmaps (void) {
free_pixmap (&sn_pix);
free_pixmap (&hl_pix);
free_pixmap (&kp_pix);
free_pixmap (&sfs_pix);
free_pixmap (&hr_pix);
free_pixmap (&un_pix);
@ -248,6 +251,7 @@ void init_pixmaps (GtkWidget *window) {
create_pixmap (window, &sn_pix, sn_xpm);
create_pixmap (window, &hl_pix, hl_xpm);
create_pixmap (window, &kp_pix, kp_xpm);
create_pixmap (window, &sfs_pix, sfs_xpm);
create_pixmap (window, &hr_pix, hr2_xpm);
create_pixmap (window, &un_pix, un_xpm);

View File

@ -55,6 +55,7 @@ extern struct pixmap hw_pix;
extern struct pixmap sn_pix;
extern struct pixmap hl_pix;
extern struct pixmap kp_pix;
extern struct pixmap sfs_pix;
extern struct pixmap hr_pix;
extern struct pixmap un_pix;

View File

@ -186,6 +186,11 @@ void server_free_info (struct server *s) {
s->info = NULL;
s->game = NULL;
}
if (s->mod) { /* Added by baa */
s->mod = NULL;
}
if (s->players) {
g_slist_foreach (s->players, (GFunc) g_free, NULL);
g_slist_free (s->players);

View File

@ -99,6 +99,10 @@ int compare_servers (const struct server *s1, const struct server *s2,
res = compare_strings (s1->game, s2->game);
break;
case SORT_SERVER_MOD:
res = compare_strings (s1->mod, s2->mod);
break;
case SORT_SERVER_PLAYERS:
res = s1->curplayers - s2->curplayers;
if (!res) {

View File

@ -29,7 +29,8 @@ enum ssort_mode {
SORT_SERVER_TO,
SORT_SERVER_PLAYERS,
SORT_SERVER_MAP,
SORT_SERVER_GAME
SORT_SERVER_GAME,
SORT_SERVER_MOD
};
enum psort_mode {

View File

@ -1,5 +1,5 @@
/* XQF - Quake server browser and launcher
* Copyright (C) 1998-2000 Roman Pozlevich <roma@botik.ru>
/* XQF - Quake server browser and launcher Copyright (C) 1998-2000 Roman
* Pozlevich <roma@botik.ru>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -68,18 +68,25 @@ static void save_list (FILE *f, struct master *m) {
}
else {
if (m->url) {
fprintf (f, "[%s]\n", m->url);
fprintf (f, "[%s %s]\n", games[m->type].id, m->url);
}
else {
fprintf (f, "[%s%s:%d]\n", PREFIX_MASTER,
(m->hostname)? m->hostname : inet_ntoa (m->host->ip), m->port);
if (m->master_type == 1)
{
fprintf (f, "[%s %s%s:%d]\n", games[m->type].id, PREFIX_GMASTER,
(m->hostname)? m->hostname : inet_ntoa (m->host->ip), m->port);
}
else
{
fprintf (f, "[%s %s%s:%d]\n", games[m->type].id, PREFIX_MASTER,
(m->hostname)? m->hostname : inet_ntoa (m->host->ip), m->port);
}
}
}
for (srv = m->servers; srv; srv = srv->next) {
s = (struct server *) srv->data;
fprintf (f, "%s %s:%d\n", games[s->type].id,
inet_ntoa (s->host->ip), s->port);
fprintf (f, "%s %s:%d\n", games[s->type].id, inet_ntoa (s->host->ip), s->port);
}
fprintf (f, "\n");
@ -171,7 +178,7 @@ static void save_server_info (const char *filename, GSList *servers) {
}
static struct master *find_master_server (char *addr, unsigned short port) {
static struct master *find_master_server (char *addr, unsigned short port, char *str) {
GSList *list;
struct master *m;
struct in_addr ip;
@ -181,15 +188,25 @@ static struct master *find_master_server (char *addr, unsigned short port) {
for (list = all_masters; list; list = list->next) {
m = (struct master *) list->data;
if (m->port && m->port == port) {
if (m->hostname) {
if (m->port && m->port == port)
{
if (m->hostname)
{
if (!g_strcasecmp (m->hostname, addr))
return m;
{
if (!str) // pre 0.9.4e list file
return m;
if (!g_strcasecmp (games[m->type].id, str)) // list file in new format
return m;
}
}
else {
if (m->host && inet_aton (addr, &ip) &&
ip.s_addr == m->host->ip.s_addr) {
return m;
else
{
if (m->host && inet_aton (addr, &ip) && ip.s_addr == m->host->ip.s_addr) {
if (!str) // pre 0.9.4e list file
return m;
if (!g_strcasecmp (games[m->type].id, str))
return m;
}
}
}
@ -298,7 +315,7 @@ static struct master *find_master_url (char *url) {
}
static struct master *read_list_parse_master (char *str) {
static struct master *read_list_parse_master (char *str, char *str2) {
char *addr;
unsigned short port;
struct master *m;
@ -308,7 +325,15 @@ static struct master *read_list_parse_master (char *str) {
if (g_strncasecmp (str, PREFIX_MASTER, sizeof (PREFIX_MASTER) - 1) == 0) {
if (parse_address (str + sizeof (PREFIX_MASTER) - 1, &addr, &port)) {
m = find_master_server (addr, port);
m = find_master_server (addr, port, str2);
g_free (addr);
return m;
}
}
if (g_strncasecmp (str, PREFIX_GMASTER, sizeof (PREFIX_GMASTER) - 1) == 0) {
if (parse_address (str + sizeof (PREFIX_GMASTER) - 1, &addr, &port)) {
m = find_master_server (addr, port, str2);
g_free (addr);
return m;
}
@ -373,16 +398,28 @@ static void read_lists (const char *filename) {
if (n < 1)
continue;
if (token[0][0] == '[') {
ch = strchr (token[0] + 1, ']');
if (token[0][0] == '[') { // line is a master
ch = strchr (token[0] + 1, ']'); // does token 0 have a ]?
if (ch) { // it's a favorites or pre 0.9.4e lists file
*ch = '\0';
if (m && m->servers)
m->servers = g_slist_reverse (m->servers);
m = read_list_parse_master (token[0] + 1, NULL);
}
else {
ch = strchr (token[1], ']'); // does token 1 have a ]?
if (ch) {
*ch = '\0';
if (m && m->servers)
m->servers = g_slist_reverse (m->servers);
*ch = '\0';
m = read_list_parse_master (token[0] + 1);
if (m && m->servers)
m->servers = g_slist_reverse (m->servers);
m = read_list_parse_master (token[1], token[0] + 1); // master, type
}
}
}
else {
if (!m || n < 2)
@ -555,7 +592,7 @@ struct master *add_master (char *path, char *name, enum server_type type,
}
}
m = find_master_server (addr, port);
m = find_master_server (addr, port, games[type].id);
if (lookup_only) {
g_free (addr);
@ -579,8 +616,12 @@ struct master *add_master (char *path, char *name, enum server_type type,
g_free (addr);
return m;
}
else {
else
{
m = create_master (name, type, FALSE);
m->master_type = 0; // Regular master
h = host_add (addr);
if (h) {
m->host = h;
@ -595,6 +636,65 @@ struct master *add_master (char *path, char *name, enum server_type type,
}
}
else if (g_strncasecmp (path, PREFIX_GMASTER, sizeof (PREFIX_GMASTER) - 1) == 0) {
if (parse_address (path + sizeof (PREFIX_GMASTER) - 1, &addr, &port)) {
if (!port) {
if (games[type].default_master_port) {
port = games[type].default_master_port;
}
else {
g_free (addr);
return NULL;
}
}
m = find_master_server (addr, port, games[type].id);
if (lookup_only) {
g_free (addr);
return m;
}
if (m) {
if (user) {
/* Master renaming is forced by user */
g_free (m->name);
m->name = g_strdup (name);
m->user = TRUE;
}
else {
/* Automatically rename masters that are not edited by user */
if (!m->user) {
g_free (m->name);
m->name = g_strdup (name);
}
}
g_free (addr);
return m;
}
else
{
m = create_master (name, type, FALSE);
m->master_type = 1; // Gamespy master
h = host_add (addr);
if (h) {
m->host = h;
host_ref (h);
g_free (addr);
}
else {
m->hostname = addr;
}
m->port = port;
}
}
}
else {
if (g_strncasecmp (path, PREFIX_URL_HTTP, sizeof (PREFIX_URL_HTTP) - 1)
== 0) {
@ -716,6 +816,11 @@ static char *builtin_masters_update_info[] = {
"ADD Q2S:HR http://www.gameaholic.com/servers/qspy-heretic2 Gameaholic.Com",
#ifdef QSTAT_HAS_UNREAL_SUPPORT
"ADD UNS gmaster://unreal.epicgames.com:28900 Epic",
#endif
NULL
};
@ -857,8 +962,14 @@ static void save_master_list (void) {
confstr = g_strjoin (" ", typeid, m->url, m->name, NULL);
}
else {
addr = g_strdup_printf (PREFIX_MASTER "%s:%d",
(m->hostname)? m->hostname : inet_ntoa (m->host->ip), m->port);
if (m->master_type == 1)
addr = g_strdup_printf (PREFIX_GMASTER "%s:%d",
(m->hostname)? m->hostname : inet_ntoa (m->host->ip), m->port);
else
addr = g_strdup_printf (PREFIX_MASTER "%s:%d",
(m->hostname)? m->hostname : inet_ntoa (m->host->ip), m->port);
confstr = g_strjoin (" ", typeid, addr, m->name, NULL);
g_free (addr);
}

View File

@ -27,6 +27,7 @@
#define FILENAME_SRVINFO "srvinfo"
#define PREFIX_MASTER "master://"
#define PREFIX_GMASTER "gmaster://"
#define PREFIX_URL_HTTP "http://"
#define ACTION_ADD "ADD"

View File

@ -90,7 +90,7 @@ void assemble_server_address (char *buf, int size, struct server *s) {
static int server_clist_refresh_row (struct server *s, int row) {
GdkPixmap *server_pixmap;
GdkBitmap *server_pixmask;
char *text[7];
char *text[8];
char buf1[256], buf2[32], buf3[32], buf4[32];
char *retries;
struct pixmap *retries_pix = NULL;
@ -139,8 +139,9 @@ static int server_clist_refresh_row (struct server *s, int row) {
g_snprintf (buf4, 32, "%d/%d", s->curplayers, s->maxplayers);
text[4] = (!s->curplayers)? buf4 : NULL;
text[5] = (s->map)? s->map : NULL;
text[5] = (s->map) ? s->map : NULL;
text[6] = (s->game)? s->game : NULL;
text[7] = (s->mod) ? s->mod : NULL;
if (row < 0) {
row = gtk_clist_append (server_clist, text);

View File

@ -709,7 +709,11 @@ static struct stat_conn *stat_update_master_qstat (struct stat_job *job,
g_snprintf (buf1, 64, "%d", maxretries + 2);
argv[argi++] = buf2;
g_snprintf (buf2, 64, "%s,outfile", games[m->type].qstat_master_option);
if (m->master_type == 1)
g_snprintf (buf2, 64, "-gsm,%s,outfile", games[m->type].qstat_str);
else
g_snprintf (buf2, 64, "%s,outfile", games[m->type].qstat_master_option);
argv[argi++] = buf3;
g_snprintf (buf3, 64, "%s:%d,-", inet_ntoa (m->host->ip), m->port);

22
xqf/src/xpm/sfs.xpm Normal file
View File

@ -0,0 +1,22 @@
/* XPM */
static char * sfs_xpm[] = {
"17 17 2 1",
" c None",
". c #000000",
" .... ",
" . ",
" . ",
" ... ",
" . ",
" . ",
" .... ... ",
" . . ",
" . . ",
" . . ",
" ... ..... ",
" . ",
" . ",
" ... ",
" . ",
" . ",
" . "};

View File

@ -38,21 +38,22 @@ GtkWidget *pane1_widget;
GtkWidget *pane2_widget;
GtkWidget *pane3_widget;
static struct clist_column server_columns[7] = {
static struct clist_column server_columns[8] = {
{ "Name", 180, GTK_JUSTIFY_LEFT, NULL },
{ "Address", 140, GTK_JUSTIFY_LEFT, NULL },
{ "Ping", 45, GTK_JUSTIFY_RIGHT, NULL },
{ "TO", 35, GTK_JUSTIFY_RIGHT, NULL },
{ "Players", 65, GTK_JUSTIFY_RIGHT, NULL },
{ "Map", 55, GTK_JUSTIFY_LEFT, NULL },
{ "Game", 55, GTK_JUSTIFY_LEFT, NULL }
{ "Game", 55, GTK_JUSTIFY_LEFT, NULL },
{ "MOD", 55, GTK_JUSTIFY_LEFT, NULL }
};
struct clist_def server_clist_def = {
CWIDGET_CLIST,
"Server List",
server_columns,
7,
8,
GTK_SELECTION_EXTENDED,
630, 270,
SORT_SERVER_PING, GTK_SORT_ASCENDING

View File

@ -1367,6 +1367,9 @@ static void about_dialog (GtkWidget *widget, gpointer data) {
"X11 Quake/QuakeWorld/Quake2/Quake3 Front-End\n"
"Version " XQF_VERSION "\n\n"
"Copyright (C) 1998-2000 Roman Pozlevich <roma@botik.ru>\n\n"
"Mod & server version filter: Bill Adams <webmaster@evil.inetarena.com>\n"
"SoF & GameSpy support: Alex Burger <alex@fragit.net>\n\n"
"http://www.linuxgames.com/xqf/");
}

View File

@ -49,6 +49,7 @@
#define SN_DEFAULT_PORT 22450 /* Sin */
#define HL_DEFAULT_PORT 27015 /* Half-Life */
#define KP_DEFAULT_PORT 31510 /* Kingpin */
#define SFS_DEFAULT_PORT 28910 /* Soldier of Fortune */
#define HR_DEFAULT_PORT 28910 /* Heretic2 */
#define UN_DEFAULT_PORT 7777 /* Unreal */
@ -85,6 +86,7 @@ enum server_type {
SN_SERVER,
HL_SERVER,
KP_SERVER,
SFS_SERVER,
HR_SERVER,
#ifdef QSTAT_HAS_UNREAL_SUPPORT
UN_SERVER,
@ -127,6 +129,7 @@ struct server {
char *name;
char *map;
char *mod;
unsigned short maxplayers;
unsigned short curplayers;
short ping;
@ -172,6 +175,8 @@ struct master {
enum master_state state;
GSList *masters;
int master_type;
};
extern time_t xqf_start_time;