Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

446 lines
12 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include <vgui/ILocalize.h>
  8. #include "vgui_controls/TextEntry.h"
  9. #include "select_player_dialog.h"
  10. #include "tf_controls.h"
  11. #include "c_playerresource.h"
  12. #include "ienginevgui.h"
  13. // memdbgon must be the last include file in a .cpp file!!!
  14. #include <tier0/memdbgon.h>
  15. int CSelectPlayerDialog::SortPartnerInfoFunc( const partner_info_t *pA, const partner_info_t *pB )
  16. {
  17. return Q_stricmp( pA->m_name.Get(), pB->m_name.Get() );
  18. }
  19. //-----------------------------------------------------------------------------
  20. // Purpose:
  21. //-----------------------------------------------------------------------------
  22. CSelectPlayerDialog::CSelectPlayerDialog( vgui::Panel *parent )
  23. : vgui::EditablePanel( parent, "SelectPlayerDialog" )
  24. , m_bAllowSameTeam( true )
  25. , m_bAllowOutsideServer( true )
  26. {
  27. if ( parent == NULL )
  28. {
  29. vgui::HScheme scheme = vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/ClientScheme.res", "ClientScheme");
  30. SetScheme(scheme);
  31. SetProportional( true );
  32. }
  33. m_pSelectFromServerButton = NULL;
  34. m_pCancelButton = NULL;
  35. m_pButtonKV = NULL;
  36. m_bReapplyButtonKVs = false;
  37. for ( int i = 0; i < SPDS_NUM_STATES; i++ )
  38. {
  39. m_pStatePanels[i] = new vgui::EditablePanel( this, VarArgs("StatePanel%d",i) );
  40. }
  41. m_pPlayerList = new vgui::EditablePanel( this, "PlayerList" );
  42. m_pPlayerListScroller = new vgui::ScrollableEditablePanel( this, m_pPlayerList, "PlayerListScroller" );
  43. m_iCurrentState = SPDS_SELECTING_PLAYER;
  44. }
  45. //-----------------------------------------------------------------------------
  46. // Purpose:
  47. //-----------------------------------------------------------------------------
  48. CSelectPlayerDialog::~CSelectPlayerDialog( void )
  49. {
  50. if ( m_pButtonKV )
  51. {
  52. m_pButtonKV->deleteThis();
  53. m_pButtonKV = NULL;
  54. }
  55. }
  56. //-----------------------------------------------------------------------------
  57. // Purpose:
  58. //-----------------------------------------------------------------------------
  59. void CSelectPlayerDialog::Reset( void )
  60. {
  61. m_iCurrentState = SPDS_SELECTING_PLAYER;
  62. }
  63. //-----------------------------------------------------------------------------
  64. // Purpose:
  65. //-----------------------------------------------------------------------------
  66. void CSelectPlayerDialog::ApplySettings( KeyValues *inResourceData )
  67. {
  68. BaseClass::ApplySettings( inResourceData );
  69. KeyValues *pItemKV = inResourceData->FindKey( "button_kv" );
  70. if ( pItemKV )
  71. {
  72. if ( m_pButtonKV )
  73. {
  74. m_pButtonKV->deleteThis();
  75. }
  76. m_pButtonKV = new KeyValues("button_kv");
  77. pItemKV->CopySubkeys( m_pButtonKV );
  78. m_bReapplyButtonKVs = true;
  79. }
  80. }
  81. //-----------------------------------------------------------------------------
  82. // Purpose:
  83. //-----------------------------------------------------------------------------
  84. void CSelectPlayerDialog::ApplySchemeSettings( vgui::IScheme *pScheme )
  85. {
  86. BaseClass::ApplySchemeSettings( pScheme );
  87. LoadControlSettings( GetResFile() );
  88. m_pCancelButton = dynamic_cast<CExButton*>( FindChildByName( "CancelButton" ) );
  89. // Find all the sub buttons, and set their action signals to point to this panel
  90. for ( int i = 0; i < SPDS_NUM_STATES; i++ )
  91. {
  92. int iButton = 0;
  93. CExButton *pButton = NULL;
  94. do
  95. {
  96. pButton = dynamic_cast<CExButton*>( m_pStatePanels[i]->FindChildByName( VarArgs("subbutton%d",iButton)) );
  97. if ( pButton )
  98. {
  99. pButton->AddActionSignalTarget( this );
  100. // The second button on the first state is the server button
  101. if ( iButton == 1 )
  102. {
  103. m_pSelectFromServerButton = pButton;
  104. }
  105. iButton++;
  106. }
  107. } while (pButton);
  108. }
  109. UpdateState();
  110. }
  111. //-----------------------------------------------------------------------------
  112. // Purpose:
  113. //-----------------------------------------------------------------------------
  114. void CSelectPlayerDialog::PerformLayout( void )
  115. {
  116. BaseClass::PerformLayout();
  117. // Layout the player list buttons
  118. if ( m_pPlayerPanels.Count() )
  119. {
  120. int iButtonH = m_pPlayerPanels[0]->GetTall() + YRES(2);
  121. m_pPlayerList->SetSize( m_pPlayerList->GetWide(), YRES(2) + (iButtonH * m_pPlayerPanels.Count()) );
  122. // These need to all be layout-complete before we can position the player panels,
  123. // because the scrollbar will cause the playerlist entries to move when it lays out.
  124. m_pPlayerList->InvalidateLayout( true );
  125. m_pPlayerListScroller->InvalidateLayout( true );
  126. m_pPlayerListScroller->GetScrollbar()->InvalidateLayout( true );
  127. for ( int i = 0; i < m_pPlayerPanels.Count(); i++ )
  128. {
  129. m_pPlayerPanels[i]->SetPos( 0, YRES(2) + (iButtonH * i) );
  130. }
  131. }
  132. }
  133. //-----------------------------------------------------------------------------
  134. // Purpose:
  135. //-----------------------------------------------------------------------------
  136. void CSelectPlayerDialog::OnCommand( const char *command )
  137. {
  138. if ( !Q_stricmp( command, "cancel" ) )
  139. {
  140. if ( m_iCurrentState != SPDS_SELECTING_PLAYER )
  141. {
  142. m_iCurrentState = SPDS_SELECTING_PLAYER;
  143. UpdateState();
  144. return;
  145. }
  146. TFModalStack()->PopModal( this );
  147. SetVisible( false );
  148. MarkForDeletion();
  149. if ( GetParent() )
  150. {
  151. PostMessage( GetParent(), new KeyValues("CancelSelection") );
  152. }
  153. return;
  154. }
  155. else if ( !Q_stricmp( command, "friends" ) )
  156. {
  157. m_iCurrentState = SPDS_SELECTING_FROM_FRIENDS;
  158. UpdateState();
  159. return;
  160. }
  161. else if ( !Q_stricmp( command, "server" ) )
  162. {
  163. m_iCurrentState = SPDS_SELECTING_FROM_SERVER;
  164. UpdateState();
  165. return;
  166. }
  167. else if ( !Q_strnicmp( command, "select_player", 13 ) )
  168. {
  169. int iPlayer = atoi( command + 13 ) - 1;
  170. if ( iPlayer >= 0 && iPlayer < m_PlayerInfoList.Count() )
  171. {
  172. m_iCurrentState = SPDS_SELECTING_PLAYER;
  173. OnCommand( "cancel" );
  174. OnSelectPlayer( m_PlayerInfoList[iPlayer].m_steamID );
  175. }
  176. return;
  177. }
  178. BaseClass::OnCommand( command );
  179. }
  180. //-----------------------------------------------------------------------------
  181. // Purpose:
  182. //-----------------------------------------------------------------------------
  183. void CSelectPlayerDialog::UpdateState( void )
  184. {
  185. for ( int i = 0; i < SPDS_NUM_STATES; i++ )
  186. {
  187. if ( !m_pStatePanels[i] )
  188. continue;
  189. m_pStatePanels[i]->SetVisible( m_iCurrentState == i );
  190. }
  191. if ( m_pSelectFromServerButton )
  192. {
  193. m_pSelectFromServerButton->SetEnabled( engine->IsInGame() );
  194. }
  195. if ( m_iCurrentState == SPDS_SELECTING_PLAYER )
  196. {
  197. m_pCancelButton->SetText( g_pVGuiLocalize->Find( "#Cancel" ) );
  198. }
  199. else
  200. {
  201. m_pCancelButton->SetText( g_pVGuiLocalize->Find( "#TF_Back" ) );
  202. }
  203. switch ( m_iCurrentState )
  204. {
  205. case SPDS_SELECTING_FROM_FRIENDS:
  206. SetupSelectFriends();
  207. break;
  208. case SPDS_SELECTING_FROM_SERVER:
  209. SetupSelectServer( false );
  210. break;
  211. case SPDS_SELECTING_PLAYER:
  212. default:
  213. m_pPlayerListScroller->SetVisible( false );
  214. break;
  215. }
  216. }
  217. //-----------------------------------------------------------------------------
  218. // Purpose:
  219. //-----------------------------------------------------------------------------
  220. void CSelectPlayerDialog::SetupSelectFriends( void )
  221. {
  222. // @todo optional check to see if friend is on my server
  223. if ( m_bAllowOutsideServer == false )
  224. {
  225. SetupSelectServer( true );
  226. return;
  227. }
  228. m_PlayerInfoList.Purge();
  229. if ( steamapicontext && steamapicontext->SteamFriends() )
  230. {
  231. // Get our game info so we can use that to test if our friends are connected to the same game as us
  232. FriendGameInfo_t myGameInfo;
  233. CSteamID mySteamID = steamapicontext->SteamUser()->GetSteamID();
  234. steamapicontext->SteamFriends()->GetFriendGamePlayed( mySteamID, &myGameInfo );
  235. int iFriends = steamapicontext->SteamFriends()->GetFriendCount( k_EFriendFlagImmediate );
  236. for ( int i = 0; i < iFriends; i++ )
  237. {
  238. CSteamID friendSteamID = steamapicontext->SteamFriends()->GetFriendByIndex( i, k_EFriendFlagImmediate );
  239. FriendGameInfo_t gameInfo;
  240. if ( !AllowOutOfGameFriends() && !steamapicontext->SteamFriends()->GetFriendGamePlayed( friendSteamID, &gameInfo ) )
  241. continue;
  242. // Friends is in-game. Make sure it's TF2.
  243. if ( AllowOutOfGameFriends() || (gameInfo.m_gameID.IsValid() && gameInfo.m_gameID == myGameInfo.m_gameID) )
  244. {
  245. const char *pszName = steamapicontext->SteamFriends()->GetFriendPersonaName( friendSteamID );
  246. int idx = m_PlayerInfoList.AddToTail();
  247. partner_info_t &info = m_PlayerInfoList[idx];
  248. info.m_steamID = friendSteamID;
  249. info.m_name = pszName;
  250. }
  251. }
  252. }
  253. UpdatePlayerList();
  254. }
  255. //-----------------------------------------------------------------------------
  256. // Purpose:
  257. //-----------------------------------------------------------------------------
  258. void CSelectPlayerDialog::SetupSelectServer( bool bFriendsOnly )
  259. {
  260. m_PlayerInfoList.Purge();
  261. if ( steamapicontext && steamapicontext->SteamUtils() )
  262. {
  263. for( int iPlayerIndex = 1 ; iPlayerIndex <= MAX_PLAYERS; iPlayerIndex++ )
  264. {
  265. // find all players who are on the local player's team
  266. int iLocalPlayerIndex = GetLocalPlayerIndex();
  267. if( ( iPlayerIndex != iLocalPlayerIndex ) && ( g_PR->IsConnected( iPlayerIndex ) ) )
  268. {
  269. player_info_t pi;
  270. if ( !engine->GetPlayerInfo( iPlayerIndex, &pi ) )
  271. continue;
  272. if ( !pi.friendsID )
  273. continue;
  274. CSteamID steamID( pi.friendsID, 1, GetUniverse(), k_EAccountTypeIndividual );
  275. if ( bFriendsOnly )
  276. {
  277. EFriendRelationship eRelationship = steamapicontext->SteamFriends()->GetFriendRelationship( steamID );
  278. if ( eRelationship != k_EFriendRelationshipFriend )
  279. {
  280. continue;
  281. }
  282. }
  283. if ( g_PR->GetTeam( iPlayerIndex ) != TF_TEAM_RED && g_PR->GetTeam( iPlayerIndex ) != TF_TEAM_BLUE )
  284. continue;
  285. if ( m_bAllowSameTeam == false )
  286. {
  287. if ( GetLocalPlayerTeam() == g_PR->GetTeam( iPlayerIndex ) )
  288. {
  289. continue;
  290. }
  291. }
  292. int idx = m_PlayerInfoList.AddToTail();
  293. partner_info_t &info = m_PlayerInfoList[idx];
  294. info.m_steamID = steamID;
  295. info.m_name = pi.name;
  296. }
  297. }
  298. }
  299. UpdatePlayerList();
  300. }
  301. //-----------------------------------------------------------------------------
  302. // Purpose:
  303. //-----------------------------------------------------------------------------
  304. void CSelectPlayerDialog::UpdatePlayerList( void )
  305. {
  306. vgui::Label *pLabelEmpty = dynamic_cast<vgui::Label*>( m_pStatePanels[m_iCurrentState]->FindChildByName("EmptyPlayerListLabel") );
  307. vgui::Label *pLabelQuery = dynamic_cast<vgui::Label*>( m_pStatePanels[m_iCurrentState]->FindChildByName("QueryLabel") );
  308. // If we have no players in our list, show the no-player label.
  309. if ( m_PlayerInfoList.Count() == 0 )
  310. {
  311. if ( pLabelEmpty )
  312. {
  313. pLabelEmpty->SetVisible( true );
  314. }
  315. if ( pLabelQuery )
  316. {
  317. pLabelQuery->SetVisible( false );
  318. }
  319. return;
  320. }
  321. // First, reapply any KVs we have to reapply
  322. if ( m_bReapplyButtonKVs )
  323. {
  324. m_bReapplyButtonKVs = false;
  325. if ( m_pButtonKV )
  326. {
  327. FOR_EACH_VEC( m_pPlayerPanels, i )
  328. {
  329. m_pPlayerPanels[i]->ApplySettings( m_pButtonKV );
  330. }
  331. }
  332. }
  333. // sort by name
  334. m_PlayerInfoList.Sort( &SortPartnerInfoFunc );
  335. // Otherwise, build the player panels from the list of steam IDs
  336. for ( int i = 0; i < m_PlayerInfoList.Count(); i++ )
  337. {
  338. if ( m_pPlayerPanels.Count() <= i )
  339. {
  340. m_pPlayerPanels.AddToTail();
  341. m_pPlayerPanels[i] = new CSelectPlayerTargetPanel( m_pPlayerList, VarArgs("player%d",i) );
  342. m_pPlayerPanels[i]->GetButton()->SetCommand( VarArgs("select_player%d",i+1) );
  343. m_pPlayerPanels[i]->GetButton()->AddActionSignalTarget( this );
  344. m_pPlayerPanels[i]->GetAvatar()->SetShouldDrawFriendIcon( false );
  345. m_pPlayerPanels[i]->GetAvatar()->SetMouseInputEnabled( false );
  346. if ( m_pButtonKV )
  347. {
  348. m_pPlayerPanels[i]->ApplySettings( m_pButtonKV );
  349. m_pPlayerPanels[i]->InvalidateLayout( true );
  350. }
  351. }
  352. m_pPlayerPanels[i]->SetInfo( m_PlayerInfoList[i].m_steamID, m_PlayerInfoList[i].m_name );
  353. }
  354. m_pPlayerListScroller->GetScrollbar()->SetAutohideButtons( true );
  355. m_pPlayerListScroller->GetScrollbar()->SetValue( 0 );
  356. // Remove any extra player panels
  357. for ( int i = m_pPlayerPanels.Count()-1; i >= m_PlayerInfoList.Count(); i-- )
  358. {
  359. m_pPlayerPanels[i]->MarkForDeletion();
  360. m_pPlayerPanels.Remove(i);
  361. }
  362. if ( pLabelEmpty )
  363. {
  364. pLabelEmpty->SetVisible( false );
  365. }
  366. if ( pLabelQuery )
  367. {
  368. pLabelQuery->SetVisible( true );
  369. }
  370. m_pPlayerListScroller->SetVisible( true );
  371. InvalidateLayout();
  372. }
  373. //-----------------------------------------------------------------------------
  374. // Purpose:
  375. //-----------------------------------------------------------------------------
  376. void CSelectPlayerTargetPanel::SetInfo( const CSteamID &steamID, const char *pszName )
  377. {
  378. if ( !steamapicontext || !steamapicontext->SteamFriends() )
  379. return;
  380. m_pAvatar->SetPlayer( steamID, k_EAvatarSize64x64 );
  381. m_pButton->SetText( pszName );
  382. }