DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

MenuScreen_Shell_Browser.cpp (13505B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
     10 it under the terms of the GNU General Public License as published by
     11 the Free Software Foundation, either version 3 of the License, or
     12 (at your option) any later version.
     13 
     14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
     15 but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 GNU General Public License for more details.
     18 
     19 You should have received a copy of the GNU General Public License
     20 along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code.  If not, please request a copy in writing from id Software at the address below.
     23 
     24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
     25 
     26 ===========================================================================
     27 */
     28 #pragma hdrstop
     29 #include "../../idLib/precompiled.h"
     30 #include "../Game_local.h"
     31 
     32 enum browserCommand_t {
     33 	BROWSER_COMMAND_REFRESH_SERVERS,
     34 	BROWSER_COMMAND_SHOW_GAMERTAG,
     35 };
     36 
     37 static const int NUM_SERVER_LIST_ITEMS = 10;
     38 
     39 /*
     40 ================================================
     41 idPair is is a template class Container composed of two objects, which can be of 
     42 any type, and provides accessors to these objects as well as Pair equality operators. The main 
     43 uses of Pairs in the engine are for the Tools and for callbacks.
     44 ================================================
     45 */
     46 template<class T, class U>
     47 class idPair {
     48 public:
     49 	idPair() { }
     50 	idPair( const T& f, const U& s ) : first( f ), second( s ) { }
     51 
     52 	const bool	operator==( const idPair<T,U>& rhs ) const {
     53 		return ( rhs.first == first ) && ( rhs.second == second );
     54 	}
     55 
     56 	const bool	operator!=( const idPair<T,U>& rhs ) const {
     57 		return !(*this == rhs);
     58 	}
     59 
     60 	T first;
     61 	U second;
     62 };
     63 
     64 /*
     65 ================================================
     66 idSort_PlayerGamesList 
     67 ================================================
     68 */
     69 class idSort_PlayerGamesList : public idSort_Quick< idPair< serverInfo_t, int >, idSort_PlayerGamesList > {
     70 public:
     71 	int Compare( const idPair< serverInfo_t, int > & a, const idPair< serverInfo_t, int > & b ) const {
     72 		if ( a.first.joinable == b.first.joinable ) {
     73 			return a.first.gameMode - b.first.gameMode;
     74 		} else if ( a.first.joinable ) {
     75 			return 1;
     76 		} else {
     77 			return -1;
     78 		}
     79 	}
     80 };
     81 
     82 /*
     83 ========================
     84 idMenuScreen_Shell_GameBrowser::Initialize
     85 ========================
     86 */
     87 void idMenuScreen_Shell_GameBrowser::Initialize( idMenuHandler * data ) {
     88 	idMenuScreen::Initialize( data );
     89 
     90 	if ( data != NULL ) {
     91 		menuGUI = data->GetGUI();
     92 	}
     93 
     94 	SetSpritePath( "menuPWF" );
     95 
     96 	listWidget = new idMenuWidget_GameBrowserList();
     97 	listWidget->SetSpritePath( GetSpritePath(), "info", "options" );
     98 	listWidget->SetNumVisibleOptions( NUM_SERVER_LIST_ITEMS );
     99 	listWidget->SetWrappingAllowed( true );
    100 	listWidget->AddEventAction( WIDGET_EVENT_SCROLL_DOWN ).Set( WIDGET_ACTION_START_REPEATER, WIDGET_ACTION_SCROLL_VERTICAL, 1 );
    101 	listWidget->AddEventAction( WIDGET_EVENT_SCROLL_UP ).Set( WIDGET_ACTION_START_REPEATER, WIDGET_ACTION_SCROLL_VERTICAL, -1 );
    102 	listWidget->AddEventAction( WIDGET_EVENT_SCROLL_DOWN_RELEASE ).Set( WIDGET_ACTION_STOP_REPEATER );
    103 	listWidget->AddEventAction( WIDGET_EVENT_SCROLL_UP_RELEASE ).Set( WIDGET_ACTION_STOP_REPEATER );
    104 	listWidget->AddEventAction( WIDGET_EVENT_SCROLL_DOWN_LSTICK ).Set( WIDGET_ACTION_START_REPEATER, WIDGET_ACTION_SCROLL_VERTICAL, 1 );
    105 	listWidget->AddEventAction( WIDGET_EVENT_SCROLL_UP_LSTICK ).Set( WIDGET_ACTION_START_REPEATER, WIDGET_ACTION_SCROLL_VERTICAL, -1 );
    106 	listWidget->AddEventAction( WIDGET_EVENT_SCROLL_DOWN_LSTICK_RELEASE ).Set( WIDGET_ACTION_STOP_REPEATER );
    107 	listWidget->AddEventAction( WIDGET_EVENT_SCROLL_UP_LSTICK_RELEASE ).Set( WIDGET_ACTION_STOP_REPEATER );
    108 	AddChild( listWidget );
    109 	
    110 	idMenuWidget_Help * const helpWidget = new ( TAG_SWF ) idMenuWidget_Help();
    111 	helpWidget->SetSpritePath( GetSpritePath(), "info", "helpTooltip" );
    112 	AddChild( helpWidget );	
    113 
    114 	while ( listWidget->GetChildren().Num() < NUM_SERVER_LIST_ITEMS ) {
    115 		idMenuWidget_ServerButton * buttonWidget = new idMenuWidget_ServerButton;
    116 		buttonWidget->AddEventAction( WIDGET_EVENT_PRESS ).Set( WIDGET_ACTION_PRESS_FOCUSED, listWidget->GetChildren().Num() );
    117 		buttonWidget->SetState( WIDGET_STATE_HIDDEN );
    118 		buttonWidget->RegisterEventObserver( helpWidget );
    119 		listWidget->AddChild( buttonWidget );
    120 	}
    121 
    122 	btnBack = new (TAG_SWF) idMenuWidget_Button();
    123 	btnBack->Initialize( data );
    124 	btnBack->SetLabel( "#str_swf_multiplayer" );
    125 	btnBack->SetSpritePath( GetSpritePath(), "info", "btnBack" );
    126 	btnBack->AddEventAction( WIDGET_EVENT_PRESS ).Set( WIDGET_ACTION_GO_BACK );
    127 	AddChild( btnBack );
    128 }
    129 
    130 /*
    131 ========================
    132 idMenuScreen_Shell_GameBrowser::ShowScreen
    133 ========================
    134 */
    135 void idMenuScreen_Shell_GameBrowser::ShowScreen( const mainMenuTransition_t transitionType ) {
    136 	idMenuHandler_Shell * const mgr = dynamic_cast< idMenuHandler_Shell * >( menuData );
    137 	if ( mgr == NULL ) {
    138 		return;
    139 	}
    140 
    141 	idSWFScriptObject & root = GetSWFObject()->GetRootObject();
    142 	if ( BindSprite( root ) ) {
    143 		idSWFTextInstance * heading = GetSprite()->GetScriptObject()->GetNestedText( "info", "txtHeading" );
    144 		if ( heading != NULL ) {
    145 			heading->SetText( "#str_swf_pwf_heading" );	// MULTIPLAYER
    146 			heading->SetStrokeInfo( true, 0.75f, 1.75f );
    147 		}
    148 
    149 		idSWFSpriteInstance * gradient = GetSprite()->GetScriptObject()->GetNestedSprite( "info", "gradient" );
    150 		if ( gradient != NULL && heading != NULL ) {
    151 			gradient->SetXPos( heading->GetTextLength() );
    152 		}
    153 	}
    154 
    155 	listWidget->ClearGames();
    156 
    157 	if ( mgr->GetCmdBar() != NULL ) {
    158 		idMenuWidget_CommandBar::buttonInfo_t * buttonInfo;
    159 
    160 		mgr->GetCmdBar()->ClearAllButtons();
    161 
    162 		buttonInfo = mgr->GetCmdBar()->GetButton( idMenuWidget_CommandBar::BUTTON_JOY2 );
    163 		if ( menuData->GetPlatform() != 2 ) {
    164 			buttonInfo->label = "#str_00395";
    165 		}
    166 		buttonInfo->action.Set( WIDGET_ACTION_GO_BACK );
    167 
    168 		buttonInfo = mgr->GetCmdBar()->GetButton( idMenuWidget_CommandBar::BUTTON_JOY3 );
    169 		buttonInfo->label = "#str_02276";
    170 		buttonInfo->action.Set( WIDGET_ACTION_COMMAND, BROWSER_COMMAND_REFRESH_SERVERS );
    171 	}
    172 
    173 	mgr->HidePacifier();
    174 
    175 	idMenuScreen::ShowScreen( transitionType );
    176 	UpdateServerList();
    177 }
    178 
    179 /*
    180 ========================
    181 idMenuScreen_Shell_GameBrowser::HideScreen
    182 ========================
    183 */
    184 void idMenuScreen_Shell_GameBrowser::HideScreen( const mainMenuTransition_t transitionType ) {
    185 	idMenuHandler_Shell * const mgr = dynamic_cast< idMenuHandler_Shell * >( menuData );
    186 	if ( mgr == NULL ) {
    187 		return;
    188 	}
    189 
    190 	mgr->HidePacifier();
    191 
    192 	session->CancelListServers();
    193 
    194 	idMenuScreen::HideScreen( transitionType );
    195 }
    196 
    197 /*
    198 ========================
    199 idMenuScreen_Shell_GameBrowser::UpdateServerList
    200 ========================
    201 */
    202 void idMenuScreen_Shell_GameBrowser::UpdateServerList() {
    203 	idMenuHandler_Shell * const mgr = dynamic_cast< idMenuHandler_Shell * >( menuData );
    204 
    205 	if ( mgr == NULL ) {
    206 		return;
    207 	}
    208 
    209 	for ( int i = 0; i < listWidget->GetChildren().Num(); ++i ) {
    210 		idMenuWidget & child = listWidget->GetChildByIndex( i );
    211 		child.SetState( WIDGET_STATE_HIDDEN );
    212 	}
    213 
    214 	// need to show the pacifier before actually making the ListServers call, because it can fail
    215 	// immediately and send back an error result to SWF. Things get confused if the showLoadingPacifier
    216 	// then gets called after that.
    217 	mgr->ShowPacifier( "#str_online_mpstatus_searching" );
    218 
    219 	session->ListServers( MakeCallback( this, &idMenuScreen_Shell_GameBrowser::OnServerListReady ) );
    220 }
    221 
    222 /*
    223 ========================
    224 idMenuScreen_Shell_GameBrowser::OnServerListReady
    225 ========================
    226 */
    227 void idMenuScreen_Shell_GameBrowser::OnServerListReady() {
    228 	idMenuHandler_Shell * const mgr = dynamic_cast< idMenuHandler_Shell * >( menuData );
    229 
    230 	if ( mgr == NULL ) {
    231 		return;
    232 	}
    233 
    234 	mgr->HidePacifier();
    235 
    236 	idList< idPair< serverInfo_t, int > > servers;
    237 	for ( int i = 0; i < session->NumServers(); ++i ) {
    238 		const serverInfo_t * const server = session->ServerInfo( i );
    239 		if ( server != NULL && server->joinable ) {
    240 			idPair< serverInfo_t, int > & serverPair = servers.Alloc();
    241 			serverPair.first = *server;
    242 			serverPair.second = i;
    243 		}
    244 	}
    245 
    246 	servers.SortWithTemplate( idSort_PlayerGamesList() );
    247 
    248 	listWidget->ClearGames();
    249 	for ( int i = 0; i < servers.Num(); ++i ) {
    250 		idPair< serverInfo_t, int > & serverPair = servers[ i ];
    251 		DescribeServer( serverPair.first, serverPair.second );
    252 	}
    253 
    254 	if ( servers.Num() > 0 ) {
    255 		listWidget->Update();
    256 		listWidget->SetViewOffset( 0 );
    257 		listWidget->SetViewIndex( 0 );
    258 		listWidget->SetFocusIndex( 0 );
    259 	} else {
    260 		listWidget->AddGame( "#str_swf_no_servers_found", idStrId(), idStr(), -1, 0, 0, false, false );
    261 		listWidget->Update();
    262 		listWidget->SetViewOffset( 0 );
    263 		listWidget->SetViewIndex( 0 );
    264 		listWidget->SetFocusIndex( 0 );
    265 	}
    266 
    267 	if ( mgr->GetCmdBar() != NULL ) {
    268 		idMenuWidget_CommandBar::buttonInfo_t * buttonInfo;
    269 
    270 		mgr->GetCmdBar()->ClearAllButtons();
    271 
    272 		if ( servers.Num() > 0 ) {
    273 			buttonInfo = mgr->GetCmdBar()->GetButton( idMenuWidget_CommandBar::BUTTON_JOY1 );
    274 			if ( menuData->GetPlatform() != 2 ) {
    275 				buttonInfo->label = "#STR_SWF_SELECT";
    276 			}
    277 			buttonInfo->action.Set( WIDGET_ACTION_PRESS_FOCUSED );
    278 		}
    279 
    280 		buttonInfo = mgr->GetCmdBar()->GetButton( idMenuWidget_CommandBar::BUTTON_JOY2 );
    281 		if ( menuData->GetPlatform() != 2 ) {
    282 			buttonInfo->label = "#str_00395";
    283 		}
    284 		buttonInfo->action.Set( WIDGET_ACTION_GO_BACK );
    285 
    286 		buttonInfo = mgr->GetCmdBar()->GetButton( idMenuWidget_CommandBar::BUTTON_JOY3 );
    287 		buttonInfo->label = "#str_02276";
    288 		buttonInfo->action.Set( WIDGET_ACTION_COMMAND, BROWSER_COMMAND_REFRESH_SERVERS );
    289 
    290 		if ( servers.Num() > 0 ) {
    291 			buttonInfo = mgr->GetCmdBar()->GetButton( idMenuWidget_CommandBar::BUTTON_JOY4 );
    292 			buttonInfo->label = "#str_swf_view_profile";
    293 			buttonInfo->action.Set( WIDGET_ACTION_COMMAND, BROWSER_COMMAND_SHOW_GAMERTAG );
    294 		}
    295 
    296 		mgr->GetCmdBar()->Update();
    297 	}
    298 }
    299 
    300 /*
    301 ========================
    302 idMenuScreen_Shell_GameBrowser::DescribeServers
    303 ========================
    304 */
    305 void idMenuScreen_Shell_GameBrowser::DescribeServer( const serverInfo_t & server, const int index ) {
    306 
    307 	idStr serverName;
    308 	int serverIndex = index;
    309 	bool joinable = false;
    310 	bool validMap = false;
    311 	int players = 0;
    312 	int maxPlayers = 0;
    313 	idStrId mapName;
    314 	idStr modeName;
    315 
    316 	const idList< mpMap_t > maps = common->GetMapList();
    317 	const bool isMapValid = ( server.gameMap >= 0 ) && ( server.gameMap < maps.Num() );
    318 	if ( !isMapValid ) {
    319 		validMap = false;
    320 		serverName = server.serverName;
    321 		mapName = "#str_online_in_lobby";
    322 		modeName = "";
    323 		players = server.numPlayers;
    324 		maxPlayers = server.maxPlayers;
    325 		joinable = server.joinable;
    326 	} else {
    327 		mapName = common->GetMapList()[ server.gameMap ].mapName;
    328 		
    329 		const idStrList & modes = common->GetModeDisplayList();
    330 		idStr mode = idLocalization::GetString( modes[ idMath::ClampInt( 0, modes.Num() - 1, server.gameMode ) ] );
    331 		validMap = true;
    332 		serverName = server.serverName;
    333 		modeName = mode;
    334 		players = server.numPlayers;
    335 		maxPlayers = server.maxPlayers;
    336 		joinable = server.joinable;
    337 	}
    338 
    339 	listWidget->AddGame( serverName, mapName, modeName, serverIndex, players, maxPlayers, joinable, validMap );
    340 }
    341 
    342 /*
    343 ========================
    344 idMenuScreen_Shell_GameBrowser::HandleAction h
    345 ========================
    346 */
    347 bool idMenuScreen_Shell_GameBrowser::HandleAction( idWidgetAction & action, const idWidgetEvent & event, idMenuWidget * widget, bool forceHandle ) {
    348 	idMenuHandler_Shell * const mgr = dynamic_cast< idMenuHandler_Shell * >( menuData );
    349 
    350 	if ( mgr == NULL ) {
    351 		return false;
    352 	}
    353 
    354 	if ( mgr->ActiveScreen() != SHELL_AREA_BROWSER ) {
    355 		return false;
    356 	}
    357 
    358 	widgetAction_t actionType = action.GetType();
    359 	const idSWFParmList & parms = action.GetParms();
    360 
    361 	switch ( actionType ) {
    362 		case WIDGET_ACTION_GO_BACK: {
    363 			menuData->SetNextScreen( SHELL_AREA_PARTY_LOBBY, MENU_TRANSITION_SIMPLE );
    364 			return true;
    365 		}
    366 		case WIDGET_ACTION_COMMAND: {
    367 			switch ( parms[ 0 ].ToInteger() ) {
    368 				case BROWSER_COMMAND_REFRESH_SERVERS: {
    369 					UpdateServerList();
    370 					break;
    371 				}
    372 				case BROWSER_COMMAND_SHOW_GAMERTAG: {
    373 					int index = listWidget->GetServerIndex();
    374 					if ( index != -1 ) {
    375 						session->ShowServerGamerCardUI( index );
    376 					}
    377 					break;
    378 				}
    379 			}
    380 			return true;
    381 		}
    382 		case WIDGET_ACTION_PRESS_FOCUSED: {
    383 			int selectionIndex = listWidget->GetFocusIndex();
    384 			if ( parms.Num() > 0 ) {
    385 				selectionIndex = parms[0].ToInteger();
    386 			}
    387 
    388 			if ( selectionIndex != listWidget->GetFocusIndex() ) {
    389 				listWidget->SetViewIndex( listWidget->GetViewOffset() + selectionIndex );
    390 				listWidget->SetFocusIndex( selectionIndex );
    391 				return true;
    392 			}
    393 
    394 			int index = listWidget->GetServerIndex();
    395 			if ( index != -1 ) {
    396 				session->ConnectToServer( index );
    397 			}
    398 			return true;
    399 		}
    400 	}
    401 
    402 	return idMenuScreen::HandleAction( action, event, widget, forceHandle );
    403 }