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 }