/* Copyright (C) 2003-2006 Andrey Nazarov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "ui_local.h" /* ============================================================================= JOIN SERVER MENU ============================================================================= */ #define ID_LIST 101 #define MAX_STATUS_RULES 64 typedef struct serverSlot_s { qboolean valid; char *rules[MAX_STATUS_RULES+1]; int numRules; char *players[MAX_STATUS_PLAYERS+1]; int numPlayers; char address[MAX_QPATH]; char realAddress[MAX_QPATH]; } serverSlot_t; typedef struct m_joinServer_s { menuFrameWork_t menu; menuList_t list; menuList_t info; menuList_t players; menuStatic_t banner; qboolean active; qboolean cursorSet; serverSlot_t servers[MAX_LOCAL_SERVERS]; char *names[MAX_LOCAL_SERVERS+1]; } m_joinServer_t; static m_joinServer_t m_join; static void UpdateSelection( void ) { serverSlot_t *s; s = &m_join.servers[m_join.list.curvalue]; if( s->valid ) { m_join.info.generic.flags &= ~QMF_HIDDEN; m_join.info.itemnames = ( const char ** )s->rules; m_join.info.numItems = s->numRules; if( s->numPlayers ) { m_join.players.generic.flags &= ~QMF_HIDDEN; m_join.players.itemnames = ( const char ** )s->players; m_join.players.numItems = s->numPlayers; } else { m_join.players.generic.flags |= QMF_HIDDEN; m_join.players.itemnames = NULL; m_join.players.numItems = 0; } m_join.menu.statusbar = "Press Enter to connect; Space to refresh"; } else { m_join.info.generic.flags |= QMF_HIDDEN; m_join.info.itemnames = NULL; m_join.info.numItems = 0; m_join.players.generic.flags |= QMF_HIDDEN; m_join.players.itemnames = NULL; m_join.players.numItems = 0; m_join.menu.statusbar = "Press Space to refresh"; } } void UI_AddToServerList( const serverStatus_t *status ) { serverSlot_t *slot; int i; char *s; const char *info; char key[MAX_STRING_CHARS]; char value[MAX_STRING_CHARS]; const playerStatus_t *player; if( !m_join.active ) { return; } // see if already added for( i = 0, slot = m_join.servers; i < m_join.list.numItems; i++, slot++ ) { if( !strcmp( status->address, slot->realAddress ) ) { break; } } if( i == m_join.list.numItems ) { // create new slot if( m_join.list.numItems == MAX_LOCAL_SERVERS ) { return; } strcpy( slot->realAddress, status->address ); strcpy( slot->address, status->address ); if( !m_join.cursorSet ) { m_join.list.curvalue = i; m_join.cursorSet = qtrue; } m_join.list.numItems++; m_join.names[m_join.list.numItems] = NULL; } slot->valid = qtrue; s = UI_FormatColumns( 3, Info_ValueForKey( status->infostring, "hostname" ), Info_ValueForKey( status->infostring, "mapname" ), va( "%i/%s", status->numPlayers, Info_ValueForKey( status->infostring, "maxclients" ) ) ); if( m_join.names[i] ) { com.Free( m_join.names[i] ); } m_join.names[i] = s; for( i = 0; i < slot->numRules; i++ ) { com.Free( slot->rules[i] ); slot->rules[i] = NULL; } for( i = 0; i < slot->numPlayers; i++ ) { com.Free( slot->players[i] ); slot->players[i] = NULL; } slot->numRules = 0; info = status->infostring; do { Info_NextPair( &info, key, value ); if( !key[0] ) { break; } s = UI_FormatColumns( 2, key, value ); slot->rules[slot->numRules++] = s; } while( info && slot->numRules < MAX_STATUS_RULES ); slot->rules[slot->numRules] = NULL; for( i = 0, player = status->players ; i < status->numPlayers; i++, player++ ) { s = UI_FormatColumns( 3, va( "%i", player->score ), va( "%i", player->ping ), player->name ); slot->players[i] = s; } slot->numPlayers = status->numPlayers; slot->players[slot->numPlayers] = NULL; UpdateSelection(); } static void PingSelected( void ) { serverSlot_t *slot; char address[MAX_QPATH]; int i; char *s; slot = &m_join.servers[m_join.list.curvalue]; slot->valid = qfalse; s = UI_FormatColumns( 3, slot->address, "???", "?/?" ); if( m_join.names[m_join.list.curvalue] ) { com.Free( m_join.names[m_join.list.curvalue] ); } m_join.names[m_join.list.curvalue] = s; for( i = 0; i < slot->numRules; i++ ) { com.Free( slot->rules[i] ); slot->rules[i] = NULL; } for( i = 0; i < slot->numPlayers; i++ ) { com.Free( slot->players[i] ); slot->players[i] = NULL; } slot->numRules = 0; slot->numPlayers = 0; UpdateSelection(); m_join.menu.statusbar = "Pinging servers, please wait..."; client.UpdateScreen(); strcpy( address, slot->realAddress ); client.SendStatusRequest( address, sizeof( address ) ); UpdateSelection(); } static void AddUnlistedServers( void ) { char *s; char address[MAX_QPATH]; serverSlot_t *slot; int i, j; m_join.active = qtrue; // ping broadcast strcpy( address, "broadcast" ); client.SendStatusRequest( address, sizeof( address ) ); for( i = 0; i < MAX_LOCAL_SERVERS; i++ ) { cvar.VariableStringBuffer( va( "adr%i", i ), address, sizeof( address ) ); if( !address[0] ) { continue; } // ignore if already listed for( j = 0, slot = m_join.servers; j < m_join.list.numItems; j++, slot++ ) { if( !Q_stricmp( address, slot->address ) ) { break; } } if( j != m_join.list.numItems ) { continue; } if( m_join.list.numItems == MAX_LOCAL_SERVERS ) { break; } // save original address strcpy( slot->address, address ); // resolve real ip client.SendStatusRequest( address, sizeof( address ) ); // save real ip strcpy( slot->realAddress, address ); s = UI_FormatColumns( 3, slot->address, "???", "?/?" ); m_join.names[m_join.list.numItems++] = s; m_join.names[m_join.list.numItems] = NULL; client.UpdateScreen(); } } static void FreeListedServers( void ) { int i, j; serverSlot_t *slot; for( i = 0, slot = m_join.servers; i < m_join.list.numItems; i++, slot++ ) { for( j = 0; j < slot->numRules; j++ ) { com.Free( slot->rules[j] ); } for( j = 0; j < slot->numPlayers; j++ ) { com.Free( slot->players[j] ); } memset( slot, 0, sizeof( *slot ) ); } for( i=0 ; i